summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--py/bc.c6
-rw-r--r--py/bc0.h34
-rw-r--r--py/compile.c12
-rw-r--r--py/emit.h6
-rw-r--r--py/emitbc.c139
-rw-r--r--py/emitnative.c4
-rw-r--r--py/showbc.c24
-rw-r--r--py/vm.c26
-rw-r--r--tests/cmdline/cmd_parsetree.py.exp78
-rw-r--r--tests/cmdline/cmd_showbc.py.exp614
-rwxr-xr-xtests/run-tests.py1
-rw-r--r--tests/stress/bytecode_limit.py26
-rw-r--r--tests/stress/bytecode_limit.py.exp1
-rwxr-xr-xtools/mpy-tool.py49
14 files changed, 583 insertions, 437 deletions
diff --git a/py/bc.c b/py/bc.c
index b98df39e2..2a21ffd4b 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 842034ebf..50c4954b0 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 eb7389ec5..d61dabb9a 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 6f3593a0e..d4aea2e4d 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 c04701ca7..14a72e276 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -28,6 +28,7 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include <assert.h>
#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;
+
+ // 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);
- 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;
+ // Emit the opcode.
+ byte *c = emit_get_cur_to_write_bytecode(emit, 2 + jump_encoding_size);
+ c[0] = b1;
+ if (jump_encoding_size == 0) {
+ if (is_signed) {
+ bytecode_offset += 0x40;
+ }
+ assert(0 <= bytecode_offset && bytecode_offset <= 0x7f);
+ c[1] = bytecode_offset;
} else {
- bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3 + 0x8000;
+ if (is_signed) {
+ bytecode_offset += 0x4000;
+ }
+ c[1] = 0x80 | (bytecode_offset & 0x7f);
+ c[2] = bytecode_offset >> 7;
}
- byte *c = emit_get_cur_to_write_bytecode(emit, 3);
- c[0] = b1;
- c[1] = bytecode_offset;
- c[2] = bytecode_offset >> 8;
}
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 ca34e89f6..bddd66142 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 8430739d8..178fa451a 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 497a56962..990009c00 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 53d62a5db..6ee96b7ca 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 '<module>' (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 '<module>' (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 031820fcd..92501e124 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 '<genexpr>' (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 '<genexpr>' (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 '<listcomp>' (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 '<listcomp>' (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 '<dictcomp>' (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 '<dictcomp>' (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 9c298dae3..d0ecc74a9 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 000000000..0cb0c21e4
--- /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 000000000..3214bfe58
--- /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 73753094e..1ce301ab9 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