Skip to content

Commit 8b65d69

Browse files
committed
py/obj: Add new type flag to indicate subscr accepts slice-on-stack.
Fixes issue #17733. Signed-off-by: Damien George <damien@micropython.org>
1 parent 17fbc5a commit 8b65d69

File tree

4 files changed

+28
-4
lines changed

4 files changed

+28
-4
lines changed

py/obj.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,8 @@ typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *);
554554
// If MP_TYPE_FLAG_ITER_IS_STREAM is set then the type implicitly gets a "return self"
555555
// getiter, and mp_stream_unbuffered_iter for iternext.
556556
// If MP_TYPE_FLAG_INSTANCE_TYPE is set then this is an instance type (i.e. defined in Python).
557+
// If MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE is set then the "subscr" slot allows a stack
558+
// allocated slice to be passed in (no references to it will be retained after the call).
557559
#define MP_TYPE_FLAG_NONE (0x0000)
558560
#define MP_TYPE_FLAG_IS_SUBCLASSED (0x0001)
559561
#define MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002)
@@ -567,6 +569,7 @@ typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *);
567569
#define MP_TYPE_FLAG_ITER_IS_CUSTOM (0x0100)
568570
#define MP_TYPE_FLAG_ITER_IS_STREAM (MP_TYPE_FLAG_ITER_IS_ITERNEXT | MP_TYPE_FLAG_ITER_IS_CUSTOM)
569571
#define MP_TYPE_FLAG_INSTANCE_TYPE (0x0200)
572+
#define MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE (0x0400)
570573

571574
typedef enum {
572575
PRINT_STR = 0,

py/objarray.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
626626
MP_DEFINE_CONST_OBJ_TYPE(
627627
mp_type_bytearray,
628628
MP_QSTR_bytearray,
629-
MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER,
629+
MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER | MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE,
630630
make_new, bytearray_make_new,
631631
print, array_print,
632632
iter, array_iterator_new,
@@ -654,7 +654,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
654654
MP_DEFINE_CONST_OBJ_TYPE(
655655
mp_type_memoryview,
656656
MP_QSTR_memoryview,
657-
MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER,
657+
MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER | MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE,
658658
make_new, memoryview_make_new,
659659
iter, array_iterator_new,
660660
unary_op, array_unary_op,

py/vm.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -865,9 +865,10 @@ unwind_jump:;
865865
// 3-argument slice includes step
866866
step = POP();
867867
}
868-
if ((*ip == MP_BC_LOAD_SUBSCR || *ip == MP_BC_STORE_SUBSCR) && mp_obj_is_native_type(mp_obj_get_type(sp[-2]))) {
868+
if ((*ip == MP_BC_LOAD_SUBSCR || *ip == MP_BC_STORE_SUBSCR)
869+
&& (mp_obj_get_type(sp[-2])->flags & MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE)) {
869870
// Fast path optimisation for when the BUILD_SLICE is immediately followed
870-
// by a LOAD/STORE_SUBSCR for a native type to avoid needing to allocate
871+
// by a LOAD/STORE_SUBSCR for an accepting type, to avoid needing to allocate
871872
// the slice on the heap. In some cases (e.g. a[1:3] = x) this can result
872873
// in no allocations at all. We can't do this for instance types because
873874
// the get/set/delattr implementation may keep a reference to the slice.

tests/basics/slice_optimse.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# test that the slice-on-stack optimisation does not break various uses of slice
2+
# (see MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE type option)
3+
4+
try:
5+
from collections import OrderedDict
6+
except ImportError:
7+
print("SKIP")
8+
raise SystemExit
9+
10+
# attempt to index with a slice, error should contain the slice (failed key)
11+
try:
12+
dict()[:]
13+
except KeyError as e:
14+
print("KeyError", e.args)
15+
16+
# put a slice and another object into an OrderedDict, and retrieve them
17+
x = OrderedDict()
18+
x[:"a"] = 1
19+
x["b"] = 2
20+
print(list(x.keys()), list(x.values()))

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy