diff --git a/py/bc.c b/py/bc.c index b98df39e28..2a21ffd4b7 100644 --- a/py/bc.c +++ b/py/bc.c @@ -335,7 +335,11 @@ uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) } } } else if (f == MP_BC_FORMAT_OFFSET) { - ip += 2; + if ((*ip & 0x80) == 0) { + ip += 1; + } else { + ip += 2; + } } ip += extra_byte; } diff --git a/py/bc0.h b/py/bc0.h index 842034ebfb..50c4954b08 100644 --- a/py/bc0.h +++ b/py/bc0.h @@ -28,6 +28,18 @@ // MicroPython bytecode opcodes, grouped based on the format of the opcode +// All opcodes are encoded as a byte with an optional argument. Arguments are +// variable-length encoded so they can be as small as possible. The possible +// encodings for arguments are (ip[0] is the opcode): +// +// - unsigned relative bytecode offset: +// - if ip[1] high bit is clear then: arg = ip[1] +// - if ip[1] high bit is set then: arg = ip[1] & 0x7f | ip[2] << 7 +// +// - signed relative bytecode offset: +// - if ip[1] high bit is clear then: arg = ip[1] - 0x40 +// - if ip[1] high bit is set then: arg = (ip[1] & 0x7f | ip[2] << 7) - 0x4000 + #define MP_BC_MASK_FORMAT (0xf0) #define MP_BC_MASK_EXTRA_BYTE (0x9e) @@ -101,17 +113,17 @@ #define MP_BC_ROT_TWO (MP_BC_BASE_BYTE_O + 0x0a) #define MP_BC_ROT_THREE (MP_BC_BASE_BYTE_O + 0x0b) -#define MP_BC_JUMP (MP_BC_BASE_JUMP_E + 0x02) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_POP_JUMP_IF_TRUE (MP_BC_BASE_JUMP_E + 0x03) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_POP_JUMP_IF_FALSE (MP_BC_BASE_JUMP_E + 0x04) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_JUMP_IF_TRUE_OR_POP (MP_BC_BASE_JUMP_E + 0x05) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_JUMP_IF_FALSE_OR_POP (MP_BC_BASE_JUMP_E + 0x06) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_UNWIND_JUMP (MP_BC_BASE_JUMP_E + 0x00) // rel byte code offset, 16-bit signed, in excess; then a byte -#define MP_BC_SETUP_WITH (MP_BC_BASE_JUMP_E + 0x07) // rel byte code offset, 16-bit unsigned -#define MP_BC_SETUP_EXCEPT (MP_BC_BASE_JUMP_E + 0x08) // rel byte code offset, 16-bit unsigned -#define MP_BC_SETUP_FINALLY (MP_BC_BASE_JUMP_E + 0x09) // rel byte code offset, 16-bit unsigned -#define MP_BC_POP_EXCEPT_JUMP (MP_BC_BASE_JUMP_E + 0x0a) // rel byte code offset, 16-bit unsigned -#define MP_BC_FOR_ITER (MP_BC_BASE_JUMP_E + 0x0b) // rel byte code offset, 16-bit unsigned +#define MP_BC_UNWIND_JUMP (MP_BC_BASE_JUMP_E + 0x00) // signed relative bytecode offset; then a byte +#define MP_BC_JUMP (MP_BC_BASE_JUMP_E + 0x02) // signed relative bytecode offset +#define MP_BC_POP_JUMP_IF_TRUE (MP_BC_BASE_JUMP_E + 0x03) // signed relative bytecode offset +#define MP_BC_POP_JUMP_IF_FALSE (MP_BC_BASE_JUMP_E + 0x04) // signed relative bytecode offset +#define MP_BC_JUMP_IF_TRUE_OR_POP (MP_BC_BASE_JUMP_E + 0x05) // signed relative bytecode offset +#define MP_BC_JUMP_IF_FALSE_OR_POP (MP_BC_BASE_JUMP_E + 0x06) // signed relative bytecode offset +#define MP_BC_SETUP_WITH (MP_BC_BASE_JUMP_E + 0x07) // unsigned relative bytecode offset +#define MP_BC_SETUP_EXCEPT (MP_BC_BASE_JUMP_E + 0x08) // unsigned relative bytecode offset +#define MP_BC_SETUP_FINALLY (MP_BC_BASE_JUMP_E + 0x09) // unsigned relative bytecode offset +#define MP_BC_POP_EXCEPT_JUMP (MP_BC_BASE_JUMP_E + 0x0a) // unsigned relative bytecode offset +#define MP_BC_FOR_ITER (MP_BC_BASE_JUMP_E + 0x0b) // unsigned relative bytecode offset #define MP_BC_WITH_CLEANUP (MP_BC_BASE_BYTE_O + 0x0c) #define MP_BC_END_FINALLY (MP_BC_BASE_BYTE_O + 0x0d) #define MP_BC_GET_ITER (MP_BC_BASE_BYTE_O + 0x0e) diff --git a/py/compile.c b/py/compile.c index eb7389ec5f..d61dabb9a5 100644 --- a/py/compile.c +++ b/py/compile.c @@ -219,7 +219,7 @@ STATIC void mp_emit_common_start_pass(mp_emit_common_t *emit, pass_kind_t pass) } else if (pass > MP_PASS_STACK_SIZE) { emit->ct_cur_obj = emit->ct_cur_obj_base; } - if (pass == MP_PASS_EMIT) { + if (pass == MP_PASS_CODE_SIZE) { if (emit->ct_cur_child == 0) { emit->children = NULL; } else { @@ -3020,7 +3020,7 @@ STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) { #endif } -STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { +STATIC bool compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { comp->pass = pass; comp->scope_cur = scope; comp->next_label = 0; @@ -3187,10 +3187,12 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { EMIT(return_value); } - EMIT(end_pass); + bool pass_complete = EMIT(end_pass); // make sure we match all the exception levels assert(comp->cur_except_level == 0); + + return pass_complete; } #if MICROPY_EMIT_INLINE_ASM @@ -3600,8 +3602,10 @@ mp_compiled_module_t mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr so } // final pass: emit code + // the emitter can request multiple of these passes if (comp->compile_error == MP_OBJ_NULL) { - compile_scope(comp, s, MP_PASS_EMIT); + while (!compile_scope(comp, s, MP_PASS_EMIT)) { + } } } } diff --git a/py/emit.h b/py/emit.h index 6f3593a0e8..d4aea2e4db 100644 --- a/py/emit.h +++ b/py/emit.h @@ -43,7 +43,7 @@ typedef enum { MP_PASS_SCOPE = 1, // work out id's and their kind, and number of labels MP_PASS_STACK_SIZE = 2, // work out maximum stack size MP_PASS_CODE_SIZE = 3, // work out code size and label offsets - MP_PASS_EMIT = 4, // emit code + MP_PASS_EMIT = 4, // emit code (may be run multiple times if the emitter requests it) } pass_kind_t; #define MP_EMIT_STAR_FLAG_SINGLE (0x01) @@ -116,7 +116,7 @@ typedef struct _emit_method_table_t { #endif void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope); - void (*end_pass)(emit_t *emit); + bool (*end_pass)(emit_t *emit); bool (*last_emit_was_return_value)(emit_t *emit); void (*adjust_stack_size)(emit_t *emit, mp_int_t delta); void (*set_source_line)(emit_t *emit, mp_uint_t line); @@ -233,7 +233,7 @@ void emit_native_xtensa_free(emit_t *emit); void emit_native_xtensawin_free(emit_t *emit); void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope); -void mp_emit_bc_end_pass(emit_t *emit); +bool mp_emit_bc_end_pass(emit_t *emit); bool mp_emit_bc_last_emit_was_return_value(emit_t *emit); void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta); void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t line); diff --git a/py/emitbc.c b/py/emitbc.c index c04701ca78..14a72e2765 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "py/mpstate.h" @@ -55,8 +56,8 @@ struct _emit_t { mp_uint_t last_source_line_offset; mp_uint_t last_source_line; - mp_uint_t max_num_labels; - mp_uint_t *label_offsets; + size_t max_num_labels; + size_t *label_offsets; size_t code_info_offset; size_t code_info_size; @@ -76,11 +77,11 @@ emit_t *emit_bc_new(mp_emit_common_t *emit_common) { void emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels) { emit->max_num_labels = max_num_labels; - emit->label_offsets = m_new(mp_uint_t, emit->max_num_labels); + emit->label_offsets = m_new(size_t, emit->max_num_labels); } void emit_bc_free(emit_t *emit) { - m_del(mp_uint_t, emit->label_offsets, emit->max_num_labels); + m_del(size_t, emit->label_offsets, emit->max_num_labels); m_del_obj(emit_t, emit); } @@ -213,34 +214,55 @@ STATIC void emit_write_bytecode_byte_child(emit_t *emit, int stack_adj, byte b, #endif } -// unsigned labels are relative to ip following this instruction, stored as 16 bits -STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) { +// Emit a jump opcode to a destination label. +// The offset to the label is relative to the ip following this instruction. +// The offset is encoded as either 1 or 2 bytes, depending on how big it is. +// The encoding of this jump opcode can change size from one pass to the next, +// but it must only ever decrease in size on successive passes. +STATIC void emit_write_bytecode_byte_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) { mp_emit_bc_adjust_stack_size(emit, stack_adj); - mp_uint_t bytecode_offset; - if (emit->pass < MP_PASS_EMIT) { - bytecode_offset = 0; - } else { - bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3; - } - byte *c = emit_get_cur_to_write_bytecode(emit, 3); - c[0] = b1; - c[1] = bytecode_offset; - c[2] = bytecode_offset >> 8; -} -// signed labels are relative to ip following this instruction, stored as 16 bits, in excess -STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) { - mp_emit_bc_adjust_stack_size(emit, stack_adj); - int bytecode_offset; - if (emit->pass < MP_PASS_EMIT) { - bytecode_offset = 0; - } else { - bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3 + 0x8000; + // Determine if the jump offset is signed or unsigned, based on the opcode. + const bool is_signed = b1 <= MP_BC_JUMP_IF_FALSE_OR_POP; + + // Default to a 2-byte encoding (the largest) with an unknown jump offset. + unsigned int jump_encoding_size = 1; + ssize_t bytecode_offset = 0; + + // Compute the jump size and offset only when code size is known. + if (emit->pass >= MP_PASS_CODE_SIZE) { + // The -2 accounts for this jump opcode taking 2 bytes (at least). + bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 2; + + // Check if the bytecode_offset is small enough to use a 1-byte encoding. + if ((is_signed && -64 <= bytecode_offset && bytecode_offset <= 63) + || (!is_signed && (size_t)bytecode_offset <= 127)) { + // Use a 1-byte jump offset. + jump_encoding_size = 0; + } + + // Adjust the offset depending on the size of the encoding of the offset. + bytecode_offset -= jump_encoding_size; + + assert(is_signed || bytecode_offset >= 0); } - byte *c = emit_get_cur_to_write_bytecode(emit, 3); + + // Emit the opcode. + byte *c = emit_get_cur_to_write_bytecode(emit, 2 + jump_encoding_size); c[0] = b1; - c[1] = bytecode_offset; - c[2] = bytecode_offset >> 8; + if (jump_encoding_size == 0) { + if (is_signed) { + bytecode_offset += 0x40; + } + assert(0 <= bytecode_offset && bytecode_offset <= 0x7f); + c[1] = bytecode_offset; + } else { + if (is_signed) { + bytecode_offset += 0x4000; + } + c[1] = 0x80 | (bytecode_offset & 0x7f); + c[2] = bytecode_offset >> 7; + } } void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { @@ -250,12 +272,6 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { emit->scope = scope; emit->last_source_line_offset = 0; emit->last_source_line = 1; - #ifndef NDEBUG - // With debugging enabled labels are checked for unique assignment - if (pass < MP_PASS_EMIT && emit->label_offsets != NULL) { - memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t)); - } - #endif emit->bytecode_offset = 0; emit->code_info_offset = 0; @@ -315,9 +331,9 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { } } -void mp_emit_bc_end_pass(emit_t *emit) { +bool mp_emit_bc_end_pass(emit_t *emit) { if (emit->pass == MP_PASS_SCOPE) { - return; + return true; } // check stack is back to zero size @@ -344,6 +360,20 @@ void mp_emit_bc_end_pass(emit_t *emit) { emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size); } else if (emit->pass == MP_PASS_EMIT) { + // Code info and/or bytecode can shrink during this pass. + assert(emit->code_info_offset <= emit->code_info_size); + assert(emit->bytecode_offset <= emit->bytecode_size); + + if (emit->code_info_offset != emit->code_info_size + || emit->bytecode_offset != emit->bytecode_size) { + // Code info and/or bytecode changed size in this pass, so request the + // compiler to do another pass with these updated sizes. + emit->code_info_size = emit->code_info_offset; + emit->bytecode_size = emit->bytecode_offset; + return false; + } + + // Bytecode is finalised, assign it to the raw code object. mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base, #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS emit->code_info_size + emit->bytecode_size, @@ -354,6 +384,8 @@ void mp_emit_bc_end_pass(emit_t *emit) { #endif emit->scope->scope_flags); } + + return true; } bool mp_emit_bc_last_emit_was_return_value(emit_t *emit) { @@ -396,15 +428,16 @@ void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { if (emit->pass == MP_PASS_SCOPE) { return; } + + // Label offsets can change from one pass to the next, but they must only + // decrease (ie code can only shrink). There will be multiple MP_PASS_EMIT + // stages until the labels no longer change, which is when the code size + // stays constant after a MP_PASS_EMIT. assert(l < emit->max_num_labels); - if (emit->pass < MP_PASS_EMIT) { - // assign label offset - assert(emit->label_offsets[l] == (mp_uint_t)-1); - emit->label_offsets[l] = emit->bytecode_offset; - } else { - // ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT - assert(emit->label_offsets[l] == emit->bytecode_offset); - } + assert(emit->pass == MP_PASS_STACK_SIZE || emit->bytecode_offset <= emit->label_offsets[l]); + + // Assign label offset. + emit->label_offsets[l] = emit->bytecode_offset; } void mp_emit_bc_import(emit_t *emit, qstr qst, int kind) { @@ -552,22 +585,22 @@ void mp_emit_bc_rot_three(emit_t *emit) { } void mp_emit_bc_jump(emit_t *emit, mp_uint_t label) { - emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_JUMP, label); + emit_write_bytecode_byte_label(emit, 0, MP_BC_JUMP, label); } void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) { if (cond) { - emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_POP_JUMP_IF_TRUE, label); + emit_write_bytecode_byte_label(emit, -1, MP_BC_POP_JUMP_IF_TRUE, label); } else { - emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_POP_JUMP_IF_FALSE, label); + emit_write_bytecode_byte_label(emit, -1, MP_BC_POP_JUMP_IF_FALSE, label); } } void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) { if (cond) { - emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_JUMP_IF_TRUE_OR_POP, label); + emit_write_bytecode_byte_label(emit, -1, MP_BC_JUMP_IF_TRUE_OR_POP, label); } else { - emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_JUMP_IF_FALSE_OR_POP, label); + emit_write_bytecode_byte_label(emit, -1, MP_BC_JUMP_IF_FALSE_OR_POP, label); } } @@ -581,9 +614,9 @@ void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_dept emit_write_bytecode_raw_byte(emit, MP_BC_POP_TOP); } } - emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); + emit_write_bytecode_byte_label(emit, 0, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); } else { - emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); + emit_write_bytecode_byte_label(emit, 0, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); emit_write_bytecode_raw_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth); } } @@ -595,7 +628,7 @@ void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) { // The SETUP_WITH opcode pops ctx_mgr from the top of the stack // and then pushes 3 entries: __exit__, ctx_mgr, as_value. int stack_adj = kind == MP_EMIT_SETUP_BLOCK_WITH ? 2 : 0; - emit_write_bytecode_byte_unsigned_label(emit, stack_adj, MP_BC_SETUP_WITH + kind, label); + emit_write_bytecode_byte_label(emit, stack_adj, MP_BC_SETUP_WITH + kind, label); } void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { @@ -617,7 +650,7 @@ void mp_emit_bc_get_iter(emit_t *emit, bool use_stack) { } void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) { - emit_write_bytecode_byte_unsigned_label(emit, 1, MP_BC_FOR_ITER, label); + emit_write_bytecode_byte_label(emit, 1, MP_BC_FOR_ITER, label); } void mp_emit_bc_for_iter_end(emit_t *emit) { @@ -626,7 +659,7 @@ void mp_emit_bc_for_iter_end(emit_t *emit) { void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { (void)within_exc_handler; - emit_write_bytecode_byte_unsigned_label(emit, 0, MP_BC_POP_EXCEPT_JUMP, label); + emit_write_bytecode_byte_label(emit, 0, MP_BC_POP_EXCEPT_JUMP, label); } void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) { diff --git a/py/emitnative.c b/py/emitnative.c index ca34e89f64..bddd661428 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -652,7 +652,7 @@ static inline void emit_native_write_code_info_qstr(emit_t *emit, qstr qst) { mp_encode_uint(&emit->as->base, mp_asm_base_get_cur_to_write_bytes, mp_emit_common_use_qstr(emit->emit_common, qst)); } -STATIC void emit_native_end_pass(emit_t *emit) { +STATIC bool emit_native_end_pass(emit_t *emit) { emit_native_global_exc_exit(emit); if (!emit->do_viper_types) { @@ -736,6 +736,8 @@ STATIC void emit_native_end_pass(emit_t *emit) { #endif emit->scope->scope_flags, 0, 0); } + + return true; } STATIC bool emit_native_last_emit_was_return_value(emit_t *emit) { diff --git a/py/showbc.c b/py/showbc.c index 8430739d8e..178fa451a2 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -38,8 +38,28 @@ unum = (unum << 7) + (*ip & 0x7f); \ } while ((*ip++ & 0x80) != 0); \ } -#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0) -#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0) + +#define DECODE_ULABEL \ + do { \ + if (ip[0] & 0x80) { \ + unum = ((ip[0] & 0x7f) | (ip[1] << 7)); \ + ip += 2; \ + } else { \ + unum = ip[0]; \ + ip += 1; \ + } \ + } while (0) + +#define DECODE_SLABEL \ + do { \ + if (ip[0] & 0x80) { \ + unum = ((ip[0] & 0x7f) | (ip[1] << 7)) - 0x4000; \ + ip += 2; \ + } else { \ + unum = ip[0] - 0x40; \ + ip += 1; \ + } \ + } while (0) #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE diff --git a/py/vm.c b/py/vm.c index 497a569622..990009c00c 100644 --- a/py/vm.c +++ b/py/vm.c @@ -61,8 +61,30 @@ do { \ unum = (unum << 7) + (*ip & 0x7f); \ } while ((*ip++ & 0x80) != 0) -#define DECODE_ULABEL size_t ulab = (ip[0] | (ip[1] << 8)); ip += 2 -#define DECODE_SLABEL size_t slab = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2 + +#define DECODE_ULABEL \ + size_t ulab; \ + do { \ + if (ip[0] & 0x80) { \ + ulab = ((ip[0] & 0x7f) | (ip[1] << 7)); \ + ip += 2; \ + } else { \ + ulab = ip[0]; \ + ip += 1; \ + } \ + } while (0) + +#define DECODE_SLABEL \ + size_t slab; \ + do { \ + if (ip[0] & 0x80) { \ + slab = ((ip[0] & 0x7f) | (ip[1] << 7)) - 0x4000; \ + ip += 2; \ + } else { \ + slab = ip[0] - 0x40; \ + ip += 1; \ + } \ + } while (0) #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE diff --git a/tests/cmdline/cmd_parsetree.py.exp b/tests/cmdline/cmd_parsetree.py.exp index 53d62a5dbd..6ee96b7caf 100644 --- a/tests/cmdline/cmd_parsetree.py.exp +++ b/tests/cmdline/cmd_parsetree.py.exp @@ -39,52 +39,52 @@ [ 13] \(rule\|arglist\)(164) (n=1) id(b) ---------------- -File cmdline/cmd_parsetree.py, code block '' (descriptor: \.\+, bytecode @\.\+ 64 bytes) -Raw bytecode (code_info_size=13, bytecode_size=51): - 20 16 01 60 28 23 23 24 24 24 24 24 25 2a 00 5f - 4b 05 00 16 02 42 f8 7f 51 16 03 10 04 16 05 23 - 00 16 06 23 01 16 07 23 02 16 08 23 03 16 09 22 - 80 7b 16 0a 23 04 14 0b 11 05 36 01 16 0c 51 63 +File cmdline/cmd_parsetree.py, code block '' (descriptor: \.\+, bytecode @\.\+ 62 bytes) +Raw bytecode (code_info_size=13, bytecode_size=49): + 20 16 01 60 27 22 23 24 24 24 24 24 25 2a 00 5f + 4b 04 16 02 42 3a 51 16 03 10 04 16 05 23 00 16 + 06 23 01 16 07 23 02 16 08 23 03 16 09 22 80 7b + 16 0a 23 04 14 0b 11 05 36 01 16 0c 51 63 arg names: (N_STATE 5) (N_EXC_STACK 0) bc=0 line=1 bc=0 line=4 - bc=8 line=5 - bc=11 line=6 - bc=14 line=7 - bc=18 line=8 - bc=22 line=9 - bc=26 line=10 - bc=30 line=11 - bc=34 line=12 - bc=39 line=13 + bc=7 line=5 + bc=9 line=6 + bc=12 line=7 + bc=16 line=8 + bc=20 line=9 + bc=24 line=10 + bc=28 line=11 + bc=32 line=12 + bc=37 line=13 00 BUILD_TUPLE 0 02 GET_ITER_STACK -03 FOR_ITER 11 -06 STORE_NAME i -08 JUMP 3 -11 LOAD_CONST_NONE -12 STORE_NAME a -14 LOAD_CONST_STRING 'str' -16 STORE_NAME b -18 LOAD_CONST_OBJ \.\+='a very long str that will not be interned' -20 STORE_NAME c -22 LOAD_CONST_OBJ \.\+=b'bytes' -24 STORE_NAME d -26 LOAD_CONST_OBJ \.\+=b'a very long bytes that will not be interned' -28 STORE_NAME e -30 LOAD_CONST_OBJ \.\+=123456789012345678901234567890 -32 STORE_NAME f -34 LOAD_CONST_SMALL_INT 123 -37 STORE_NAME g -39 LOAD_CONST_OBJ \.\+="fstring: '{}'" -41 LOAD_METHOD format -43 LOAD_NAME b -45 CALL_METHOD n=1 nkw=0 -47 STORE_NAME h -49 LOAD_CONST_NONE -50 RETURN_VALUE +03 FOR_ITER 9 +05 STORE_NAME i +07 JUMP 3 +09 LOAD_CONST_NONE +10 STORE_NAME a +12 LOAD_CONST_STRING 'str' +14 STORE_NAME b +16 LOAD_CONST_OBJ \.\+='a very long str that will not be interned' +18 STORE_NAME c +20 LOAD_CONST_OBJ \.\+=b'bytes' +22 STORE_NAME d +24 LOAD_CONST_OBJ \.\+=b'a very long bytes that will not be interned' +26 STORE_NAME e +28 LOAD_CONST_OBJ \.\+=123456789012345678901234567890 +30 STORE_NAME f +32 LOAD_CONST_SMALL_INT 123 +35 STORE_NAME g +37 LOAD_CONST_OBJ \.\+="fstring: '{}'" +39 LOAD_METHOD format +41 LOAD_NAME b +43 CALL_METHOD n=1 nkw=0 +45 STORE_NAME h +47 LOAD_CONST_NONE +48 RETURN_VALUE mem: total=\\d\+, current=\\d\+, peak=\\d\+ stack: \\d\+ out of \\d\+ GC: total: \\d\+, used: \\d\+, free: \\d\+ diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index 031820fcd9..92501e1248 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -47,10 +47,10 @@ arg names: 42 IMPORT_STAR 43 LOAD_CONST_NONE 44 RETURN_VALUE -File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 48\[24\] bytes) -Raw bytecode (code_info_size=8\[46\], bytecode_size=398): +File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 45\[68\] bytes) +Raw bytecode (code_info_size=8\[46\], bytecode_size=372): a8 12 9\[bf\] 03 02 60 60 26 22 24 64 22 26 25 25 24 - 26 23 63 22 22 25 23 23 31 6d 25 65 25 25 69 68 + 26 23 63 22 22 25 23 23 2f 6c 25 65 25 25 69 68 26 65 27 6a 62 20 23 62 2a 29 69 24 25 28 67 26 ######## \.\+81 63 @@ -80,65 +80,65 @@ arg names: bc=59 line=26 bc=62 line=27 bc=65 line=28 - bc=82 line=29 - bc=95 line=32 - bc=100 line=33 - bc=105 line=36 - bc=110 line=37 - bc=115 line=38 - bc=124 line=41 - bc=132 line=44 - bc=138 line=45 - bc=143 line=48 - bc=150 line=49 - bc=160 line=52 - bc=162 line=55 - bc=162 line=56 - bc=165 line=57 - bc=167 line=60 - bc=177 line=61 - bc=186 line=62 - bc=195 line=65 - bc=199 line=66 - bc=204 line=67 - bc=212 line=68 - bc=219 line=71 - bc=225 line=72 - bc=232 line=73 - bc=242 line=74 - bc=250 line=77 - bc=254 line=78 - bc=260 line=80 - bc=263 line=81 - bc=266 line=82 - bc=273 line=83 - bc=276 line=84 - bc=283 line=85 - bc=289 line=88 - bc=296 line=89 - bc=301 line=92 - bc=307 line=93 - bc=310 line=94 + bc=80 line=29 + bc=92 line=32 + bc=97 line=33 + bc=102 line=36 + bc=107 line=37 + bc=112 line=38 + bc=121 line=41 + bc=129 line=44 + bc=135 line=45 + bc=140 line=48 + bc=147 line=49 + bc=157 line=52 + bc=159 line=55 + bc=159 line=56 + bc=162 line=57 + bc=164 line=60 + bc=174 line=61 + bc=183 line=62 + bc=192 line=65 + bc=196 line=66 + bc=201 line=67 + bc=209 line=68 + bc=216 line=71 + bc=222 line=72 + bc=229 line=73 + bc=239 line=74 + bc=247 line=77 + bc=250 line=78 + bc=255 line=80 + bc=258 line=81 + bc=260 line=82 + bc=266 line=83 + bc=268 line=84 + bc=274 line=85 + bc=279 line=88 + bc=285 line=89 + bc=289 line=92 + bc=293 line=93 + bc=295 line=94 ######## - bc=321 line=96 - bc=329 line=98 - bc=332 line=99 - bc=335 line=100 - bc=338 line=101 + bc=303 line=96 + bc=310 line=98 + bc=313 line=99 + bc=315 line=100 + bc=317 line=101 ######## - bc=346 line=103 - bc=354 line=106 - bc=359 line=107 - bc=365 line=110 - bc=368 line=111 - bc=374 line=114 - bc=374 line=117 - bc=379 line=118 - bc=391 line=121 - bc=391 line=122 - bc=392 line=123 - bc=394 line=126 - bc=396 line=127 + bc=323 line=103 + bc=329 line=106 + bc=333 line=107 + bc=339 line=110 + bc=342 line=111 + bc=348 line=114 + bc=348 line=117 + bc=353 line=118 + bc=365 line=121 + bc=365 line=122 + bc=366 line=123 + bc=368 line=126 + bc=370 line=127 00 LOAD_CONST_NONE 01 LOAD_CONST_FALSE 02 BINARY_OP 27 __add__ @@ -195,216 +195,216 @@ arg names: 68 DUP_TOP 69 ROT_THREE 70 BINARY_OP 2 __eq__ -71 JUMP_IF_FALSE_OR_POP 79 -74 LOAD_FAST 1 -75 BINARY_OP 2 __eq__ -76 JUMP 81 -79 ROT_TWO -80 POP_TOP -81 STORE_FAST 10 -82 LOAD_FAST 0 -83 LOAD_DEREF 14 -85 BINARY_OP 2 __eq__ -86 JUMP_IF_FALSE_OR_POP 93 -89 LOAD_DEREF 14 -91 LOAD_FAST 1 -92 BINARY_OP 2 __eq__ -93 UNARY_OP 3 -94 STORE_FAST 10 -95 LOAD_DEREF 14 -97 LOAD_ATTR c -99 STORE_FAST 11 -100 LOAD_FAST 11 -101 LOAD_DEREF 14 -103 STORE_ATTR c -105 LOAD_DEREF 14 -107 LOAD_CONST_SMALL_INT 0 -108 LOAD_SUBSCR -109 STORE_FAST 12 -110 LOAD_FAST 12 -111 LOAD_DEREF 14 -113 LOAD_CONST_SMALL_INT 0 -114 STORE_SUBSCR -115 LOAD_DEREF 14 -117 LOAD_CONST_SMALL_INT 0 -118 DUP_TOP_TWO -119 LOAD_SUBSCR -120 LOAD_FAST 12 -121 BINARY_OP 14 __iadd__ -122 ROT_THREE -123 STORE_SUBSCR -124 LOAD_DEREF 14 -126 LOAD_CONST_NONE -127 LOAD_CONST_NONE -128 BUILD_SLICE 2 -130 LOAD_SUBSCR -131 STORE_FAST 0 -132 LOAD_FAST 1 -133 UNPACK_SEQUENCE 2 -135 STORE_FAST 0 -136 STORE_DEREF 14 -138 LOAD_FAST 0 -139 UNPACK_EX 1 -141 STORE_FAST 0 -142 STORE_FAST 0 -143 LOAD_DEREF 14 -145 LOAD_FAST 0 -146 ROT_TWO -147 STORE_FAST 0 -148 STORE_DEREF 14 -150 LOAD_FAST 1 -151 LOAD_DEREF 14 -153 LOAD_FAST 0 -154 ROT_THREE -155 ROT_TWO -156 STORE_FAST 0 -157 STORE_DEREF 14 -159 STORE_FAST 1 -160 DELETE_FAST 0 -162 LOAD_FAST 0 -163 STORE_GLOBAL gl -165 DELETE_GLOBAL gl -167 LOAD_FAST 14 -168 LOAD_FAST 15 -169 MAKE_CLOSURE \.\+ 2 -172 LOAD_FAST 2 -173 GET_ITER -174 CALL_FUNCTION n=1 nkw=0 -176 STORE_FAST 0 -177 LOAD_FAST 14 -178 LOAD_FAST 15 -179 MAKE_CLOSURE \.\+ 2 -182 LOAD_FAST 2 -183 CALL_FUNCTION n=1 nkw=0 -185 STORE_FAST 0 -186 LOAD_FAST 14 -187 LOAD_FAST 15 -188 MAKE_CLOSURE \.\+ 2 -191 LOAD_FAST 2 -192 CALL_FUNCTION n=1 nkw=0 -194 STORE_FAST 0 -195 LOAD_FAST 0 -196 CALL_FUNCTION n=0 nkw=0 -198 POP_TOP -199 LOAD_FAST 0 -200 LOAD_CONST_SMALL_INT 1 -201 CALL_FUNCTION n=1 nkw=0 -203 POP_TOP -204 LOAD_FAST 0 -205 LOAD_CONST_STRING 'b' -207 LOAD_CONST_SMALL_INT 1 -208 CALL_FUNCTION n=0 nkw=1 -211 POP_TOP -212 LOAD_FAST 0 -213 LOAD_DEREF 14 -215 LOAD_NULL -216 CALL_FUNCTION_VAR_KW n=0 nkw=0 -218 POP_TOP -219 LOAD_FAST 0 -220 LOAD_METHOD b -222 CALL_METHOD n=0 nkw=0 -224 POP_TOP -225 LOAD_FAST 0 -226 LOAD_METHOD b -228 LOAD_CONST_SMALL_INT 1 -229 CALL_METHOD n=1 nkw=0 -231 POP_TOP -232 LOAD_FAST 0 -233 LOAD_METHOD b -235 LOAD_CONST_STRING 'c' -237 LOAD_CONST_SMALL_INT 1 -238 CALL_METHOD n=0 nkw=1 -241 POP_TOP -242 LOAD_FAST 0 -243 LOAD_METHOD b -245 LOAD_FAST 1 -246 LOAD_NULL -247 CALL_METHOD_VAR_KW n=0 nkw=0 -249 POP_TOP -250 LOAD_FAST 0 -251 POP_JUMP_IF_FALSE 260 -254 LOAD_DEREF 16 -256 POP_TOP -257 JUMP 263 -260 LOAD_GLOBAL y +71 JUMP_IF_FALSE_OR_POP 77 +73 LOAD_FAST 1 +74 BINARY_OP 2 __eq__ +75 JUMP 79 +77 ROT_TWO +78 POP_TOP +79 STORE_FAST 10 +80 LOAD_FAST 0 +81 LOAD_DEREF 14 +83 BINARY_OP 2 __eq__ +84 JUMP_IF_FALSE_OR_POP 90 +86 LOAD_DEREF 14 +88 LOAD_FAST 1 +89 BINARY_OP 2 __eq__ +90 UNARY_OP 3 +91 STORE_FAST 10 +92 LOAD_DEREF 14 +94 LOAD_ATTR c +96 STORE_FAST 11 +97 LOAD_FAST 11 +98 LOAD_DEREF 14 +100 STORE_ATTR c +102 LOAD_DEREF 14 +104 LOAD_CONST_SMALL_INT 0 +105 LOAD_SUBSCR +106 STORE_FAST 12 +107 LOAD_FAST 12 +108 LOAD_DEREF 14 +110 LOAD_CONST_SMALL_INT 0 +111 STORE_SUBSCR +112 LOAD_DEREF 14 +114 LOAD_CONST_SMALL_INT 0 +115 DUP_TOP_TWO +116 LOAD_SUBSCR +117 LOAD_FAST 12 +118 BINARY_OP 14 __iadd__ +119 ROT_THREE +120 STORE_SUBSCR +121 LOAD_DEREF 14 +123 LOAD_CONST_NONE +124 LOAD_CONST_NONE +125 BUILD_SLICE 2 +127 LOAD_SUBSCR +128 STORE_FAST 0 +129 LOAD_FAST 1 +130 UNPACK_SEQUENCE 2 +132 STORE_FAST 0 +133 STORE_DEREF 14 +135 LOAD_FAST 0 +136 UNPACK_EX 1 +138 STORE_FAST 0 +139 STORE_FAST 0 +140 LOAD_DEREF 14 +142 LOAD_FAST 0 +143 ROT_TWO +144 STORE_FAST 0 +145 STORE_DEREF 14 +147 LOAD_FAST 1 +148 LOAD_DEREF 14 +150 LOAD_FAST 0 +151 ROT_THREE +152 ROT_TWO +153 STORE_FAST 0 +154 STORE_DEREF 14 +156 STORE_FAST 1 +157 DELETE_FAST 0 +159 LOAD_FAST 0 +160 STORE_GLOBAL gl +162 DELETE_GLOBAL gl +164 LOAD_FAST 14 +165 LOAD_FAST 15 +166 MAKE_CLOSURE \.\+ 2 +169 LOAD_FAST 2 +170 GET_ITER +171 CALL_FUNCTION n=1 nkw=0 +173 STORE_FAST 0 +174 LOAD_FAST 14 +175 LOAD_FAST 15 +176 MAKE_CLOSURE \.\+ 2 +179 LOAD_FAST 2 +180 CALL_FUNCTION n=1 nkw=0 +182 STORE_FAST 0 +183 LOAD_FAST 14 +184 LOAD_FAST 15 +185 MAKE_CLOSURE \.\+ 2 +188 LOAD_FAST 2 +189 CALL_FUNCTION n=1 nkw=0 +191 STORE_FAST 0 +192 LOAD_FAST 0 +193 CALL_FUNCTION n=0 nkw=0 +195 POP_TOP +196 LOAD_FAST 0 +197 LOAD_CONST_SMALL_INT 1 +198 CALL_FUNCTION n=1 nkw=0 +200 POP_TOP +201 LOAD_FAST 0 +202 LOAD_CONST_STRING 'b' +204 LOAD_CONST_SMALL_INT 1 +205 CALL_FUNCTION n=0 nkw=1 +208 POP_TOP +209 LOAD_FAST 0 +210 LOAD_DEREF 14 +212 LOAD_NULL +213 CALL_FUNCTION_VAR_KW n=0 nkw=0 +215 POP_TOP +216 LOAD_FAST 0 +217 LOAD_METHOD b +219 CALL_METHOD n=0 nkw=0 +221 POP_TOP +222 LOAD_FAST 0 +223 LOAD_METHOD b +225 LOAD_CONST_SMALL_INT 1 +226 CALL_METHOD n=1 nkw=0 +228 POP_TOP +229 LOAD_FAST 0 +230 LOAD_METHOD b +232 LOAD_CONST_STRING 'c' +234 LOAD_CONST_SMALL_INT 1 +235 CALL_METHOD n=0 nkw=1 +238 POP_TOP +239 LOAD_FAST 0 +240 LOAD_METHOD b +242 LOAD_FAST 1 +243 LOAD_NULL +244 CALL_METHOD_VAR_KW n=0 nkw=0 +246 POP_TOP +247 LOAD_FAST 0 +248 POP_JUMP_IF_FALSE 255 +250 LOAD_DEREF 16 +252 POP_TOP +253 JUMP 258 +255 LOAD_GLOBAL y +257 POP_TOP +258 JUMP 263 +260 LOAD_DEREF 14 262 POP_TOP -263 JUMP 269 -266 LOAD_DEREF 14 -268 POP_TOP -269 LOAD_FAST 0 -270 POP_JUMP_IF_TRUE 266 -273 JUMP 279 -276 LOAD_DEREF 14 -278 POP_TOP -279 LOAD_FAST 0 -280 POP_JUMP_IF_FALSE 276 -283 LOAD_FAST 0 -284 JUMP_IF_TRUE_OR_POP 288 -287 LOAD_FAST 0 -288 STORE_FAST 0 -289 LOAD_DEREF 14 -291 GET_ITER_STACK -292 FOR_ITER 301 -295 STORE_FAST 0 -296 LOAD_FAST 1 -297 POP_TOP -298 JUMP 292 -301 SETUP_FINALLY 329 -304 SETUP_EXCEPT 320 -307 JUMP 313 -310 JUMP 317 -313 LOAD_FAST 0 -314 POP_JUMP_IF_TRUE 310 -317 POP_EXCEPT_JUMP 328 -320 POP_TOP -321 LOAD_DEREF 14 -323 POP_TOP -324 POP_EXCEPT_JUMP 328 -327 END_FINALLY -328 LOAD_CONST_NONE -329 LOAD_FAST 1 -330 POP_TOP -331 END_FINALLY -332 JUMP 350 -335 SETUP_EXCEPT 345 -338 UNWIND_JUMP 354 1 -342 POP_EXCEPT_JUMP 350 -345 POP_TOP -346 POP_EXCEPT_JUMP 350 -349 END_FINALLY -350 LOAD_FAST 0 -351 POP_JUMP_IF_TRUE 335 -354 LOAD_FAST 0 -355 SETUP_WITH 363 -358 POP_TOP -359 LOAD_DEREF 14 -361 POP_TOP -362 LOAD_CONST_NONE -363 WITH_CLEANUP -364 END_FINALLY -365 LOAD_CONST_SMALL_INT 1 -366 STORE_DEREF 16 -368 LOAD_FAST_N 16 -370 MAKE_CLOSURE \.\+ 1 -373 STORE_FAST 13 -374 LOAD_CONST_SMALL_INT 0 -375 LOAD_CONST_NONE -376 IMPORT_NAME 'a' -378 STORE_FAST 0 -379 LOAD_CONST_SMALL_INT 0 -380 LOAD_CONST_STRING 'b' -382 BUILD_TUPLE 1 -384 IMPORT_NAME 'a' -386 IMPORT_FROM 'b' -388 STORE_DEREF 14 -390 POP_TOP -391 RAISE_LAST -392 LOAD_CONST_SMALL_INT 1 -393 RAISE_OBJ -394 LOAD_CONST_NONE -395 RETURN_VALUE -396 LOAD_CONST_SMALL_INT 1 -397 RETURN_VALUE +263 LOAD_FAST 0 +264 POP_JUMP_IF_TRUE 260 +266 JUMP 271 +268 LOAD_DEREF 14 +270 POP_TOP +271 LOAD_FAST 0 +272 POP_JUMP_IF_FALSE 268 +274 LOAD_FAST 0 +275 JUMP_IF_TRUE_OR_POP 278 +277 LOAD_FAST 0 +278 STORE_FAST 0 +279 LOAD_DEREF 14 +281 GET_ITER_STACK +282 FOR_ITER 289 +284 STORE_FAST 0 +285 LOAD_FAST 1 +286 POP_TOP +287 JUMP 282 +289 SETUP_FINALLY 310 +291 SETUP_EXCEPT 302 +293 JUMP 297 +295 JUMP 300 +297 LOAD_FAST 0 +298 POP_JUMP_IF_TRUE 295 +300 POP_EXCEPT_JUMP 309 +302 POP_TOP +303 LOAD_DEREF 14 +305 POP_TOP +306 POP_EXCEPT_JUMP 309 +308 END_FINALLY +309 LOAD_CONST_NONE +310 LOAD_FAST 1 +311 POP_TOP +312 END_FINALLY +313 JUMP 326 +315 SETUP_EXCEPT 322 +317 UNWIND_JUMP 329 1 +320 POP_EXCEPT_JUMP 326 +322 POP_TOP +323 POP_EXCEPT_JUMP 326 +325 END_FINALLY +326 LOAD_FAST 0 +327 POP_JUMP_IF_TRUE 315 +329 LOAD_FAST 0 +330 SETUP_WITH 337 +332 POP_TOP +333 LOAD_DEREF 14 +335 POP_TOP +336 LOAD_CONST_NONE +337 WITH_CLEANUP +338 END_FINALLY +339 LOAD_CONST_SMALL_INT 1 +340 STORE_DEREF 16 +342 LOAD_FAST_N 16 +344 MAKE_CLOSURE \.\+ 1 +347 STORE_FAST 13 +348 LOAD_CONST_SMALL_INT 0 +349 LOAD_CONST_NONE +350 IMPORT_NAME 'a' +352 STORE_FAST 0 +353 LOAD_CONST_SMALL_INT 0 +354 LOAD_CONST_STRING 'b' +356 BUILD_TUPLE 1 +358 IMPORT_NAME 'a' +360 IMPORT_FROM 'b' +362 STORE_DEREF 14 +364 POP_TOP +365 RAISE_LAST +366 LOAD_CONST_SMALL_INT 1 +367 RAISE_OBJ +368 LOAD_CONST_NONE +369 RETURN_VALUE +370 LOAD_CONST_SMALL_INT 1 +371 RETURN_VALUE File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 59 bytes) Raw bytecode (code_info_size=8, bytecode_size=51): a8 10 0a 02 80 82 34 38 81 57 c0 57 c1 57 c2 57 @@ -539,10 +539,10 @@ arg names: self 09 POP_TOP 10 LOAD_CONST_NONE 11 RETURN_VALUE -File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 31 bytes) -Raw bytecode (code_info_size=9, bytecode_size=22): - c3 40 0c 12 04 04 04 80 3b 53 b2 53 53 4b 0d 00 - c3 25 01 44 f7 7f 25 00 67 59 42 f0 7f 51 63 +File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 28 bytes) +Raw bytecode (code_info_size=9, bytecode_size=19): + c3 40 0c 12 04 04 04 80 3b 53 b2 53 53 4b 0b c3 + 25 01 44 39 25 00 67 59 42 33 51 63 arg names: * * * (N_STATE 9) (N_EXC_STACK 0) @@ -552,20 +552,20 @@ arg names: * * * 01 LOAD_FAST 2 02 LOAD_NULL 03 LOAD_NULL -04 FOR_ITER 20 -07 STORE_FAST 3 -08 LOAD_DEREF 1 -10 POP_JUMP_IF_FALSE 4 -13 LOAD_DEREF 0 -15 YIELD_VALUE -16 POP_TOP -17 JUMP 4 -20 LOAD_CONST_NONE -21 RETURN_VALUE -File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 29 bytes) -Raw bytecode (code_info_size=8, bytecode_size=21): - 4b 0c 14 04 04 04 80 3c 2b 00 b2 5f 4b 0d 00 c3 - 25 01 44 f7 7f 25 00 2f 14 42 f0 7f 63 +04 FOR_ITER 17 +06 STORE_FAST 3 +07 LOAD_DEREF 1 +09 POP_JUMP_IF_FALSE 4 +11 LOAD_DEREF 0 +13 YIELD_VALUE +14 POP_TOP +15 JUMP 4 +17 LOAD_CONST_NONE +18 RETURN_VALUE +File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 26 bytes) +Raw bytecode (code_info_size=8, bytecode_size=18): + 4b 0c 14 04 04 04 80 3c 2b 00 b2 5f 4b 0b c3 25 + 01 44 39 25 00 2f 14 42 33 63 arg names: * * * (N_STATE 10) (N_EXC_STACK 0) @@ -574,18 +574,18 @@ arg names: * * * 00 BUILD_LIST 0 02 LOAD_FAST 2 03 GET_ITER_STACK -04 FOR_ITER 20 -07 STORE_FAST 3 -08 LOAD_DEREF 1 -10 POP_JUMP_IF_FALSE 4 -13 LOAD_DEREF 0 -15 STORE_COMP 20 -17 JUMP 4 -20 RETURN_VALUE -File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 31 bytes) -Raw bytecode (code_info_size=8, bytecode_size=23): - 53 0c 15 04 04 04 80 3d 2c 00 b2 5f 4b 0f 00 c3 - 25 01 44 f7 7f 25 00 25 00 2f 19 42 ee 7f 63 +04 FOR_ITER 17 +06 STORE_FAST 3 +07 LOAD_DEREF 1 +09 POP_JUMP_IF_FALSE 4 +11 LOAD_DEREF 0 +13 STORE_COMP 20 +15 JUMP 4 +17 RETURN_VALUE +File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 28 bytes) +Raw bytecode (code_info_size=8, bytecode_size=20): + 53 0c 15 04 04 04 80 3d 2c 00 b2 5f 4b 0d c3 25 + 01 44 39 25 00 25 00 2f 19 42 31 63 arg names: * * * (N_STATE 11) (N_EXC_STACK 0) @@ -594,15 +594,15 @@ arg names: * * * 00 BUILD_MAP 0 02 LOAD_FAST 2 03 GET_ITER_STACK -04 FOR_ITER 22 -07 STORE_FAST 3 -08 LOAD_DEREF 1 -10 POP_JUMP_IF_FALSE 4 +04 FOR_ITER 19 +06 STORE_FAST 3 +07 LOAD_DEREF 1 +09 POP_JUMP_IF_FALSE 4 +11 LOAD_DEREF 0 13 LOAD_DEREF 0 -15 LOAD_DEREF 0 -17 STORE_COMP 25 -19 JUMP 4 -22 RETURN_VALUE +15 STORE_COMP 25 +17 JUMP 4 +19 RETURN_VALUE File cmdline/cmd_showbc.py, code block 'closure' (descriptor: \.\+, bytecode @\.\+ 20 bytes) Raw bytecode (code_info_size=8, bytecode_size=12): 19 0c 16 04 80 6f 25 23 25 00 81 f2 c1 81 27 00 diff --git a/tests/run-tests.py b/tests/run-tests.py index 9c298dae31..d0ecc74a9a 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -527,6 +527,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): "micropython/opt_level_lineno.py" ) # native doesn't have proper traceback info skip_tests.add("micropython/schedule.py") # native code doesn't check pending events + skip_tests.add("stress/bytecode_limit.py") # bytecode specific test def run_one_test(test_file): test_file = test_file.replace("\\", "/") diff --git a/tests/stress/bytecode_limit.py b/tests/stress/bytecode_limit.py new file mode 100644 index 0000000000..0cb0c21e40 --- /dev/null +++ b/tests/stress/bytecode_limit.py @@ -0,0 +1,26 @@ +# Test the limits of bytecode generation. + +body = " with f()()() as a:\n try:\n f()()()\n except Exception:\n pass\n" + +# Test changing size of code info (source line/bytecode mapping) due to changing +# bytecode size in the final passes. This test is very specific to how the +# code info is encoded, and how jump offsets shrink in the final passes. This +# test should fail if the bytecode emitter doesn't correctly handle shrinking of +# the code info section. +exec( + """ +x = 0 +if x: +""" + + body * 13 + + """ +x = [1 if x else 123] + + + + + + +print(x) +""" +) diff --git a/tests/stress/bytecode_limit.py.exp b/tests/stress/bytecode_limit.py.exp new file mode 100644 index 0000000000..3214bfe58c --- /dev/null +++ b/tests/stress/bytecode_limit.py.exp @@ -0,0 +1 @@ +[123] diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 73753094ec..1ce301ab94 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -242,17 +242,17 @@ class Opcodes: MP_BC_ROT_TWO = (MP_BC_BASE_BYTE_O + 0x0a) MP_BC_ROT_THREE = (MP_BC_BASE_BYTE_O + 0x0b) - MP_BC_JUMP = (MP_BC_BASE_JUMP_E + 0x02) # rel byte code offset, 16-bit signed, in excess - MP_BC_POP_JUMP_IF_TRUE = (MP_BC_BASE_JUMP_E + 0x03) # rel byte code offset, 16-bit signed, in excess - MP_BC_POP_JUMP_IF_FALSE = (MP_BC_BASE_JUMP_E + 0x04) # rel byte code offset, 16-bit signed, in excess - MP_BC_JUMP_IF_TRUE_OR_POP = (MP_BC_BASE_JUMP_E + 0x05) # rel byte code offset, 16-bit signed, in excess - MP_BC_JUMP_IF_FALSE_OR_POP = (MP_BC_BASE_JUMP_E + 0x06) # rel byte code offset, 16-bit signed, in excess - MP_BC_UNWIND_JUMP = (MP_BC_BASE_JUMP_E + 0x00) # rel byte code offset, 16-bit signed, in excess; then a byte - MP_BC_SETUP_WITH = (MP_BC_BASE_JUMP_E + 0x07) # rel byte code offset, 16-bit unsigned - MP_BC_SETUP_EXCEPT = (MP_BC_BASE_JUMP_E + 0x08) # rel byte code offset, 16-bit unsigned - MP_BC_SETUP_FINALLY = (MP_BC_BASE_JUMP_E + 0x09) # rel byte code offset, 16-bit unsigned - MP_BC_POP_EXCEPT_JUMP = (MP_BC_BASE_JUMP_E + 0x0a) # rel byte code offset, 16-bit unsigned - MP_BC_FOR_ITER = (MP_BC_BASE_JUMP_E + 0x0b) # rel byte code offset, 16-bit unsigned + MP_BC_UNWIND_JUMP = (MP_BC_BASE_JUMP_E + 0x00) # signed relative bytecode offset; then a byte + MP_BC_JUMP = (MP_BC_BASE_JUMP_E + 0x02) # signed relative bytecode offset + MP_BC_POP_JUMP_IF_TRUE = (MP_BC_BASE_JUMP_E + 0x03) # signed relative bytecode offset + MP_BC_POP_JUMP_IF_FALSE = (MP_BC_BASE_JUMP_E + 0x04) # signed relative bytecode offset + MP_BC_JUMP_IF_TRUE_OR_POP = (MP_BC_BASE_JUMP_E + 0x05) # signed relative bytecode offset + MP_BC_JUMP_IF_FALSE_OR_POP = (MP_BC_BASE_JUMP_E + 0x06) # signed relative bytecode offset + MP_BC_SETUP_WITH = (MP_BC_BASE_JUMP_E + 0x07) # unsigned relative bytecode offset + MP_BC_SETUP_EXCEPT = (MP_BC_BASE_JUMP_E + 0x08) # unsigned relative bytecode offset + MP_BC_SETUP_FINALLY = (MP_BC_BASE_JUMP_E + 0x09) # unsigned relative bytecode offset + MP_BC_POP_EXCEPT_JUMP = (MP_BC_BASE_JUMP_E + 0x0a) # unsigned relative bytecode offset + MP_BC_FOR_ITER = (MP_BC_BASE_JUMP_E + 0x0b) # unsigned relative bytecode offset MP_BC_WITH_CLEANUP = (MP_BC_BASE_BYTE_O + 0x0c) MP_BC_END_FINALLY = (MP_BC_BASE_BYTE_O + 0x0d) MP_BC_GET_ITER = (MP_BC_BASE_BYTE_O + 0x0e) @@ -289,6 +289,16 @@ class Opcodes: MP_BC_IMPORT_STAR = (MP_BC_BASE_BYTE_E + 0x09) # fmt: on + # Create sets of related opcodes. + ALL_OFFSET_SIGNED = ( + MP_BC_UNWIND_JUMP, + MP_BC_JUMP, + MP_BC_POP_JUMP_IF_TRUE, + MP_BC_POP_JUMP_IF_FALSE, + MP_BC_JUMP_IF_TRUE_OR_POP, + MP_BC_JUMP_IF_FALSE_OR_POP, + ) + # Create a dict mapping opcode value to opcode name. mapping = ["unknown" for _ in range(256)] for op_name in list(locals()): @@ -323,7 +333,10 @@ def mp_opcode_format(bytecode, ip, count_var_uint): ip += 1 ip += 1 elif f == MP_BC_FORMAT_OFFSET: - ip += 2 + if bytecode[ip] & 0x80 == 0: + ip += 1 + else: + ip += 2 ip += extra_byte return f, ip - ip_start @@ -342,8 +355,16 @@ def mp_opcode_decode(bytecode, ip): arg = arg << 7 | bytecode[ip] & 0x7F ip += 1 elif f == MP_BC_FORMAT_OFFSET: - arg = bytecode[ip] | bytecode[ip + 1] << 8 - ip += 2 + if bytecode[ip] & 0x80 == 0: + arg = bytecode[ip] + ip += 1 + if opcode in Opcodes.ALL_OFFSET_SIGNED: + arg -= 0x40 + else: + arg = bytecode[ip] & 0x7F | bytecode[ip + 1] << 7 + ip += 2 + if opcode in Opcodes.ALL_OFFSET_SIGNED: + arg -= 0x4000 ip += extra_byte return f, ip - ip_start, arg