Skip to content

Commit f4df3aa

Browse files
committed
py: Allow bytecode/native to put iter_buf on stack for simple for loops.
So that the "for x in it: ..." statement can now work without using the heap (so long as the iterator argument fits in an iter_buf structure).
1 parent ae8d867 commit f4df3aa

9 files changed

Lines changed: 57 additions & 19 deletions

File tree

py/bc0.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
#define MP_BC_POP_BLOCK (0x44)
8080
#define MP_BC_POP_EXCEPT (0x45)
8181
#define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte
82+
#define MP_BC_GET_ITER_STACK (0x47)
8283

8384
#define MP_BC_BUILD_TUPLE (0x50) // uint
8485
#define MP_BC_BUILD_LIST (0x51) // uint

py/compile.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,7 +1475,7 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
14751475
uint pop_label = comp_next_label(comp);
14761476

14771477
compile_node(comp, pns->nodes[1]); // iterator
1478-
EMIT(get_iter);
1478+
EMIT_ARG(get_iter, true);
14791479
EMIT_ARG(label_assign, continue_label);
14801480
EMIT_ARG(for_iter, pop_label);
14811481
c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable
@@ -1484,7 +1484,7 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
14841484
EMIT_ARG(jump, continue_label);
14851485
}
14861486
EMIT_ARG(label_assign, pop_label);
1487-
EMIT(for_iter_end);
1487+
EMIT_ARG(for_iter_end, true);
14881488

14891489
// break/continue apply to outer loop (if any) in the else block
14901490
END_BREAK_CONTINUE_BLOCK
@@ -1680,7 +1680,7 @@ STATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
16801680
}
16811681

16821682
STATIC void compile_yield_from(compiler_t *comp) {
1683-
EMIT(get_iter);
1683+
EMIT_ARG(get_iter, false);
16841684
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
16851685
EMIT(yield_from);
16861686
}
@@ -2372,7 +2372,7 @@ STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns,
23722372
close_over_variables_etc(comp, this_scope, 0, 0);
23732373

23742374
compile_node(comp, pns_comp_for->nodes[1]); // source of the iterator
2375-
EMIT(get_iter);
2375+
EMIT_ARG(get_iter, false);
23762376
EMIT_ARG(call_function, 1, 0, 0);
23772377
}
23782378

@@ -2900,13 +2900,13 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_struct_t *pn
29002900
// for loop
29012901
mp_parse_node_struct_t *pns_comp_for2 = (mp_parse_node_struct_t*)pn_iter;
29022902
compile_node(comp, pns_comp_for2->nodes[1]);
2903-
EMIT(get_iter);
2903+
EMIT_ARG(get_iter, false);
29042904
compile_scope_comp_iter(comp, pns_comp_for2, pn_inner_expr, for_depth + 1);
29052905
}
29062906

29072907
EMIT_ARG(jump, l_top);
29082908
EMIT_ARG(label_assign, l_end);
2909-
EMIT(for_iter_end);
2909+
EMIT_ARG(for_iter_end, false);
29102910
}
29112911

29122912
STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) {

py/emit.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ typedef struct _emit_method_table_t {
110110
void (*setup_except)(emit_t *emit, mp_uint_t label);
111111
void (*setup_finally)(emit_t *emit, mp_uint_t label);
112112
void (*end_finally)(emit_t *emit);
113-
void (*get_iter)(emit_t *emit);
113+
void (*get_iter)(emit_t *emit, bool use_stack);
114114
void (*for_iter)(emit_t *emit, mp_uint_t label);
115-
void (*for_iter_end)(emit_t *emit);
115+
void (*for_iter_end)(emit_t *emit, bool use_stack);
116116
void (*pop_block)(emit_t *emit);
117117
void (*pop_except)(emit_t *emit);
118118
void (*unary_op)(emit_t *emit, mp_unary_op_t op);
@@ -228,9 +228,9 @@ void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label);
228228
void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label);
229229
void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label);
230230
void mp_emit_bc_end_finally(emit_t *emit);
231-
void mp_emit_bc_get_iter(emit_t *emit);
231+
void mp_emit_bc_get_iter(emit_t *emit, bool use_stack);
232232
void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label);
233-
void mp_emit_bc_for_iter_end(emit_t *emit);
233+
void mp_emit_bc_for_iter_end(emit_t *emit, bool use_stack);
234234
void mp_emit_bc_pop_block(emit_t *emit);
235235
void mp_emit_bc_pop_except(emit_t *emit);
236236
void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op);

py/emitbc.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,10 @@ void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_dept
734734
if (label & MP_EMIT_BREAK_FROM_FOR) {
735735
// need to pop the iterator if we are breaking out of a for loop
736736
emit_write_bytecode_byte(emit, MP_BC_POP_TOP);
737+
// also pop the iter_buf
738+
for (size_t i = 0; i < sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t); ++i) {
739+
emit_write_bytecode_byte(emit, MP_BC_POP_TOP);
740+
}
737741
}
738742
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
739743
} else {
@@ -773,18 +777,23 @@ void mp_emit_bc_end_finally(emit_t *emit) {
773777
emit_write_bytecode_byte(emit, MP_BC_END_FINALLY);
774778
}
775779

776-
void mp_emit_bc_get_iter(emit_t *emit) {
777-
emit_bc_pre(emit, 0);
778-
emit_write_bytecode_byte(emit, MP_BC_GET_ITER);
780+
void mp_emit_bc_get_iter(emit_t *emit, bool use_stack) {
781+
emit_bc_pre(emit, use_stack ? sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t) : 0);
782+
emit_write_bytecode_byte(emit, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER);
779783
}
780784

781785
void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) {
782786
emit_bc_pre(emit, 1);
783787
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_FOR_ITER, label);
784788
}
785789

786-
void mp_emit_bc_for_iter_end(emit_t *emit) {
790+
void mp_emit_bc_for_iter_end(emit_t *emit, bool use_stack) {
787791
emit_bc_pre(emit, -1);
792+
if (use_stack) {
793+
for (size_t i = 0; i < sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t); ++i) {
794+
mp_emit_bc_pop_top(emit);
795+
}
796+
}
788797
}
789798

790799
void mp_emit_bc_pop_block(emit_t *emit) {

py/emitnative.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,14 +1799,19 @@ STATIC void emit_native_end_finally(emit_t *emit) {
17991799
emit_post(emit);
18001800
}
18011801

1802-
STATIC void emit_native_get_iter(emit_t *emit) {
1802+
STATIC void emit_native_get_iter(emit_t *emit, bool use_stack) {
18031803
// perhaps the difficult one, as we want to rewrite for loops using native code
18041804
// in cases where we iterate over a Python object, can we use normal runtime calls?
18051805

18061806
vtype_kind_t vtype;
18071807
emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
18081808
assert(vtype == VTYPE_PYOBJ);
1809-
assert(0); // TODO allocate memory for iter_buf
1809+
if (use_stack) {
1810+
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t));
1811+
} else {
1812+
// mp_getiter will allocate the iter_buf on the heap
1813+
ASM_MOV_IMM_TO_REG(emit->as, 0, REG_ARG_2);
1814+
}
18101815
emit_call(emit, MP_F_GETITER);
18111816
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
18121817
}
@@ -1822,10 +1827,13 @@ STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) {
18221827
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
18231828
}
18241829

1825-
STATIC void emit_native_for_iter_end(emit_t *emit) {
1830+
STATIC void emit_native_for_iter_end(emit_t *emit, bool use_stack) {
18261831
// adjust stack counter (we get here from for_iter ending, which popped the value for us)
18271832
emit_native_pre(emit);
18281833
adjust_stack(emit, -1);
1834+
if (use_stack) {
1835+
adjust_stack(emit, -(sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t)));
1836+
}
18291837
emit_post(emit);
18301838
}
18311839

py/showbc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,10 @@ const byte *mp_bytecode_print_str(const byte *ip) {
387387
printf("GET_ITER");
388388
break;
389389

390+
case MP_BC_GET_ITER_STACK:
391+
printf("GET_ITER_STACK");
392+
break;
393+
390394
case MP_BC_FOR_ITER:
391395
DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward
392396
printf("FOR_ITER " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));

py/vm.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,9 @@ unwind_jump:;
681681
}
682682
ip = (const byte*)MP_OBJ_TO_PTR(POP()); // pop destination ip for jump
683683
if (unum != 0) {
684+
// pop iter and iter_buf
684685
sp--;
686+
sp -= sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t);
685687
}
686688
DISPATCH_WITH_PEND_EXC_CHECK();
687689
}
@@ -726,6 +728,15 @@ unwind_jump:;
726728
SET_TOP(mp_getiter(TOP(), NULL));
727729
DISPATCH();
728730

731+
ENTRY(MP_BC_GET_ITER_STACK): {
732+
MARK_EXC_IP_SELECTIVE();
733+
mp_obj_t obj = TOP();
734+
mp_obj_iter_buf_t *iter_buf = (mp_obj_iter_buf_t*)sp;
735+
sp += sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t);
736+
SET_TOP(mp_getiter(obj, iter_buf));
737+
DISPATCH();
738+
}
739+
729740
ENTRY(MP_BC_FOR_ITER): {
730741
MARK_EXC_IP_SELECTIVE();
731742
DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward

py/vmentrytable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ static const void *const entry_table[256] = {
7373
[MP_BC_SETUP_FINALLY] = &&entry_MP_BC_SETUP_FINALLY,
7474
[MP_BC_END_FINALLY] = &&entry_MP_BC_END_FINALLY,
7575
[MP_BC_GET_ITER] = &&entry_MP_BC_GET_ITER,
76+
[MP_BC_GET_ITER_STACK] = &&entry_MP_BC_GET_ITER_STACK,
7677
[MP_BC_FOR_ITER] = &&entry_MP_BC_FOR_ITER,
7778
[MP_BC_POP_BLOCK] = &&entry_MP_BC_POP_BLOCK,
7879
[MP_BC_POP_EXCEPT] = &&entry_MP_BC_POP_EXCEPT,

tests/cmdline/cmd_showbc.py.exp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ byt
3131
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
3232
########
3333
\.\+rg names:
34-
(N_STATE 22)
34+
(N_STATE 23)
3535
(N_EXC_STACK 2)
3636
(INIT_CELL 14)
3737
(INIT_CELL 15)
@@ -245,12 +245,16 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
245245
\\d\+ LOAD_FAST 0
246246
\\d\+ STORE_FAST 0
247247
\\d\+ LOAD_DEREF 14
248-
\\d\+ GET_ITER
248+
\\d\+ GET_ITER_STACK
249249
\\d\+ FOR_ITER \\d\+
250250
\\d\+ STORE_FAST 0
251251
\\d\+ LOAD_FAST 1
252252
\\d\+ POP_TOP
253253
\\d\+ JUMP \\d\+
254+
\\d\+ POP_TOP
255+
\\d\+ POP_TOP
256+
\\d\+ POP_TOP
257+
\\d\+ POP_TOP
254258
\\d\+ SETUP_FINALLY \\d\+
255259
\\d\+ SETUP_EXCEPT \\d\+
256260
\\d\+ JUMP \\d\+

0 commit comments

Comments
 (0)