py: Change jump opcodes to emit 1-byte jump offset when possible.

This commit introduces changes:

- All jump opcodes are changed to have variable length arguments, of either
  1 or 2 bytes (previously they were fixed at 2 bytes).  In most cases only
  1 byte is needed to encode the short jump offset, saving bytecode size.

- The bytecode emitter now selects 1 byte jump arguments when the jump
  offset is guaranteed to fit in 1 byte.  This is achieved by checking if
  the code size changed during the last pass and, if it did (if it shrank),
  then requesting that the compiler make another pass to get the correct
  offsets of the now-smaller code.  This can continue multiple times until
  the code stabilises.  The code can only ever shrink so this iteration is
  guaranteed to complete.  In most cases no extra passes are needed, the
  original 4 passes are enough to get it right by the 4th pass (because the
  2nd pass computes roughly the correct labels and the 3rd pass computes
  the correct size for the jump argument).

This change to the jump opcode encoding reduces .mpy files and RAM usage
(when bytecode is in RAM) by about 2% on average.

The performance of the VM is not impacted, at least within measurment of
the performance benchmark suite.

Code size is reduced for builds that include a decent amount of frozen
bytecode.  ARM Cortex-M builds without any frozen code increase by about
350 bytes.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George 2022-03-16 09:37:58 +11:00
parent 9e3e67b1d8
commit 538c3c0a55
14 changed files with 584 additions and 438 deletions

View File

@ -335,8 +335,12 @@ uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint)
}
}
} else if (f == MP_BC_FORMAT_OFFSET) {
if ((*ip & 0x80) == 0) {
ip += 1;
} else {
ip += 2;
}
}
ip += extra_byte;
}
*opcode_size = ip - ip_start;

View File

@ -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)

View File

@ -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)) {
}
}
}
}

View File

@ -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);

View File

@ -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;
}
byte *c = emit_get_cur_to_write_bytecode(emit, 3);
c[0] = b1;
c[1] = bytecode_offset;
c[2] = bytecode_offset >> 8;
// 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;
}
// 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;
// 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;
if (jump_encoding_size == 0) {
if (is_signed) {
bytecode_offset += 0x40;
}
assert(0 <= bytecode_offset && bytecode_offset <= 0x7f);
c[1] = bytecode_offset;
c[2] = bytecode_offset >> 8;
} 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);
assert(emit->pass == MP_PASS_STACK_SIZE || emit->bytecode_offset <= emit->label_offsets[l]);
// Assign label offset.
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);
}
}
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) {

View File

@ -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) {

View File

@ -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

26
py/vm.c
View File

@ -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

View File

@ -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\+

View File

@ -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

View File

@ -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("\\", "/")

View File

@ -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)
"""
)

View File

@ -0,0 +1 @@
[123]

View File

@ -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,6 +333,9 @@ def mp_opcode_format(bytecode, ip, count_var_uint):
ip += 1
ip += 1
elif f == MP_BC_FORMAT_OFFSET:
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
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