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>
This commit is contained in:
parent
64bfaae7ab
commit
f2040bfc7e
@ -72,7 +72,8 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha
|
||||
#endif
|
||||
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
|
||||
mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, false);
|
||||
mp_module_context_t *ctx = m_new_obj(mp_module_context_t);
|
||||
mp_compiled_module_t cm = mp_compile_to_raw_code(&parse_tree, source_name, false, ctx);
|
||||
|
||||
vstr_t vstr;
|
||||
vstr_init(&vstr, 16);
|
||||
@ -83,7 +84,7 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha
|
||||
} else {
|
||||
vstr_add_str(&vstr, output_file);
|
||||
}
|
||||
mp_raw_code_save_file(rc, vstr_null_terminated_str(&vstr));
|
||||
mp_raw_code_save_file(&cm, vstr_null_terminated_str(&vstr));
|
||||
vstr_clear(&vstr);
|
||||
|
||||
nlr_pop();
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/objfun.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
@ -449,7 +450,10 @@ STATIC mp_obj_t extra_coverage(void) {
|
||||
mp_printf(&mp_plat_print, "# VM\n");
|
||||
|
||||
// call mp_execute_bytecode with invalide bytecode (should raise NotImplementedError)
|
||||
mp_module_context_t context;
|
||||
mp_obj_fun_bc_t fun_bc;
|
||||
fun_bc.context = &context;
|
||||
fun_bc.child_table = NULL;
|
||||
fun_bc.bytecode = (const byte *)"\x01"; // just needed for n_state
|
||||
mp_code_state_t *code_state = m_new_obj_var(mp_code_state_t, mp_obj_t, 1);
|
||||
code_state->fun_bc = &fun_bc;
|
||||
|
@ -61,7 +61,8 @@ void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) {
|
||||
// all functions must go through this one to emit bytes
|
||||
// if as->pass < MP_ASM_PASS_EMIT, then this function just counts the number
|
||||
// of bytes needed and returns NULL, and callers should not store any data
|
||||
uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write) {
|
||||
uint8_t *mp_asm_base_get_cur_to_write_bytes(void *as_in, size_t num_bytes_to_write) {
|
||||
mp_asm_base_t *as = as_in;
|
||||
uint8_t *c = NULL;
|
||||
if (as->pass == MP_ASM_PASS_EMIT) {
|
||||
assert(as->code_offset + num_bytes_to_write <= as->code_size);
|
||||
|
@ -45,7 +45,7 @@ typedef struct _mp_asm_base_t {
|
||||
void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels);
|
||||
void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code);
|
||||
void mp_asm_base_start_pass(mp_asm_base_t *as, int pass);
|
||||
uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write);
|
||||
uint8_t *mp_asm_base_get_cur_to_write_bytes(void *as, size_t num_bytes_to_write);
|
||||
void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label);
|
||||
void mp_asm_base_align(mp_asm_base_t *as, unsigned int align);
|
||||
void mp_asm_base_data(mp_asm_base_t *as, unsigned int bytesize, uintptr_t val);
|
||||
|
69
py/bc.c
69
py/bc.c
@ -29,9 +29,9 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/bc0.h"
|
||||
#include "py/bc.h"
|
||||
#include "py/objfun.h"
|
||||
|
||||
#if MICROPY_DEBUG_VERBOSE // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@ -40,7 +40,23 @@
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
#if !MICROPY_PERSISTENT_CODE
|
||||
void mp_encode_uint(void *env, mp_encode_uint_allocator_t allocator, mp_uint_t val) {
|
||||
// We store each 7 bits in a separate byte, and that's how many bytes needed
|
||||
byte buf[MP_ENCODE_UINT_MAX_BYTES];
|
||||
byte *p = buf + sizeof(buf);
|
||||
// We encode in little-ending order, but store in big-endian, to help decoding
|
||||
do {
|
||||
*--p = val & 0x7f;
|
||||
val >>= 7;
|
||||
} while (val != 0);
|
||||
byte *c = allocator(env, buf + sizeof(buf) - p);
|
||||
if (c != NULL) {
|
||||
while (p != buf + sizeof(buf) - 1) {
|
||||
*c++ = *p++ | 0x80;
|
||||
}
|
||||
*c = *p;
|
||||
}
|
||||
}
|
||||
|
||||
mp_uint_t mp_decode_uint(const byte **ptr) {
|
||||
mp_uint_t unum = 0;
|
||||
@ -72,8 +88,6 @@ const byte *mp_decode_uint_skip(const byte *ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
// generic message, used also for other argument issues
|
||||
@ -107,8 +121,8 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) {
|
||||
// On entry code_state should be allocated somewhere (stack/heap) and
|
||||
// contain the following valid entries:
|
||||
// - code_state->fun_bc should contain a pointer to the function object
|
||||
// - code_state->ip should contain the offset in bytes from the pointer
|
||||
// code_state->fun_bc->bytecode to the entry n_state (0 for bytecode, non-zero for native)
|
||||
// - code_state->ip should contain a pointer to the beginning of the prelude
|
||||
// - code_state->n_state should be the number of objects in the local state
|
||||
void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
|
||||
// usage for the common case of positional only args.
|
||||
@ -116,9 +130,6 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
|
||||
// get the function object that we want to set up (could be bytecode or native code)
|
||||
mp_obj_fun_bc_t *self = code_state->fun_bc;
|
||||
|
||||
// ip comes in as an offset into bytecode, so turn it into a true pointer
|
||||
code_state->ip = self->bytecode + (size_t)code_state->ip;
|
||||
|
||||
#if MICROPY_STACKLESS
|
||||
code_state->prev = NULL;
|
||||
#endif
|
||||
@ -134,6 +145,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
|
||||
// Decode prelude
|
||||
size_t n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args;
|
||||
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);
|
||||
MP_BC_PRELUDE_SIZE_DECODE(code_state->ip);
|
||||
(void)n_state_unused;
|
||||
(void)n_exc_stack_unused;
|
||||
|
||||
@ -194,14 +206,20 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
|
||||
*var_pos_kw_args = dict;
|
||||
}
|
||||
|
||||
// get pointer to arg_names array
|
||||
const mp_obj_t *arg_names = (const mp_obj_t *)self->const_table;
|
||||
|
||||
for (size_t i = 0; i < n_kw; i++) {
|
||||
// the keys in kwargs are expected to be qstr objects
|
||||
mp_obj_t wanted_arg_name = kwargs[2 * i];
|
||||
|
||||
// get pointer to arg_names array
|
||||
const uint8_t *arg_names = code_state->ip;
|
||||
arg_names = mp_decode_uint_skip(arg_names);
|
||||
|
||||
for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) {
|
||||
if (wanted_arg_name == arg_names[j]) {
|
||||
qstr arg_qstr = mp_decode_uint(&arg_names);
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
arg_qstr = self->context->constants.qstr_table[arg_qstr];
|
||||
#endif
|
||||
if (wanted_arg_name == MP_OBJ_NEW_QSTR(arg_qstr)) {
|
||||
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
|
||||
mp_raise_msg_varg(&mp_type_TypeError,
|
||||
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
|
||||
|
||||
// Check that all mandatory keyword args are specified
|
||||
// Fill in default kw args if we have them
|
||||
const uint8_t *arg_names = mp_decode_uint_skip(code_state->ip);
|
||||
for (size_t i = 0; i < n_pos_args; i++) {
|
||||
arg_names = mp_decode_uint_skip(arg_names);
|
||||
}
|
||||
for (size_t i = 0; i < n_kwonly_args; i++) {
|
||||
qstr arg_qstr = mp_decode_uint(&arg_names);
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
arg_qstr = self->context->constants.qstr_table[arg_qstr];
|
||||
#endif
|
||||
if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) {
|
||||
mp_map_elem_t *elem = NULL;
|
||||
if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
if (elem != NULL) {
|
||||
code_state->state[n_state - 1 - n_pos_args - i] = elem->value;
|
||||
} else {
|
||||
mp_raise_msg_varg(&mp_type_TypeError,
|
||||
MP_ERROR_TEXT("function missing required keyword argument '%q'"), MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i]));
|
||||
MP_ERROR_TEXT("function missing required keyword argument '%q'"), arg_qstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -273,12 +299,8 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
|
||||
}
|
||||
}
|
||||
|
||||
// read the size part of the prelude
|
||||
const byte *ip = code_state->ip;
|
||||
MP_BC_PRELUDE_SIZE_DECODE(ip);
|
||||
|
||||
// jump over code info (source file and line-number mapping)
|
||||
ip += n_info;
|
||||
// jump over code info (source file, argument names and line-number mapping)
|
||||
const uint8_t *ip = code_state->ip + n_info;
|
||||
|
||||
// bytecode prelude: initialise closed over variables
|
||||
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
|
||||
mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
|
||||
}
|
||||
|
||||
#if !MICROPY_PERSISTENT_CODE
|
||||
// so bytecode is aligned
|
||||
ip = MP_ALIGN(ip, sizeof(mp_uint_t));
|
||||
#endif
|
||||
|
||||
// now that we skipped over the prelude, set the ip for the VM
|
||||
code_state->ip = ip;
|
||||
|
||||
|
84
py/bc.h
84
py/bc.h
@ -28,7 +28,6 @@
|
||||
#define MICROPY_INCLUDED_PY_BC_H
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/objfun.h"
|
||||
|
||||
// bytecode layout:
|
||||
//
|
||||
@ -50,7 +49,9 @@
|
||||
//
|
||||
// source info section:
|
||||
// simple_name : var qstr
|
||||
// source_file : var qstr
|
||||
// argname0 : var qstr
|
||||
// ... : var qstr
|
||||
// argnameN : var qstr N = num_pos_args + num_kwonly_args - 1
|
||||
// <line number info>
|
||||
//
|
||||
// closure section:
|
||||
@ -58,19 +59,16 @@
|
||||
// ... : byte
|
||||
// local_numN : byte N = n_cells-1
|
||||
//
|
||||
// <word alignment padding> only needed if bytecode contains pointers
|
||||
//
|
||||
// <bytecode>
|
||||
//
|
||||
//
|
||||
// constant table layout:
|
||||
//
|
||||
// argname0 : obj (qstr)
|
||||
// ... : obj (qstr)
|
||||
// argnameN : obj (qstr) N = num_pos_args + num_kwonly_args
|
||||
// const0 : obj
|
||||
// constN : obj
|
||||
|
||||
#define MP_ENCODE_UINT_MAX_BYTES ((MP_BYTES_PER_OBJ_WORD * 8 + 6) / 7)
|
||||
|
||||
#define MP_BC_PRELUDE_SIG_ENCODE(S, E, scope, out_byte, out_env) \
|
||||
do { \
|
||||
/*// Get values to store in prelude */ \
|
||||
@ -182,9 +180,9 @@ typedef struct _mp_bytecode_prelude_t {
|
||||
uint n_pos_args;
|
||||
uint n_kwonly_args;
|
||||
uint n_def_pos_args;
|
||||
qstr qstr_block_name;
|
||||
qstr qstr_source_file;
|
||||
qstr qstr_block_name_idx;
|
||||
const byte *line_info;
|
||||
const byte *line_info_top;
|
||||
const byte *opcodes;
|
||||
} mp_bytecode_prelude_t;
|
||||
|
||||
@ -198,12 +196,46 @@ typedef struct _mp_exc_stack_t {
|
||||
mp_obj_base_t *prev_exc;
|
||||
} mp_exc_stack_t;
|
||||
|
||||
// Constants associated with a module, to interface bytecode with runtime.
|
||||
typedef struct _mp_module_constants_t {
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
qstr_short_t *qstr_table;
|
||||
#else
|
||||
qstr source_file;
|
||||
#endif
|
||||
mp_obj_t *obj_table;
|
||||
} mp_module_constants_t;
|
||||
|
||||
// State associated with a module.
|
||||
typedef struct _mp_module_context_t {
|
||||
mp_obj_module_t module;
|
||||
mp_module_constants_t constants;
|
||||
} mp_module_context_t;
|
||||
|
||||
// Outer level struct defining a compiled module.
|
||||
typedef struct _mp_compiled_module_t {
|
||||
const mp_module_context_t *context;
|
||||
const struct _mp_raw_code_t *rc;
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
bool has_native;
|
||||
size_t n_qstr;
|
||||
size_t n_obj;
|
||||
#endif
|
||||
} mp_compiled_module_t;
|
||||
|
||||
// Outer level struct defining a frozen module.
|
||||
typedef struct _mp_frozen_module_t {
|
||||
const mp_module_constants_t constants;
|
||||
const struct _mp_raw_code_t *rc;
|
||||
} mp_frozen_module_t;
|
||||
|
||||
// State for an executing function.
|
||||
typedef struct _mp_code_state_t {
|
||||
// The fun_bc entry points to the underlying function object that is being executed.
|
||||
// It is needed to access the start of bytecode and the const_table.
|
||||
// It is also needed to prevent the GC from reclaiming the bytecode during execution,
|
||||
// because the ip pointer below will always point to the interior of the bytecode.
|
||||
mp_obj_fun_bc_t *fun_bc;
|
||||
struct _mp_obj_fun_bc_t *fun_bc;
|
||||
const byte *ip;
|
||||
mp_obj_t *sp;
|
||||
uint16_t n_state;
|
||||
@ -222,6 +254,10 @@ typedef struct _mp_code_state_t {
|
||||
// mp_exc_stack_t exc_state[0];
|
||||
} mp_code_state_t;
|
||||
|
||||
// Allocator may return NULL, in which case data is not stored (can be used to compute size).
|
||||
typedef uint8_t *(*mp_encode_uint_allocator_t)(void *env, size_t nbytes);
|
||||
|
||||
void mp_encode_uint(void *env, mp_encode_uint_allocator_t allocator, mp_uint_t val);
|
||||
mp_uint_t mp_decode_uint(const byte **ptr);
|
||||
mp_uint_t mp_decode_uint_value(const byte *ptr);
|
||||
const byte *mp_decode_uint_skip(const byte *ptr);
|
||||
@ -229,10 +265,10 @@ const byte *mp_decode_uint_skip(const byte *ptr);
|
||||
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc);
|
||||
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);
|
||||
void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
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);
|
||||
void mp_bytecode_print2(const mp_print_t *print, const byte *code, size_t len, const mp_uint_t *const_table);
|
||||
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);
|
||||
void mp_bytecode_print2(const mp_print_t *print, const byte *code, size_t len, const mp_module_constants_t *cm);
|
||||
const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip);
|
||||
#define mp_bytecode_print_inst(print, code, const_table) mp_bytecode_print2(print, code, 1, const_table)
|
||||
#define mp_bytecode_print_inst(print, code, x_table) mp_bytecode_print2(print, code, 1, x_table)
|
||||
|
||||
// Helper macros to access pointer with least significant bits holding flags
|
||||
#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);
|
||||
|
||||
#endif
|
||||
|
||||
static inline size_t mp_bytecode_get_source_line(const byte *line_info, size_t bc_offset) {
|
||||
static inline void mp_module_context_alloc_tables(mp_module_context_t *context, size_t n_qstr, size_t n_obj) {
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
size_t nq = (n_qstr * sizeof(qstr_short_t) + sizeof(mp_uint_t) - 1) / sizeof(mp_uint_t);
|
||||
size_t no = n_obj;
|
||||
mp_uint_t *mem = m_new(mp_uint_t, nq + no);
|
||||
context->constants.qstr_table = (void *)(mem);
|
||||
context->constants.obj_table = (void *)(mem + nq);
|
||||
#else
|
||||
if (n_obj == 0) {
|
||||
context->constants.obj_table = NULL;
|
||||
} else {
|
||||
context->constants.obj_table = m_new(mp_obj_t, n_obj);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline size_t mp_bytecode_get_source_line(const byte *line_info, const byte *line_info_top, size_t bc_offset) {
|
||||
size_t source_line = 1;
|
||||
size_t c;
|
||||
while ((c = *line_info)) {
|
||||
while (line_info < line_info_top) {
|
||||
size_t c = *line_info;
|
||||
size_t b, l;
|
||||
if ((c & 0x80) == 0) {
|
||||
// 0b0LLBBBBB encoding
|
||||
|
@ -54,7 +54,7 @@ STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj
|
||||
// the correct one
|
||||
if (mp_obj_is_type(self->module_fun, &mp_type_fun_bc)) {
|
||||
mp_obj_fun_bc_t *fun_bc = MP_OBJ_TO_PTR(self->module_fun);
|
||||
fun_bc->globals = globals;
|
||||
((mp_module_context_t *)fun_bc->context)->module.globals = globals;
|
||||
}
|
||||
|
||||
// execute code
|
||||
|
@ -146,28 +146,28 @@ STATIC mp_import_stat_t stat_top_level_dir_or_file(qstr mod_name, vstr_t *dest)
|
||||
}
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER
|
||||
STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) {
|
||||
STATIC void do_load_from_lexer(mp_module_context_t *context, mp_lexer_t *lex) {
|
||||
#if MICROPY_PY___FILE__
|
||||
qstr source_name = lex->source_name;
|
||||
mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
|
||||
mp_store_attr(MP_OBJ_FROM_PTR(&context->module), MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
|
||||
#endif
|
||||
|
||||
// parse, compile and execute the module in its context
|
||||
mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj);
|
||||
mp_obj_dict_t *mod_globals = context->module.globals;
|
||||
mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD) || MICROPY_MODULE_FROZEN_MPY
|
||||
STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char *source_name) {
|
||||
STATIC void do_execute_raw_code(mp_module_context_t *context, const mp_raw_code_t *rc, const mp_module_context_t *mc, const char *source_name) {
|
||||
(void)source_name;
|
||||
|
||||
#if MICROPY_PY___FILE__
|
||||
mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(qstr_from_str(source_name)));
|
||||
mp_store_attr(MP_OBJ_FROM_PTR(&context->module), MP_QSTR___file__, MP_OBJ_NEW_QSTR(qstr_from_str(source_name)));
|
||||
#endif
|
||||
|
||||
// execute the module in its context
|
||||
mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj);
|
||||
mp_obj_dict_t *mod_globals = context->module.globals;
|
||||
|
||||
// save context
|
||||
mp_obj_dict_t *volatile old_globals = mp_globals_get();
|
||||
@ -179,7 +179,7 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, co
|
||||
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_obj_t module_fun = mp_make_function_from_raw_code(raw_code, MP_OBJ_NULL, MP_OBJ_NULL);
|
||||
mp_obj_t module_fun = mp_make_function_from_raw_code(rc, mc, NULL);
|
||||
mp_call_function_0(module_fun);
|
||||
|
||||
// finish nlr block, restore context
|
||||
@ -195,7 +195,7 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, co
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
STATIC void do_load(mp_module_context_t *module_obj, vstr_t *file) {
|
||||
#if MICROPY_MODULE_FROZEN || MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER)
|
||||
const char *file_str = vstr_null_terminated_str(file);
|
||||
#endif
|
||||
@ -222,7 +222,9 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// its data) in the list of frozen files, execute it.
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
if (frozen_type == MP_FROZEN_MPY) {
|
||||
do_execute_raw_code(module_obj, modref, file_str + frozen_path_prefix_len);
|
||||
const mp_frozen_module_t *frozen = modref;
|
||||
module_obj->constants = frozen->constants;
|
||||
do_execute_raw_code(module_obj, frozen->rc, module_obj, file_str + frozen_path_prefix_len);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -234,8 +236,8 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// the correct format and, if so, load and execute the file.
|
||||
#if MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD
|
||||
if (file_str[file->len - 3] == 'm') {
|
||||
mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str);
|
||||
do_execute_raw_code(module_obj, raw_code, file_str);
|
||||
mp_compiled_module_t cm = mp_raw_code_load_file(file_str, module_obj);
|
||||
do_execute_raw_code(module_obj, cm.rc, cm.context, file_str);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -434,7 +436,7 @@ STATIC mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name,
|
||||
size_t orig_path_len = path->len;
|
||||
vstr_add_str(path, PATH_SEP_CHAR "__init__.py");
|
||||
if (stat_file_py_or_mpy(path) == MP_IMPORT_STAT_FILE) {
|
||||
do_load(module_obj, path);
|
||||
do_load(MP_OBJ_TO_PTR(module_obj), path);
|
||||
} else {
|
||||
// No-op. Nothing to load.
|
||||
// mp_warning("%s is imported as namespace package", vstr_str(&path));
|
||||
@ -443,7 +445,7 @@ STATIC mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name,
|
||||
path->len = orig_path_len;
|
||||
} else { // MP_IMPORT_STAT_FILE
|
||||
// File -- execute "path.(m)py".
|
||||
do_load(module_obj, path);
|
||||
do_load(MP_OBJ_TO_PTR(module_obj), path);
|
||||
// Note: This should be the last component in the import path. If
|
||||
// there are remaining components then it's an ImportError
|
||||
// because the current path(the module that was just loaded) is
|
||||
|
171
py/compile.c
171
py/compile.c
@ -35,6 +35,7 @@
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/asmbase.h"
|
||||
#include "py/nativeglue.h"
|
||||
#include "py/persistentcode.h"
|
||||
|
||||
#if MICROPY_ENABLE_COMPILER
|
||||
@ -88,7 +89,7 @@ typedef enum {
|
||||
#if MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER
|
||||
|
||||
#define NATIVE_EMITTER(f) emit_native_table[mp_dynamic_compiler.native_arch]->emit_##f
|
||||
#define NATIVE_EMITTER_TABLE emit_native_table[mp_dynamic_compiler.native_arch]
|
||||
#define NATIVE_EMITTER_TABLE (emit_native_table[mp_dynamic_compiler.native_arch])
|
||||
|
||||
STATIC const emit_method_table_t *emit_native_table[] = {
|
||||
NULL,
|
||||
@ -121,7 +122,7 @@ STATIC const emit_method_table_t *emit_native_table[] = {
|
||||
#else
|
||||
#error "unknown native emitter"
|
||||
#endif
|
||||
#define NATIVE_EMITTER_TABLE &NATIVE_EMITTER(method_table)
|
||||
#define NATIVE_EMITTER_TABLE (&NATIVE_EMITTER(method_table))
|
||||
#endif
|
||||
|
||||
#if MICROPY_EMIT_INLINE_ASM && MICROPY_DYNAMIC_COMPILER
|
||||
@ -162,8 +163,6 @@ STATIC const emit_inline_asm_method_table_t *emit_asm_table[] = {
|
||||
|
||||
// elements in this struct are ordered to make it compact
|
||||
typedef struct _compiler_t {
|
||||
qstr source_file;
|
||||
|
||||
uint8_t is_repl;
|
||||
uint8_t pass; // holds enum type pass_kind_t
|
||||
uint8_t have_star;
|
||||
@ -185,7 +184,10 @@ typedef struct _compiler_t {
|
||||
scope_t *scope_head;
|
||||
scope_t *scope_cur;
|
||||
|
||||
mp_emit_common_t emit_common;
|
||||
|
||||
emit_t *emit; // current emitter
|
||||
emit_t *emit_bc;
|
||||
#if NEED_METHOD_TABLE
|
||||
const emit_method_table_t *emit_method_table; // current emit method table
|
||||
#endif
|
||||
@ -196,6 +198,72 @@ typedef struct _compiler_t {
|
||||
#endif
|
||||
} compiler_t;
|
||||
|
||||
/******************************************************************************/
|
||||
// mp_emit_common_t helper functions
|
||||
// These are defined here so they can be inlined, to reduce code size.
|
||||
|
||||
STATIC void mp_emit_common_init(mp_emit_common_t *emit, qstr source_file) {
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
mp_map_init(&emit->qstr_map, 1);
|
||||
|
||||
// add the source file as the first entry in the qstr table
|
||||
mp_map_elem_t *elem = mp_map_lookup(&emit->qstr_map, MP_OBJ_NEW_QSTR(source_file), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
||||
elem->value = MP_OBJ_NEW_SMALL_INT(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void mp_emit_common_start_pass(mp_emit_common_t *emit, pass_kind_t pass) {
|
||||
emit->pass = pass;
|
||||
if (pass == MP_PASS_STACK_SIZE) {
|
||||
emit->ct_cur_obj_base = emit->ct_cur_obj;
|
||||
} else if (pass > MP_PASS_STACK_SIZE) {
|
||||
emit->ct_cur_obj = emit->ct_cur_obj_base;
|
||||
}
|
||||
if (pass == MP_PASS_EMIT) {
|
||||
if (emit->ct_cur_child == 0) {
|
||||
emit->children = NULL;
|
||||
} else {
|
||||
emit->children = m_new0(mp_raw_code_t *, emit->ct_cur_child);
|
||||
}
|
||||
}
|
||||
emit->ct_cur_child = 0;
|
||||
}
|
||||
|
||||
STATIC void mp_emit_common_finalise(mp_emit_common_t *emit, bool has_native_code) {
|
||||
emit->ct_cur_obj += has_native_code; // allocate an additional slot for &mp_fun_table
|
||||
emit->const_table = m_new0(mp_uint_t, emit->ct_cur_obj);
|
||||
emit->ct_cur_obj = has_native_code; // reserve slot 0 for &mp_fun_table
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
if (has_native_code) {
|
||||
// store mp_fun_table pointer at the start of the constant table
|
||||
emit->const_table[0] = (mp_uint_t)(uintptr_t)&mp_fun_table;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void mp_emit_common_populate_module_context(mp_emit_common_t *emit, qstr source_file, mp_module_context_t *context) {
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
size_t qstr_map_used = emit->qstr_map.used;
|
||||
mp_module_context_alloc_tables(context, qstr_map_used, emit->ct_cur_obj);
|
||||
for (size_t i = 0; i < emit->qstr_map.alloc; ++i) {
|
||||
if (mp_map_slot_is_filled(&emit->qstr_map, i)) {
|
||||
size_t idx = MP_OBJ_SMALL_INT_VALUE(emit->qstr_map.table[i].value);
|
||||
qstr qst = MP_OBJ_QSTR_VALUE(emit->qstr_map.table[i].key);
|
||||
context->constants.qstr_table[idx] = qst;
|
||||
}
|
||||
}
|
||||
#else
|
||||
mp_module_context_alloc_tables(context, 0, emit->ct_cur_obj);
|
||||
context->constants.source_file = source_file;
|
||||
#endif
|
||||
|
||||
if (emit->ct_cur_obj > 0) {
|
||||
memcpy(context->constants.obj_table, emit->const_table, emit->ct_cur_obj * sizeof(mp_uint_t));
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
STATIC void compile_error_set_line(compiler_t *comp, mp_parse_node_t pn) {
|
||||
// if the line of the error is unknown then try to update it from the pn
|
||||
if (comp->compile_error_line == 0 && MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
@ -246,7 +314,7 @@ STATIC void compile_decrease_except_level(compiler_t *comp) {
|
||||
}
|
||||
|
||||
STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) {
|
||||
scope_t *scope = scope_new(kind, pn, comp->source_file, emit_options);
|
||||
scope_t *scope = scope_new(kind, pn, emit_options);
|
||||
scope->parent = comp->scope_cur;
|
||||
scope->next = NULL;
|
||||
if (comp->scope_head == NULL) {
|
||||
@ -290,7 +358,8 @@ STATIC void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *
|
||||
STATIC void compile_load_id(compiler_t *comp, qstr qst) {
|
||||
if (comp->pass == MP_PASS_SCOPE) {
|
||||
mp_emit_common_get_id_for_load(comp->scope_cur, qst);
|
||||
} else {
|
||||
}
|
||||
{
|
||||
#if NEED_METHOD_TABLE
|
||||
mp_emit_common_id_op(comp->emit, &comp->emit_method_table->load_id, comp->scope_cur, qst);
|
||||
#else
|
||||
@ -302,7 +371,8 @@ STATIC void compile_load_id(compiler_t *comp, qstr qst) {
|
||||
STATIC void compile_store_id(compiler_t *comp, qstr qst) {
|
||||
if (comp->pass == MP_PASS_SCOPE) {
|
||||
mp_emit_common_get_id_for_modification(comp->scope_cur, qst);
|
||||
} else {
|
||||
}
|
||||
{
|
||||
#if NEED_METHOD_TABLE
|
||||
mp_emit_common_id_op(comp->emit, &comp->emit_method_table->store_id, comp->scope_cur, qst);
|
||||
#else
|
||||
@ -314,7 +384,8 @@ STATIC void compile_store_id(compiler_t *comp, qstr qst) {
|
||||
STATIC void compile_delete_id(compiler_t *comp, qstr qst) {
|
||||
if (comp->pass == MP_PASS_SCOPE) {
|
||||
mp_emit_common_get_id_for_modification(comp->scope_cur, qst);
|
||||
} else {
|
||||
}
|
||||
{
|
||||
#if NEED_METHOD_TABLE
|
||||
mp_emit_common_id_op(comp->emit, &comp->emit_method_table->delete_id, comp->scope_cur, qst);
|
||||
#else
|
||||
@ -819,7 +890,7 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, size_t name_len, mp_par
|
||||
compile_syntax_error(comp, name_nodes[1], MP_ERROR_TEXT("invalid micropython decorator"));
|
||||
}
|
||||
|
||||
#if MICROPY_DYNAMIC_COMPILER
|
||||
#if MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER
|
||||
if (*emit_options == MP_EMIT_OPT_NATIVE_PYTHON || *emit_options == MP_EMIT_OPT_VIPER) {
|
||||
if (emit_native_table[mp_dynamic_compiler.native_arch] == NULL) {
|
||||
compile_syntax_error(comp, name_nodes[1], MP_ERROR_TEXT("invalid arch"));
|
||||
@ -2082,6 +2153,7 @@ STATIC void compile_lambdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
STATIC void compile_namedexpr_helper(compiler_t *comp, mp_parse_node_t pn_name, mp_parse_node_t pn_expr) {
|
||||
if (!MP_PARSE_NODE_IS_ID(pn_name)) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pn_name, MP_ERROR_TEXT("can't assign to expression"));
|
||||
return; // because pn_name is not a valid qstr (in compile_store_id below)
|
||||
}
|
||||
compile_node(comp, pn_expr);
|
||||
EMIT(dup_top);
|
||||
@ -2814,6 +2886,7 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn
|
||||
// comes before a star, so counts as a positional parameter
|
||||
comp->scope_cur->num_pos_args += 1;
|
||||
}
|
||||
mp_emit_common_use_qstr(&comp->emit_common, param_name);
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT(pn));
|
||||
pns = (mp_parse_node_struct_t *)pn;
|
||||
@ -2827,6 +2900,7 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn
|
||||
// comes before a star, so counts as a positional parameter
|
||||
comp->scope_cur->num_pos_args += 1;
|
||||
}
|
||||
mp_emit_common_use_qstr(&comp->emit_common, param_name);
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_star) {
|
||||
if (comp->have_star) {
|
||||
// more than one star
|
||||
@ -2976,6 +3050,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
||||
comp->pass = pass;
|
||||
comp->scope_cur = scope;
|
||||
comp->next_label = 0;
|
||||
mp_emit_common_start_pass(&comp->emit_common, pass);
|
||||
EMIT_ARG(start_pass, pass, scope);
|
||||
reserve_labels_for_native(comp, 6); // used by native's start_pass
|
||||
|
||||
@ -2984,6 +3059,14 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
||||
// they will be computed in this first pass
|
||||
scope->stack_size = 0;
|
||||
scope->exc_stack_size = 0;
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
if (scope->emit_options == MP_EMIT_OPT_NATIVE_PYTHON || scope->emit_options == MP_EMIT_OPT_VIPER) {
|
||||
// allow native code to perfom basic tasks during the pass scope
|
||||
// note: the first argument passed here is mp_emit_common_t, not the native emitter context
|
||||
NATIVE_EMITTER_TABLE->start_pass((void *)&comp->emit_common, comp->pass, scope);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// compile
|
||||
@ -3064,6 +3147,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
||||
if (comp->pass == MP_PASS_SCOPE) {
|
||||
scope_find_or_add_id(comp->scope_cur, qstr_arg, ID_INFO_KIND_LOCAL);
|
||||
scope->num_pos_args = 1;
|
||||
mp_emit_common_use_qstr(&comp->emit_common, MP_QSTR__star_);
|
||||
}
|
||||
|
||||
// Set the source line number for the start of the comprehension
|
||||
@ -3296,9 +3380,10 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
||||
f, mp_asm_base_get_code_size((mp_asm_base_t *)comp->emit_inline_asm),
|
||||
NULL,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
0, 0, 0, 0, NULL,
|
||||
0,
|
||||
0, 0, NULL,
|
||||
#endif
|
||||
comp->scope_cur->num_pos_args, 0, type_sig);
|
||||
0, comp->scope_cur->num_pos_args, type_sig);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3310,7 +3395,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void scope_compute_things(scope_t *scope) {
|
||||
STATIC void scope_compute_things(scope_t *scope, mp_emit_common_t *emit_common) {
|
||||
// in MicroPython we put the *x parameter after all other parameters (except **y)
|
||||
if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
|
||||
id_info_t *id_param = NULL;
|
||||
@ -3399,6 +3484,7 @@ STATIC void scope_compute_things(scope_t *scope) {
|
||||
}
|
||||
scope->num_pos_args += num_free; // free vars are counted as params for passing them into the function
|
||||
scope->num_locals += num_free;
|
||||
mp_emit_common_use_qstr(emit_common, MP_QSTR__star_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3406,15 +3492,15 @@ STATIC void scope_compute_things(scope_t *scope) {
|
||||
#if !MICROPY_PERSISTENT_CODE_SAVE
|
||||
STATIC
|
||||
#endif
|
||||
mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) {
|
||||
mp_compiled_module_t mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl, mp_module_context_t *context) {
|
||||
// put compiler state on the stack, it's relatively small
|
||||
compiler_t comp_state = {0};
|
||||
compiler_t *comp = &comp_state;
|
||||
|
||||
comp->source_file = source_file;
|
||||
comp->is_repl = is_repl;
|
||||
comp->break_label = INVALID_LABEL;
|
||||
comp->continue_label = INVALID_LABEL;
|
||||
mp_emit_common_init(&comp->emit_common, source_file);
|
||||
|
||||
// create the module scope
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
@ -3425,10 +3511,11 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f
|
||||
scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, parse_tree->root, emit_opt);
|
||||
|
||||
// create standard emitter; it's used at least for MP_PASS_SCOPE
|
||||
emit_t *emit_bc = emit_bc_new();
|
||||
emit_t *emit_bc = emit_bc_new(&comp->emit_common);
|
||||
|
||||
// compile pass 1
|
||||
// compile MP_PASS_SCOPE
|
||||
comp->emit = emit_bc;
|
||||
comp->emit_bc = emit_bc;
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
comp->emit_method_table = &emit_bc_method_table;
|
||||
#endif
|
||||
@ -3458,14 +3545,24 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f
|
||||
}
|
||||
|
||||
// compute some things related to scope and identifiers
|
||||
bool has_native_code = false;
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
scope_compute_things(s);
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
if (s->emit_options == MP_EMIT_OPT_NATIVE_PYTHON || s->emit_options == MP_EMIT_OPT_VIPER) {
|
||||
has_native_code = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
scope_compute_things(s, &comp->emit_common);
|
||||
}
|
||||
|
||||
// set max number of labels now that it's calculated
|
||||
emit_bc_set_max_num_labels(emit_bc, max_num_labels);
|
||||
|
||||
// compile pass 2 and 3
|
||||
// finalise and allocate the constant table
|
||||
mp_emit_common_finalise(&comp->emit_common, has_native_code);
|
||||
|
||||
// compile MP_PASS_STACK_SIZE, MP_PASS_CODE_SIZE, MP_PASS_EMIT
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
emit_t *emit_native = NULL;
|
||||
#endif
|
||||
@ -3505,7 +3602,7 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f
|
||||
case MP_EMIT_OPT_NATIVE_PYTHON:
|
||||
case MP_EMIT_OPT_VIPER:
|
||||
if (emit_native == NULL) {
|
||||
emit_native = NATIVE_EMITTER(new)(&comp->compile_error, &comp->next_label, max_num_labels);
|
||||
emit_native = NATIVE_EMITTER(new)(&comp->emit_common, &comp->compile_error, &comp->next_label, max_num_labels);
|
||||
}
|
||||
comp->emit_method_table = NATIVE_EMITTER_TABLE;
|
||||
comp->emit = emit_native;
|
||||
@ -3540,10 +3637,33 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f
|
||||
// number for the start of this scope
|
||||
compile_error_set_line(comp, comp->scope_cur->pn);
|
||||
// add a traceback to the exception using relevant source info
|
||||
mp_obj_exception_add_traceback(comp->compile_error, comp->source_file,
|
||||
mp_obj_exception_add_traceback(comp->compile_error, source_file,
|
||||
comp->compile_error_line, comp->scope_cur->simple_name);
|
||||
}
|
||||
|
||||
// construct the global qstr/const table for this module
|
||||
mp_compiled_module_t cm;
|
||||
cm.rc = module_scope->raw_code;
|
||||
cm.context = context;
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
cm.has_native = has_native_code;
|
||||
cm.n_qstr = comp->emit_common.qstr_map.used;
|
||||
cm.n_obj = comp->emit_common.ct_cur_obj;
|
||||
#endif
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
mp_emit_common_populate_module_context(&comp->emit_common, source_file, context);
|
||||
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
// now that the module context is valid, the raw codes can be printed
|
||||
if (mp_verbose_flag >= 2) {
|
||||
for (scope_t *s = comp->scope_head; s != NULL; s = s->next) {
|
||||
mp_raw_code_t *rc = s->raw_code;
|
||||
mp_bytecode_print(&mp_plat_print, rc, rc->fun_data, rc->fun_data_len, &cm.context->constants);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// free the emitters
|
||||
|
||||
emit_bc_free(emit_bc);
|
||||
@ -3562,7 +3682,6 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f
|
||||
mp_parse_tree_clear(parse_tree);
|
||||
|
||||
// free the scopes
|
||||
mp_raw_code_t *outer_raw_code = module_scope->raw_code;
|
||||
for (scope_t *s = module_scope; s;) {
|
||||
scope_t *next = s->next;
|
||||
scope_free(s);
|
||||
@ -3571,15 +3690,17 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f
|
||||
|
||||
if (comp->compile_error != MP_OBJ_NULL) {
|
||||
nlr_raise(comp->compile_error);
|
||||
} else {
|
||||
return outer_raw_code;
|
||||
}
|
||||
|
||||
return cm;
|
||||
}
|
||||
|
||||
mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) {
|
||||
mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, is_repl);
|
||||
mp_module_context_t *context = m_new_obj(mp_module_context_t);
|
||||
context->module.globals = mp_globals_get();
|
||||
mp_compiled_module_t cm = mp_compile_to_raw_code(parse_tree, source_file, is_repl, context);
|
||||
// return function that executes the outer module
|
||||
return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL);
|
||||
return mp_make_function_from_raw_code(cm.rc, cm.context, NULL);
|
||||
}
|
||||
|
||||
#endif // MICROPY_ENABLE_COMPILER
|
||||
|
@ -32,11 +32,12 @@
|
||||
|
||||
// the compiler will raise an exception if an error occurred
|
||||
// the compiler will clear the parse tree before it returns
|
||||
// mp_globals_get() will be used for the context
|
||||
mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl);
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
// this has the same semantics as mp_compile
|
||||
mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl);
|
||||
mp_compiled_module_t mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl, mp_module_context_t *globals);
|
||||
#endif
|
||||
|
||||
// this is implemented in runtime.c
|
||||
|
@ -30,6 +30,7 @@
|
||||
// MicroPython runtime API defined in py/obj.h and py/runtime.h.
|
||||
|
||||
#include "py/nativeglue.h"
|
||||
#include "py/objfun.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/objtype.h"
|
||||
|
||||
@ -177,8 +178,8 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
|
||||
#define mp_unary_op(op, obj) (mp_fun_table.unary_op((op), (obj)))
|
||||
#define mp_binary_op(op, lhs, rhs) (mp_fun_table.binary_op((op), (lhs), (rhs)))
|
||||
|
||||
#define mp_make_function_from_raw_code(rc, def_args, def_kw_args) \
|
||||
(mp_fun_table.make_function_from_raw_code((rc), (def_args), (def_kw_args)))
|
||||
#define mp_make_function_from_raw_code(rc, context, def_args) \
|
||||
(mp_fun_table.make_function_from_raw_code((rc), (context), (def_args)))
|
||||
|
||||
#define mp_call_function_n_kw(fun, n_args, n_kw, args) \
|
||||
(mp_fun_table.call_function_n_kw((fun), (n_args) | ((n_kw) << 8), args))
|
||||
@ -187,11 +188,10 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
|
||||
(mp_fun_table.arg_check_num_sig((n_args), (n_kw), MP_OBJ_FUN_MAKE_SIG((n_args_min), (n_args_max), (takes_kw))))
|
||||
|
||||
#define MP_DYNRUNTIME_INIT_ENTRY \
|
||||
mp_obj_t old_globals = mp_fun_table.swap_globals(self->globals); \
|
||||
mp_obj_t old_globals = mp_fun_table.swap_globals(self->context->module.globals); \
|
||||
mp_raw_code_t rc; \
|
||||
rc.kind = MP_CODE_NATIVE_VIPER; \
|
||||
rc.scope_flags = 0; \
|
||||
rc.const_table = (void *)self->const_table; \
|
||||
(void)rc;
|
||||
|
||||
#define MP_DYNRUNTIME_INIT_EXIT \
|
||||
@ -199,7 +199,7 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
|
||||
return mp_const_none;
|
||||
|
||||
#define MP_DYNRUNTIME_MAKE_FUNCTION(f) \
|
||||
(mp_make_function_from_raw_code((rc.fun_data = (f), &rc), MP_OBJ_NULL, MP_OBJ_NULL))
|
||||
(mp_make_function_from_raw_code((rc.fun_data = (f), &rc), self->context, NULL))
|
||||
|
||||
#define mp_import_name(name, fromlist, level) \
|
||||
(mp_fun_table.import_name((name), (fromlist), (level)))
|
||||
|
50
py/emit.h
50
py/emit.h
@ -92,6 +92,18 @@ typedef enum {
|
||||
|
||||
typedef struct _emit_t emit_t;
|
||||
|
||||
typedef struct _mp_emit_common_t {
|
||||
pass_kind_t pass;
|
||||
uint16_t ct_cur_obj_base;
|
||||
uint16_t ct_cur_obj;
|
||||
uint16_t ct_cur_child;
|
||||
mp_uint_t *const_table;
|
||||
mp_raw_code_t **children;
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
mp_map_t qstr_map;
|
||||
#endif
|
||||
} mp_emit_common_t;
|
||||
|
||||
typedef struct _mp_emit_method_table_id_ops_t {
|
||||
void (*local)(emit_t *emit, qstr qst, mp_uint_t local_num, int kind);
|
||||
void (*global)(emit_t *emit, qstr qst, int kind);
|
||||
@ -99,7 +111,7 @@ typedef struct _mp_emit_method_table_id_ops_t {
|
||||
|
||||
typedef struct _emit_method_table_t {
|
||||
#if MICROPY_DYNAMIC_COMPILER
|
||||
emit_t *(*emit_new)(mp_obj_t * error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *(*emit_new)(mp_emit_common_t * emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
void (*emit_free)(emit_t *emit);
|
||||
#endif
|
||||
|
||||
@ -161,6 +173,28 @@ typedef struct _emit_method_table_t {
|
||||
void (*end_except_handler)(emit_t *emit);
|
||||
} emit_method_table_t;
|
||||
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
qstr_short_t mp_emit_common_use_qstr(mp_emit_common_t *emit, qstr qst);
|
||||
#else
|
||||
static inline qstr_short_t mp_emit_common_use_qstr(mp_emit_common_t *emit, qstr qst) {
|
||||
return qst;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline size_t mp_emit_common_alloc_const_obj(mp_emit_common_t *emit, mp_obj_t obj) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
emit->const_table[emit->ct_cur_obj] = (mp_uint_t)obj;
|
||||
}
|
||||
return emit->ct_cur_obj++;
|
||||
}
|
||||
|
||||
static inline size_t mp_emit_common_alloc_const_child(mp_emit_common_t *emit, mp_raw_code_t *rc) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
emit->children[emit->ct_cur_child] = rc;
|
||||
}
|
||||
return emit->ct_cur_child++;
|
||||
}
|
||||
|
||||
static inline void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) {
|
||||
scope_find_or_add_id(scope, qst, ID_INFO_KIND_GLOBAL_IMPLICIT);
|
||||
}
|
||||
@ -180,13 +214,13 @@ extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops;
|
||||
extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops;
|
||||
extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops;
|
||||
|
||||
emit_t *emit_bc_new(void);
|
||||
emit_t *emit_native_x64_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_x86_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_thumb_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_arm_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_xtensa_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_xtensawin_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_bc_new(mp_emit_common_t *emit_common);
|
||||
emit_t *emit_native_x64_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_x86_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_thumb_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_arm_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_xtensa_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_xtensawin_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
|
||||
|
||||
void emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels);
|
||||
|
||||
|
156
py/emitbc.c
156
py/emitbc.c
@ -36,8 +36,7 @@
|
||||
|
||||
#if MICROPY_ENABLE_COMPILER
|
||||
|
||||
#define BYTES_FOR_INT ((MP_BYTES_PER_OBJ_WORD * 8 + 6) / 7)
|
||||
#define DUMMY_DATA_SIZE (BYTES_FOR_INT)
|
||||
#define DUMMY_DATA_SIZE (MP_ENCODE_UINT_MAX_BYTES)
|
||||
|
||||
struct _emit_t {
|
||||
// Accessed as mp_obj_t, so must be aligned as such, and we rely on the
|
||||
@ -50,6 +49,7 @@ struct _emit_t {
|
||||
|
||||
int stack_size;
|
||||
|
||||
mp_emit_common_t *emit_common;
|
||||
scope_t *scope;
|
||||
|
||||
mp_uint_t last_source_line_offset;
|
||||
@ -66,17 +66,11 @@ struct _emit_t {
|
||||
|
||||
size_t n_info;
|
||||
size_t n_cell;
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
uint16_t ct_cur_obj;
|
||||
uint16_t ct_num_obj;
|
||||
uint16_t ct_cur_raw_code;
|
||||
#endif
|
||||
mp_uint_t *const_table;
|
||||
};
|
||||
|
||||
emit_t *emit_bc_new(void) {
|
||||
emit_t *emit_bc_new(mp_emit_common_t *emit_common) {
|
||||
emit_t *emit = m_new0(emit_t, 1);
|
||||
emit->emit_common = emit_common;
|
||||
return emit;
|
||||
}
|
||||
|
||||
@ -90,26 +84,9 @@ void emit_bc_free(emit_t *emit) {
|
||||
m_del_obj(emit_t, emit);
|
||||
}
|
||||
|
||||
typedef byte *(*emit_allocator_t)(emit_t *emit, int nbytes);
|
||||
|
||||
STATIC void emit_write_uint(emit_t *emit, emit_allocator_t allocator, mp_uint_t val) {
|
||||
// We store each 7 bits in a separate byte, and that's how many bytes needed
|
||||
byte buf[BYTES_FOR_INT];
|
||||
byte *p = buf + sizeof(buf);
|
||||
// We encode in little-ending order, but store in big-endian, to help decoding
|
||||
do {
|
||||
*--p = val & 0x7f;
|
||||
val >>= 7;
|
||||
} while (val != 0);
|
||||
byte *c = allocator(emit, buf + sizeof(buf) - p);
|
||||
while (p != buf + sizeof(buf) - 1) {
|
||||
*c++ = *p++ | 0x80;
|
||||
}
|
||||
*c = *p;
|
||||
}
|
||||
|
||||
// all functions must go through this one to emit code info
|
||||
STATIC byte *emit_get_cur_to_write_code_info(emit_t *emit, int num_bytes_to_write) {
|
||||
STATIC uint8_t *emit_get_cur_to_write_code_info(void *emit_in, size_t num_bytes_to_write) {
|
||||
emit_t *emit = emit_in;
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
emit->code_info_offset += num_bytes_to_write;
|
||||
return emit->dummy_data;
|
||||
@ -126,14 +103,7 @@ STATIC void emit_write_code_info_byte(emit_t *emit, byte val) {
|
||||
}
|
||||
|
||||
STATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) {
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
assert((qst >> 16) == 0);
|
||||
byte *c = emit_get_cur_to_write_code_info(emit, 2);
|
||||
c[0] = qst;
|
||||
c[1] = qst >> 8;
|
||||
#else
|
||||
emit_write_uint(emit, emit_get_cur_to_write_code_info, qst);
|
||||
#endif
|
||||
mp_encode_uint(emit, emit_get_cur_to_write_code_info, mp_emit_common_use_qstr(emit->emit_common, qst));
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_SOURCE_LINE
|
||||
@ -166,7 +136,8 @@ STATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_sk
|
||||
#endif
|
||||
|
||||
// all functions must go through this one to emit byte code
|
||||
STATIC byte *emit_get_cur_to_write_bytecode(emit_t *emit, int num_bytes_to_write) {
|
||||
STATIC uint8_t *emit_get_cur_to_write_bytecode(void *emit_in, size_t num_bytes_to_write) {
|
||||
emit_t *emit = emit_in;
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
emit->bytecode_offset += num_bytes_to_write;
|
||||
return emit->dummy_data;
|
||||
@ -189,12 +160,12 @@ STATIC void emit_write_bytecode_byte(emit_t *emit, int stack_adj, byte b1) {
|
||||
c[0] = b1;
|
||||
}
|
||||
|
||||
// Similar to emit_write_bytecode_uint(), just some extra handling to encode sign
|
||||
// Similar to mp_encode_uint(), just some extra handling to encode sign
|
||||
STATIC void emit_write_bytecode_byte_int(emit_t *emit, int stack_adj, byte b1, mp_int_t num) {
|
||||
emit_write_bytecode_byte(emit, stack_adj, b1);
|
||||
|
||||
// We store each 7 bits in a separate byte, and that's how many bytes needed
|
||||
byte buf[BYTES_FOR_INT];
|
||||
byte buf[MP_ENCODE_UINT_MAX_BYTES];
|
||||
byte *p = buf + sizeof(buf);
|
||||
// We encode in little-ending order, but store in big-endian, to help decoding
|
||||
do {
|
||||
@ -218,61 +189,25 @@ STATIC void emit_write_bytecode_byte_int(emit_t *emit, int stack_adj, byte b1, m
|
||||
|
||||
STATIC void emit_write_bytecode_byte_uint(emit_t *emit, int stack_adj, byte b, mp_uint_t val) {
|
||||
emit_write_bytecode_byte(emit, stack_adj, b);
|
||||
emit_write_uint(emit, emit_get_cur_to_write_bytecode, val);
|
||||
mp_encode_uint(emit, emit_get_cur_to_write_bytecode, val);
|
||||
}
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
STATIC void emit_write_bytecode_byte_const(emit_t *emit, int stack_adj, byte b, mp_uint_t n, mp_uint_t c) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
emit->const_table[n] = c;
|
||||
}
|
||||
STATIC void emit_write_bytecode_byte_const(emit_t *emit, int stack_adj, byte b, mp_uint_t n) {
|
||||
emit_write_bytecode_byte_uint(emit, stack_adj, b, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void emit_write_bytecode_byte_qstr(emit_t *emit, int stack_adj, byte b, qstr qst) {
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
assert((qst >> 16) == 0);
|
||||
mp_emit_bc_adjust_stack_size(emit, stack_adj);
|
||||
byte *c = emit_get_cur_to_write_bytecode(emit, 3);
|
||||
c[0] = b;
|
||||
c[1] = qst;
|
||||
c[2] = qst >> 8;
|
||||
#else
|
||||
emit_write_bytecode_byte_uint(emit, stack_adj, b, qst);
|
||||
#endif
|
||||
emit_write_bytecode_byte_uint(emit, stack_adj, b, mp_emit_common_use_qstr(emit->emit_common, qst));
|
||||
}
|
||||
|
||||
STATIC void emit_write_bytecode_byte_obj(emit_t *emit, int stack_adj, byte b, mp_obj_t obj) {
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
emit_write_bytecode_byte_const(emit, stack_adj, b,
|
||||
emit->scope->num_pos_args + emit->scope->num_kwonly_args
|
||||
+ emit->ct_cur_obj++, (mp_uint_t)obj);
|
||||
#else
|
||||
// aligns the pointer so it is friendly to GC
|
||||
emit_write_bytecode_byte(emit, stack_adj, b);
|
||||
emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(mp_obj_t));
|
||||
mp_obj_t *c = (mp_obj_t *)emit_get_cur_to_write_bytecode(emit, sizeof(mp_obj_t));
|
||||
// Verify thar c is already uint-aligned
|
||||
assert(c == MP_ALIGN(c, sizeof(mp_obj_t)));
|
||||
*c = obj;
|
||||
#endif
|
||||
mp_emit_common_alloc_const_obj(emit->emit_common, obj));
|
||||
}
|
||||
|
||||
STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, int stack_adj, byte b, mp_raw_code_t *rc) {
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
STATIC void emit_write_bytecode_byte_child(emit_t *emit, int stack_adj, byte b, mp_raw_code_t *rc) {
|
||||
emit_write_bytecode_byte_const(emit, stack_adj, b,
|
||||
emit->scope->num_pos_args + emit->scope->num_kwonly_args
|
||||
+ emit->ct_num_obj + emit->ct_cur_raw_code++, (mp_uint_t)(uintptr_t)rc);
|
||||
#else
|
||||
// aligns the pointer so it is friendly to GC
|
||||
emit_write_bytecode_byte(emit, stack_adj, b);
|
||||
emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(void *));
|
||||
void **c = (void **)emit_get_cur_to_write_bytecode(emit, sizeof(void *));
|
||||
// Verify thar c is already uint-aligned
|
||||
assert(c == MP_ALIGN(c, sizeof(void *)));
|
||||
*c = rc;
|
||||
#endif
|
||||
mp_emit_common_alloc_const_child(emit->emit_common, rc));
|
||||
#if MICROPY_PY_SYS_SETTRACE
|
||||
rc->line_of_definition = emit->last_source_line;
|
||||
#endif
|
||||
@ -343,27 +278,19 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
}
|
||||
|
||||
// Write number of cells and size of the source code info
|
||||
if (pass >= MP_PASS_CODE_SIZE) {
|
||||
MP_BC_PRELUDE_SIZE_ENCODE(emit->n_info, emit->n_cell, emit_write_code_info_byte, emit);
|
||||
if (emit->pass >= MP_PASS_CODE_SIZE) {
|
||||
size_t n_info = emit->n_info;
|
||||
size_t n_cell = emit->n_cell;
|
||||
MP_BC_PRELUDE_SIZE_ENCODE(n_info, n_cell, emit_write_code_info_byte, emit);
|
||||
}
|
||||
|
||||
emit->n_info = emit->code_info_offset;
|
||||
|
||||
// Write the name and source file of this function.
|
||||
// Write the name of this function.
|
||||
emit_write_code_info_qstr(emit, scope->simple_name);
|
||||
emit_write_code_info_qstr(emit, scope->source_file);
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
emit->ct_cur_obj = 0;
|
||||
emit->ct_cur_raw_code = 0;
|
||||
#endif
|
||||
|
||||
if (pass == MP_PASS_EMIT) {
|
||||
// Write argument names (needed to resolve positional args passed as
|
||||
// keywords). We store them as full word-sized objects for efficient access
|
||||
// in mp_setup_code_state this is the start of the prelude and is guaranteed
|
||||
// to be aligned on a word boundary.
|
||||
|
||||
// Write argument names, needed to resolve positional args passed as keywords.
|
||||
{
|
||||
// For a given argument position (indexed by i) we need to find the
|
||||
// corresponding id_info which is a parameter, as it has the correct
|
||||
// qstr name to use as the argument name. Note that it's not a simple
|
||||
@ -383,7 +310,7 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit->const_table[i] = (mp_uint_t)MP_OBJ_NEW_QSTR(qst);
|
||||
emit_write_code_info_qstr(emit, qst);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -396,8 +323,6 @@ void mp_emit_bc_end_pass(emit_t *emit) {
|
||||
// check stack is back to zero size
|
||||
assert(emit->stack_size == 0);
|
||||
|
||||
emit_write_code_info_byte(emit, 0); // end of line number info
|
||||
|
||||
// Calculate size of source code info section
|
||||
emit->n_info = emit->code_info_offset - emit->n_info;
|
||||
|
||||
@ -412,39 +337,20 @@ void mp_emit_bc_end_pass(emit_t *emit) {
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->ct_num_obj == emit->ct_cur_obj));
|
||||
emit->ct_num_obj = emit->ct_cur_obj;
|
||||
#endif
|
||||
|
||||
if (emit->pass == MP_PASS_CODE_SIZE) {
|
||||
#if !MICROPY_PERSISTENT_CODE
|
||||
// so bytecode is aligned
|
||||
emit->code_info_offset = (size_t)MP_ALIGN(emit->code_info_offset, sizeof(mp_uint_t));
|
||||
#endif
|
||||
|
||||
// calculate size of total code-info + bytecode, in bytes
|
||||
emit->code_info_size = emit->code_info_offset;
|
||||
emit->bytecode_size = emit->bytecode_offset;
|
||||
emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size);
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
emit->const_table = m_new0(mp_uint_t,
|
||||
emit->scope->num_pos_args + emit->scope->num_kwonly_args
|
||||
+ emit->ct_cur_obj + emit->ct_cur_raw_code);
|
||||
#else
|
||||
emit->const_table = m_new0(mp_uint_t,
|
||||
emit->scope->num_pos_args + emit->scope->num_kwonly_args);
|
||||
#endif
|
||||
|
||||
} else if (emit->pass == MP_PASS_EMIT) {
|
||||
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,
|
||||
#endif
|
||||
emit->const_table,
|
||||
emit->emit_common->children,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
emit->ct_cur_obj, emit->ct_cur_raw_code,
|
||||
emit->emit_common->ct_cur_child,
|
||||
#endif
|
||||
emit->scope->scope_flags);
|
||||
}
|
||||
@ -783,21 +689,21 @@ void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) {
|
||||
|
||||
void mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
|
||||
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
|
||||
emit_write_bytecode_byte_raw_code(emit, 1, MP_BC_MAKE_FUNCTION, scope->raw_code);
|
||||
emit_write_bytecode_byte_child(emit, 1, MP_BC_MAKE_FUNCTION, scope->raw_code);
|
||||
} else {
|
||||
emit_write_bytecode_byte_raw_code(emit, -1, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code);
|
||||
emit_write_bytecode_byte_child(emit, -1, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_emit_bc_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
|
||||
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
|
||||
int stack_adj = -n_closed_over + 1;
|
||||
emit_write_bytecode_byte_raw_code(emit, stack_adj, MP_BC_MAKE_CLOSURE, scope->raw_code);
|
||||
emit_write_bytecode_byte_child(emit, stack_adj, MP_BC_MAKE_CLOSURE, scope->raw_code);
|
||||
emit_write_bytecode_raw_byte(emit, n_closed_over);
|
||||
} else {
|
||||
assert(n_closed_over <= 255);
|
||||
int stack_adj = -2 - (mp_int_t)n_closed_over + 1;
|
||||
emit_write_bytecode_byte_raw_code(emit, stack_adj, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code);
|
||||
emit_write_bytecode_byte_child(emit, stack_adj, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code);
|
||||
emit_write_bytecode_raw_byte(emit, n_closed_over);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,17 @@
|
||||
|
||||
#if MICROPY_ENABLE_COMPILER
|
||||
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
qstr_short_t mp_emit_common_use_qstr(mp_emit_common_t *emit, qstr qst) {
|
||||
mp_map_elem_t *elem = mp_map_lookup(&emit->qstr_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
||||
if (elem->value == MP_OBJ_NULL) {
|
||||
assert(emit->pass == MP_PASS_SCOPE);
|
||||
elem->value = MP_OBJ_NEW_SMALL_INT(emit->qstr_map.used - 1);
|
||||
}
|
||||
return MP_OBJ_SMALL_INT_VALUE(elem->value);
|
||||
}
|
||||
#endif
|
||||
|
||||
void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst) {
|
||||
// name adding/lookup
|
||||
id_info_t *id = scope_find_or_add_id(scope, qst, ID_INFO_KIND_GLOBAL_IMPLICIT);
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "py/emitglue.h"
|
||||
#include "py/runtime0.h"
|
||||
#include "py/bc.h"
|
||||
#include "py/objfun.h"
|
||||
#include "py/profile.h"
|
||||
|
||||
#if MICROPY_DEBUG_VERBOSE // print debugging info
|
||||
@ -63,20 +64,22 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
|
||||
size_t len,
|
||||
#endif
|
||||
const mp_uint_t *const_table,
|
||||
mp_raw_code_t **children,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
uint16_t n_obj, uint16_t n_raw_code,
|
||||
size_t n_children,
|
||||
#endif
|
||||
mp_uint_t scope_flags) {
|
||||
|
||||
rc->kind = MP_CODE_BYTECODE;
|
||||
rc->scope_flags = scope_flags;
|
||||
rc->fun_data = code;
|
||||
rc->const_table = const_table;
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
|
||||
rc->fun_data_len = len;
|
||||
rc->n_obj = n_obj;
|
||||
rc->n_raw_code = n_raw_code;
|
||||
#endif
|
||||
rc->children = children;
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
rc->n_children = n_children;
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_SYS_SETTRACE
|
||||
@ -85,26 +88,22 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
#if !MICROPY_DEBUG_PRINTERS
|
||||
#if !(MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS)
|
||||
const size_t len = 0;
|
||||
#endif
|
||||
DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " flags=%x\n", code, len, (uint)scope_flags);
|
||||
#endif
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
if (mp_verbose_flag >= 2) {
|
||||
mp_bytecode_print(&mp_plat_print, rc, code, len, const_table);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table,
|
||||
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len,
|
||||
mp_raw_code_t **children,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
size_t n_children,
|
||||
uint16_t prelude_offset,
|
||||
uint16_t n_obj, uint16_t n_raw_code,
|
||||
uint16_t n_qstr, mp_qstr_link_entry_t *qstr_link,
|
||||
#endif
|
||||
mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig) {
|
||||
mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t type_sig) {
|
||||
|
||||
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
|
||||
|
||||
@ -135,20 +134,24 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
|
||||
|
||||
rc->kind = kind;
|
||||
rc->scope_flags = scope_flags;
|
||||
rc->n_pos_args = n_pos_args;
|
||||
rc->fun_data = fun_data;
|
||||
rc->const_table = const_table;
|
||||
rc->type_sig = type_sig;
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
|
||||
rc->fun_data_len = fun_len;
|
||||
#endif
|
||||
rc->children = children;
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
rc->fun_data_len = fun_len;
|
||||
rc->n_children = n_children;
|
||||
rc->prelude_offset = prelude_offset;
|
||||
rc->n_obj = n_obj;
|
||||
rc->n_raw_code = n_raw_code;
|
||||
rc->n_qstr = n_qstr;
|
||||
rc->qstr_link = qstr_link;
|
||||
#endif
|
||||
|
||||
// These two entries are only needed for MP_CODE_NATIVE_ASM.
|
||||
rc->n_pos_args = n_pos_args;
|
||||
rc->type_sig = type_sig;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, (uint)scope_flags);
|
||||
for (mp_uint_t i = 0; i < fun_len; i++) {
|
||||
@ -170,15 +173,15 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) {
|
||||
mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, const mp_obj_t *def_args) {
|
||||
DEBUG_OP_printf("make_function_from_raw_code %p\n", rc);
|
||||
assert(rc != NULL);
|
||||
|
||||
// def_args must be MP_OBJ_NULL or a tuple
|
||||
assert(def_args == MP_OBJ_NULL || mp_obj_is_type(def_args, &mp_type_tuple));
|
||||
assert(def_args == NULL || def_args[0] == MP_OBJ_NULL || mp_obj_is_type(def_args[0], &mp_type_tuple));
|
||||
|
||||
// def_kw_args must be MP_OBJ_NULL or a dict
|
||||
assert(def_kw_args == MP_OBJ_NULL || mp_obj_is_type(def_kw_args, &mp_type_dict));
|
||||
assert(def_args == NULL || def_args[1] == MP_OBJ_NULL || mp_obj_is_type(def_args[1], &mp_type_dict));
|
||||
|
||||
// make the function, depending on the raw code kind
|
||||
mp_obj_t fun;
|
||||
@ -186,7 +189,7 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
case MP_CODE_NATIVE_PY:
|
||||
case MP_CODE_NATIVE_VIPER:
|
||||
fun = mp_obj_new_fun_native(def_args, def_kw_args, rc->fun_data, rc->const_table);
|
||||
fun = mp_obj_new_fun_native(def_args, rc->fun_data, context, rc->children);
|
||||
// Check for a generator function, and if so change the type of the object
|
||||
if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
|
||||
((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_native_gen_wrap;
|
||||
@ -201,7 +204,7 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar
|
||||
default:
|
||||
// rc->kind should always be set and BYTECODE is the only remaining case
|
||||
assert(rc->kind == MP_CODE_BYTECODE);
|
||||
fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->fun_data, rc->const_table);
|
||||
fun = mp_obj_new_fun_bc(def_args, rc->fun_data, context, rc->children);
|
||||
// check for generator functions and if so change the type of the object
|
||||
if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
|
||||
((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;
|
||||
@ -218,16 +221,16 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar
|
||||
return fun;
|
||||
}
|
||||
|
||||
mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args) {
|
||||
mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, mp_uint_t n_closed_over, const mp_obj_t *args) {
|
||||
DEBUG_OP_printf("make_closure_from_raw_code %p " UINT_FMT " %p\n", rc, n_closed_over, args);
|
||||
// make function object
|
||||
mp_obj_t ffun;
|
||||
if (n_closed_over & 0x100) {
|
||||
// default positional and keyword args given
|
||||
ffun = mp_make_function_from_raw_code(rc, args[0], args[1]);
|
||||
ffun = mp_make_function_from_raw_code(rc, context, args);
|
||||
} else {
|
||||
// default positional and keyword args not given
|
||||
ffun = mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL);
|
||||
ffun = mp_make_function_from_raw_code(rc, context, NULL);
|
||||
}
|
||||
// wrap function in closure object
|
||||
return mp_obj_new_closure(ffun, n_closed_over & 0xff, args + ((n_closed_over >> 7) & 2));
|
||||
|
@ -54,16 +54,20 @@ typedef struct _mp_qstr_link_entry_t {
|
||||
uint16_t qst;
|
||||
} mp_qstr_link_entry_t;
|
||||
|
||||
// compiled bytecode: instance in RAM, referenced by outer scope, usually freed after first (and only) use
|
||||
// mpy file: instance in RAM, created when .mpy file is loaded (same comments as above)
|
||||
// frozen: instance in ROM
|
||||
typedef struct _mp_raw_code_t {
|
||||
mp_uint_t kind : 3; // of type mp_raw_code_kind_t
|
||||
mp_uint_t scope_flags : 7;
|
||||
mp_uint_t n_pos_args : 11;
|
||||
const void *fun_data;
|
||||
const mp_uint_t *const_table;
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
|
||||
size_t fun_data_len; // so mp_raw_code_save and mp_bytecode_print work
|
||||
#endif
|
||||
struct _mp_raw_code_t **children;
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
size_t fun_data_len;
|
||||
uint16_t n_obj;
|
||||
uint16_t n_raw_code;
|
||||
size_t n_children;
|
||||
#if MICROPY_PY_SYS_SETTRACE
|
||||
mp_bytecode_prelude_t prelude;
|
||||
// line_of_definition is a Python source line where the raw_code was
|
||||
@ -89,22 +93,22 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
|
||||
size_t len,
|
||||
#endif
|
||||
const mp_uint_t *const_table,
|
||||
mp_raw_code_t **children,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
uint16_t n_obj, uint16_t n_raw_code,
|
||||
size_t n_children,
|
||||
#endif
|
||||
mp_uint_t scope_flags);
|
||||
|
||||
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len,
|
||||
const mp_uint_t *const_table,
|
||||
mp_raw_code_t **children,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
size_t n_children,
|
||||
uint16_t prelude_offset,
|
||||
uint16_t n_obj, uint16_t n_raw_code,
|
||||
uint16_t n_qstr, mp_qstr_link_entry_t *qstr_link,
|
||||
#endif
|
||||
mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig);
|
||||
mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t type_sig);
|
||||
|
||||
mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
|
||||
mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);
|
||||
mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, const mp_obj_t *def_args);
|
||||
mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, mp_uint_t n_closed_over, const mp_obj_t *args);
|
||||
|
||||
#endif // MICROPY_INCLUDED_PY_EMITGLUE_H
|
||||
|
263
py/emitnative.c
263
py/emitnative.c
@ -48,6 +48,7 @@
|
||||
|
||||
#include "py/emit.h"
|
||||
#include "py/nativeglue.h"
|
||||
#include "py/objfun.h"
|
||||
#include "py/objstr.h"
|
||||
|
||||
#if MICROPY_DEBUG_VERBOSE // print debugging info
|
||||
@ -92,9 +93,13 @@
|
||||
#define OFFSETOF_CODE_STATE_FUN_BC (offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_CODE_STATE_IP (offsetof(mp_code_state_t, ip) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_CODE_STATE_SP (offsetof(mp_code_state_t, sp) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_OBJ_FUN_BC_GLOBALS (offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_CODE_STATE_N_STATE (offsetof(mp_code_state_t, n_state) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_OBJ_FUN_BC_CONTEXT (offsetof(mp_obj_fun_bc_t, context) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_OBJ_FUN_BC_CHILD_TABLE (offsetof(mp_obj_fun_bc_t, child_table) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_OBJ_FUN_BC_BYTECODE (offsetof(mp_obj_fun_bc_t, bytecode) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_OBJ_FUN_BC_CONST_TABLE (offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_MODULE_CONTEXT_OBJ_TABLE (offsetof(mp_module_context_t, constants.obj_table) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_MODULE_CONTEXT_GLOBALS (offsetof(mp_module_context_t, module.globals) / sizeof(uintptr_t))
|
||||
#define INDEX_OF_MP_FUN_TABLE_IN_CONST_TABLE (0)
|
||||
|
||||
// If not already defined, set parent args to same as child call registers
|
||||
#ifndef REG_PARENT_RET
|
||||
@ -205,6 +210,7 @@ typedef struct _exc_stack_entry_t {
|
||||
} exc_stack_entry_t;
|
||||
|
||||
struct _emit_t {
|
||||
mp_emit_common_t *emit_common;
|
||||
mp_obj_t *error_slot;
|
||||
uint *label_slot;
|
||||
uint exit_label;
|
||||
@ -225,18 +231,17 @@ struct _emit_t {
|
||||
exc_stack_entry_t *exc_stack;
|
||||
|
||||
int prelude_offset;
|
||||
#if N_PRELUDE_AS_BYTES_OBJ
|
||||
size_t prelude_const_table_offset;
|
||||
#endif
|
||||
int start_offset;
|
||||
int n_state;
|
||||
uint16_t code_state_start;
|
||||
uint16_t stack_start;
|
||||
int stack_size;
|
||||
uint16_t n_info;
|
||||
uint16_t n_cell;
|
||||
|
||||
uint16_t const_table_cur_obj;
|
||||
uint16_t const_table_num_obj;
|
||||
uint16_t const_table_cur_raw_code;
|
||||
mp_uint_t *const_table;
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
uint16_t qstr_link_cur;
|
||||
mp_qstr_link_entry_t *qstr_link;
|
||||
@ -255,8 +260,9 @@ STATIC void emit_native_global_exc_entry(emit_t *emit);
|
||||
STATIC void emit_native_global_exc_exit(emit_t *emit);
|
||||
STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj);
|
||||
|
||||
emit_t *EXPORT_FUN(new)(mp_obj_t * error_slot, uint *label_slot, mp_uint_t max_num_labels) {
|
||||
emit_t *EXPORT_FUN(new)(mp_emit_common_t * emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels) {
|
||||
emit_t *emit = m_new0(emit_t, 1);
|
||||
emit->emit_common = emit_common;
|
||||
emit->error_slot = error_slot;
|
||||
emit->label_slot = label_slot;
|
||||
emit->stack_info_alloc = 8;
|
||||
@ -340,30 +346,22 @@ STATIC void emit_native_mov_reg_qstr_obj(emit_t *emit, int reg_dest, qstr qst) {
|
||||
emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \
|
||||
} while (false)
|
||||
|
||||
#define emit_native_mov_state_imm_fix_u16_via(emit, local_num, imm, reg_temp) \
|
||||
do { \
|
||||
ASM_MOV_REG_IMM_FIX_U16((emit)->as, (reg_temp), (imm)); \
|
||||
emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \
|
||||
} while (false)
|
||||
|
||||
#define emit_native_mov_state_imm_fix_word_via(emit, local_num, imm, reg_temp) \
|
||||
do { \
|
||||
ASM_MOV_REG_IMM_FIX_WORD((emit)->as, (reg_temp), (imm)); \
|
||||
emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \
|
||||
} while (false)
|
||||
|
||||
STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope);
|
||||
|
||||
if (pass == MP_PASS_SCOPE) {
|
||||
// Note: the first argument passed here is mp_emit_common_t, not the native emitter context
|
||||
#if N_PRELUDE_AS_BYTES_OBJ
|
||||
if (scope->emit_options == MP_EMIT_OPT_NATIVE_PYTHON) {
|
||||
mp_emit_common_alloc_const_obj((mp_emit_common_t *)emit, mp_const_none);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
emit->pass = pass;
|
||||
emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER;
|
||||
emit->stack_size = 0;
|
||||
#if N_PRELUDE_AS_BYTES_OBJ
|
||||
emit->const_table_cur_obj = emit->do_viper_types ? 0 : 1; // reserve first obj for prelude bytes obj
|
||||
#else
|
||||
emit->const_table_cur_obj = 0;
|
||||
#endif
|
||||
emit->const_table_cur_raw_code = 0;
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
emit->qstr_link_cur = 0;
|
||||
#endif
|
||||
@ -455,8 +453,9 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
||||
#endif
|
||||
|
||||
// Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, 0);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, INDEX_OF_MP_FUN_TABLE_IN_CONST_TABLE);
|
||||
|
||||
// Store function object (passed as first arg) to stack if needed
|
||||
if (NEED_FUN_OBJ(emit)) {
|
||||
@ -514,7 +513,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
||||
emit->stack_start = SIZEOF_CODE_STATE;
|
||||
#if N_PRELUDE_AS_BYTES_OBJ
|
||||
// Load index of prelude bytes object in const_table
|
||||
mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)(emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1));
|
||||
mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->prelude_const_table_offset);
|
||||
#else
|
||||
mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->prelude_offset);
|
||||
#endif
|
||||
@ -536,8 +535,9 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
||||
|
||||
// Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, LOCAL_IDX_FUN_OBJ(emit));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_TEMP0, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONTEXT);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_TEMP0, INDEX_OF_MP_FUN_TABLE_IN_CONST_TABLE);
|
||||
} else {
|
||||
// The locals and stack start after the code_state structure
|
||||
emit->stack_start = emit->code_state_start + SIZEOF_CODE_STATE;
|
||||
@ -555,22 +555,33 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
||||
#endif
|
||||
|
||||
// Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, INDEX_OF_MP_FUN_TABLE_IN_CONST_TABLE);
|
||||
|
||||
// Set code_state.fun_bc
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);
|
||||
|
||||
// Set code_state.ip (offset from start of this function to prelude info)
|
||||
// Set code_state.ip, a pointer to the beginning of the prelude
|
||||
// Need to use some locals for this, so assert that they are available for use
|
||||
MP_STATIC_ASSERT(REG_LOCAL_3 != REG_PARENT_ARG_1);
|
||||
MP_STATIC_ASSERT(REG_LOCAL_3 != REG_PARENT_ARG_2);
|
||||
MP_STATIC_ASSERT(REG_LOCAL_3 != REG_PARENT_ARG_3);
|
||||
MP_STATIC_ASSERT(REG_LOCAL_3 != REG_PARENT_ARG_4);
|
||||
int code_state_ip_local = emit->code_state_start + OFFSETOF_CODE_STATE_IP;
|
||||
#if N_PRELUDE_AS_BYTES_OBJ
|
||||
// Prelude is a bytes object in const_table; store ip = prelude->data - fun_bc->bytecode
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1);
|
||||
// Prelude is a bytes object in const_table[prelude_const_table_offset].
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, emit->prelude_const_table_offset);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, offsetof(mp_obj_str_t, data) / sizeof(uintptr_t));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_PARENT_ARG_1, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_BYTECODE);
|
||||
ASM_SUB_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1);
|
||||
emit_native_mov_state_reg(emit, code_state_ip_local, REG_LOCAL_3);
|
||||
#else
|
||||
MP_STATIC_ASSERT(REG_LOCAL_2 != REG_PARENT_ARG_1);
|
||||
MP_STATIC_ASSERT(REG_LOCAL_2 != REG_PARENT_ARG_2);
|
||||
MP_STATIC_ASSERT(REG_LOCAL_2 != REG_PARENT_ARG_3);
|
||||
MP_STATIC_ASSERT(REG_LOCAL_2 != REG_PARENT_ARG_4);
|
||||
// Prelude is at the end of the machine code
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_BYTECODE);
|
||||
if (emit->pass == MP_PASS_CODE_SIZE) {
|
||||
// Commit to the encoding size based on the value of prelude_offset in this pass.
|
||||
// By using 32768 as the cut-off it is highly unlikely that prelude_offset will
|
||||
@ -579,14 +590,16 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
||||
}
|
||||
if (emit->prelude_offset_uses_u16_encoding) {
|
||||
assert(emit->prelude_offset <= 65535);
|
||||
emit_native_mov_state_imm_fix_u16_via(emit, code_state_ip_local, emit->prelude_offset, REG_PARENT_ARG_1);
|
||||
ASM_MOV_REG_IMM_FIX_U16((emit)->as, REG_LOCAL_2, emit->prelude_offset);
|
||||
} else {
|
||||
emit_native_mov_state_imm_fix_word_via(emit, code_state_ip_local, emit->prelude_offset, REG_PARENT_ARG_1);
|
||||
ASM_MOV_REG_IMM_FIX_WORD((emit)->as, REG_LOCAL_2, emit->prelude_offset);
|
||||
}
|
||||
ASM_ADD_REG_REG(emit->as, REG_LOCAL_3, REG_LOCAL_2);
|
||||
#endif
|
||||
emit_native_mov_state_reg(emit, code_state_ip_local, REG_LOCAL_3);
|
||||
|
||||
// Set code_state.n_state (only works on little endian targets due to n_state being uint16_t)
|
||||
emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, n_state) / sizeof(uintptr_t), emit->n_state, REG_ARG_1);
|
||||
emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_N_STATE, emit->n_state, REG_ARG_1);
|
||||
|
||||
// Put address of code_state into first arg
|
||||
ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, emit->code_state_start);
|
||||
@ -628,30 +641,17 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
||||
emit->local_vtype[id->local_num] = VTYPE_PYOBJ;
|
||||
}
|
||||
}
|
||||
|
||||
if (pass == MP_PASS_EMIT) {
|
||||
// write argument names as qstr objects
|
||||
// see comment in corresponding part of emitbc.c about the logic here
|
||||
for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) {
|
||||
qstr qst = MP_QSTR__star_;
|
||||
for (int j = 0; j < scope->id_info_len; ++j) {
|
||||
id_info_t *id = &scope->id_info[j];
|
||||
if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) {
|
||||
qst = id->qst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit->const_table[i] = (mp_uint_t)MP_OBJ_NEW_QSTR(qst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline void emit_native_write_code_info_byte(emit_t *emit, byte val) {
|
||||
mp_asm_base_data(&emit->as->base, 1, val);
|
||||
}
|
||||
|
||||
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) {
|
||||
emit_native_global_exc_exit(emit);
|
||||
|
||||
@ -662,21 +662,25 @@ STATIC void emit_native_end_pass(emit_t *emit) {
|
||||
size_t n_exc_stack = 0; // exc-stack not needed for native code
|
||||
MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, emit->scope, emit_native_write_code_info_byte, emit);
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
size_t n_info = 4;
|
||||
#else
|
||||
size_t n_info = 1;
|
||||
#endif
|
||||
MP_BC_PRELUDE_SIZE_ENCODE(n_info, emit->n_cell, emit_native_write_code_info_byte, emit);
|
||||
size_t n_info = emit->n_info;
|
||||
size_t n_cell = emit->n_cell;
|
||||
MP_BC_PRELUDE_SIZE_ENCODE(n_info, n_cell, emit_native_write_code_info_byte, emit);
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name);
|
||||
mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name >> 8);
|
||||
mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file);
|
||||
mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file >> 8);
|
||||
#else
|
||||
mp_asm_base_data(&emit->as->base, 1, 1);
|
||||
#endif
|
||||
// bytecode prelude: source info (function and argument qstrs)
|
||||
size_t info_start = mp_asm_base_get_code_pos(&emit->as->base);
|
||||
emit_native_write_code_info_qstr(emit, emit->scope->simple_name);
|
||||
for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
|
||||
qstr qst = MP_QSTR__star_;
|
||||
for (int j = 0; j < emit->scope->id_info_len; ++j) {
|
||||
id_info_t *id = &emit->scope->id_info[j];
|
||||
if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) {
|
||||
qst = id->qst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit_native_write_code_info_qstr(emit, qst);
|
||||
}
|
||||
emit->n_info = mp_asm_base_get_code_pos(&emit->as->base) - info_start;
|
||||
|
||||
// bytecode prelude: initialise closed over variables
|
||||
size_t cell_start = mp_asm_base_get_code_pos(&emit->as->base);
|
||||
@ -690,13 +694,14 @@ STATIC void emit_native_end_pass(emit_t *emit) {
|
||||
emit->n_cell = mp_asm_base_get_code_pos(&emit->as->base) - cell_start;
|
||||
|
||||
#if N_PRELUDE_AS_BYTES_OBJ
|
||||
// Prelude bytes object is after qstr arg names and mp_fun_table
|
||||
size_t table_off = emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1;
|
||||
// Create the prelude as a bytes object, and store it in the constant table
|
||||
mp_obj_t prelude = mp_const_none;
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
void *buf = emit->as->base.code_base + emit->prelude_offset;
|
||||
size_t n = emit->as->base.code_offset - emit->prelude_offset;
|
||||
emit->const_table[table_off] = (uintptr_t)mp_obj_new_bytes(buf, n);
|
||||
prelude = mp_obj_new_bytes(buf, n);
|
||||
}
|
||||
emit->prelude_const_table_offset = mp_emit_common_alloc_const_obj(emit->emit_common, prelude);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -706,31 +711,15 @@ STATIC void emit_native_end_pass(emit_t *emit) {
|
||||
assert(emit->stack_size == 0);
|
||||
assert(emit->exc_stack_size == 0);
|
||||
|
||||
// Deal with const table accounting
|
||||
assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->const_table_num_obj == emit->const_table_cur_obj));
|
||||
emit->const_table_num_obj = emit->const_table_cur_obj;
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
// Allocate qstr_link table if needed
|
||||
if (emit->pass == MP_PASS_CODE_SIZE) {
|
||||
size_t const_table_alloc = 1 + emit->const_table_num_obj + emit->const_table_cur_raw_code;
|
||||
size_t nqstr = 0;
|
||||
if (!emit->do_viper_types) {
|
||||
// Add room for qstr names of arguments
|
||||
nqstr = emit->scope->num_pos_args + emit->scope->num_kwonly_args;
|
||||
const_table_alloc += nqstr;
|
||||
}
|
||||
emit->const_table = m_new(mp_uint_t, const_table_alloc);
|
||||
#if !MICROPY_DYNAMIC_COMPILER
|
||||
// Store mp_fun_table pointer just after qstrs
|
||||
// (but in dynamic-compiler mode eliminate dependency on mp_fun_table)
|
||||
emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)&mp_fun_table;
|
||||
#endif
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
size_t qstr_link_alloc = emit->qstr_link_cur;
|
||||
if (qstr_link_alloc > 0) {
|
||||
emit->qstr_link = m_new(mp_qstr_link_entry_t, qstr_link_alloc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
void *f = mp_asm_base_get_code(&emit->as->base);
|
||||
@ -738,13 +727,14 @@ STATIC void emit_native_end_pass(emit_t *emit) {
|
||||
|
||||
mp_emit_glue_assign_native(emit->scope->raw_code,
|
||||
emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY,
|
||||
f, f_len, emit->const_table,
|
||||
f, f_len,
|
||||
emit->emit_common->children,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
emit->emit_common->ct_cur_child,
|
||||
emit->prelude_offset,
|
||||
emit->const_table_cur_obj, emit->const_table_cur_raw_code,
|
||||
emit->qstr_link_cur, emit->qstr_link,
|
||||
#endif
|
||||
emit->scope->num_pos_args, emit->scope->scope_flags, 0);
|
||||
emit->scope->scope_flags, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1137,29 +1127,19 @@ STATIC exc_stack_entry_t *emit_native_pop_exc_stack(emit_t *emit) {
|
||||
return e;
|
||||
}
|
||||
|
||||
STATIC void emit_load_reg_with_ptr(emit_t *emit, int reg, mp_uint_t ptr, size_t table_off) {
|
||||
if (!emit->do_viper_types) {
|
||||
// Skip qstr names of arguments
|
||||
table_off += emit->scope->num_pos_args + emit->scope->num_kwonly_args;
|
||||
}
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
emit->const_table[table_off] = ptr;
|
||||
}
|
||||
STATIC void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj) {
|
||||
size_t table_off = mp_emit_common_alloc_const_obj(emit->emit_common, obj);
|
||||
emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_FUN_OBJ(emit));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONTEXT);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, reg, REG_TEMP0, table_off);
|
||||
}
|
||||
|
||||
STATIC void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj) {
|
||||
// First entry is for mp_fun_table
|
||||
size_t table_off = 1 + emit->const_table_cur_obj++;
|
||||
emit_load_reg_with_ptr(emit, reg, (mp_uint_t)obj, table_off);
|
||||
}
|
||||
|
||||
STATIC void emit_load_reg_with_raw_code(emit_t *emit, int reg, mp_raw_code_t *rc) {
|
||||
// First entry is for mp_fun_table, then constant objects
|
||||
size_t table_off = 1 + emit->const_table_num_obj + emit->const_table_cur_raw_code++;
|
||||
emit_load_reg_with_ptr(emit, reg, (mp_uint_t)rc, table_off);
|
||||
STATIC void emit_load_reg_with_child(emit_t *emit, int reg, mp_raw_code_t *rc) {
|
||||
size_t table_off = mp_emit_common_alloc_const_child(emit->emit_common, rc);
|
||||
emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_FUN_OBJ(emit));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CHILD_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, reg, REG_TEMP0, table_off);
|
||||
}
|
||||
|
||||
STATIC void emit_native_label_assign(emit_t *emit, mp_uint_t l) {
|
||||
@ -1203,7 +1183,8 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) {
|
||||
if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {
|
||||
// Set new globals
|
||||
emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_FUN_OBJ(emit));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, OFFSETOF_OBJ_FUN_BC_GLOBALS);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, OFFSETOF_MODULE_CONTEXT_GLOBALS);
|
||||
emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
|
||||
|
||||
// Save old globals (or NULL if globals didn't change)
|
||||
@ -1254,7 +1235,8 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) {
|
||||
#if N_NLR_SETJMP
|
||||
// Reload REG_FUN_TABLE, since it may be clobbered by longjmp
|
||||
emit_native_mov_reg_state(emit, REG_LOCAL_1, LOCAL_IDX_FUN_OBJ(emit));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_1, REG_LOCAL_1, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_1, REG_LOCAL_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_1, REG_LOCAL_1, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_1, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
|
||||
#endif
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, LOCAL_IDX_EXC_HANDLER_PC(emit));
|
||||
@ -1385,11 +1367,7 @@ STATIC void emit_native_import(emit_t *emit, qstr qst, int kind) {
|
||||
STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
DEBUG_printf("load_const_tok(tok=%u)\n", tok);
|
||||
if (tok == MP_TOKEN_ELLIPSIS) {
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
emit_native_load_const_obj(emit, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj));
|
||||
#else
|
||||
emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj));
|
||||
#endif
|
||||
} else {
|
||||
emit_native_pre(emit);
|
||||
if (tok == MP_TOKEN_KW_NONE) {
|
||||
@ -2682,33 +2660,46 @@ STATIC void emit_native_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_ri
|
||||
STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
|
||||
// call runtime, with type info for args, or don't support dict/default params, or only support Python objects for them
|
||||
emit_native_pre(emit);
|
||||
emit_native_mov_reg_state(emit, REG_ARG_2, LOCAL_IDX_FUN_OBJ(emit));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_2, OFFSETOF_OBJ_FUN_BC_CONTEXT);
|
||||
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
|
||||
need_reg_all(emit);
|
||||
ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL);
|
||||
ASM_MOV_REG_IMM(emit->as, REG_ARG_3, (mp_uint_t)MP_OBJ_NULL);
|
||||
ASM_MOV_REG_IMM(emit->as, REG_ARG_3, 0);
|
||||
} else {
|
||||
vtype_kind_t vtype_def_tuple, vtype_def_dict;
|
||||
emit_pre_pop_reg_reg(emit, &vtype_def_dict, REG_ARG_3, &vtype_def_tuple, REG_ARG_2);
|
||||
assert(vtype_def_tuple == VTYPE_PYOBJ);
|
||||
assert(vtype_def_dict == VTYPE_PYOBJ);
|
||||
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2);
|
||||
need_reg_all(emit);
|
||||
}
|
||||
emit_load_reg_with_raw_code(emit, REG_ARG_1, scope->raw_code);
|
||||
emit_load_reg_with_child(emit, REG_ARG_1, scope->raw_code);
|
||||
ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_RAW_CODE);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
}
|
||||
|
||||
STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
|
||||
// make function
|
||||
emit_native_pre(emit);
|
||||
emit_native_mov_reg_state(emit, REG_ARG_2, LOCAL_IDX_FUN_OBJ(emit));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_2, OFFSETOF_OBJ_FUN_BC_CONTEXT);
|
||||
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
|
||||
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over);
|
||||
ASM_MOV_REG_IMM(emit->as, REG_ARG_2, n_closed_over);
|
||||
need_reg_all(emit);
|
||||
ASM_MOV_REG_IMM(emit->as, REG_ARG_3, 0);
|
||||
} else {
|
||||
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over + 2);
|
||||
ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0x100 | n_closed_over);
|
||||
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2 + n_closed_over);
|
||||
adjust_stack(emit, 2 + n_closed_over);
|
||||
need_reg_all(emit);
|
||||
}
|
||||
emit_load_reg_with_raw_code(emit, REG_ARG_1, scope->raw_code);
|
||||
ASM_CALL_IND(emit->as, MP_F_MAKE_CLOSURE_FROM_RAW_CODE);
|
||||
emit_load_reg_with_child(emit, REG_ARG_1, scope->raw_code);
|
||||
ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_RAW_CODE);
|
||||
|
||||
// make closure
|
||||
#if REG_ARG_1 != REG_RET
|
||||
ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_RET);
|
||||
#endif
|
||||
ASM_MOV_REG_IMM(emit->as, REG_ARG_2, n_closed_over);
|
||||
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over);
|
||||
if (n_pos_defaults != 0 || n_kw_defaults != 0) {
|
||||
adjust_stack(emit, -2);
|
||||
}
|
||||
ASM_CALL_IND(emit->as, MP_F_NEW_CLOSURE);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
|
||||
[MP_F_UNPACK_EX] = 3,
|
||||
[MP_F_DELETE_NAME] = 1,
|
||||
[MP_F_DELETE_GLOBAL] = 1,
|
||||
[MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3,
|
||||
[MP_F_NEW_CLOSURE] = 3,
|
||||
[MP_F_ARG_CHECK_NUM_SIG] = 3,
|
||||
[MP_F_SETUP_CODE_STATE] = 4,
|
||||
[MP_F_SMALL_INT_FLOOR_DIVIDE] = 2,
|
||||
|
@ -57,7 +57,7 @@ extern const char mp_frozen_str_content[];
|
||||
|
||||
#include "py/emitglue.h"
|
||||
|
||||
extern const mp_raw_code_t *const mp_frozen_mpy_content[];
|
||||
extern const mp_frozen_module_t *const mp_frozen_mpy_content[];
|
||||
|
||||
#endif // MICROPY_MODULE_FROZEN_MPY
|
||||
|
||||
|
@ -328,6 +328,14 @@
|
||||
#define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE || MICROPY_MODULE_FROZEN_MPY)
|
||||
#endif
|
||||
|
||||
// Whether bytecode uses a qstr_table to map internal qstr indices in the bytecode
|
||||
// to global qstr values in the runtime (behaviour when feature is enabled), or
|
||||
// just stores global qstr values directly in the bytecode. This must be enabled
|
||||
// if MICROPY_PERSISTENT_CODE is enabled.
|
||||
#ifndef MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
#define MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE (MICROPY_PERSISTENT_CODE)
|
||||
#endif
|
||||
|
||||
// Whether to emit x64 native code
|
||||
#ifndef MICROPY_EMIT_X64
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
|
@ -300,7 +300,7 @@ const mp_fun_table_t mp_fun_table = {
|
||||
mp_unpack_ex,
|
||||
mp_delete_name,
|
||||
mp_delete_global,
|
||||
mp_make_closure_from_raw_code,
|
||||
mp_obj_new_closure,
|
||||
mp_arg_check_num_sig,
|
||||
mp_setup_code_state,
|
||||
mp_small_int_floor_divide,
|
||||
@ -344,4 +344,8 @@ const mp_fun_table_t mp_fun_table = {
|
||||
&mp_stream_write_obj,
|
||||
};
|
||||
|
||||
#elif MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER
|
||||
|
||||
const int mp_fun_table;
|
||||
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
|
@ -75,7 +75,7 @@ typedef enum {
|
||||
MP_F_UNPACK_EX,
|
||||
MP_F_DELETE_NAME,
|
||||
MP_F_DELETE_GLOBAL,
|
||||
MP_F_MAKE_CLOSURE_FROM_RAW_CODE,
|
||||
MP_F_NEW_CLOSURE,
|
||||
MP_F_ARG_CHECK_NUM_SIG,
|
||||
MP_F_SETUP_CODE_STATE,
|
||||
MP_F_SMALL_INT_FLOOR_DIVIDE,
|
||||
@ -112,7 +112,7 @@ typedef struct _mp_fun_table_t {
|
||||
void (*set_store)(mp_obj_t self_in, mp_obj_t item);
|
||||
mp_obj_t (*list_append)(mp_obj_t self_in, mp_obj_t arg);
|
||||
mp_obj_t (*dict_store)(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
|
||||
mp_obj_t (*make_function_from_raw_code)(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
|
||||
mp_obj_t (*make_function_from_raw_code)(const mp_raw_code_t *rc, const mp_module_context_t *cm, const mp_obj_t *def_args);
|
||||
mp_obj_t (*call_function_n_kw)(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args);
|
||||
mp_obj_t (*call_method_n_kw)(size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
mp_obj_t (*call_method_n_kw_var)(bool have_self, size_t n_args_n_kw, const mp_obj_t *args);
|
||||
@ -129,7 +129,7 @@ typedef struct _mp_fun_table_t {
|
||||
void (*unpack_ex)(mp_obj_t seq, size_t num, mp_obj_t *items);
|
||||
void (*delete_name)(qstr qst);
|
||||
void (*delete_global)(qstr qst);
|
||||
mp_obj_t (*make_closure_from_raw_code)(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);
|
||||
mp_obj_t (*new_closure)(mp_obj_t fun, size_t n_closed_over, const mp_obj_t *closed);
|
||||
void (*arg_check_num_sig)(size_t n_args, size_t n_kw, uint32_t sig);
|
||||
void (*setup_code_state)(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
mp_int_t (*small_int_floor_divide)(mp_int_t num, mp_int_t denom);
|
||||
@ -172,6 +172,12 @@ typedef struct _mp_fun_table_t {
|
||||
const mp_obj_fun_builtin_var_t *stream_write_obj;
|
||||
} mp_fun_table_t;
|
||||
|
||||
#if (MICROPY_EMIT_NATIVE && !MICROPY_DYNAMIC_COMPILER) || MICROPY_ENABLE_DYNRUNTIME
|
||||
extern const mp_fun_table_t mp_fun_table;
|
||||
#elif MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER
|
||||
// In dynamic-compiler mode eliminate dependency on entries in mp_fun_table.
|
||||
// This only needs to be an independent pointer, content doesn't matter.
|
||||
extern const int mp_fun_table;
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_INCLUDED_PY_NATIVEGLUE_H
|
||||
|
4
py/obj.h
4
py/obj.h
@ -781,9 +781,6 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, mp_rom_err
|
||||
#ifdef va_start
|
||||
mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list arg); // same fmt restrictions as above
|
||||
#endif
|
||||
mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table);
|
||||
mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table);
|
||||
mp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig);
|
||||
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
|
||||
mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed);
|
||||
mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items);
|
||||
@ -992,7 +989,6 @@ typedef struct _mp_obj_fun_builtin_var_t {
|
||||
} mp_obj_fun_builtin_var_t;
|
||||
|
||||
qstr mp_obj_fun_get_name(mp_const_obj_t fun);
|
||||
qstr mp_obj_code_get_name(const byte *code_info);
|
||||
|
||||
mp_obj_t mp_identity(mp_obj_t self);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(mp_identity_obj);
|
||||
|
50
py/objfun.c
50
py/objfun.c
@ -143,13 +143,13 @@ const mp_obj_type_t mp_type_fun_builtin_var = {
|
||||
/******************************************************************************/
|
||||
/* byte code functions */
|
||||
|
||||
qstr mp_obj_code_get_name(const byte *code_info) {
|
||||
STATIC qstr mp_obj_code_get_name(const mp_obj_fun_bc_t *fun, const byte *code_info) {
|
||||
MP_BC_PRELUDE_SIZE_DECODE(code_info);
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
return code_info[0] | (code_info[1] << 8);
|
||||
#else
|
||||
return mp_decode_uint_value(code_info);
|
||||
mp_uint_t name = mp_decode_uint_value(code_info);
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
name = fun->context->constants.qstr_table[name];
|
||||
#endif
|
||||
return name;
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
@ -167,7 +167,7 @@ qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) {
|
||||
|
||||
const byte *bc = fun->bytecode;
|
||||
MP_BC_PRELUDE_SIG_DECODE(bc);
|
||||
return mp_obj_code_get_name(bc);
|
||||
return mp_obj_code_get_name(fun, bc);
|
||||
}
|
||||
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
@ -209,7 +209,7 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) {
|
||||
|
||||
#define INIT_CODESTATE(code_state, _fun_bc, _n_state, n_args, n_kw, args) \
|
||||
code_state->fun_bc = _fun_bc; \
|
||||
code_state->ip = 0; \
|
||||
code_state->ip = _fun_bc->bytecode; \
|
||||
code_state->n_state = _n_state; \
|
||||
mp_setup_code_state(code_state, n_args, n_kw, args); \
|
||||
code_state->old_globals = mp_globals_get();
|
||||
@ -240,7 +240,7 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args
|
||||
INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args);
|
||||
|
||||
// execute the byte code with the correct globals context
|
||||
mp_globals_set(self->globals);
|
||||
mp_globals_set(self->context->module.globals);
|
||||
|
||||
return code_state;
|
||||
}
|
||||
@ -285,7 +285,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
|
||||
INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args);
|
||||
|
||||
// execute the byte code with the correct globals context
|
||||
mp_globals_set(self->globals);
|
||||
mp_globals_set(self->context->module.globals);
|
||||
mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL);
|
||||
mp_globals_set(code_state->old_globals);
|
||||
|
||||
@ -358,7 +358,7 @@ void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
}
|
||||
if (attr == MP_QSTR___globals__) {
|
||||
mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
dest[0] = MP_OBJ_FROM_PTR(self->globals);
|
||||
dest[0] = MP_OBJ_FROM_PTR(self->context->module.globals);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -377,25 +377,29 @@ const mp_obj_type_t mp_type_fun_bc = {
|
||||
#endif
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table) {
|
||||
mp_obj_t mp_obj_new_fun_bc(const mp_obj_t *def_args, const byte *code, const mp_module_context_t *context, struct _mp_raw_code_t *const *child_table) {
|
||||
size_t n_def_args = 0;
|
||||
size_t n_extra_args = 0;
|
||||
mp_obj_tuple_t *def_args = MP_OBJ_TO_PTR(def_args_in);
|
||||
if (def_args_in != MP_OBJ_NULL) {
|
||||
assert(mp_obj_is_type(def_args_in, &mp_type_tuple));
|
||||
n_def_args = def_args->len;
|
||||
n_extra_args = def_args->len;
|
||||
mp_obj_tuple_t *def_pos_args = NULL;
|
||||
mp_obj_t def_kw_args = MP_OBJ_NULL;
|
||||
if (def_args != NULL && def_args[0] != MP_OBJ_NULL) {
|
||||
assert(mp_obj_is_type(def_args[0], &mp_type_tuple));
|
||||
def_pos_args = MP_OBJ_TO_PTR(def_args[0]);
|
||||
n_def_args = def_pos_args->len;
|
||||
n_extra_args = def_pos_args->len;
|
||||
}
|
||||
if (def_kw_args != MP_OBJ_NULL) {
|
||||
if (def_args != NULL && def_args[1] != MP_OBJ_NULL) {
|
||||
assert(mp_obj_is_type(def_args[1], &mp_type_dict));
|
||||
def_kw_args = def_args[1];
|
||||
n_extra_args += 1;
|
||||
}
|
||||
mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args);
|
||||
o->base.type = &mp_type_fun_bc;
|
||||
o->globals = mp_globals_get();
|
||||
o->bytecode = code;
|
||||
o->const_table = const_table;
|
||||
if (def_args != NULL) {
|
||||
memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
|
||||
o->context = context;
|
||||
o->child_table = child_table;
|
||||
if (def_pos_args != NULL) {
|
||||
memcpy(o->extra_args, def_pos_args->items, n_def_args * sizeof(mp_obj_t));
|
||||
}
|
||||
if (def_kw_args != MP_OBJ_NULL) {
|
||||
o->extra_args[n_def_args] = def_kw_args;
|
||||
@ -423,8 +427,8 @@ STATIC const mp_obj_type_t mp_type_fun_native = {
|
||||
.unary_op = mp_generic_unary_op,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table) {
|
||||
mp_obj_fun_bc_t *o = MP_OBJ_TO_PTR(mp_obj_new_fun_bc(def_args_in, def_kw_args, (const byte *)fun_data, const_table));
|
||||
mp_obj_t mp_obj_new_fun_native(const mp_obj_t *def_args, const void *fun_data, const mp_module_context_t *mc, struct _mp_raw_code_t *const *child_table) {
|
||||
mp_obj_fun_bc_t *o = MP_OBJ_TO_PTR(mp_obj_new_fun_bc(def_args, (const byte *)fun_data, mc, child_table));
|
||||
o->base.type = &mp_type_fun_native;
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
10
py/objfun.h
10
py/objfun.h
@ -26,13 +26,14 @@
|
||||
#ifndef MICROPY_INCLUDED_PY_OBJFUN_H
|
||||
#define MICROPY_INCLUDED_PY_OBJFUN_H
|
||||
|
||||
#include "py/bc.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
typedef struct _mp_obj_fun_bc_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_dict_t *globals; // the context within which this function was defined
|
||||
const byte *bytecode; // bytecode for the function
|
||||
const mp_uint_t *const_table; // constant table
|
||||
const mp_module_context_t *context; // context within which this function was defined
|
||||
struct _mp_raw_code_t *const *child_table; // table of children
|
||||
const byte *bytecode; // bytecode for the function
|
||||
#if MICROPY_PY_SYS_SETTRACE
|
||||
const struct _mp_raw_code_t *rc;
|
||||
#endif
|
||||
@ -42,6 +43,9 @@ typedef struct _mp_obj_fun_bc_t {
|
||||
mp_obj_t extra_args[];
|
||||
} mp_obj_fun_bc_t;
|
||||
|
||||
mp_obj_t mp_obj_new_fun_bc(const mp_obj_t *def_args, const byte *code, const mp_module_context_t *cm, struct _mp_raw_code_t *const *raw_code_table);
|
||||
mp_obj_t mp_obj_new_fun_native(const mp_obj_t *def_args, const void *fun_data, const mp_module_context_t *cm, struct _mp_raw_code_t *const *raw_code_table);
|
||||
mp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig);
|
||||
void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
|
||||
|
||||
#endif // MICROPY_INCLUDED_PY_OBJFUN_H
|
||||
|
@ -65,7 +65,7 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons
|
||||
|
||||
o->pend_exc = mp_const_none;
|
||||
o->code_state.fun_bc = self_fun;
|
||||
o->code_state.ip = 0;
|
||||
o->code_state.ip = self_fun->bytecode;
|
||||
o->code_state.n_state = n_state;
|
||||
mp_setup_code_state(&o->code_state, n_args, n_kw, args);
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
@ -91,14 +91,18 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k
|
||||
// The state for a native generating function is held in the same struct as a bytecode function
|
||||
mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
// Determine start of prelude, and extract n_state from it
|
||||
// Determine start of prelude.
|
||||
uintptr_t prelude_offset = ((uintptr_t *)self_fun->bytecode)[0];
|
||||
#if MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ
|
||||
// Prelude is in bytes object in const_table, at index prelude_offset
|
||||
mp_obj_str_t *prelude_bytes = MP_OBJ_TO_PTR(self_fun->const_table[prelude_offset]);
|
||||
prelude_offset = (const byte *)prelude_bytes->data - self_fun->bytecode;
|
||||
mp_obj_str_t *prelude_bytes = MP_OBJ_TO_PTR(self_fun->context->constants.obj_table[prelude_offset]);
|
||||
const uint8_t *prelude_ptr = prelude_bytes->data;
|
||||
#else
|
||||
const uint8_t *prelude_ptr = self_fun->bytecode + prelude_offset;
|
||||
#endif
|
||||
const uint8_t *ip = self_fun->bytecode + prelude_offset;
|
||||
|
||||
// Extract n_state from the prelude.
|
||||
const uint8_t *ip = prelude_ptr;
|
||||
size_t n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args;
|
||||
MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args);
|
||||
size_t n_exc_stack = 0;
|
||||
@ -111,7 +115,7 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k
|
||||
// Parse the input arguments and set up the code state
|
||||
o->pend_exc = mp_const_none;
|
||||
o->code_state.fun_bc = self_fun;
|
||||
o->code_state.ip = (const byte *)prelude_offset;
|
||||
o->code_state.ip = prelude_ptr;
|
||||
o->code_state.n_state = n_state;
|
||||
mp_setup_code_state(&o->code_state, n_args, n_kw, args);
|
||||
|
||||
@ -184,7 +188,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
|
||||
|
||||
// Set up the correct globals context for the generator and execute it
|
||||
self->code_state.old_globals = mp_globals_get();
|
||||
mp_globals_set(self->code_state.fun_bc->globals);
|
||||
mp_globals_set(self->code_state.fun_bc->context->module.globals);
|
||||
|
||||
mp_vm_return_kind_t ret_kind;
|
||||
|
||||
|
@ -112,6 +112,7 @@ const mp_obj_type_t mp_type_module = {
|
||||
.attr = module_attr,
|
||||
};
|
||||
|
||||
#include "py/bc.h"
|
||||
mp_obj_t mp_obj_new_module(qstr module_name) {
|
||||
mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
|
||||
mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
||||
@ -122,12 +123,12 @@ mp_obj_t mp_obj_new_module(qstr module_name) {
|
||||
}
|
||||
|
||||
// create new module object
|
||||
mp_obj_module_t *o = m_new_obj(mp_obj_module_t);
|
||||
o->base.type = &mp_type_module;
|
||||
o->globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE));
|
||||
mp_module_context_t *o = m_new_obj(mp_module_context_t);
|
||||
o->module.base.type = &mp_type_module;
|
||||
o->module.globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE));
|
||||
|
||||
// store __name__ entry in the module
|
||||
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(module_name));
|
||||
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->module.globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(module_name));
|
||||
|
||||
// store the new module into the slot in the global dict holding all modules
|
||||
el->value = MP_OBJ_FROM_PTR(o);
|
||||
|
@ -63,57 +63,6 @@ STATIC int mp_small_int_bits(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#define QSTR_WINDOW_SIZE (32)
|
||||
|
||||
typedef struct _qstr_window_t {
|
||||
uint16_t idx; // indexes the head of the window
|
||||
uint16_t window[QSTR_WINDOW_SIZE];
|
||||
} qstr_window_t;
|
||||
|
||||
// Push a qstr to the head of the window, and the tail qstr is overwritten
|
||||
STATIC void qstr_window_push(qstr_window_t *qw, qstr qst) {
|
||||
qw->idx = (qw->idx + 1) % QSTR_WINDOW_SIZE;
|
||||
qw->window[qw->idx] = qst;
|
||||
}
|
||||
|
||||
// Pull an existing qstr from within the window to the head of the window
|
||||
STATIC qstr qstr_window_pull(qstr_window_t *qw, size_t idx) {
|
||||
qstr qst = qw->window[idx];
|
||||
if (idx > qw->idx) {
|
||||
memmove(&qw->window[idx], &qw->window[idx + 1], (QSTR_WINDOW_SIZE - idx - 1) * sizeof(uint16_t));
|
||||
qw->window[QSTR_WINDOW_SIZE - 1] = qw->window[0];
|
||||
idx = 0;
|
||||
}
|
||||
memmove(&qw->window[idx], &qw->window[idx + 1], (qw->idx - idx) * sizeof(uint16_t));
|
||||
qw->window[qw->idx] = qst;
|
||||
return qst;
|
||||
}
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_LOAD
|
||||
|
||||
// Access a qstr at the given index, relative to the head of the window (0=head)
|
||||
STATIC qstr qstr_window_access(qstr_window_t *qw, size_t idx) {
|
||||
return qstr_window_pull(qw, (qw->idx + QSTR_WINDOW_SIZE - idx) % QSTR_WINDOW_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
|
||||
// Insert a qstr at the head of the window, either by pulling an existing one or pushing a new one
|
||||
STATIC size_t qstr_window_insert(qstr_window_t *qw, qstr qst) {
|
||||
for (size_t idx = 0; idx < QSTR_WINDOW_SIZE; ++idx) {
|
||||
if (qw->window[idx] == qst) {
|
||||
qstr_window_pull(qw, idx);
|
||||
return (qw->idx + QSTR_WINDOW_SIZE - idx) % QSTR_WINDOW_SIZE;
|
||||
}
|
||||
}
|
||||
qstr_window_push(qw, qst);
|
||||
return QSTR_WINDOW_SIZE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct _bytecode_prelude_t {
|
||||
uint n_state;
|
||||
uint n_exc_stack;
|
||||
@ -124,23 +73,6 @@ typedef struct _bytecode_prelude_t {
|
||||
uint code_info_size;
|
||||
} bytecode_prelude_t;
|
||||
|
||||
// ip will point to start of opcodes
|
||||
// return value will point to simple_name, source_file qstrs
|
||||
STATIC byte *extract_prelude(const byte **ip, bytecode_prelude_t *prelude) {
|
||||
MP_BC_PRELUDE_SIG_DECODE(*ip);
|
||||
prelude->n_state = n_state;
|
||||
prelude->n_exc_stack = n_exc_stack;
|
||||
prelude->scope_flags = scope_flags;
|
||||
prelude->n_pos_args = n_pos_args;
|
||||
prelude->n_kwonly_args = n_kwonly_args;
|
||||
prelude->n_def_pos_args = n_def_pos_args;
|
||||
MP_BC_PRELUDE_SIZE_DECODE(*ip);
|
||||
byte *ip_info = (byte *)*ip;
|
||||
*ip += n_info;
|
||||
*ip += n_cell;
|
||||
return ip_info;
|
||||
}
|
||||
|
||||
#endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_LOAD
|
||||
@ -148,13 +80,14 @@ STATIC byte *extract_prelude(const byte **ip, bytecode_prelude_t *prelude) {
|
||||
#include "py/parsenum.h"
|
||||
|
||||
STATIC int read_byte(mp_reader_t *reader);
|
||||
STATIC size_t read_uint(mp_reader_t *reader, byte **out);
|
||||
STATIC size_t read_uint(mp_reader_t *reader);
|
||||
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
|
||||
typedef struct _reloc_info_t {
|
||||
mp_reader_t *reader;
|
||||
mp_uint_t *const_table;
|
||||
uint8_t *rodata;
|
||||
uint8_t *bss;
|
||||
} reloc_info_t;
|
||||
|
||||
#if MICROPY_EMIT_THUMB
|
||||
@ -197,13 +130,13 @@ void mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) {
|
||||
while ((op = read_byte(ri->reader)) != 0xff) {
|
||||
if (op & 1) {
|
||||
// Point to new location to make adjustments
|
||||
size_t addr = read_uint(ri->reader, NULL);
|
||||
size_t addr = read_uint(ri->reader);
|
||||
if ((addr & 1) == 0) {
|
||||
// Point to somewhere in text
|
||||
addr_to_adjust = &((uintptr_t *)text)[addr >> 1];
|
||||
} else {
|
||||
// Point to somewhere in rodata
|
||||
addr_to_adjust = &((uintptr_t *)ri->const_table[1])[addr >> 1];
|
||||
addr_to_adjust = &((uintptr_t *)ri->rodata)[addr >> 1];
|
||||
}
|
||||
}
|
||||
op >>= 1;
|
||||
@ -212,15 +145,18 @@ void mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) {
|
||||
if (op <= 5) {
|
||||
if (op & 1) {
|
||||
// Read in number of adjustments to make
|
||||
n = read_uint(ri->reader, NULL);
|
||||
n = read_uint(ri->reader);
|
||||
}
|
||||
op >>= 1;
|
||||
if (op == 0) {
|
||||
// Destination is text
|
||||
dest = reloc_text;
|
||||
} else if (op == 1) {
|
||||
// Destination is rodata
|
||||
dest = (uintptr_t)ri->rodata;
|
||||
} else {
|
||||
// Destination is rodata (op=1) or bss (op=1 if no rodata, else op=2)
|
||||
dest = ri->const_table[op];
|
||||
// Destination is bss
|
||||
dest = (uintptr_t)ri->bss;
|
||||
}
|
||||
} else if (op == 6) {
|
||||
// Destination is mp_fun_table itself
|
||||
@ -247,14 +183,10 @@ STATIC void read_bytes(mp_reader_t *reader, byte *buf, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC size_t read_uint(mp_reader_t *reader, byte **out) {
|
||||
STATIC size_t read_uint(mp_reader_t *reader) {
|
||||
size_t unum = 0;
|
||||
for (;;) {
|
||||
byte b = reader->readbyte(reader->data);
|
||||
if (out != NULL) {
|
||||
**out = b;
|
||||
++*out;
|
||||
}
|
||||
unum = (unum << 7) | (b & 0x7f);
|
||||
if ((b & 0x80) == 0) {
|
||||
break;
|
||||
@ -263,35 +195,41 @@ STATIC size_t read_uint(mp_reader_t *reader, byte **out) {
|
||||
return unum;
|
||||
}
|
||||
|
||||
STATIC qstr load_qstr(mp_reader_t *reader, qstr_window_t *qw) {
|
||||
size_t len = read_uint(reader, NULL);
|
||||
if (len == 0) {
|
||||
// static qstr
|
||||
return read_byte(reader);
|
||||
}
|
||||
STATIC qstr load_qstr(mp_reader_t *reader) {
|
||||
size_t len = read_uint(reader);
|
||||
if (len & 1) {
|
||||
// qstr in window
|
||||
return qstr_window_access(qw, len >> 1);
|
||||
// static qstr
|
||||
return len >> 1;
|
||||
}
|
||||
len >>= 1;
|
||||
char *str = m_new(char, len);
|
||||
read_bytes(reader, (byte *)str, len);
|
||||
read_byte(reader); // read and discard null terminator
|
||||
qstr qst = qstr_from_strn(str, len);
|
||||
m_del(char, str, len);
|
||||
qstr_window_push(qw, qst);
|
||||
return qst;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t load_obj(mp_reader_t *reader) {
|
||||
byte obj_type = read_byte(reader);
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
if (obj_type == 't') {
|
||||
return MP_OBJ_FROM_PTR(&mp_fun_table);
|
||||
} else
|
||||
#endif
|
||||
if (obj_type == 'e') {
|
||||
return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj);
|
||||
} else {
|
||||
size_t len = read_uint(reader, NULL);
|
||||
size_t len = read_uint(reader);
|
||||
if (len == 0 && obj_type == 'b') {
|
||||
read_byte(reader); // skip null terminator
|
||||
return mp_const_empty_bytes;
|
||||
}
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, len);
|
||||
read_bytes(reader, (byte *)vstr.buf, len);
|
||||
if (obj_type == 's' || obj_type == 'b') {
|
||||
read_byte(reader); // skip null terminator
|
||||
return mp_obj_new_str_from_vstr(obj_type == 's' ? &mp_type_str : &mp_type_bytes, &vstr);
|
||||
} else if (obj_type == 'i') {
|
||||
return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL);
|
||||
@ -302,58 +240,12 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void load_prelude_qstrs(mp_reader_t *reader, qstr_window_t *qw, byte *ip) {
|
||||
qstr simple_name = load_qstr(reader, qw);
|
||||
ip[0] = simple_name;
|
||||
ip[1] = simple_name >> 8;
|
||||
qstr source_file = load_qstr(reader, qw);
|
||||
ip[2] = source_file;
|
||||
ip[3] = source_file >> 8;
|
||||
}
|
||||
|
||||
STATIC void load_prelude(mp_reader_t *reader, qstr_window_t *qw, byte **ip, bytecode_prelude_t *prelude) {
|
||||
// Read in the prelude header
|
||||
byte *ip_read = *ip;
|
||||
read_uint(reader, &ip_read); // read in n_state/etc (is effectively a var-uint)
|
||||
read_uint(reader, &ip_read); // read in n_info/n_cell (is effectively a var-uint)
|
||||
|
||||
// Prelude header has been read into *ip, now decode and extract values from it
|
||||
extract_prelude((const byte **)ip, prelude);
|
||||
|
||||
// Load qstrs in prelude
|
||||
load_prelude_qstrs(reader, qw, ip_read);
|
||||
ip_read += 4;
|
||||
|
||||
// Read remaining code info
|
||||
read_bytes(reader, ip_read, *ip - ip_read);
|
||||
}
|
||||
|
||||
STATIC void load_bytecode(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte *ip_top) {
|
||||
while (ip < ip_top) {
|
||||
*ip = read_byte(reader);
|
||||
size_t sz;
|
||||
uint f = mp_opcode_format(ip, &sz, false);
|
||||
++ip;
|
||||
--sz;
|
||||
if (f == MP_BC_FORMAT_QSTR) {
|
||||
qstr qst = load_qstr(reader, qw);
|
||||
*ip++ = qst;
|
||||
*ip++ = qst >> 8;
|
||||
sz -= 2;
|
||||
} else if (f == MP_BC_FORMAT_VAR_UINT) {
|
||||
while ((*ip++ = read_byte(reader)) & 0x80) {
|
||||
}
|
||||
}
|
||||
read_bytes(reader, ip, sz);
|
||||
ip += sz;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) {
|
||||
STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) {
|
||||
// Load function kind and data length
|
||||
size_t kind_len = read_uint(reader, NULL);
|
||||
size_t kind_len = read_uint(reader);
|
||||
int kind = (kind_len & 3) + MP_CODE_BYTECODE;
|
||||
size_t fun_data_len = kind_len >> 2;
|
||||
bool has_children = !!(kind_len & 4);
|
||||
size_t fun_data_len = kind_len >> 3;
|
||||
|
||||
#if !MICROPY_EMIT_MACHINE_CODE
|
||||
if (kind != MP_CODE_BYTECODE) {
|
||||
@ -362,23 +254,18 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) {
|
||||
#endif
|
||||
|
||||
uint8_t *fun_data = NULL;
|
||||
bytecode_prelude_t prelude = {0};
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
size_t prelude_offset = 0;
|
||||
mp_uint_t type_sig = 0;
|
||||
size_t n_qstr_link = 0;
|
||||
mp_uint_t native_scope_flags = 0;
|
||||
mp_uint_t native_n_pos_args = 0;
|
||||
mp_uint_t native_type_sig = 0;
|
||||
#endif
|
||||
|
||||
if (kind == MP_CODE_BYTECODE) {
|
||||
// Allocate memory for the bytecode
|
||||
fun_data = m_new(uint8_t, fun_data_len);
|
||||
|
||||
// Load prelude
|
||||
byte *ip = fun_data;
|
||||
load_prelude(reader, qw, &ip, &prelude);
|
||||
|
||||
// Load bytecode
|
||||
load_bytecode(reader, qw, ip, fun_data + fun_data_len);
|
||||
read_bytes(reader, fun_data, fun_data_len);
|
||||
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
} else {
|
||||
@ -389,10 +276,10 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) {
|
||||
|
||||
if (kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER) {
|
||||
// Parse qstr link table and link native code
|
||||
n_qstr_link = read_uint(reader, NULL);
|
||||
size_t n_qstr_link = read_uint(reader);
|
||||
for (size_t i = 0; i < n_qstr_link; ++i) {
|
||||
size_t off = read_uint(reader, NULL);
|
||||
qstr qst = load_qstr(reader, qw);
|
||||
size_t off = read_uint(reader);
|
||||
qstr qst = load_qstr(reader);
|
||||
uint8_t *dest = fun_data + (off >> 2);
|
||||
if ((off & 3) == 0) {
|
||||
// Generic 16-bit link
|
||||
@ -409,113 +296,92 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) {
|
||||
}
|
||||
|
||||
if (kind == MP_CODE_NATIVE_PY) {
|
||||
// Extract prelude for later use
|
||||
prelude_offset = read_uint(reader, NULL);
|
||||
// Read prelude offset within fun_data, and extract scope flags.
|
||||
prelude_offset = read_uint(reader);
|
||||
const byte *ip = fun_data + prelude_offset;
|
||||
byte *ip_info = extract_prelude(&ip, &prelude);
|
||||
// Load qstrs in prelude
|
||||
load_prelude_qstrs(reader, qw, ip_info);
|
||||
MP_BC_PRELUDE_SIG_DECODE(ip);
|
||||
native_scope_flags = scope_flags;
|
||||
} else {
|
||||
// Load basic scope info for viper and asm
|
||||
prelude.scope_flags = read_uint(reader, NULL);
|
||||
prelude.n_pos_args = 0;
|
||||
prelude.n_kwonly_args = 0;
|
||||
// Load basic scope info for viper and asm.
|
||||
native_scope_flags = read_uint(reader);
|
||||
if (kind == MP_CODE_NATIVE_ASM) {
|
||||
prelude.n_pos_args = read_uint(reader, NULL);
|
||||
type_sig = read_uint(reader, NULL);
|
||||
native_n_pos_args = read_uint(reader);
|
||||
native_type_sig = read_uint(reader);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t n_obj = 0;
|
||||
size_t n_raw_code = 0;
|
||||
mp_uint_t *const_table = NULL;
|
||||
size_t n_children = 0;
|
||||
mp_raw_code_t **children = NULL;
|
||||
|
||||
if (kind != MP_CODE_NATIVE_ASM) {
|
||||
// Load constant table for bytecode, native and viper
|
||||
|
||||
// Number of entries in constant table
|
||||
n_obj = read_uint(reader, NULL);
|
||||
n_raw_code = read_uint(reader, NULL);
|
||||
|
||||
// Allocate constant table
|
||||
size_t n_alloc = prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code;
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
if (kind != MP_CODE_BYTECODE) {
|
||||
++n_alloc; // additional entry for mp_fun_table
|
||||
if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) {
|
||||
++n_alloc; // additional entry for rodata
|
||||
}
|
||||
if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) {
|
||||
++n_alloc; // additional entry for BSS
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const_table = m_new(mp_uint_t, n_alloc);
|
||||
mp_uint_t *ct = const_table;
|
||||
|
||||
// Load function argument names (initial entries in const_table)
|
||||
// (viper has n_pos_args=n_kwonly_args=0 so doesn't load any qstrs here)
|
||||
for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) {
|
||||
*ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader, qw));
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
// Load optional BSS/rodata for viper.
|
||||
uint8_t *rodata = NULL;
|
||||
uint8_t *bss = NULL;
|
||||
if (kind == MP_CODE_NATIVE_VIPER) {
|
||||
size_t rodata_size = 0;
|
||||
if (native_scope_flags & MP_SCOPE_FLAG_VIPERRODATA) {
|
||||
rodata_size = read_uint(reader);
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
if (kind != MP_CODE_BYTECODE) {
|
||||
// Populate mp_fun_table entry
|
||||
*ct++ = (mp_uint_t)(uintptr_t)&mp_fun_table;
|
||||
size_t bss_size = 0;
|
||||
if (native_scope_flags & MP_SCOPE_FLAG_VIPERBSS) {
|
||||
bss_size = read_uint(reader);
|
||||
}
|
||||
|
||||
// Allocate and load rodata if needed
|
||||
if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) {
|
||||
size_t size = read_uint(reader, NULL);
|
||||
uint8_t *rodata = m_new(uint8_t, size);
|
||||
read_bytes(reader, rodata, size);
|
||||
*ct++ = (uintptr_t)rodata;
|
||||
if (rodata_size + bss_size != 0) {
|
||||
bss_size = (uintptr_t)MP_ALIGN(bss_size, sizeof(uintptr_t));
|
||||
uint8_t *data = m_new0(uint8_t, bss_size + rodata_size);
|
||||
bss = data;
|
||||
rodata = bss + bss_size;
|
||||
if (native_scope_flags & MP_SCOPE_FLAG_VIPERRODATA) {
|
||||
read_bytes(reader, rodata, rodata_size);
|
||||
}
|
||||
|
||||
// Allocate BSS if needed
|
||||
if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) {
|
||||
size_t size = read_uint(reader, NULL);
|
||||
uint8_t *bss = m_new0(uint8_t, size);
|
||||
*ct++ = (uintptr_t)bss;
|
||||
}
|
||||
// Viper code with BSS/rodata should not have any children.
|
||||
// Reuse the children pointer to reference the BSS/rodata
|
||||
// memory so that it is not reclaimed by the GC.
|
||||
assert(!has_children);
|
||||
children = (void *)data;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// Load constant objects and raw code children
|
||||
for (size_t i = 0; i < n_obj; ++i) {
|
||||
*ct++ = (mp_uint_t)load_obj(reader);
|
||||
}
|
||||
for (size_t i = 0; i < n_raw_code; ++i) {
|
||||
*ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader, qw);
|
||||
// Load children if any.
|
||||
if (has_children) {
|
||||
n_children = read_uint(reader);
|
||||
children = m_new(mp_raw_code_t *, n_children);
|
||||
for (size_t i = 0; i < n_children; ++i) {
|
||||
children[i] = load_raw_code(reader);
|
||||
}
|
||||
}
|
||||
|
||||
// Create raw_code and return it
|
||||
mp_raw_code_t *rc = mp_emit_glue_new_raw_code();
|
||||
if (kind == MP_CODE_BYTECODE) {
|
||||
const byte *ip = fun_data;
|
||||
MP_BC_PRELUDE_SIG_DECODE(ip);
|
||||
// Assign bytecode to raw code object
|
||||
mp_emit_glue_assign_bytecode(rc, fun_data,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
|
||||
fun_data_len,
|
||||
#endif
|
||||
const_table,
|
||||
children,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
n_obj, n_raw_code,
|
||||
n_children,
|
||||
#endif
|
||||
prelude.scope_flags);
|
||||
scope_flags);
|
||||
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
} else {
|
||||
// Relocate and commit code to executable address space
|
||||
reloc_info_t ri = {reader, const_table};
|
||||
reloc_info_t ri = {reader, rodata, bss};
|
||||
#if defined(MP_PLAT_COMMIT_EXEC)
|
||||
void *opt_ri = (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL;
|
||||
void *opt_ri = (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL;
|
||||
fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len, opt_ri);
|
||||
#else
|
||||
if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) {
|
||||
if (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) {
|
||||
#if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE
|
||||
// If native code needs relocations then it's not guaranteed that a pointer to
|
||||
// the head of `buf` (containing the machine code) will be retained for the GC
|
||||
@ -534,26 +400,27 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) {
|
||||
|
||||
// Assign native code to raw code object
|
||||
mp_emit_glue_assign_native(rc, kind,
|
||||
fun_data, fun_data_len, const_table,
|
||||
fun_data, fun_data_len,
|
||||
children,
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
n_children,
|
||||
prelude_offset,
|
||||
n_obj, n_raw_code,
|
||||
n_qstr_link, NULL,
|
||||
0, NULL,
|
||||
#endif
|
||||
prelude.n_pos_args, prelude.scope_flags, type_sig);
|
||||
native_scope_flags, native_n_pos_args, native_type_sig
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) {
|
||||
mp_compiled_module_t mp_raw_code_load(mp_reader_t *reader, mp_module_context_t *context) {
|
||||
byte header[4];
|
||||
read_bytes(reader, header, sizeof(header));
|
||||
if (header[0] != 'M'
|
||||
|| header[1] != MPY_VERSION
|
||||
|| MPY_FEATURE_DECODE_FLAGS(header[2]) != MPY_FEATURE_FLAGS
|
||||
|| header[3] > mp_small_int_bits()
|
||||
|| read_uint(reader, NULL) > QSTR_WINDOW_SIZE) {
|
||||
|| header[3] > mp_small_int_bits()) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file"));
|
||||
}
|
||||
if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE) {
|
||||
@ -562,25 +429,49 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy arch"));
|
||||
}
|
||||
}
|
||||
qstr_window_t qw;
|
||||
qw.idx = 0;
|
||||
mp_raw_code_t *rc = load_raw_code(reader, &qw);
|
||||
|
||||
size_t n_qstr = read_uint(reader);
|
||||
size_t n_obj = read_uint(reader);
|
||||
mp_module_context_alloc_tables(context, n_qstr, n_obj);
|
||||
|
||||
// Load qstrs.
|
||||
for (size_t i = 0; i < n_qstr; ++i) {
|
||||
context->constants.qstr_table[i] = load_qstr(reader);
|
||||
}
|
||||
|
||||
// Load constant objects.
|
||||
for (size_t i = 0; i < n_obj; ++i) {
|
||||
context->constants.obj_table[i] = load_obj(reader);
|
||||
}
|
||||
|
||||
// Load top-level module.
|
||||
mp_compiled_module_t cm2;
|
||||
cm2.rc = load_raw_code(reader);
|
||||
cm2.context = context;
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE
|
||||
cm2.has_native = MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE;
|
||||
cm2.n_qstr = n_qstr;
|
||||
cm2.n_obj = n_obj;
|
||||
#endif
|
||||
|
||||
reader->close(reader->data);
|
||||
return rc;
|
||||
|
||||
return cm2;
|
||||
}
|
||||
|
||||
mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) {
|
||||
mp_compiled_module_t mp_raw_code_load_mem(const byte *buf, size_t len, mp_module_context_t *context) {
|
||||
mp_reader_t reader;
|
||||
mp_reader_new_mem(&reader, buf, len, 0);
|
||||
return mp_raw_code_load(&reader);
|
||||
return mp_raw_code_load(&reader, context);
|
||||
}
|
||||
|
||||
#if MICROPY_HAS_FILE_READER
|
||||
|
||||
mp_raw_code_t *mp_raw_code_load_file(const char *filename) {
|
||||
mp_compiled_module_t mp_raw_code_load_file(const char *filename, mp_module_context_t *context) {
|
||||
mp_reader_t reader;
|
||||
mp_reader_new_file(&reader, filename);
|
||||
return mp_raw_code_load(&reader);
|
||||
return mp_raw_code_load(&reader, context);
|
||||
}
|
||||
|
||||
#endif // MICROPY_HAS_FILE_READER
|
||||
@ -607,26 +498,25 @@ STATIC void mp_print_uint(mp_print_t *print, size_t n) {
|
||||
print->print_strn(print->data, (char *)p, buf + sizeof(buf) - p);
|
||||
}
|
||||
|
||||
STATIC void save_qstr(mp_print_t *print, qstr_window_t *qw, qstr qst) {
|
||||
STATIC void save_qstr(mp_print_t *print, qstr qst) {
|
||||
if (qst <= QSTR_LAST_STATIC) {
|
||||
// encode static qstr
|
||||
byte buf[2] = {0, qst & 0xff};
|
||||
mp_print_bytes(print, buf, 2);
|
||||
return;
|
||||
}
|
||||
size_t idx = qstr_window_insert(qw, qst);
|
||||
if (idx < QSTR_WINDOW_SIZE) {
|
||||
// qstr found in window, encode index to it
|
||||
mp_print_uint(print, idx << 1 | 1);
|
||||
mp_print_uint(print, qst << 1 | 1);
|
||||
return;
|
||||
}
|
||||
size_t len;
|
||||
const byte *str = qstr_data(qst, &len);
|
||||
mp_print_uint(print, len << 1);
|
||||
mp_print_bytes(print, str, len);
|
||||
mp_print_bytes(print, str, len + 1); // +1 to store null terminator
|
||||
}
|
||||
|
||||
STATIC void save_obj(mp_print_t *print, mp_obj_t o) {
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
if (o == MP_OBJ_FROM_PTR(&mp_fun_table)) {
|
||||
byte obj_type = 't';
|
||||
mp_print_bytes(print, &obj_type, 1);
|
||||
} else
|
||||
#endif
|
||||
if (mp_obj_is_str_or_bytes(o)) {
|
||||
byte obj_type;
|
||||
if (mp_obj_is_str(o)) {
|
||||
@ -638,7 +528,7 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) {
|
||||
const char *str = mp_obj_str_get_data(o, &len);
|
||||
mp_print_bytes(print, &obj_type, 1);
|
||||
mp_print_uint(print, len);
|
||||
mp_print_bytes(print, (const byte *)str, len);
|
||||
mp_print_bytes(print, (const byte *)str, len + 1); // +1 to store null terminator
|
||||
} else if (MP_OBJ_TO_PTR(o) == &mp_const_ellipsis_obj) {
|
||||
byte obj_type = 'e';
|
||||
mp_print_bytes(print, &obj_type, 1);
|
||||
@ -667,136 +557,45 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void save_prelude_qstrs(mp_print_t *print, qstr_window_t *qw, const byte *ip) {
|
||||
save_qstr(print, qw, ip[0] | (ip[1] << 8)); // simple_name
|
||||
save_qstr(print, qw, ip[2] | (ip[3] << 8)); // source_file
|
||||
}
|
||||
|
||||
STATIC void save_bytecode(mp_print_t *print, qstr_window_t *qw, const byte *ip, const byte *ip_top) {
|
||||
while (ip < ip_top) {
|
||||
size_t sz;
|
||||
uint f = mp_opcode_format(ip, &sz, true);
|
||||
if (f == MP_BC_FORMAT_QSTR) {
|
||||
mp_print_bytes(print, ip, 1);
|
||||
qstr qst = ip[1] | (ip[2] << 8);
|
||||
save_qstr(print, qw, qst);
|
||||
ip += 3;
|
||||
sz -= 3;
|
||||
}
|
||||
mp_print_bytes(print, ip, sz);
|
||||
ip += sz;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *qstr_window) {
|
||||
STATIC void save_raw_code(mp_print_t *print, const mp_raw_code_t *rc) {
|
||||
// Save function kind and data length
|
||||
mp_print_uint(print, (rc->fun_data_len << 2) | (rc->kind - MP_CODE_BYTECODE));
|
||||
mp_print_uint(print, (rc->fun_data_len << 3) | ((rc->n_children != 0) << 2) | (rc->kind - MP_CODE_BYTECODE));
|
||||
|
||||
bytecode_prelude_t prelude;
|
||||
// Save function code.
|
||||
mp_print_bytes(print, rc->fun_data, rc->fun_data_len);
|
||||
|
||||
if (rc->kind == MP_CODE_BYTECODE) {
|
||||
// Extract prelude
|
||||
const byte *ip = rc->fun_data;
|
||||
const byte *ip_info = extract_prelude(&ip, &prelude);
|
||||
|
||||
// Save prelude
|
||||
mp_print_bytes(print, rc->fun_data, ip_info - (const byte *)rc->fun_data);
|
||||
save_prelude_qstrs(print, qstr_window, ip_info);
|
||||
ip_info += 4;
|
||||
mp_print_bytes(print, ip_info, ip - ip_info);
|
||||
|
||||
// Save bytecode
|
||||
const byte *ip_top = (const byte *)rc->fun_data + rc->fun_data_len;
|
||||
save_bytecode(print, qstr_window, ip, ip_top);
|
||||
#if MICROPY_EMIT_MACHINE_CODE
|
||||
} else {
|
||||
// Save native code
|
||||
mp_print_bytes(print, rc->fun_data, rc->fun_data_len);
|
||||
|
||||
if (rc->kind == MP_CODE_NATIVE_PY || rc->kind == MP_CODE_NATIVE_VIPER) {
|
||||
// Save qstr link table for native code
|
||||
mp_print_uint(print, rc->n_qstr);
|
||||
for (size_t i = 0; i < rc->n_qstr; ++i) {
|
||||
mp_print_uint(print, rc->qstr_link[i].off);
|
||||
save_qstr(print, qstr_window, rc->qstr_link[i].qst);
|
||||
}
|
||||
if (rc->kind == MP_CODE_NATIVE_PY || rc->kind == MP_CODE_NATIVE_VIPER) {
|
||||
// Save qstr link table for native code
|
||||
mp_print_uint(print, rc->n_qstr);
|
||||
for (size_t i = 0; i < rc->n_qstr; ++i) {
|
||||
mp_print_uint(print, rc->qstr_link[i].off);
|
||||
save_qstr(print, rc->qstr_link[i].qst);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc->kind == MP_CODE_NATIVE_PY) {
|
||||
// Save prelude size
|
||||
mp_print_uint(print, rc->prelude_offset);
|
||||
|
||||
// Extract prelude and save qstrs in prelude
|
||||
const byte *ip = (const byte *)rc->fun_data + rc->prelude_offset;
|
||||
const byte *ip_info = extract_prelude(&ip, &prelude);
|
||||
save_prelude_qstrs(print, qstr_window, ip_info);
|
||||
} else {
|
||||
// Save basic scope info for viper and asm
|
||||
mp_print_uint(print, rc->scope_flags & MP_SCOPE_FLAG_ALL_SIG);
|
||||
prelude.n_pos_args = 0;
|
||||
prelude.n_kwonly_args = 0;
|
||||
if (rc->kind == MP_CODE_NATIVE_ASM) {
|
||||
mp_print_uint(print, rc->n_pos_args);
|
||||
mp_print_uint(print, rc->type_sig);
|
||||
}
|
||||
if (rc->kind == MP_CODE_NATIVE_PY) {
|
||||
// Save prelude size
|
||||
mp_print_uint(print, rc->prelude_offset);
|
||||
} else if (rc->kind == MP_CODE_NATIVE_VIPER || rc->kind == MP_CODE_NATIVE_ASM) {
|
||||
// Save basic scope info for viper and asm
|
||||
mp_print_uint(print, rc->scope_flags & MP_SCOPE_FLAG_ALL_SIG);
|
||||
if (rc->kind == MP_CODE_NATIVE_ASM) {
|
||||
mp_print_uint(print, rc->n_pos_args);
|
||||
mp_print_uint(print, rc->type_sig);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (rc->kind != MP_CODE_NATIVE_ASM) {
|
||||
// Save constant table for bytecode, native and viper
|
||||
|
||||
// Number of entries in constant table
|
||||
mp_print_uint(print, rc->n_obj);
|
||||
mp_print_uint(print, rc->n_raw_code);
|
||||
|
||||
const mp_uint_t *const_table = rc->const_table;
|
||||
|
||||
// Save function argument names (initial entries in const_table)
|
||||
// (viper has n_pos_args=n_kwonly_args=0 so doesn't save any qstrs here)
|
||||
for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) {
|
||||
mp_obj_t o = (mp_obj_t)*const_table++;
|
||||
save_qstr(print, qstr_window, MP_OBJ_QSTR_VALUE(o));
|
||||
}
|
||||
|
||||
if (rc->kind != MP_CODE_BYTECODE) {
|
||||
// Skip saving mp_fun_table entry
|
||||
++const_table;
|
||||
}
|
||||
|
||||
// Save constant objects and raw code children
|
||||
for (size_t i = 0; i < rc->n_obj; ++i) {
|
||||
save_obj(print, (mp_obj_t)*const_table++);
|
||||
}
|
||||
for (size_t i = 0; i < rc->n_raw_code; ++i) {
|
||||
save_raw_code(print, (mp_raw_code_t *)(uintptr_t)*const_table++, qstr_window);
|
||||
if (rc->n_children) {
|
||||
mp_print_uint(print, rc->n_children);
|
||||
for (size_t i = 0; i < rc->n_children; ++i) {
|
||||
save_raw_code(print, rc->children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool mp_raw_code_has_native(mp_raw_code_t *rc) {
|
||||
if (rc->kind != MP_CODE_BYTECODE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const byte *ip = rc->fun_data;
|
||||
bytecode_prelude_t prelude;
|
||||
extract_prelude(&ip, &prelude);
|
||||
|
||||
const mp_uint_t *const_table = rc->const_table
|
||||
+ prelude.n_pos_args + prelude.n_kwonly_args
|
||||
+ rc->n_obj;
|
||||
|
||||
for (size_t i = 0; i < rc->n_raw_code; ++i) {
|
||||
if (mp_raw_code_has_native((mp_raw_code_t *)(uintptr_t)*const_table++)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) {
|
||||
void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print) {
|
||||
// header contains:
|
||||
// byte 'M'
|
||||
// byte version
|
||||
@ -813,16 +612,27 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) {
|
||||
mp_small_int_bits(),
|
||||
#endif
|
||||
};
|
||||
if (mp_raw_code_has_native(rc)) {
|
||||
if (cm->has_native) {
|
||||
header[2] |= MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC);
|
||||
}
|
||||
mp_print_bytes(print, header, sizeof(header));
|
||||
mp_print_uint(print, QSTR_WINDOW_SIZE);
|
||||
|
||||
qstr_window_t qw;
|
||||
qw.idx = 0;
|
||||
memset(qw.window, 0, sizeof(qw.window));
|
||||
save_raw_code(print, rc, &qw);
|
||||
// Number of entries in constant table.
|
||||
mp_print_uint(print, cm->n_qstr);
|
||||
mp_print_uint(print, cm->n_obj);
|
||||
|
||||
// Save qstrs.
|
||||
for (size_t i = 0; i < cm->n_qstr; ++i) {
|
||||
save_qstr(print, cm->context->constants.qstr_table[i]);
|
||||
}
|
||||
|
||||
// Save constant objects.
|
||||
for (size_t i = 0; i < cm->n_obj; ++i) {
|
||||
save_obj(print, (mp_obj_t)cm->context->constants.obj_table[i]);
|
||||
}
|
||||
|
||||
// Save outer raw code, which will save all its child raw codes.
|
||||
save_raw_code(print, cm->rc);
|
||||
}
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_SAVE_FILE
|
||||
@ -839,12 +649,12 @@ STATIC void fd_print_strn(void *env, const char *str, size_t len) {
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename) {
|
||||
void mp_raw_code_save_file(mp_compiled_module_t *cm, const char *filename) {
|
||||
MP_THREAD_GIL_EXIT();
|
||||
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
MP_THREAD_GIL_ENTER();
|
||||
mp_print_t fd_print = {(void *)(intptr_t)fd, fd_print_strn};
|
||||
mp_raw_code_save(rc, &fd_print);
|
||||
mp_raw_code_save(cm, &fd_print);
|
||||
MP_THREAD_GIL_EXIT();
|
||||
close(fd);
|
||||
MP_THREAD_GIL_ENTER();
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "py/emitglue.h"
|
||||
|
||||
// The current version of .mpy files
|
||||
#define MPY_VERSION 5
|
||||
#define MPY_VERSION 6
|
||||
|
||||
// Macros to encode/decode flags to/from the feature byte
|
||||
#define MPY_FEATURE_ENCODE_FLAGS(flags) (flags)
|
||||
@ -102,12 +102,12 @@ enum {
|
||||
MP_NATIVE_ARCH_XTENSAWIN,
|
||||
};
|
||||
|
||||
mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader);
|
||||
mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len);
|
||||
mp_raw_code_t *mp_raw_code_load_file(const char *filename);
|
||||
mp_compiled_module_t mp_raw_code_load(mp_reader_t *reader, mp_module_context_t *ctx);
|
||||
mp_compiled_module_t mp_raw_code_load_mem(const byte *buf, size_t len, mp_module_context_t *ctx);
|
||||
mp_compiled_module_t mp_raw_code_load_file(const char *filename, mp_module_context_t *ctx);
|
||||
|
||||
void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print);
|
||||
void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename);
|
||||
void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print);
|
||||
void mp_raw_code_save_file(mp_compiled_module_t *cm, const char *filename);
|
||||
|
||||
void mp_native_relocate(void *reloc, uint8_t *text, uintptr_t reloc_text);
|
||||
|
||||
|
47
py/profile.c
47
py/profile.c
@ -27,14 +27,16 @@
|
||||
#include "py/profile.h"
|
||||
#include "py/bc0.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/objfun.h"
|
||||
|
||||
#if MICROPY_PY_SYS_SETTRACE
|
||||
|
||||
#define prof_trace_cb MP_STATE_THREAD(prof_trace_callback)
|
||||
#define QSTR_MAP(context, idx) (context->constants.qstr_table[idx])
|
||||
|
||||
STATIC uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc) {
|
||||
const mp_bytecode_prelude_t *prelude = &rc->prelude;
|
||||
return mp_bytecode_get_source_line(prelude->line_info, bc);
|
||||
return mp_bytecode_get_source_line(prelude->line_info, prelude->line_info_top, bc);
|
||||
}
|
||||
|
||||
void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude) {
|
||||
@ -50,13 +52,14 @@ void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelud
|
||||
|
||||
MP_BC_PRELUDE_SIZE_DECODE(ip);
|
||||
|
||||
prelude->line_info = ip + 4;
|
||||
prelude->line_info_top = ip + n_info;
|
||||
prelude->opcodes = ip + n_info + n_cell;
|
||||
|
||||
qstr block_name = ip[0] | (ip[1] << 8);
|
||||
qstr source_file = ip[2] | (ip[3] << 8);
|
||||
prelude->qstr_block_name = block_name;
|
||||
prelude->qstr_source_file = source_file;
|
||||
prelude->qstr_block_name_idx = mp_decode_uint_value(ip);
|
||||
for (size_t i = 0; i < 1 + n_pos_args + n_kwonly_args; ++i) {
|
||||
ip = mp_decode_uint_skip(ip);
|
||||
}
|
||||
prelude->line_info = ip;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@ -69,22 +72,19 @@ STATIC void code_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t k
|
||||
const mp_bytecode_prelude_t *prelude = &rc->prelude;
|
||||
mp_printf(print,
|
||||
"<code object %q at 0x%p, file \"%q\", line %d>",
|
||||
prelude->qstr_block_name,
|
||||
QSTR_MAP(o->context, prelude->qstr_block_name_idx),
|
||||
o,
|
||||
prelude->qstr_source_file,
|
||||
QSTR_MAP(o->context, 0),
|
||||
rc->line_of_definition
|
||||
);
|
||||
}
|
||||
|
||||
STATIC mp_obj_tuple_t *code_consts(const mp_raw_code_t *rc) {
|
||||
const mp_bytecode_prelude_t *prelude = &rc->prelude;
|
||||
int start = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj;
|
||||
int stop = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj + rc->n_raw_code;
|
||||
mp_obj_tuple_t *consts = MP_OBJ_TO_PTR(mp_obj_new_tuple(stop - start + 1, NULL));
|
||||
STATIC mp_obj_tuple_t *code_consts(const mp_module_context_t *context, const mp_raw_code_t *rc) {
|
||||
mp_obj_tuple_t *consts = MP_OBJ_TO_PTR(mp_obj_new_tuple(rc->n_children + 1, NULL));
|
||||
|
||||
size_t const_no = 0;
|
||||
for (int i = start; i < stop; ++i) {
|
||||
mp_obj_t code = mp_obj_new_code((const mp_raw_code_t *)MP_OBJ_TO_PTR(rc->const_table[i]));
|
||||
for (size_t i = 0; i < rc->n_children; ++i) {
|
||||
mp_obj_t code = mp_obj_new_code(context, rc->children[i]);
|
||||
if (code == MP_OBJ_NULL) {
|
||||
m_malloc_fail(sizeof(mp_obj_code_t));
|
||||
}
|
||||
@ -149,16 +149,16 @@ STATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
);
|
||||
break;
|
||||
case MP_QSTR_co_consts:
|
||||
dest[0] = MP_OBJ_FROM_PTR(code_consts(rc));
|
||||
dest[0] = MP_OBJ_FROM_PTR(code_consts(o->context, rc));
|
||||
break;
|
||||
case MP_QSTR_co_filename:
|
||||
dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_source_file);
|
||||
dest[0] = MP_OBJ_NEW_QSTR(QSTR_MAP(o->context, 0));
|
||||
break;
|
||||
case MP_QSTR_co_firstlineno:
|
||||
dest[0] = MP_OBJ_NEW_SMALL_INT(mp_prof_bytecode_lineno(rc, 0));
|
||||
break;
|
||||
case MP_QSTR_co_name:
|
||||
dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_block_name);
|
||||
dest[0] = MP_OBJ_NEW_QSTR(QSTR_MAP(o->context, prelude->qstr_block_name_idx));
|
||||
break;
|
||||
case MP_QSTR_co_names:
|
||||
dest[0] = MP_OBJ_FROM_PTR(o->dict_locals);
|
||||
@ -180,12 +180,13 @@ const mp_obj_type_t mp_type_settrace_codeobj = {
|
||||
.attr = code_attr,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_code(const mp_raw_code_t *rc) {
|
||||
mp_obj_t mp_obj_new_code(const mp_module_context_t *context, const mp_raw_code_t *rc) {
|
||||
mp_obj_code_t *o = m_new_obj_maybe(mp_obj_code_t);
|
||||
if (o == NULL) {
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
o->base.type = &mp_type_settrace_codeobj;
|
||||
o->context = context;
|
||||
o->rc = rc;
|
||||
o->dict_locals = mp_locals_get(); // this is a wrong! how to do this properly?
|
||||
o->lnotab = MP_OBJ_NULL;
|
||||
@ -204,9 +205,9 @@ STATIC void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t
|
||||
mp_printf(print,
|
||||
"<frame at 0x%p, file '%q', line %d, code %q>",
|
||||
frame,
|
||||
prelude->qstr_source_file,
|
||||
QSTR_MAP(code->context, 0),
|
||||
frame->lineno,
|
||||
prelude->qstr_block_name
|
||||
QSTR_MAP(code->context, prelude->qstr_block_name_idx)
|
||||
);
|
||||
}
|
||||
|
||||
@ -229,7 +230,7 @@ STATIC void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(o->code);
|
||||
break;
|
||||
case MP_QSTR_f_globals:
|
||||
dest[0] = MP_OBJ_FROM_PTR(o->code_state->fun_bc->globals);
|
||||
dest[0] = MP_OBJ_FROM_PTR(o->code_state->fun_bc->context->module.globals);
|
||||
break;
|
||||
case MP_QSTR_f_lasti:
|
||||
dest[0] = MP_OBJ_NEW_SMALL_INT(o->lasti);
|
||||
@ -258,7 +259,7 @@ mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state) {
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
mp_obj_code_t *code = o->code = MP_OBJ_TO_PTR(mp_obj_new_code(code_state->fun_bc->rc));
|
||||
mp_obj_code_t *code = o->code = MP_OBJ_TO_PTR(mp_obj_new_code(code_state->fun_bc->context, code_state->fun_bc->rc));
|
||||
if (code == NULL) {
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
@ -34,7 +34,9 @@
|
||||
#define mp_prof_is_executing MP_STATE_THREAD(prof_callback_is_executing)
|
||||
|
||||
typedef struct _mp_obj_code_t {
|
||||
// TODO this was 4 words
|
||||
mp_obj_base_t base;
|
||||
const mp_module_context_t *context;
|
||||
const mp_raw_code_t *rc;
|
||||
mp_obj_dict_t *dict_locals;
|
||||
mp_obj_t lnotab;
|
||||
@ -53,7 +55,7 @@ typedef struct _mp_obj_frame_t {
|
||||
|
||||
void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude);
|
||||
|
||||
mp_obj_t mp_obj_new_code(const mp_raw_code_t *rc);
|
||||
mp_obj_t mp_obj_new_code(const mp_module_context_t *mc, const mp_raw_code_t *rc);
|
||||
mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state);
|
||||
|
||||
// This is the implementation for the sys.settrace
|
||||
|
@ -46,6 +46,7 @@ enum {
|
||||
};
|
||||
|
||||
typedef size_t qstr;
|
||||
typedef uint16_t qstr_short_t;
|
||||
|
||||
#if MICROPY_QSTR_BYTES_IN_HASH == 1
|
||||
typedef uint8_t qstr_hash_t;
|
||||
|
@ -40,7 +40,7 @@ STATIC const uint8_t scope_simple_name_table[] = {
|
||||
[SCOPE_GEN_EXPR] = MP_QSTR__lt_genexpr_gt_,
|
||||
};
|
||||
|
||||
scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options) {
|
||||
scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, mp_uint_t emit_options) {
|
||||
// Make sure those qstrs indeed fit in an uint8_t.
|
||||
MP_STATIC_ASSERT(MP_QSTR__lt_module_gt_ <= UINT8_MAX);
|
||||
MP_STATIC_ASSERT(MP_QSTR__lt_lambda_gt_ <= UINT8_MAX);
|
||||
@ -52,7 +52,6 @@ scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_u
|
||||
scope_t *scope = m_new0(scope_t, 1);
|
||||
scope->kind = kind;
|
||||
scope->pn = pn;
|
||||
scope->source_file = source_file;
|
||||
if (kind == SCOPE_FUNCTION || kind == SCOPE_CLASS) {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT(pn));
|
||||
scope->simple_name = MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)pn)->nodes[0]);
|
||||
|
@ -75,7 +75,6 @@ typedef struct _scope_t {
|
||||
struct _scope_t *next;
|
||||
mp_parse_node_t pn;
|
||||
mp_raw_code_t *raw_code;
|
||||
uint16_t source_file; // a qstr
|
||||
uint16_t simple_name; // a qstr
|
||||
uint16_t scope_flags; // see runtime0.h
|
||||
uint16_t emit_options; // see emitglue.h
|
||||
@ -90,7 +89,7 @@ typedef struct _scope_t {
|
||||
id_info_t *id_info;
|
||||
} scope_t;
|
||||
|
||||
scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options);
|
||||
scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, mp_uint_t emit_options);
|
||||
void scope_free(scope_t *scope);
|
||||
id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, id_info_kind_t kind);
|
||||
id_info_t *scope_find(scope_t *scope, qstr qstr);
|
||||
|
73
py/showbc.c
73
py/showbc.c
@ -41,43 +41,32 @@
|
||||
#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)
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
|
||||
#define DECODE_QSTR \
|
||||
qst = ip[0] | ip[1] << 8; \
|
||||
ip += 2;
|
||||
#define DECODE_PTR \
|
||||
DECODE_UINT; \
|
||||
unum = mp_showbc_const_table[unum]
|
||||
#define DECODE_OBJ \
|
||||
DECODE_UINT; \
|
||||
unum = mp_showbc_const_table[unum]
|
||||
qst = mp_showbc_constants->qstr_table[unum]
|
||||
|
||||
#else
|
||||
|
||||
#define DECODE_QSTR { \
|
||||
qst = 0; \
|
||||
do { \
|
||||
qst = (qst << 7) + (*ip & 0x7f); \
|
||||
} while ((*ip++ & 0x80) != 0); \
|
||||
}
|
||||
#define DECODE_PTR do { \
|
||||
ip = (byte *)MP_ALIGN(ip, sizeof(void *)); \
|
||||
unum = (uintptr_t)*(void **)ip; \
|
||||
ip += sizeof(void *); \
|
||||
} while (0)
|
||||
#define DECODE_OBJ do { \
|
||||
ip = (byte *)MP_ALIGN(ip, sizeof(mp_obj_t)); \
|
||||
unum = (mp_uint_t)*(mp_obj_t *)ip; \
|
||||
ip += sizeof(mp_obj_t); \
|
||||
} while (0)
|
||||
#define DECODE_QSTR \
|
||||
DECODE_UINT; \
|
||||
qst = unum;
|
||||
|
||||
#endif
|
||||
|
||||
const byte *mp_showbc_code_start;
|
||||
const mp_uint_t *mp_showbc_const_table;
|
||||
#define DECODE_PTR \
|
||||
DECODE_UINT;
|
||||
|
||||
void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *ip, mp_uint_t len, const mp_uint_t *const_table) {
|
||||
#define DECODE_OBJ \
|
||||
DECODE_UINT; \
|
||||
unum = (mp_uint_t)mp_showbc_constants->obj_table[unum]
|
||||
|
||||
const byte * mp_showbc_code_start;
|
||||
const mp_module_constants_t *mp_showbc_constants;
|
||||
|
||||
#include "py/emitglue.h"
|
||||
void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *ip, mp_uint_t len, const mp_module_constants_t *cm) {
|
||||
mp_showbc_code_start = ip;
|
||||
|
||||
// Decode prelude
|
||||
@ -85,16 +74,15 @@ void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *i
|
||||
MP_BC_PRELUDE_SIZE_DECODE(ip);
|
||||
const byte *code_info = ip;
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
qstr block_name = code_info[0] | (code_info[1] << 8);
|
||||
qstr source_file = code_info[2] | (code_info[3] << 8);
|
||||
code_info += 4;
|
||||
#else
|
||||
qstr block_name = mp_decode_uint(&code_info);
|
||||
qstr source_file = mp_decode_uint(&code_info);
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
block_name = cm->qstr_table[block_name];
|
||||
qstr source_file = cm->qstr_table[0];
|
||||
#else
|
||||
qstr source_file = cm->source_file;
|
||||
#endif
|
||||
mp_printf(print, "File %s, code block '%s' (descriptor: %p, bytecode @%p " UINT_FMT " bytes)\n",
|
||||
qstr_str(source_file), qstr_str(block_name), descr, mp_showbc_code_start, len);
|
||||
mp_printf(print, "File %s, code block '%s' (descriptor: %p, bytecode @%p " UINT_FMT " bytes)\n",// rct=%p\n",
|
||||
qstr_str(source_file), qstr_str(block_name), descr, mp_showbc_code_start, len);// , ((mp_raw_code_t*)descr)->children);
|
||||
|
||||
// raw bytecode dump
|
||||
size_t prelude_size = ip - mp_showbc_code_start + n_info + n_cell;
|
||||
@ -111,7 +99,11 @@ void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *i
|
||||
// bytecode prelude: arg names (as qstr objects)
|
||||
mp_printf(print, "arg names:");
|
||||
for (mp_uint_t i = 0; i < n_pos_args + n_kwonly_args; i++) {
|
||||
mp_printf(print, " %s", qstr_str(MP_OBJ_QSTR_VALUE(const_table[i])));
|
||||
qstr qst = mp_decode_uint(&code_info);
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
qst = cm->qstr_table[qst];
|
||||
#endif
|
||||
mp_printf(print, " %s", qstr_str(qst));
|
||||
}
|
||||
mp_printf(print, "\n");
|
||||
|
||||
@ -120,6 +112,7 @@ void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *i
|
||||
|
||||
// skip over code_info
|
||||
ip += n_info;
|
||||
const byte *line_info_top = ip;
|
||||
|
||||
// bytecode prelude: initialise closed over variables
|
||||
for (size_t i = 0; i < n_cell; ++i) {
|
||||
@ -132,7 +125,7 @@ void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *i
|
||||
mp_int_t bc = 0;
|
||||
mp_uint_t source_line = 1;
|
||||
mp_printf(print, " bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line);
|
||||
for (const byte *ci = code_info; *ci;) {
|
||||
for (const byte *ci = code_info; ci < line_info_top;) {
|
||||
if ((ci[0] & 0x80) == 0) {
|
||||
// 0b0LLBBBBB encoding
|
||||
bc += ci[0] & 0x1f;
|
||||
@ -147,7 +140,7 @@ void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *i
|
||||
mp_printf(print, " bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line);
|
||||
}
|
||||
}
|
||||
mp_bytecode_print2(print, ip, len - prelude_size, const_table);
|
||||
mp_bytecode_print2(print, ip, len - prelude_size, cm);
|
||||
}
|
||||
|
||||
const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
|
||||
@ -535,9 +528,9 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
|
||||
return ip;
|
||||
}
|
||||
|
||||
void mp_bytecode_print2(const mp_print_t *print, const byte *ip, size_t len, const mp_uint_t *const_table) {
|
||||
void mp_bytecode_print2(const mp_print_t *print, const byte *ip, size_t len, const mp_module_constants_t *cm) {
|
||||
mp_showbc_code_start = ip;
|
||||
mp_showbc_const_table = const_table;
|
||||
mp_showbc_constants = cm;
|
||||
while (ip < len + mp_showbc_code_start) {
|
||||
mp_printf(print, "%02u ", (uint)(ip - mp_showbc_code_start));
|
||||
ip = mp_bytecode_print_str(print, ip);
|
||||
|
73
py/vm.c
73
py/vm.c
@ -31,9 +31,9 @@
|
||||
|
||||
#include "py/emitglue.h"
|
||||
#include "py/objtype.h"
|
||||
#include "py/objfun.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/bc0.h"
|
||||
#include "py/bc.h"
|
||||
#include "py/profile.h"
|
||||
|
||||
// *FORMAT-OFF*
|
||||
@ -44,7 +44,7 @@
|
||||
#else
|
||||
#define TRACE_PREFIX mp_printf(&mp_plat_print, "sp=%d ", (int)(sp - &code_state->state[0] + 1))
|
||||
#endif
|
||||
#define TRACE(ip) TRACE_PREFIX; mp_bytecode_print2(&mp_plat_print, ip, 1, code_state->fun_bc->const_table);
|
||||
#define TRACE(ip) TRACE_PREFIX; mp_bytecode_print2(&mp_plat_print, ip, 1, &code_state->fun_bc->context->constants);
|
||||
#else
|
||||
#define TRACE(ip)
|
||||
#endif
|
||||
@ -64,35 +64,28 @@
|
||||
#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
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
|
||||
#define DECODE_QSTR \
|
||||
qstr qst = ip[0] | ip[1] << 8; \
|
||||
ip += 2;
|
||||
#define DECODE_PTR \
|
||||
DECODE_UINT; \
|
||||
void *ptr = (void*)(uintptr_t)code_state->fun_bc->const_table[unum]
|
||||
#define DECODE_OBJ \
|
||||
DECODE_UINT; \
|
||||
mp_obj_t obj = (mp_obj_t)code_state->fun_bc->const_table[unum]
|
||||
qstr qst = qstr_table[unum]
|
||||
|
||||
#else
|
||||
|
||||
#define DECODE_QSTR qstr qst = 0; \
|
||||
do { \
|
||||
qst = (qst << 7) + (*ip & 0x7f); \
|
||||
} while ((*ip++ & 0x80) != 0)
|
||||
#define DECODE_PTR \
|
||||
ip = (byte*)MP_ALIGN(ip, sizeof(void*)); \
|
||||
void *ptr = *(void**)ip; \
|
||||
ip += sizeof(void*)
|
||||
#define DECODE_OBJ \
|
||||
ip = (byte*)MP_ALIGN(ip, sizeof(mp_obj_t)); \
|
||||
mp_obj_t obj = *(mp_obj_t*)ip; \
|
||||
ip += sizeof(mp_obj_t)
|
||||
#define DECODE_QSTR \
|
||||
DECODE_UINT; \
|
||||
qstr qst = unum;
|
||||
|
||||
#endif
|
||||
|
||||
#define DECODE_PTR \
|
||||
DECODE_UINT; \
|
||||
void *ptr = (void *)(uintptr_t)code_state->fun_bc->child_table[unum]
|
||||
|
||||
#define DECODE_OBJ \
|
||||
DECODE_UINT; \
|
||||
mp_obj_t obj = (mp_obj_t)code_state->fun_bc->context->constants.obj_table[unum]
|
||||
|
||||
#define PUSH(val) *++sp = (val)
|
||||
#define POP() (*sp--)
|
||||
#define TOP() (*sp)
|
||||
@ -255,6 +248,9 @@ outer_dispatch_loop:
|
||||
// local variables that are not visible to the exception handler
|
||||
const byte *ip = code_state->ip;
|
||||
mp_obj_t *sp = code_state->sp;
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
const qstr_short_t *qstr_table = code_state->fun_bc->context->constants.qstr_table;
|
||||
#endif
|
||||
mp_obj_t obj_shared;
|
||||
MICROPY_VM_HOOK_INIT
|
||||
|
||||
@ -859,15 +855,15 @@ unwind_jump:;
|
||||
|
||||
ENTRY(MP_BC_MAKE_FUNCTION): {
|
||||
DECODE_PTR;
|
||||
PUSH(mp_make_function_from_raw_code(ptr, MP_OBJ_NULL, MP_OBJ_NULL));
|
||||
PUSH(mp_make_function_from_raw_code(ptr, code_state->fun_bc->context, NULL));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS): {
|
||||
DECODE_PTR;
|
||||
// Stack layout: def_tuple def_dict <- TOS
|
||||
mp_obj_t def_dict = POP();
|
||||
SET_TOP(mp_make_function_from_raw_code(ptr, TOP(), def_dict));
|
||||
sp -= 1;
|
||||
SET_TOP(mp_make_function_from_raw_code(ptr, code_state->fun_bc->context, sp));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@ -876,7 +872,7 @@ unwind_jump:;
|
||||
size_t n_closed_over = *ip++;
|
||||
// Stack layout: closed_overs <- TOS
|
||||
sp -= n_closed_over - 1;
|
||||
SET_TOP(mp_make_closure_from_raw_code(ptr, n_closed_over, sp));
|
||||
SET_TOP(mp_make_closure_from_raw_code(ptr, code_state->fun_bc->context, n_closed_over, sp));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@ -885,7 +881,7 @@ unwind_jump:;
|
||||
size_t n_closed_over = *ip++;
|
||||
// Stack layout: def_tuple def_dict closed_overs <- TOS
|
||||
sp -= 2 + n_closed_over - 1;
|
||||
SET_TOP(mp_make_closure_from_raw_code(ptr, 0x100 | n_closed_over, sp));
|
||||
SET_TOP(mp_make_closure_from_raw_code(ptr, code_state->fun_bc->context, 0x100 | n_closed_over, sp));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@ -1384,23 +1380,20 @@ unwind_loop:
|
||||
const byte *ip = code_state->fun_bc->bytecode;
|
||||
MP_BC_PRELUDE_SIG_DECODE(ip);
|
||||
MP_BC_PRELUDE_SIZE_DECODE(ip);
|
||||
const byte *line_info_top = ip + n_info;
|
||||
const byte *bytecode_start = ip + n_info + n_cell;
|
||||
#if !MICROPY_PERSISTENT_CODE
|
||||
// so bytecode is aligned
|
||||
bytecode_start = MP_ALIGN(bytecode_start, sizeof(mp_uint_t));
|
||||
#endif
|
||||
size_t bc = code_state->ip - bytecode_start;
|
||||
#if MICROPY_PERSISTENT_CODE
|
||||
qstr block_name = ip[0] | (ip[1] << 8);
|
||||
qstr source_file = ip[2] | (ip[3] << 8);
|
||||
ip += 4;
|
||||
#else
|
||||
qstr block_name = mp_decode_uint_value(ip);
|
||||
ip = mp_decode_uint_skip(ip);
|
||||
qstr source_file = mp_decode_uint_value(ip);
|
||||
ip = mp_decode_uint_skip(ip);
|
||||
for (size_t i = 0; i < 1 + n_pos_args + n_kwonly_args; ++i) {
|
||||
ip = mp_decode_uint_skip(ip);
|
||||
}
|
||||
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
|
||||
block_name = code_state->fun_bc->context->constants.qstr_table[block_name];
|
||||
qstr source_file = code_state->fun_bc->context->constants.qstr_table[0];
|
||||
#else
|
||||
qstr source_file = code_state->fun_bc->context->constants.source_file;
|
||||
#endif
|
||||
size_t source_line = mp_bytecode_get_source_line(ip, bc);
|
||||
size_t source_line = mp_bytecode_get_source_line(ip, line_info_top, bc);
|
||||
mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name);
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,11 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) {
|
||||
// source is a raw_code object, create the function
|
||||
module_fun = mp_make_function_from_raw_code(source, MP_OBJ_NULL, MP_OBJ_NULL);
|
||||
const mp_frozen_module_t *frozen = source;
|
||||
mp_module_context_t *ctx = m_new_obj(mp_module_context_t);
|
||||
ctx->module.globals = mp_globals_get();
|
||||
ctx->constants = frozen->constants;
|
||||
module_fun = mp_make_function_from_raw_code(frozen->rc, ctx, NULL);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
@ -39,50 +39,52 @@
|
||||
[ 13] \(rule\|arglist\)(164) (n=1)
|
||||
id(b)
|
||||
----------------
|
||||
File cmdline/cmd_parsetree.py, code block '<module>' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
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
|
||||
arg names:
|
||||
(N_STATE 5)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
bc=0 line=4
|
||||
bc=9 line=5
|
||||
bc=12 line=6
|
||||
bc=16 line=7
|
||||
bc=22 line=8
|
||||
bc=27 line=9
|
||||
bc=32 line=10
|
||||
bc=37 line=11
|
||||
bc=42 line=12
|
||||
bc=48 line=13
|
||||
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
|
||||
00 BUILD_TUPLE 0
|
||||
02 GET_ITER_STACK
|
||||
03 FOR_ITER 12
|
||||
03 FOR_ITER 11
|
||||
06 STORE_NAME i
|
||||
09 JUMP 3
|
||||
12 LOAD_CONST_NONE
|
||||
13 STORE_NAME a
|
||||
16 LOAD_CONST_STRING 'str'
|
||||
19 STORE_NAME b
|
||||
22 LOAD_CONST_OBJ \.\+
|
||||
24 STORE_NAME c
|
||||
27 LOAD_CONST_OBJ \.\+
|
||||
29 STORE_NAME d
|
||||
32 LOAD_CONST_OBJ \.\+
|
||||
34 STORE_NAME e
|
||||
37 LOAD_CONST_OBJ \.\+
|
||||
39 STORE_NAME f
|
||||
42 LOAD_CONST_SMALL_INT 123
|
||||
45 STORE_NAME g
|
||||
48 LOAD_CONST_OBJ \.\+
|
||||
50 LOAD_METHOD format
|
||||
53 LOAD_NAME b
|
||||
56 CALL_METHOD n=1 nkw=0
|
||||
58 STORE_NAME h
|
||||
61 LOAD_CONST_NONE
|
||||
62 RETURN_VALUE
|
||||
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
|
||||
mem: total=\\d\+, current=\\d\+, peak=\\d\+
|
||||
stack: \\d\+ out of \\d\+
|
||||
GC: total: \\d\+, used: \\d\+, free: \\d\+
|
||||
|
@ -1,51 +1,144 @@
|
||||
File cmdline/cmd_showbc.py, code block '<module>' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
File cmdline/cmd_showbc.py, code block '<module>' (descriptor: \.\+, bytecode @\.\+ 63 bytes)
|
||||
Raw bytecode (code_info_size=18, bytecode_size=45):
|
||||
10 20 01 60 20 84 7d 64 60 88 07 64 60 69 20 62
|
||||
64 20 32 00 16 02 32 01 16 02 81 2a 01 53 33 02
|
||||
16 02 32 03 16 02 54 32 04 10 03 34 02 16 03 19
|
||||
03 32 05 16 02 80 10 04 2a 01 1b 05 69 51 63
|
||||
arg names:
|
||||
(N_STATE 3)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=\\d\+ line=160
|
||||
bc=0 line=4
|
||||
bc=0 line=5
|
||||
bc=4 line=130
|
||||
bc=8 line=133
|
||||
bc=8 line=136
|
||||
bc=16 line=143
|
||||
bc=20 line=146
|
||||
bc=20 line=149
|
||||
bc=29 line=152
|
||||
bc=29 line=153
|
||||
bc=31 line=156
|
||||
bc=35 line=159
|
||||
bc=35 line=160
|
||||
00 MAKE_FUNCTION \.\+
|
||||
\\d\+ STORE_NAME f
|
||||
\\d\+ MAKE_FUNCTION \.\+
|
||||
\\d\+ STORE_NAME f
|
||||
\\d\+ LOAD_CONST_SMALL_INT 1
|
||||
\\d\+ BUILD_TUPLE 1
|
||||
\\d\+ LOAD_NULL
|
||||
\\d\+ MAKE_FUNCTION_DEFARGS \.\+
|
||||
\\d\+ STORE_NAME f
|
||||
\\d\+ MAKE_FUNCTION \.\+
|
||||
\\d\+ STORE_NAME f
|
||||
\\d\+ LOAD_BUILD_CLASS
|
||||
\\d\+ MAKE_FUNCTION \.\+
|
||||
\\d\+ LOAD_CONST_STRING 'Class'
|
||||
\\d\+ CALL_FUNCTION n=2 nkw=0
|
||||
\\d\+ STORE_NAME Class
|
||||
\\d\+ DELETE_NAME Class
|
||||
\\d\+ MAKE_FUNCTION \.\+
|
||||
\\d\+ STORE_NAME f
|
||||
\\d\+ LOAD_CONST_SMALL_INT 0
|
||||
\\d\+ LOAD_CONST_STRING '*'
|
||||
\\d\+ BUILD_TUPLE 1
|
||||
\\d\+ IMPORT_NAME 'sys'
|
||||
\\d\+ IMPORT_STAR
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
02 STORE_NAME f
|
||||
04 MAKE_FUNCTION \.\+
|
||||
06 STORE_NAME f
|
||||
08 LOAD_CONST_SMALL_INT 1
|
||||
09 BUILD_TUPLE 1
|
||||
11 LOAD_NULL
|
||||
12 MAKE_FUNCTION_DEFARGS \.\+
|
||||
14 STORE_NAME f
|
||||
16 MAKE_FUNCTION \.\+
|
||||
18 STORE_NAME f
|
||||
20 LOAD_BUILD_CLASS
|
||||
21 MAKE_FUNCTION \.\+
|
||||
23 LOAD_CONST_STRING 'Class'
|
||||
25 CALL_FUNCTION n=2 nkw=0
|
||||
27 STORE_NAME Class
|
||||
29 DELETE_NAME Class
|
||||
31 MAKE_FUNCTION \.\+
|
||||
33 STORE_NAME f
|
||||
35 LOAD_CONST_SMALL_INT 0
|
||||
36 LOAD_CONST_STRING '*'
|
||||
38 BUILD_TUPLE 1
|
||||
40 IMPORT_NAME 'sys'
|
||||
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):
|
||||
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 65 27 6a 62 20 23 62 2a 29 69 24 25 28 67 26
|
||||
########
|
||||
\.\+rg names:
|
||||
\.\+81 63
|
||||
arg names:
|
||||
(N_STATE 22)
|
||||
(N_EXC_STACK 2)
|
||||
(INIT_CELL 14)
|
||||
(INIT_CELL 15)
|
||||
(INIT_CELL 16)
|
||||
bc=0 line=1
|
||||
bc=0 line=4
|
||||
bc=0 line=7
|
||||
bc=6 line=8
|
||||
bc=8 line=9
|
||||
bc=12 line=10
|
||||
bc=16 line=13
|
||||
bc=18 line=14
|
||||
bc=24 line=15
|
||||
bc=29 line=16
|
||||
bc=34 line=17
|
||||
bc=38 line=18
|
||||
bc=44 line=19
|
||||
bc=47 line=20
|
||||
bc=50 line=23
|
||||
bc=52 line=24
|
||||
bc=54 line=25
|
||||
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=\\d\+ line=127
|
||||
bc=321 line=96
|
||||
bc=329 line=98
|
||||
bc=332 line=99
|
||||
bc=335 line=100
|
||||
bc=338 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
|
||||
00 LOAD_CONST_NONE
|
||||
01 LOAD_CONST_FALSE
|
||||
02 BINARY_OP 27 __add__
|
||||
@ -80,247 +173,251 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
42 STORE_MAP
|
||||
43 STORE_FAST 3
|
||||
44 LOAD_CONST_STRING 'a'
|
||||
47 STORE_FAST 4
|
||||
48 LOAD_CONST_OBJ \.\+
|
||||
\\d\+ STORE_FAST 5
|
||||
\\d\+ LOAD_CONST_SMALL_INT 1
|
||||
\\d\+ STORE_FAST 6
|
||||
\\d\+ LOAD_CONST_SMALL_INT 2
|
||||
\\d\+ STORE_FAST 7
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_DEREF 14
|
||||
58 BINARY_OP 27 __add__
|
||||
\\d\+ STORE_FAST 8
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ UNARY_OP 1 __neg__
|
||||
\\d\+ STORE_FAST 9
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ UNARY_OP 3
|
||||
\\d\+ STORE_FAST 10
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ DUP_TOP
|
||||
\\d\+ ROT_THREE
|
||||
\\d\+ BINARY_OP 2 __eq__
|
||||
\\d\+ JUMP_IF_FALSE_OR_POP \\d\+
|
||||
\\d\+ LOAD_FAST 1
|
||||
\\d\+ BINARY_OP 2 __eq__
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ ROT_TWO
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ STORE_FAST 10
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ BINARY_OP 2 __eq__
|
||||
\\d\+ JUMP_IF_FALSE_OR_POP \\d\+
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_FAST 1
|
||||
\\d\+ BINARY_OP 2 __eq__
|
||||
\\d\+ UNARY_OP 3
|
||||
\\d\+ STORE_FAST 10
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_ATTR c
|
||||
\\d\+ STORE_FAST 11
|
||||
\\d\+ LOAD_FAST 11
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ STORE_ATTR c
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_CONST_SMALL_INT 0
|
||||
\\d\+ LOAD_SUBSCR
|
||||
\\d\+ STORE_FAST 12
|
||||
\\d\+ LOAD_FAST 12
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_CONST_SMALL_INT 0
|
||||
\\d\+ STORE_SUBSCR
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_CONST_SMALL_INT 0
|
||||
\\d\+ DUP_TOP_TWO
|
||||
\\d\+ LOAD_SUBSCR
|
||||
\\d\+ LOAD_FAST 12
|
||||
\\d\+ BINARY_OP 14 __iadd__
|
||||
\\d\+ ROT_THREE
|
||||
\\d\+ STORE_SUBSCR
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ BUILD_SLICE 2
|
||||
\\d\+ LOAD_SUBSCR
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ LOAD_FAST 1
|
||||
\\d\+ UNPACK_SEQUENCE 2
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ STORE_DEREF 14
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ UNPACK_EX 1
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ ROT_TWO
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ STORE_DEREF 14
|
||||
\\d\+ LOAD_FAST 1
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ ROT_THREE
|
||||
\\d\+ ROT_TWO
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ STORE_DEREF 14
|
||||
\\d\+ STORE_FAST 1
|
||||
\\d\+ DELETE_FAST 0
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ STORE_GLOBAL gl
|
||||
\\d\+ DELETE_GLOBAL gl
|
||||
\\d\+ LOAD_FAST 14
|
||||
\\d\+ LOAD_FAST 15
|
||||
\\d\+ MAKE_CLOSURE \.\+ 2
|
||||
\\d\+ LOAD_FAST 2
|
||||
\\d\+ GET_ITER
|
||||
\\d\+ CALL_FUNCTION n=1 nkw=0
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ LOAD_FAST 14
|
||||
\\d\+ LOAD_FAST 15
|
||||
\\d\+ MAKE_CLOSURE \.\+ 2
|
||||
\\d\+ LOAD_FAST 2
|
||||
\\d\+ CALL_FUNCTION n=1 nkw=0
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ LOAD_FAST 14
|
||||
\\d\+ LOAD_FAST 15
|
||||
\\d\+ MAKE_CLOSURE \.\+ 2
|
||||
\\d\+ LOAD_FAST 2
|
||||
\\d\+ CALL_FUNCTION n=1 nkw=0
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ CALL_FUNCTION n=0 nkw=0
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_CONST_SMALL_INT 1
|
||||
\\d\+ CALL_FUNCTION n=1 nkw=0
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_CONST_STRING 'b'
|
||||
\\d\+ LOAD_CONST_SMALL_INT 1
|
||||
\\d\+ CALL_FUNCTION n=0 nkw=1
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_NULL
|
||||
\\d\+ CALL_FUNCTION_VAR_KW n=0 nkw=0
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_METHOD b
|
||||
\\d\+ CALL_METHOD n=0 nkw=0
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_METHOD b
|
||||
\\d\+ LOAD_CONST_SMALL_INT 1
|
||||
\\d\+ CALL_METHOD n=1 nkw=0
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_METHOD b
|
||||
\\d\+ LOAD_CONST_STRING 'c'
|
||||
\\d\+ LOAD_CONST_SMALL_INT 1
|
||||
\\d\+ CALL_METHOD n=0 nkw=1
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_METHOD b
|
||||
\\d\+ LOAD_FAST 1
|
||||
\\d\+ LOAD_NULL
|
||||
\\d\+ CALL_METHOD_VAR_KW n=0 nkw=0
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ POP_JUMP_IF_FALSE \\d\+
|
||||
\\d\+ LOAD_DEREF 16
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ LOAD_GLOBAL y
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ POP_JUMP_IF_TRUE \\d\+
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ POP_JUMP_IF_FALSE \\d\+
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ JUMP_IF_TRUE_OR_POP \\d\+
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ GET_ITER_STACK
|
||||
\\d\+ FOR_ITER \\d\+
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ LOAD_FAST 1
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ SETUP_FINALLY \\d\+
|
||||
\\d\+ SETUP_EXCEPT \\d\+
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ POP_JUMP_IF_TRUE \\d\+
|
||||
\\d\+ POP_EXCEPT_JUMP \\d\+
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ POP_EXCEPT_JUMP \\d\+
|
||||
\\d\+ END_FINALLY
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ LOAD_FAST 1
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ END_FINALLY
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ SETUP_EXCEPT \\d\+
|
||||
\\d\+ UNWIND_JUMP \\d\+ 1
|
||||
\\d\+ POP_EXCEPT_JUMP \\d\+
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ POP_EXCEPT_JUMP \\d\+
|
||||
\\d\+ END_FINALLY
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ POP_JUMP_IF_TRUE \\d\+
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ SETUP_WITH \\d\+
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ WITH_CLEANUP
|
||||
\\d\+ END_FINALLY
|
||||
\\d\+ LOAD_CONST_SMALL_INT 1
|
||||
\\d\+ STORE_DEREF 16
|
||||
\\d\+ LOAD_FAST_N 16
|
||||
\\d\+ MAKE_CLOSURE \.\+ 1
|
||||
\\d\+ STORE_FAST 13
|
||||
\\d\+ LOAD_CONST_SMALL_INT 0
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ IMPORT_NAME 'a'
|
||||
\\d\+ STORE_FAST 0
|
||||
\\d\+ LOAD_CONST_SMALL_INT 0
|
||||
\\d\+ LOAD_CONST_STRING 'b'
|
||||
\\d\+ BUILD_TUPLE 1
|
||||
\\d\+ IMPORT_NAME 'a'
|
||||
\\d\+ IMPORT_FROM 'b'
|
||||
\\d\+ STORE_DEREF 14
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ RAISE_LAST
|
||||
\\d\+ LOAD_CONST_SMALL_INT 1
|
||||
\\d\+ RAISE_OBJ
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ RETURN_VALUE
|
||||
\\d\+ LOAD_CONST_SMALL_INT 1
|
||||
\\d\+ RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+rg names:
|
||||
46 STORE_FAST 4
|
||||
47 LOAD_CONST_OBJ \.\+=b'a'
|
||||
49 STORE_FAST 5
|
||||
50 LOAD_CONST_SMALL_INT 1
|
||||
51 STORE_FAST 6
|
||||
52 LOAD_CONST_SMALL_INT 2
|
||||
53 STORE_FAST 7
|
||||
54 LOAD_FAST 0
|
||||
55 LOAD_DEREF 14
|
||||
57 BINARY_OP 27 __add__
|
||||
58 STORE_FAST 8
|
||||
59 LOAD_FAST 0
|
||||
60 UNARY_OP 1 __neg__
|
||||
61 STORE_FAST 9
|
||||
62 LOAD_FAST 0
|
||||
63 UNARY_OP 3
|
||||
64 STORE_FAST 10
|
||||
65 LOAD_FAST 0
|
||||
66 LOAD_DEREF 14
|
||||
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
|
||||
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
|
||||
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
|
||||
c3 57 c4 57 c5 57 c6 57 c7 57 c8 c9 82 57 ca 57
|
||||
cb 57 cc 57 cd 57 ce 57 cf 57 26 10 57 26 11 57
|
||||
26 12 26 13 b9 24 13 f2 59 51 63
|
||||
arg names:
|
||||
(N_STATE 22)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=\\d\+ line=133
|
||||
bc=0 line=131
|
||||
bc=20 line=132
|
||||
bc=44 line=133
|
||||
00 LOAD_CONST_SMALL_INT 1
|
||||
01 DUP_TOP
|
||||
02 STORE_FAST 0
|
||||
@ -367,28 +464,29 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
48 POP_TOP
|
||||
49 LOAD_CONST_NONE
|
||||
50 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 20 bytes)
|
||||
Raw bytecode (code_info_size=9, bytecode_size=11):
|
||||
a1 01 0b 02 06 80 88 40 00 82 2a 01 53 b0 21 00
|
||||
01 c1 51 63
|
||||
arg names: a
|
||||
(N_STATE 5)
|
||||
(N_EXC_STACK 0)
|
||||
(INIT_CELL 0)
|
||||
########
|
||||
bc=\\d\+ line=139
|
||||
bc=0 line=1
|
||||
bc=0 line=137
|
||||
bc=0 line=139
|
||||
00 LOAD_CONST_SMALL_INT 2
|
||||
01 BUILD_TUPLE 1
|
||||
03 LOAD_NULL
|
||||
04 LOAD_FAST 0
|
||||
05 MAKE_CLOSURE_DEFARGS \.\+ 1
|
||||
\\d\+ STORE_FAST 1
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
08 STORE_FAST 1
|
||||
09 LOAD_CONST_NONE
|
||||
10 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 21 bytes)
|
||||
Raw bytecode (code_info_size=8, bytecode_size=13):
|
||||
88 40 0a 02 80 8f 23 23 51 67 59 81 67 59 81 5e
|
||||
51 68 59 51 63
|
||||
arg names:
|
||||
(N_STATE 2)
|
||||
(N_EXC_STACK 0)
|
||||
@ -409,49 +507,47 @@ arg names:
|
||||
10 POP_TOP
|
||||
11 LOAD_CONST_NONE
|
||||
12 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'Class' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
File cmdline/cmd_showbc.py, code block 'Class' (descriptor: \.\+, bytecode @\.\+ 1\[56\] bytes)
|
||||
Raw bytecode (code_info_size=\[56\], bytecode_size=10):
|
||||
00 \.\+ 11 0c 16 0d 10 03 16 0e 51 63
|
||||
arg names:
|
||||
(N_STATE 1)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=12 line=150
|
||||
bc=8 line=150
|
||||
00 LOAD_NAME __name__
|
||||
03 STORE_NAME __module__
|
||||
06 LOAD_CONST_STRING 'Class'
|
||||
09 STORE_NAME __qualname__
|
||||
12 LOAD_CONST_NONE
|
||||
13 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
02 STORE_NAME __module__
|
||||
04 LOAD_CONST_STRING 'Class'
|
||||
06 STORE_NAME __qualname__
|
||||
08 LOAD_CONST_NONE
|
||||
09 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 18 bytes)
|
||||
Raw bytecode (code_info_size=6, bytecode_size=12):
|
||||
19 08 02 0f 80 9c 12 10 12 11 b0 15 02 36 00 59
|
||||
51 63
|
||||
arg names: self
|
||||
(N_STATE 4)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
bc=0 line=157
|
||||
00 LOAD_GLOBAL super
|
||||
\\d\+ LOAD_GLOBAL __class__
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_SUPER_METHOD f
|
||||
\\d\+ CALL_METHOD n=0 nkw=0
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block '<genexpr>' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
02 LOAD_GLOBAL __class__
|
||||
04 LOAD_FAST 0
|
||||
05 LOAD_SUPER_METHOD f
|
||||
07 CALL_METHOD n=0 nkw=0
|
||||
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
|
||||
arg names: * * *
|
||||
(N_STATE 9)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
bc=0 line=60
|
||||
########
|
||||
00 LOAD_NULL
|
||||
01 LOAD_FAST 2
|
||||
02 LOAD_NULL
|
||||
@ -466,16 +562,15 @@ arg names: * * *
|
||||
17 JUMP 4
|
||||
20 LOAD_CONST_NONE
|
||||
21 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block '<listcomp>' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
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
|
||||
arg names: * * *
|
||||
(N_STATE 10)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
bc=0 line=61
|
||||
########
|
||||
00 BUILD_LIST 0
|
||||
02 LOAD_FAST 2
|
||||
03 GET_ITER_STACK
|
||||
@ -487,15 +582,15 @@ arg names: * * *
|
||||
15 STORE_COMP 20
|
||||
17 JUMP 4
|
||||
20 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block '<dictcomp>' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
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
|
||||
arg names: * * *
|
||||
(N_STATE 11)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=0 line=62
|
||||
00 BUILD_MAP 0
|
||||
02 LOAD_FAST 2
|
||||
03 GET_ITER_STACK
|
||||
@ -508,16 +603,17 @@ arg names: * * *
|
||||
17 STORE_COMP 25
|
||||
19 JUMP 4
|
||||
22 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'closure' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
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
|
||||
29 00 51 63
|
||||
arg names: *
|
||||
(N_STATE 4)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=\\d\+ line=114
|
||||
bc=0 line=112
|
||||
bc=5 line=113
|
||||
bc=8 line=114
|
||||
00 LOAD_DEREF 0
|
||||
02 LOAD_CONST_SMALL_INT 1
|
||||
03 BINARY_OP 27 __add__
|
||||
@ -527,16 +623,14 @@ arg names: *
|
||||
08 DELETE_DEREF 0
|
||||
10 LOAD_CONST_NONE
|
||||
11 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+63
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 13 bytes)
|
||||
Raw bytecode (code_info_size=8, bytecode_size=5):
|
||||
9a 01 0a 02 04 09 80 8b b1 25 00 f2 63
|
||||
arg names: * b
|
||||
(N_STATE 4)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=\\d\+ line=140
|
||||
bc=0 line=140
|
||||
00 LOAD_FAST 1
|
||||
01 LOAD_DEREF 0
|
||||
03 BINARY_OP 27 __add__
|
||||
|
@ -1,19 +1,17 @@
|
||||
File cmdline/cmd_verbose.py, code block '<module>' (descriptor: \.\+, bytecode \.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
08 \.\+
|
||||
########
|
||||
\.\+63
|
||||
File cmdline/cmd_verbose.py, code block '<module>' (descriptor: \.\+, bytecode @\.\+ 12 bytes)
|
||||
Raw bytecode (code_info_size=4, bytecode_size=8):
|
||||
08 04 01 40 11 02 81 34 01 59 51 63
|
||||
arg names:
|
||||
(N_STATE 2)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
bc=0 line=3
|
||||
00 LOAD_NAME print
|
||||
03 LOAD_CONST_SMALL_INT 1
|
||||
04 CALL_FUNCTION n=1 nkw=0
|
||||
06 POP_TOP
|
||||
07 LOAD_CONST_NONE
|
||||
08 RETURN_VALUE
|
||||
02 LOAD_CONST_SMALL_INT 1
|
||||
03 CALL_FUNCTION n=1 nkw=0
|
||||
05 POP_TOP
|
||||
06 LOAD_CONST_NONE
|
||||
07 RETURN_VALUE
|
||||
1
|
||||
mem: total=\\d\+, current=\\d\+, peak=\\d\+
|
||||
stack: \\d\+ out of \\d\+
|
||||
|
@ -49,7 +49,6 @@ user_files = {
|
||||
"/mod0.mpy": b"", # empty file
|
||||
"/mod1.mpy": b"M", # too short header
|
||||
"/mod2.mpy": b"M\x00\x00\x00", # bad version
|
||||
"/mod3.mpy": b"M\x00\x00\x00\x7f", # qstr window too large
|
||||
}
|
||||
|
||||
# create and mount a user filesystem
|
||||
|
@ -1,4 +1,3 @@
|
||||
mod0 ValueError incompatible .mpy file
|
||||
mod1 ValueError incompatible .mpy file
|
||||
mod2 ValueError incompatible .mpy file
|
||||
mod3 ValueError incompatible .mpy file
|
||||
|
@ -49,14 +49,14 @@ class UserFS:
|
||||
# by the required value of sys.implementation.mpy.
|
||||
features0_file_contents = {
|
||||
# -march=x64
|
||||
0xA05: b'M\x05\x0a\x1f \x84b\xe9/\x00\x00\x00SH\x8b\x1ds\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dA\x00\x00\x00H\x8b\x7f\x08L\x8bc(A\xff\xd4H\x8d5\x1f\x00\x00\x00H\x89\xc5H\x8b\x05-\x00\x00\x00\x0f\xb78\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x84@\x12factorial\x10\x00\x00\r \x01"\x9f\x1c\x01\x1e\xff',
|
||||
0xA06: b'M\x06\n\x1f\x01\x004build/features0.native.mpy\x00\x8aB\xe9/\x00\x00\x00SH\x8b\x1d\x83\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dQ\x00\x00\x00H\x8bG\x08L\x8bc(H\x8bx\x08A\xff\xd4H\x8d5+\x00\x00\x00H\x89\xc5H\x8b\x059\x00\x00\x00\x0f\xb78\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x85\x00\x12factorial\x00\x10\r$\x01&\x9f \x01"\xff',
|
||||
# -march=armv7m
|
||||
0x1605: b"M\x05\x16\x1f \x84\x12\x1a\xe0\x00\x00\x13\xb5\nK\nJ{D\x9cX\x02!\xe3h\x98G\x03F\x01 3\xb9\x02!#i\x01\x93\x02\xb0\xbd\xe8\x10@\x18GXC\x01;\xf4\xe7\x00\xbfj\x00\x00\x00\x00\x00\x00\x00\xf8\xb5\tN\tK~D\xf4X@hgi\xb8G\x05F\x07K\x07I\xf2XyD\x10\x88ck\x98G(F\xb8G h\xf8\xbd6\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x01\x84\x00\x12factorial\x10\x00\x00\r<\x01>\x9f8\x01:\xff",
|
||||
0x1606: b"M\x06\x16\x1f\x01\x004build/features0.native.mpy\x00\x88B\x1a\xe0\x00\x00\x13\xb5\nK\nJ{D\x9cX\x02!\xe3h\x98G\x03F\x01 3\xb9\x02!#i\x01\x93\x02\xb0\xbd\xe8\x10@\x18GXC\x01;\xf4\xe7\x00\xbfn\x00\x00\x00\x00\x00\x00\x00\xf8\xb5\nN\nK~D\xf4XChgiXh\xb8G\x05F\x07K\x08I\xf2XyD\x10\x88ck\x98G(F\xb8G h\xf8\xbd\x00\xbf:\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x84\x00\x00\x00\x00\x00\x00\x00\x01\x84\x10\x12factorial\x00\x10\r>\x01@\x9f:\x01<\xff",
|
||||
}
|
||||
|
||||
# Populate other armv7m-derived archs based on armv7m.
|
||||
for arch in (0x1A05, 0x1E05, 0x2205):
|
||||
features0_file_contents[arch] = features0_file_contents[0x1605]
|
||||
for arch in (0x1A06, 0x1E06, 0x2206):
|
||||
features0_file_contents[arch] = features0_file_contents[0x1606]
|
||||
|
||||
if sys.implementation.mpy not in features0_file_contents:
|
||||
print("SKIP")
|
||||
|
@ -52,49 +52,62 @@ class UserFS:
|
||||
# fmt: off
|
||||
user_files = {
|
||||
# bad architecture
|
||||
'/mod0.mpy': b'M\x05\xfe\x00\x10',
|
||||
'/mod0.mpy': b'M\x06\xfe\x00\x10',
|
||||
|
||||
# test loading of viper and asm
|
||||
'/mod1.mpy': (
|
||||
b'M\x05\x0a\x1f\x20' # header
|
||||
b'M\x06\x0a\x1f' # header
|
||||
|
||||
b'\x20' # n bytes, bytecode
|
||||
b'\x00\x08\x02m\x02m' # prelude
|
||||
b'\x02' # n_qstr
|
||||
b'\x00' # n_obj
|
||||
|
||||
b'\x0emod1.py\x00' # qstr0 = "mod1.py"
|
||||
b'\x0aouter\x00' # qstr1 = "outer"
|
||||
|
||||
b'\x2c' # 5 bytes, have children, bytecode
|
||||
b'\x00\x02' # prelude
|
||||
b'\x01' # simple name (qstr index)
|
||||
b'\x51' # LOAD_CONST_NONE
|
||||
b'\x63' # RETURN_VALUE
|
||||
|
||||
b'\x00\x02' # n_obj, n_raw_code
|
||||
b'\x02' # 2 children
|
||||
|
||||
b'\x22' # n bytes, viper code
|
||||
b'\x00\x00\x00\x00\x00\x00' # dummy machine code
|
||||
b'\x00\x00' # qstr0
|
||||
b'\x01\x0c\x0aprint' # n_qstr, qstr0
|
||||
b'\x00\x00\x00' # scope_flags, n_obj, n_raw_code
|
||||
b'\x42' # 8 bytes, no children, viper code
|
||||
b'\x00\x00\x00\x00\x00\x00' # dummy machine code
|
||||
b'\x00\x00' # slot for qstr0
|
||||
b'\x01\x0c\x0aprint\x00' # n_qstr=1, qstr0
|
||||
b'\x00' # scope_flags
|
||||
|
||||
b'\x23' # n bytes, asm code
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00' # dummy machine code
|
||||
b'\x00\x00\x00' # scope_flags, n_pos_args, type_sig
|
||||
b'\x43' # 8 bytes, no children, asm code
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00' # dummy machine code
|
||||
b'\x00\x00\x00' # scope_flags, n_pos_args, type_sig
|
||||
),
|
||||
|
||||
# test loading viper with additional scope flags and relocation
|
||||
'/mod2.mpy': (
|
||||
b'M\x05\x0a\x1f\x20' # header
|
||||
b'M\x06\x0a\x1f' # header
|
||||
|
||||
b'\x20' # n bytes, bytecode
|
||||
b'\x00\x08\x02m\x02m' # prelude
|
||||
b'\x02' # n_qstr
|
||||
b'\x00' # n_obj
|
||||
|
||||
b'\x0emod2.py\x00' # qstr0 = "mod2.py"
|
||||
b'\x0aouter\x00' # qstr1 = "outer"
|
||||
|
||||
b'\x2c' # 5 bytes, have children, bytecode
|
||||
b'\x00\x02' # prelude
|
||||
b'\x01' # simple name (qstr index)
|
||||
b'\x51' # LOAD_CONST_NONE
|
||||
b'\x63' # RETURN_VALUE
|
||||
|
||||
b'\x00\x01' # n_obj, n_raw_code
|
||||
b'\x01' # 1 child
|
||||
|
||||
b'\x12' # n bytes(=4), viper code
|
||||
b'\x00\x00\x00\x00' # dummy machine code
|
||||
b'\x00' # n_qstr
|
||||
b'\x70' # scope_flags: VIPERBSS | VIPERRODATA | VIPERRELOC
|
||||
b'\x00\x00' # n_obj, n_raw_code
|
||||
b'\x06rodata' # rodata, 6 bytes
|
||||
b'\x04' # bss, 4 bytes
|
||||
b'\x03\x01\x00' # dummy relocation of rodata
|
||||
b'\x22' # 4 bytes, no children, viper code
|
||||
b'\x00\x00\x00\x00' # dummy machine code
|
||||
b'\x00' # n_qstr=0
|
||||
b'\x70' # scope_flags: VIPERBSS | VIPERRODATA | VIPERRELOC
|
||||
b'\x06\x04' # rodata=6 bytes, bss=4 bytes
|
||||
b'rodata' # rodata content
|
||||
b'\x03\x01\x00' # dummy relocation of rodata
|
||||
),
|
||||
}
|
||||
# fmt: on
|
||||
|
@ -23,7 +23,7 @@ def f():
|
||||
x = ("const tuple", None, False, True, 1, 2, 3)
|
||||
result = 123
|
||||
"""
|
||||
file_data = b'M\x05\x02\x1f \x81\x0c\x10\x12\x00\x07\x0etest.py\x8b\x07e`\x00T2\x00\x10\x02A4\x02\x16\x012\x01\x16\x02f"\x80{\x16\x0cresultQc\x00\x02\x81\x1c\x00\x10\x05\x07,EE\x00\x11\x00\x17\x16\x00\x16\x10\x03\x16\x00\x1a2\x00\x16\x00\x112\x01\x16\x00\xa42\x02\x16\x00}Qc\x00\x03<\x1a\x0c\x00\x11\x03@\x00\xb1\xb0\x18\x06argQc\x00\x00\x00\x89\x01,\t\x0e\x00\xa4\x03` \x00Qc\x00\x00\x00\x89,\t\x0e\x00}\x01``\x00Qc\x00\x00\x00\x89\x81l8\x16\t\x03\x80\x08/,##\x00\x12\x00{\x12\x00\x97\x12\x00B\x12\x00K*\x04Y\x12\x00$\x12\x007\x12\x006*\x03Y#\x00\xc0#\x01\xc0#\x02QPR\x81\x82\x83*\x07\xc0Qc\x03\x00s\x1cthis will be a string objectb\x1bthis will be a bytes objects\x0bconst tuple'
|
||||
file_data = b'M\x06\x02\x1f\x14\x03\x0etest.py\x00\x0f\x02A\x00\x02f\x00\x0cresult\x00/-5#\x82I\x81{\x81w\x82/\x81\x05\x81\x17Iom\x82\x13\x06arg\x00s\x1cthis will be a string object\x00b\x1bthis will be a bytes object\x00s\x0bconst tuple\x00\x81\\\x10\n\x01\x89\x07d`T2\x00\x10\x024\x02\x16\x022\x01\x16\x03"\x80{\x16\x04Qc\x02\x81d\x00\x08\x02(DD\x11\x05\x16\x06\x10\x02\x16\x072\x00\x16\x082\x01\x16\t2\x02\x16\nQc\x03`\x1a\x08\x08\x12\x13@\xb1\xb0\x18\x13Qc@\t\x08\t\x12` Qc@\t\x08\n\x12``Qc\x83\x008\x0e\x03\x80\x08+)##\x12\x0b\x12\x0c\x12\r\x12\x0e*\x04Y\x12\x0f\x12\x10\x12\x11*\x03Y#\x00\xc0#\x01\xc0#\x02QPR\x81\x82\x83*\x07\xc0Qc'
|
||||
|
||||
|
||||
class File(uio.IOBase):
|
||||
|
@ -78,7 +78,7 @@ def f1():
|
||||
x = ("const tuple 9", None, False, True, 1, 2, 3)
|
||||
result = 123
|
||||
"""
|
||||
file_data = b'M\x05\x02\x1f \x81\\\x10\x1a\x00\x07\x0etest.pyk@k@\x85\x18\x85\x1f\x00T2\x00\x10\x04A04\x02\x16\x01T2\x01\x10\x04A14\x02\x16\x012\x02\x16\x04f02\x03\x16\x04f1"\x80{\x16\x0cresultQc\x00\x04\x814\x00\x12\t\x0b,%%%\x00\x11\x00\x17\x16\x00\x16\x10\x03\x16\x00\x1a2\x00\x16\x04a02\x01\x16\x04a12\x02\x16\x04a22\x03\x16\x04a3Qc\x00\x04(\t\x0c\x07\x0b \x00Qc\x00\x00\x00\x89(\t\x0c\t\x03@\x00Qc\x00\x00\x00\x89(\t\x0c\t\x03`\x00Qc\x00\x00\x00\x89,\t\x0e\t\x03` \x00Qc\x00\x00\x00\x89\x818\x00\x14\x13\x03l`%%%\x00\x11\x00\x17\x16\x00\x16\x10\x03\x16\x00\x1a2\x00\x16\x0b2\x01\x16\x0b2\x02\x16\x0b2\x03\x16\x0bQc\x00\x04,\t\x0e\x07\x0b``\x00Qc\x00\x00\x00\x89,\t\x0e\t\x03\x80\x07\x00Qc\x00\x00\x00\x89,\t\x0e\t\x03\x80\x08\x00Qc\x00\x00\x00\x89,\t\x0e\t\x03\x80\t\x00Qc\x00\x00\x00\x89\x94\x1cPP\x13\x03\x80\x0b8;555222\x1f%\x1f%\x1f"\x1f"\x1f%\x1f%\x1f"\x1f%\x1f"\x1f%)\x1f"//\x00\x12\x00\t\x12\x00\n\x12\x00\x0b\x12\x00\x0c\x12\x00\r\x12\x00\x0e\x12\x00\x0f*\x07Y\x12\x00\x10\x12\x00\x11\x12\x00\x12\x12\x00\x13\x12\x00\x14\x12\x00\x15\x12\x00\x16\x12\x00\x17*\x08Y\x12\x00\x18\x12\x00\x19\x12\x00\x1a\x12\x00\x1b\x12\x00\x1c\x12\x00\x1d*\x06Y\x12\x00\x1e\x12\x00\x1f\x12\x00 \x12\x00!\x12\x00"\x12\x00#*\x06Y\x12\x00$\x12\x00%\x12\x00&\x12\x00\'\x12\x00(\x12\x00)*\x06Y\x12\x00*\x12\x00+\x12\x00,\x12\x00-\x12\x00.*\x05Y\x12\x00/\x12\x000\x12\x001\x12\x002\x12\x003*\x05Y\x12\x004\x12\x005\x12\x006\x12\x007\x12\x008*\x05Y\x12\x009\x12\x00:\x12\x00;\x12\x00<\x12\x00=\x12\x00>\x12\x00?\x12\x00@\x12\x00A\x12\x00B\x12\x00C*\x0bY\x12\x00D\x12\x00E\x12\x00F\x12\x00G\x12\x00H\x12\x00I\x12\x00J\x12\x00K\x12\x00L\x12\x00M\x12\x00N*\x0bY\x12\x00O\x12\x00P\x12\x00Q\x12\x00R\x12\x00S\x12\x00T\x12\x00U\x12\x00V\x12\x00W\x12\x00X*\nY\x12\x00Y\x12\x00Z\x12\x00[\x12\x00\\\x12\x00]\x12\x00^\x12\x00_\x12\x00`\x12\x00a\x12\x00b*\nY\x12\x00c\x12\x00d\x12\x00e\x12\x00f\x12\x00g\x12\x00h\x12\x00i\x12\x00j\x12\x00k\x12\x00l\x12\x00m*\x0bY\x12\x00n\x12\x00o\x12\x00p\x12\x00q\x12\x00r\x12\x00s\x12\x00t\x12\x00u\x12\x00v\x12\x00w\x12\x00x*\x0bY\x12\x00y\x12\x00z\x12\x00{\x12\x00|\x12\x00}\x12\x00~\x12\x00\x7f\x12\x00\x80\x12\x00\x81\x12\x00\x82*\nY\x12\x00\x83\x12\x00\x84\x12\x00\x85\x12\x00\x86\x12\x00\x87\x12\x00\x88\x12\x00\x89\x12\x00\x8a\x12\x00\x8b\x12\x00\x8c\x12\x00\x8d*\x0bY\x12\x00\x8e\x12\x00\x8f\x12\x00\x90\x12\x00\x91\x12\x00\x92\x12\x00\x93\x12\x00\x94\x12\x00\x95\x12\x00\x96\x12\x00\x97*\nY\x12\x00\x98\x12\x00\x99\x12\x00\x9a\x12\x00\x9b\x12\x00\x9c\x12\x00\x9d\x12\x00\x9e\x12\x00\x9f\x12\x00\xa0\x12\x00\xa2\x12\x00\xa3*\x0bY\x12\x00\xa4\x12\x00\xa5*\x02Y\x12\nname0\x12\nname1\x12\nname2\x12\nname3\x12\nname4\x12\nname5\x12\nname6\x12\nname7\x12\nname8\x12\nname9*\nY\x12$quite_a_long_name0\x12$quite_a_long_name1\x12$quite_a_long_name2\x12$quite_a_long_name3*\x04Y\x12$quite_a_long_name4\x12$quite_a_long_name5\x12$quite_a_long_name6\x12$quite_a_long_name7*\x04Y\x12$quite_a_long_name8\x12$quite_a_long_name9\x12&quite_a_long_name10\x12&quite_a_long_name11*\x04YQc\x00\x00\x86H8H?/\x80#####################+++++++++\x00#\x00\xc0#\x01\xc0#\x02\xc0#\x03\xc0#\x04\xc0#\x05\xc0#\x06\xc0#\x07\xc0#\x08\xc0#\t\xc0#\n\xc0#\x0b\xc0#\x0c\xc0#\r\xc0#\x0e\xc0#\x0f\xc0#\x10\xc0#\x11\xc0#\x12\xc0#\x13\xc0#\x14QPR\x81\x82\x83*\x07\xc0#\x15QPR\x81\x82\x83*\x07\xc0#\x16QPR\x81\x82\x83*\x07\xc0#\x17QPR\x81\x82\x83*\x07\xc0#\x18QPR\x81\x82\x83*\x07\xc0#\x19QPR\x81\x82\x83*\x07\xc0#\x1aQPR\x81\x82\x83*\x07\xc0#\x1bQPR\x81\x82\x83*\x07\xc0#\x1cQPR\x81\x82\x83*\x07\xc0#\x1dQPR\x81\x82\x83*\x07\xc0Qc\x1e\x00s\x1ethis will be a string object 0s\x1ethis will be a string object 1s\x1ethis will be a string object 2s\x1ethis will be a string object 3s\x1ethis will be a string object 4s\x1ethis will be a string object 5s\x1ethis will be a string object 6s\x1ethis will be a string object 7s\x1ethis will be a string object 8s\x1ethis will be a string object 9b\x1dthis will be a bytes object 0b\x1dthis will be a bytes object 1b\x1dthis will be a bytes object 2b\x1dthis will be a bytes object 3b\x1dthis will be a bytes object 4b\x1dthis will be a bytes object 5b\x1dthis will be a bytes object 6b\x1dthis will be a bytes object 7b\x1dthis will be a bytes object 8b\x1dthis will be a bytes object 9s\rconst tuple 0s\rconst tuple 1s\rconst tuple 2s\rconst tuple 3s\rconst tuple 4s\rconst tuple 5s\rconst tuple 6s\rconst tuple 7s\rconst tuple 8s\rconst tuple 9'
|
||||
file_data = b"M\x06\x02\x1f\x81=\x1e\x0etest.py\x00\x0f\x04A0\x00\x04A1\x00\x04f0\x00\x04f1\x00\x0cresult\x00/-5\x04a0\x00\x04a1\x00\x04a2\x00\x04a3\x00\x13\x15\x17\x19\x1b\x1d\x1f!#%')+1379;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}\x7f\x81\x01\x81\x03\x81\x05\x81\x07\x81\t\x81\x0b\x81\r\x81\x0f\x81\x11\x81\x13\x81\x15\x81\x17\x81\x19\x81\x1b\x81\x1d\x81\x1f\x81!\x81#\x81%\x81'\x81)\x81+\x81-\x81/\x811\x813\x815\x817\x819\x81;\x81=\x81?\x81A\x81C\x81E\x81G\x81I\x81K\x81M\x81O\x81Q\x81S\x81U\x81W\x81Y\x81[\x81]\x81_\x81a\x81c\x81e\x81g\x81i\x81k\x81m\x81o\x81q\x81s\x81u\x81w\x81y\x81{\x81}\x81\x7f\x82\x01\x82\x03\x82\x05\x82\x07\x82\t\x82\x0b\x82\r\x82\x0f\x82\x11\x82\x13\x82\x15\x82\x17\x82\x19\x82\x1b\x82\x1d\x82\x1f\x82!\x82#\x82%\x82'\x82)\x82+\x82-\x82/\x821\x823\x825\x827\x829\x82;\x82=\x82?\x82A\x82E\x82G\x82I\x82K\nname0\x00\nname1\x00\nname2\x00\nname3\x00\nname4\x00\nname5\x00\nname6\x00\nname7\x00\nname8\x00\nname9\x00$quite_a_long_name0\x00$quite_a_long_name1\x00$quite_a_long_name2\x00$quite_a_long_name3\x00$quite_a_long_name4\x00$quite_a_long_name5\x00$quite_a_long_name6\x00$quite_a_long_name7\x00$quite_a_long_name8\x00$quite_a_long_name9\x00&quite_a_long_name10\x00&quite_a_long_name11\x00s\x1ethis will be a string object 0\x00s\x1ethis will be a string object 1\x00s\x1ethis will be a string object 2\x00s\x1ethis will be a string object 3\x00s\x1ethis will be a string object 4\x00s\x1ethis will be a string object 5\x00s\x1ethis will be a string object 6\x00s\x1ethis will be a string object 7\x00s\x1ethis will be a string object 8\x00s\x1ethis will be a string object 9\x00b\x1dthis will be a bytes object 0\x00b\x1dthis will be a bytes object 1\x00b\x1dthis will be a bytes object 2\x00b\x1dthis will be a bytes object 3\x00b\x1dthis will be a bytes object 4\x00b\x1dthis will be a bytes object 5\x00b\x1dthis will be a bytes object 6\x00b\x1dthis will be a bytes object 7\x00b\x1dthis will be a bytes object 8\x00b\x1dthis will be a bytes object 9\x00s\rconst tuple 0\x00s\rconst tuple 1\x00s\rconst tuple 2\x00s\rconst tuple 3\x00s\rconst tuple 4\x00s\rconst tuple 5\x00s\rconst tuple 6\x00s\rconst tuple 7\x00s\rconst tuple 8\x00s\rconst tuple 9\x00\x82d\x10\x12\x01i@i@\x84\x18\x84\x1fT2\x00\x10\x024\x02\x16\x02T2\x01\x10\x034\x02\x16\x032\x02\x16\x042\x03\x16\x05\"\x80{\x16\x06Qc\x04\x82\x0c\x00\n\x02($$$\x11\x07\x16\x08\x10\x02\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04@\t\x08\n\x81\x0b Qc@\t\x08\x0b\x81\x0b@Qc@\t\x08\x0c\x81\x0b`QcH\t\n\r\x81\x0b` Qc\x82\x14\x00\x0c\x03h`$$$\x11\x07\x16\x08\x10\x03\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04H\t\n\n\x81\x0b``QcH\t\n\x0b\x81\x0b\x80\x07QcH\t\n\x0c\x81\x0b\x80\x08QcH\t\n\r\x81\x0b\x80\tQc\xa08P:\x04\x80\x0b13///---997799<\x1f%\x1f\"\x1f%)\x1f\"//\x12\x0e\x12\x0f\x12\x10\x12\x11\x12\x12\x12\x13\x12\x14*\x07Y\x12\x15\x12\x16\x12\x17\x12\x18\x12\x19\x12\x1a\x12\x08\x12\x07*\x08Y\x12\x1b\x12\x1c\x12\t\x12\x1d\x12\x1e\x12\x1f*\x06Y\x12 \x12!\x12\"\x12#\x12$\x12%*\x06Y\x12&\x12'\x12(\x12)\x12*\x12+*\x06Y\x12,\x12-\x12.\x12/\x120*\x05Y\x121\x122\x123\x124\x125*\x05Y\x126\x127\x128\x129\x12:*\x05Y\x12;\x12<\x12=\x12>\x12?\x12@\x12A\x12B\x12C\x12D\x12E*\x0bY\x12F\x12G\x12H\x12I\x12J\x12K\x12L\x12M\x12N\x12O\x12P*\x0bY\x12Q\x12R\x12S\x12T\x12U\x12V\x12W\x12X\x12Y\x12Z*\nY\x12[\x12\\\x12]\x12^\x12_\x12`\x12a\x12b\x12c\x12d*\nY\x12e\x12f\x12g\x12h\x12i\x12j\x12k\x12l\x12m\x12n\x12o*\x0bY\x12p\x12q\x12r\x12s\x12t\x12u\x12v\x12w\x12x\x12y\x12z*\x0bY\x12{\x12|\x12}\x12~\x12\x7f\x12\x81\x00\x12\x81\x01\x12\x81\x02\x12\x81\x03\x12\x81\x04*\nY\x12\x81\x05\x12\x81\x06\x12\x81\x07\x12\x81\x08\x12\x81\t\x12\x81\n\x12\x81\x0b\x12\x81\x0c\x12\x81\r\x12\x81\x0e\x12\x81\x0f*\x0bY\x12\x81\x10\x12\x81\x11\x12\x81\x12\x12\x81\x13\x12\x81\x14\x12\x81\x15\x12\x81\x16\x12\x81\x17\x12\x81\x18\x12\x81\x19*\nY\x12\x81\x1a\x12\x81\x1b\x12\x81\x1c\x12\x81\x1d\x12\x81\x1e\x12\x81\x1f\x12\x81 \x12\x81!\x12\x81\"\x12\x81#\x12\x81$*\x0bY\x12\x81%\x12\x81&*\x02Y\x12\x81'\x12\x81(\x12\x81)\x12\x81*\x12\x81+\x12\x81,\x12\x81-\x12\x81.\x12\x81/\x12\x810*\nY\x12\x811\x12\x812\x12\x813\x12\x814*\x04Y\x12\x815\x12\x816\x12\x817\x12\x818*\x04Y\x12\x819\x12\x81:\x12\x81;\x12\x81<*\x04YQc\x8cp8@\x05\x80#####################+++++++++#\x00\xc0#\x01\xc0#\x02\xc0#\x03\xc0#\x04\xc0#\x05\xc0#\x06\xc0#\x07\xc0#\x08\xc0#\t\xc0#\n\xc0#\x0b\xc0#\x0c\xc0#\r\xc0#\x0e\xc0#\x0f\xc0#\x10\xc0#\x11\xc0#\x12\xc0#\x13\xc0#\x14QPR\x81\x82\x83*\x07\xc0#\x15QPR\x81\x82\x83*\x07\xc0#\x16QPR\x81\x82\x83*\x07\xc0#\x17QPR\x81\x82\x83*\x07\xc0#\x18QPR\x81\x82\x83*\x07\xc0#\x19QPR\x81\x82\x83*\x07\xc0#\x1aQPR\x81\x82\x83*\x07\xc0#\x1bQPR\x81\x82\x83*\x07\xc0#\x1cQPR\x81\x82\x83*\x07\xc0#\x1dQPR\x81\x82\x83*\x07\xc0Qc"
|
||||
|
||||
|
||||
class File(uio.IOBase):
|
||||
|
1326
tools/mpy-tool.py
1326
tools/mpy-tool.py
File diff suppressed because it is too large
Load Diff
@ -35,7 +35,7 @@ sys.path.append(os.path.dirname(__file__) + "/../py")
|
||||
import makeqstrdata as qstrutil
|
||||
|
||||
# MicroPython constants
|
||||
MPY_VERSION = 5
|
||||
MPY_VERSION = 6
|
||||
MP_NATIVE_ARCH_X86 = 1
|
||||
MP_NATIVE_ARCH_X64 = 2
|
||||
MP_NATIVE_ARCH_ARMV7M = 5
|
||||
@ -860,11 +860,12 @@ class MPYOutput:
|
||||
|
||||
def write_qstr(self, s):
|
||||
if s in qstrutil.static_qstr_list:
|
||||
self.write_bytes(bytes([0, qstrutil.static_qstr_list.index(s) + 1]))
|
||||
self.write_uint((qstrutil.static_qstr_list.index(s) + 1) << 1 | 1)
|
||||
else:
|
||||
s = bytes(s, "ascii")
|
||||
self.write_uint(len(s) << 1)
|
||||
self.write_bytes(s)
|
||||
self.write_bytes(b"\x00")
|
||||
|
||||
def write_reloc(self, base, offset, dest, n):
|
||||
need_offset = not (base == self.prev_base and offset == self.prev_offset + 1)
|
||||
@ -905,14 +906,19 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs):
|
||||
out.open(fmpy)
|
||||
|
||||
# MPY: header
|
||||
out.write_bytes(
|
||||
bytearray(
|
||||
[ord("M"), MPY_VERSION, env.arch.mpy_feature, MP_SMALL_INT_BITS, QSTR_WINDOW_SIZE]
|
||||
)
|
||||
)
|
||||
out.write_bytes(bytearray([ord("M"), MPY_VERSION, env.arch.mpy_feature, MP_SMALL_INT_BITS]))
|
||||
|
||||
# MPY: n_qstr
|
||||
out.write_uint(1)
|
||||
|
||||
# MPY: n_obj
|
||||
out.write_uint(0)
|
||||
|
||||
# MPY: qstr table
|
||||
out.write_qstr(fmpy) # filename
|
||||
|
||||
# MPY: kind/len
|
||||
out.write_uint(len(env.full_text) << 2 | (MP_CODE_NATIVE_VIPER - MP_CODE_BYTECODE))
|
||||
out.write_uint(len(env.full_text) << 3 | (MP_CODE_NATIVE_VIPER - MP_CODE_BYTECODE))
|
||||
|
||||
# MPY: machine code
|
||||
out.write_bytes(env.full_text)
|
||||
@ -936,20 +942,15 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs):
|
||||
scope_flags |= MP_SCOPE_FLAG_VIPERBSS
|
||||
out.write_uint(scope_flags)
|
||||
|
||||
# MPY: n_obj
|
||||
out.write_uint(0)
|
||||
|
||||
# MPY: n_raw_code
|
||||
out.write_uint(0)
|
||||
|
||||
# MPY: rodata and/or bss
|
||||
# MPY: bss and/or rodata
|
||||
if len(env.full_rodata):
|
||||
rodata_const_table_idx = 1
|
||||
out.write_uint(len(env.full_rodata))
|
||||
out.write_bytes(env.full_rodata)
|
||||
if len(env.full_bss):
|
||||
bss_const_table_idx = bool(env.full_rodata) + 1
|
||||
bss_const_table_idx = 2
|
||||
out.write_uint(len(env.full_bss))
|
||||
if len(env.full_rodata):
|
||||
out.write_bytes(env.full_rodata)
|
||||
|
||||
# MPY: relocation information
|
||||
prev_kind = None
|
||||
|
Loading…
Reference in New Issue
Block a user