8000 py: Rework bytecode and .mpy file format to be mostly static data. · micropython/micropython@f2040bf · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit f2040bf

Browse files
committed
py: Rework bytecode and .mpy file format to be mostly static data.
Background: .mpy files are precompiled .py files, built using mpy-cross, that contain compiled bytecode functions (and can also contain machine code). The benefit of using an .mpy file over a .py file is that they are faster to import and take less memory when importing. They are also smaller on disk. But the real benefit of .mpy files comes when they are frozen into the firmware. This is done by loading the .mpy file during compilation of the firmware and turning it into a set of big C data structures (the job of mpy-tool.py), which are then compiled and downloaded into the ROM of a device. These C data structures can be executed in-place, ie directly from ROM. This makes importing even faster because there is very little to do, and also means such frozen modules take up much less RAM (because their bytecode stays in ROM). The downside of frozen code is that it requires recompiling and reflashing the entire firmware. This can be a big barrier to entry, slows down development time, and makes it harder to do OTA updates of frozen code (because the whole firmware must be updated). This commit attempts to solve this problem by providing a solution that sits between loading .mpy files into RAM and freezing them into the firmware. The .mpy file format has been reworked so that it consists of data and bytecode which is mostly static and ready to run in-place. If these new .mpy files are located in flash/ROM which is memory addressable, the .mpy file can be executed (mostly) in-place. With this approach there is still a small amount of unpacking and linking of the .mpy file that needs to be done when it's imported, but it's still much better than loading an .mpy from disk into RAM (although not as good as freezing .mpy files into the firmware). The main trick to make static .mpy files is to adjust the bytecode so any qstrs that it references now go through a lookup table to convert from local qstr number in the module to global qstr number in the firmware. That means the bytecode does not need linking/rewriting of qstrs when it's loaded. Instead only a small qstr table needs to be built (and put in RAM) at import time. This means the bytecode itself is static/constant and can be used directly if it's in addressable memory. Also the qstr string data in the .mpy file, and some constant object data, can be used directly. Note that the qstr table is global to the module (ie not per function). In more detail, in the VM what used to be (schematically): qst = DECODE_QSTR_VALUE; is now (schematically): idx = DECODE_QSTR_INDEX; qst = qstr_table[idx]; That allows the bytecode to be fixed at compile time and not need relinking/rewriting of the qstr values. Only qstr_table needs to be linked when the .mpy is loaded. Incidentally, this helps to reduce the size of bytecode because what used to be 2-byte qstr values in the bytecode are now (mostly) 1-byte indices. If the module uses the same qstr more than two times then the bytecode is smaller than before. The following changes are measured for this commit compared to the previous (the baseline): - average 7%-9% reduction in size of .mpy files - frozen code size is reduced by about 5%-7% - importing .py files uses about 5% less RAM in total - importing .mpy files uses about 4% less RAM in total - importing .py and .mpy files takes about the same time as before The qstr indirection in the bytecode has only a small impact on VM performance. For stm32 on PYBv1.0 the performance change of this commit is: diff of scores (higher is better) N=100 M=100 baseline -> this-commit diff diff% (error%) bm_chaos.py 371.07 -> 357.39 : -13.68 = -3.687% (+/-0.02%) bm_fannkuch.py 78.72 -> 77.49 : -1.23 = -1.563% (+/-0.01%) bm_fft.py 2591.73 -> 2539.28 : -52.45 = -2.024% (+/-0.00%) bm_float.py 6034.93 -> 5908.30 : -126.63 = -2.098% (+/-0.01%) bm_hexiom.py 48.96 -> 47.93 : -1.03 = -2.104% (+/-0.00%) bm_nqueens.py 4510.63 -> 4459.94 : -50.69 = -1.124% (+/-0.00%) bm_pidigits.py 650.28 -> 644.96 : -5.32 = -0.818% (+/-0.23%) core_import_mpy_multi.py 564.77 -> 581.49 : +16.72 = +2.960% (+/-0.01%) core_import_mpy_single.py 68.67 -> 67.16 : -1.51 = -2.199% (+/-0.01%) core_qstr.py 64.16 -> 64.12 : -0.04 = -0.062% (+/-0.00%) core_yield_from.py 362.58 -> 354.50 : -8.08 = -2.228% (+/-0.00%) misc_aes.py 429.69 -> 405.59 : -24.10 = -5.609% (+/-0.01%) misc_mandel.py 3485.13 -> 3416.51 : -68.62 = -1.969% (+/-0.00%) misc_pystone.py 2496.53 -> 2405.56 : -90.97 = -3.644% (+/-0.01%) misc_raytrace.py 381.47 -> 374.01 : -7.46 = -1.956% (+/-0.01%) viper_call0.py 576.73 -> 572.49 : -4.24 = -0.735% (+/-0.04%) viper_call1a.py 550.37 -> 546.21 : -4.16 = -0.756% (+/-0.09%) viper_call1b.py 438.23 -> 435.68 : -2.55 = -0.582% (+/-0.06%) viper_call1c.py 442.84 -> 440.04 : -2.80 = -0.632% (+/-0.08%) viper_call2a.py 536.31 -> 532.35 : -3.96 = -0.738% (+/-0.06%) viper_call2b.py 382.34 -> 377.07 : -5.27 = -1.378% (+/-0.03%) And for unix on x64: diff of scores (higher is better) N=2000 M=2000 baseline -> this-commit diff diff% (error%) bm_chaos.py 13594.20 -> 13073.84 : -520.36 = -3.828% (+/-5.44%) bm_fannkuch.py 60.63 -> 59.58 : -1.05 = -1.732% (+/-3.01%) bm_fft.py 112009.15 -> 111603.32 : -405.83 = -0.362% (+/-4.03%) bm_float.py 246202.55 -> 247923.81 : +1721.26 = +0.699% (+/-2.79%) bm_hexiom.py 615.65 -> 617.21 : +1.56 = +0.253% (+/-1.64%) bm_nqueens.py 215807.95 -> 215600.96 : -206.99 = -0.096% (+/-3.52%) bm_pidigits.py 8246.74 -> 8422.82 : +176.08 = +2.135% (+/-3.64%) misc_aes.py 16133.00 -> 16452.74 : +319.74 = +1.982% (+/-1.50%) misc_mandel.py 128146.69 -> 130796.43 : +2649.74 = +2.068% (+/-3.18%) misc_pystone.py 83811.49 -> 83124.85 : -686.64 = -0.819% (+/-1.03%) misc_raytrace.py 21688.02 -> 21385.10 : -302.92 = -1.397% (+/-3.20%) The code size change is (firmware with a lot of frozen code benefits the most): bare-arm: +396 +0.697% minimal x86: +1595 +0.979% [incl +32(data)] unix x64: +2408 +0.470% [incl +800(data)] unix nanbox: +1396 +0.309% [incl -96(data)] stm32: -1256 -0.318% PYBV10 cc3200: +288 +0.157% esp8266: -260 -0.037% GENERIC esp32: -216 -0.014% GENERIC[incl -1072(data)] nrf: +116 +0.067% pca10040 rp2: -664 -0.135% PICO samd: +844 +0.607% ADAFRUIT_ITSYBITSY_M4_EXPRESS As part of this change the .mpy file format version is bumped to version 6. And mpy-tool.py has been improved to provide a good visualisation of the contents of .mpy files. In summary: this commit changes the bytecode to use qstr indirection, and reworks the .mpy file format to be simpler and allow .mpy files to be executed in-place. Performance is not impacted too much. Eventually it will be possible to store such .mpy files in a linear, read-only, memory- mappable filesystem so they can be executed from flash/ROM. This will essentially be able to replace frozen code for most applications. Signed-off-by: Damien George <damien@micropython.org>
1 parent 64bfaae commit f2040bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2378
-1743
lines changed

mpy-cross/main.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha
7272
#endif
7373

7474
mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
75-
mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, false);
75+
mp_module_context_t *ctx = m_new_obj(mp_module_context_t);
76+
mp_compiled_module_t cm = mp_compile_to_raw_code(&parse_tree, source_name, false, ctx);
7677

7778
vstr_t vstr;
7879
vstr_init(&vstr, 16);
@@ -83,7 +84,7 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha
8384
} else {
8485
vstr_add_str(&vstr, output_file);
8586
}
86-
mp_raw_code_save_file(rc, vstr_null_terminated_str(&vstr));
87+
mp_raw_code_save_file(&cm, vstr_null_terminated_str(&vstr));
8788
vstr_clear(&vstr);
8889

8990
nlr_pop();

ports/unix/coverage.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <string.h>
33

44
#include "py/obj.h"
5+
#include "py/objfun.h"
56
#include "py/objstr.h"
67
#include "py/runtime.h"
78
#include "py/gc.h"
@@ -449,7 +450,10 @@ STATIC mp_obj_t extra_coverage(void) {
449450
mp_printf(&mp_plat_print, "# VM\n");
450451

451452
// call mp_execute_bytecode with invalide bytecode (should raise NotImplementedError)
453+
mp_module_context_t context;
452454
mp_obj_fun_bc_t fun_bc;
455+
fun_bc.context = &context;
456+
fun_bc.child_table = NULL;
453457
fun_bc.bytecode = (const byte *)"\x01"; // just needed for n_state
454458
mp_code_state_t *code_state = m_new_obj_var(mp_code_state_t, mp_obj_t, 1);
455459
code_state->fun_bc = &fun_bc;

py/asmbase.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) {
6161
// all functions must go through this one to emit bytes
6262
// if as->pass < MP_ASM_PASS_EMIT, then this function just counts the number
6363
// of bytes needed and returns NULL, and callers should not store any data
64-
uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write) {
64+
uint8_t *mp_asm_base_get_cur_to_write_bytes(void *as_in, size_t num_bytes_to_write) {
65+
mp_asm_base_t *as = as_in;
6566
uint8_t *c = NULL;
6667
if (as->pass == MP_ASM_PASS_EMIT) {
6768
assert(as->code_offset + num_bytes_to_write <= as->code_size);

py/asmbase.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ typedef struct _mp_asm_base_t {
4545
void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels);
4646
void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code);
4747
void mp_asm_base_start_pass(mp_asm_base_t *as, int pass);
48-
uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write);
48+
uint8_t *mp_asm_base_get_cur_to_write_bytes(void *as, size_t num_bytes_to_write);
4949
void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label);
5050
void mp_asm_base_align(mp_asm_base_t *as, unsigned int align);
5151
void mp_asm_base_data(mp_asm_base_t *as, unsigned int bytesize, uintptr_t val);

py/bc.c

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
#include <string.h>
3030
#include <assert.h>
3131

32-
#include "py/runtime.h"
3332
#include "py/bc0.h"
3433
#include "py/bc.h"
34+
#include "py/objfun.h"
3535

3636
#if MICROPY_DEBUG_VERBOSE // print debugging info
3737
#define DEBUG_PRINT (1)
@@ -40,7 +40,23 @@
4040
#define DEBUG_printf(...) (void)0
4141
#endif
4242

43-
#if !MICROPY_PERSISTENT_CODE
43+
void mp_encode_uint(void *env, mp_encode_uint_allocator_t allocator, mp_uint_t val) {
44+
// We store each 7 bits in a separate byte, and that's how many bytes needed
45+
byte buf[MP_ENCODE_UINT_MAX_BYTES];
46+
byte *p = buf + sizeof(buf);
47+
// We encode in little-ending order, but store in big-endian, to help decoding
48+
do {
49+
*--p = val & 0x7f;
50+
val >>= 7;
51+
} while (val != 0);
52+
byte *c = allocator(env, buf + sizeof(buf) - p);
53+
if (c != NULL) {
54+
while (p != buf + sizeof(buf) - 1) {
55+
*c++ = *p++ | 0x80;
56+
}
57+
*c = *p;
58+
}
59+
}
4460

4561
mp_uint_t mp_decode_uint(const byte **ptr) {
4662
mp_uint_t unum = 0;
@@ -72,8 +88,6 @@ const byte *mp_decode_uint_skip(const byte *ptr) {
7288
return ptr;
7389
}
7490

75-
#endif
76-
7791
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
7892
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
7993
// generic message, used also for other argument issues
@@ -107,18 +121,15 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) {
107121
// On entry code_state should be allocated somewhere (stack/heap) and
108122
// contain the following valid entries:
109123
// - code_state->fun_bc should contain a pointer to the function object
110-
// - code_state->ip should contain the offset in bytes from the pointer
111-
// code_state->fun_bc->bytecode to the entry n_state (0 for bytecode, non-zero for native)
124+
// - code_state->ip should contain a pointer to the beginning of the prelude
125+
// - code_state->n_state should be the number of objects in the local state
112126
void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) {
113127
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
114128
// usage for the common case of positional only args.
115129

116130
// get the function object that we want to set up (could be bytecode or native code)
117131
mp_obj_fun_bc_t *self = code_state->fun_bc;
118132

119-
// ip comes in as an offset into bytecode, so turn it into a true pointer
120-
code_state->ip = self->bytecode + (size_t)code_state->ip;
121-
122133
#if MICROPY_STACKLESS
123134
code_state->prev = NULL;
124135
#endif
@@ -134,6 +145,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
134145
// Decode prelude
135146
size_t n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args;
136147
MP_BC_PRELUDE_SIG_DECODE_INTO(code_state->ip, n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args);
148+
MP_BC_PRELUDE_SIZE_DECODE(code_state->ip);
137149
(void)n_state_unused;
138150
(void)n_exc_stack_unused;
139151

@@ -194,14 +206,20 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
194206
*var_pos_kw_args = dict;
195207
}
196208

197-
// get pointer to arg_names array
198-
const mp_obj_t *arg_names = (const mp_obj_t *)self->const_table;
199-
200209
for (size_t i = 0; i < n_kw; i++) {
201210
// the keys in kwargs are expected to be qstr objects
202211
mp_obj_t wanted_arg_name = kwargs[2 * i];
212+
213+
// get pointer to arg_names array
214+
const uint8_t *arg_names = code_state->ip;
215+
arg_names = mp_decode_uint_skip(arg_names);
216+
203217
for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) {
204-
if (wanted_arg_name == arg_names[j]) {
218+
qstr arg_qstr = mp_decode_uint(&arg_names);
219+
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
220+
arg_qstr = self->context->constants.qstr_table[arg_qstr];
221+
#endif
222+
if (wanted_arg_name == MP_OBJ_NEW_QSTR(arg_qstr)) {
205223
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
206224
mp_raise_msg_varg(&mp_type_TypeError,
207225
MP_ERROR_TEXT("function got multiple values for argument '%q'"), MP_OBJ_QSTR_VALUE(wanted_arg_name));
@@ -248,17 +266,25 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
248266

249267
// Check that all mandatory keyword args are specified
250268
// Fill in default kw args if we have them
269+
const uint8_t *arg_names = mp_decode_uint_skip(code_state->ip);
270+
for (size_t i = 0; i < n_pos_args; i++) {
271+
arg_names = mp_decode_uint_skip(arg_names);
272+
}
251273
for (size_t i = 0; i < n_kwonly_args; i++) {
274+
qstr arg_qstr = mp_decode_uint(&arg_names);
275+
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
276+
arg_qstr = self->context->constants.qstr_table[arg_qstr];
277+
#endif
252278
if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) {
253279
mp_map_elem_t *elem = NULL;
254280
if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {
255-
elem = mp_map_lookup(&((mp_obj_dict_t *)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, arg_names[n_pos_args + i], MP_MAP_LOOKUP);
281+
elem = mp_map_lookup(&((mp_obj_dict_t *)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, MP_OBJ_NEW_QSTR(arg_qstr), MP_MAP_LOOKUP);
256282
}
257283
if (elem != NULL) {
258284
code_state->state[n_state - 1 - n_pos_args - i] = elem->value;
259285
} else {
260286
mp_raise_msg_varg(&mp_type_TypeError,
261-
MP_ERROR_TEXT("function missing required keyword argument '%q'"), MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i]));
287+
MP_ERROR_TEXT("function missing required keyword argument '%q'"), arg_qstr);
262288
}
263289
}
264290
}
@@ -273,12 +299,8 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
273299
}
274300
}
275301

276-
// read the size part of the prelude
277-
const byte *ip = code_state->ip;
278-
MP_BC_PRELUDE_SIZE_DECODE(ip);
279-
280-
// jump over code info (source file and line-number mapping)
281-
ip += n_info;
302+
// jump over code info (source file, argument names and line-number mapping)
303+
const uint8_t *ip = code_state->ip + n_info;
282304

283305
// bytecode prelude: initialise closed over variables
284306
for (; n_cell; --n_cell) {
@@ -287,11 +309,6 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
287309
mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
288310
}
289311

290-
#if !MICROPY_PERSISTENT_CODE
291-
// so bytecode is aligned
292-
ip = MP_ALIGN(ip, sizeof(mp_uint_t));
293-
#endif
294-
295312
// now that we skipped over the prelude, set the ip for the VM
296313
code_state->ip = ip;
297314

py/bc.h

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#define MICROPY_INCLUDED_PY_BC_H
2929

3030
#include "py/runtime.h"
31-
#include "py/objfun.h"
3231

3332
// bytecode layout:
3433
//
@@ -50,27 +49,26 @@
5049
//
5150
// source info section:
5251
// simple_name : var qstr
53-
// source_file : var qstr
52+
// argname0 : var qstr
53+
// ... : var qstr
54+
// argnameN : var qstr N = num_pos_args + num_kwonly_args - 1
5455
// <line number info>
5556
//
5657
// closure section:
5758
// local_num0 : byte
5859
// ... : byte
5960
// local_numN : byte N = n_cells-1
6061
//
61-
// <word alignment padding> only needed if bytecode contains pointers
62-
//
6362
// <bytecode>
6463
//
6564
//
6665
// constant table layout:
6766
//
68-
// argname0 : obj (qstr)
69-
// ... : obj (qstr)
70-
// argnameN : obj (qstr) N = num_pos_args + num_kwonly_args
7167
// const0 : obj
7268
// constN : obj
7369

70+
#define MP_ENCODE_UINT_MAX_BYTES ((MP_BYTES_PER_OBJ_WORD * 8 + 6) / 7)
71+
7472
#define MP_BC_PRELUDE_SIG_ENCODE(S, E, scope, out_byte, out_env) \
7573
do { \
7674
/*// Get values to store in prelude */ \
@@ -182,9 +180,9 @@ typedef struct _mp_bytecode_prelude_t {
182180
uint n_pos_args;
183181
uint n_kwonly_args;
184182
uint n_def_pos_args;
185-
qstr qstr_block_name;
186-
qstr qstr_source_file;
183+
qstr qstr_block_name_idx;
187184
const byte *line_info;
185+
const byte *line_info_top;
188186
const byte *opcodes;
189187
} mp_bytecode_prelude_t;
190188

@@ -198,12 +196,46 @@ typedef struct _mp_exc_stack_t {
198196
mp_obj_base_t *prev_exc;
199197
} mp_exc_stack_t;
200198

199+
// Constants associated with a module, to interface bytecode with runtime.
200+
typedef struct _mp_module_constants_t {
201+
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
202+
qstr_short_t *qstr_table;
203+
#else
204+
qstr source_file;
205+
#endif
206+
mp_obj_t *obj_table;
207+
} mp_module_constants_t;
208+
209+
// State associated with a module.
210+
typedef struct _mp_module_context_t {
211+
mp_obj_module_t module;
212+
mp_module_constants_t constants;
213+
} mp_module_context_t;
214+
215+
// Outer level struct defining a compiled module.
216+
typedef struct _mp_compiled_module_t {
217+
const mp_module_context_t *context;
218+
const struct _mp_raw_code_t *rc;
219+
#if MICROPY_PERSISTENT_CODE_SAVE
220+
bool has_native;
221+
size_t n_qstr;
222+
size_t n_obj;
223+
#endif
224+
} mp_compiled_module_t;
225+
226+
// Outer level struct defining a frozen module.
227+
typedef struct _mp_frozen_module_t {
228+
const mp_module_constants_t constants;
229+
const struct _mp_raw_code_t *rc;
230+
} mp_frozen_module_t;
231+
232+
// State for an executing function.
201233
typedef struct _mp_code_state_t {
202234
// The fun_bc entry points to the underlying function object that is being executed.
203235
// It is needed to access the start of bytecode and the const_table.
204236
// It is also needed to prevent the GC from reclaiming the bytecode during execution,
205237
// because the ip pointer below will always point to the interior of the bytecode.
206-
mp_obj_fun_bc_t *fun_bc;
238+
struct _mp_obj_fun_bc_t *fun_bc;
207239
const byte *ip;
208240
mp_obj_t *sp;
209241
uint16_t n_state;
@@ -222,17 +254,21 @@ typedef struct _mp_code_state_t {
222254
// mp_exc_stack_t exc_state[0];
223255
} mp_code_state_t;
224256

257+
// Allocator may return NULL, in which case data is not stored (can be used to compute size).
258+
typedef uint8_t *(*mp_encode_uint_allocator_t)(void *env, size_t nbytes);
259+
260+
void mp_encode_uint(void *env, mp_encode_uint_allocator_t allocator, mp_uint_t val);
225261
mp_uint_t mp_decode_uint(const byte **ptr);
226262
mp_uint_t mp_decode_uint_value(const byte *ptr);
227263
const byte *mp_decode_uint_skip(const byte *ptr);
228264

229265
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc);
230266
mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args);
231267
void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args);
232-
void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table);
233-
void mp_bytecode_print2(const mp_print_t *print, const byte *code, size_t len, const mp_uint_t *const_table);
268+
void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *code, mp_uint_t len, const mp_module_constants_t *cm);
269+
void mp_bytecode_print2(const mp_print_t *print, const byte *code, size_t len, const mp_module_constants_t *cm);
234270
const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip);
235-
#define mp_bytecode_print_inst(print, code, const_table) mp_bytecode_print2(print, code, 1, const_table)
271+
#define mp_bytecode_print_inst(print, code, x_table) mp_bytecode_print2(print, code, 1, x_table)
236272

237273
// Helper macros to access pointer with least significant bits holding flags
238274
#define MP_TAGPTR_PTR(x) ((void *)((uintptr_t)(x) & ~((uintptr_t)3)))
@@ -246,10 +282,26 @@ uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint);
246282

247283
#endif
248284

249-
static inline size_t mp_bytecode_get_source_line(const byte *line_info, size_t bc_offset) {
285+
static inline void mp_module_context_alloc_tables(mp_module_context_t *context, size_t n_qstr, size_t n_obj) {
286+
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
287+
size_t nq = (n_qstr * sizeof(qstr_short_t) + sizeof(mp_uint_t) - 1) / sizeof(mp_uint_t);
288+
size_t no = n_obj;
289+
mp_uint_t *mem = m_new(mp_uint_t, nq + no);
290+
context->constants.qstr_table = (void *)(mem);
291+
context->constants.obj_table = (void *)(mem + nq);
292+
#else
293+
if (n_obj == 0) {
294+
context->constants.obj_table = NULL;
295+
} else {
296+
context->constants.obj_table = m_new(mp_obj_t, n_obj);
297+
}
298+
#endif
299+
}
300+
301+
static inline size_t mp_bytecode_get_source_line(const byte *line_info, const byte *line_info_top, size_t bc_offset) {
250302
size_t source_line = 1;
251-
size_t c;
252-
while ((c = *line_info)) {
303+
while (line_info < line_info_top) {
304+
size_t c = *line_info;
253305
size_t b, l;
254306
if ((c & 0x80) == 0) {
255307
// 0b0LLBBBBB encoding

py/builtinevex.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj
5454
// the correct one
5555
if (mp_obj_is_type(self->module_fun, &mp_type_fun_bc)) {
5656
mp_obj_fun_bc_t *fun_bc = MP_OBJ_TO_PTR(self->module_fun);
57-
fun_bc->globals = globals;
57+
((mp_module_context_t *)fun_bc->context)->module.globals = globals;
5858
}
5959

6060
// execute code

0 commit comments

Comments
 (0)
0