diff --git a/py/bc.c b/py/bc.c index 91ef9c070fde6fb586704a04847c1129940b1e3e..b5515bcd7916136ffa7c1b666a9faf7a19334843 100644 --- a/py/bc.c +++ b/py/bc.c @@ -93,7 +93,6 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t // usage for the common case of positional only args. mp_obj_fun_bc_t *self = self_in; mp_uint_t n_state = code_state->n_state; - const byte *ip = code_state->ip; code_state->code_info = self->bytecode; code_state->sp = &code_state->state[0] - 1; @@ -153,13 +152,21 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t *var_pos_kw_args = dict; } + // get pointer to arg_names array at start of bytecode prelude + const mp_obj_t *arg_names; + { + const byte *code_info = code_state->code_info; + mp_uint_t code_info_size = mp_decode_uint(&code_info); + arg_names = (const mp_obj_t*)(code_state->code_info + code_info_size); + } + for (mp_uint_t i = 0; i < n_kw; i++) { - qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]); + mp_obj_t wanted_arg_name = kwargs[2 * i]; for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) { - if (arg_name == self->args[j]) { + if (wanted_arg_name == arg_names[j]) { if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, - "function got multiple values for argument '%s'", qstr_str(arg_name))); + "function got multiple values for argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(wanted_arg_name)))); } code_state->state[n_state - 1 - j] = kwargs[2 * i + 1]; goto continue2; @@ -202,13 +209,13 @@ continue2:; if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) { mp_map_elem_t *elem = NULL; if (self->has_def_kw_args) { - elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, MP_OBJ_NEW_QSTR(self->args[self->n_pos_args + i]), MP_MAP_LOOKUP); + elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, arg_names[self->n_pos_args + i], MP_MAP_LOOKUP); } if (elem != NULL) { code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, - "function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i]))); + "function missing required keyword argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(arg_names[self->n_pos_args + i])))); } } } @@ -225,6 +232,7 @@ continue2:; } // bytecode prelude: initialise closed over variables + const byte *ip = code_state->ip; for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) { mp_uint_t local_num = *ip++; code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]); diff --git a/py/bc.h b/py/bc.h index 6cda15b0461d4fb729becb6167ed6b6ffedb7cb0..058eaba401dc98a7c053883de55611753ad2951e 100644 --- a/py/bc.h +++ b/py/bc.h @@ -53,7 +53,7 @@ mp_uint_t mp_decode_uint(const byte **ptr); mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc); void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); -void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len); +void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *code, mp_uint_t len); void mp_bytecode_print2(const byte *code, mp_uint_t len); // Helper macros to access pointer with least significant bit holding a flag diff --git a/py/emitbc.c b/py/emitbc.c index 05dc79ef4fc84246862f9176b6b11666abced9f1..cee6d3396c1cf0e1075873152df5befdc1ea691a 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -218,6 +218,13 @@ STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, mp_uint_t val) { emit_write_uint(emit, emit_get_cur_to_write_bytecode, val); } +STATIC void emit_write_bytecode_prealigned_ptr(emit_t* emit, void *ptr) { + mp_uint_t *c = (mp_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_uint_t)); + // Verify thar c is already uint-aligned + assert(c == MP_ALIGN(c, sizeof(mp_uint_t))); + *c = (mp_uint_t)ptr; +} + // aligns the pointer so it is friendly to GC STATIC void emit_write_bytecode_byte_ptr(emit_t* emit, byte b, void *ptr) { emit_write_bytecode_byte(emit, b); @@ -294,7 +301,16 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { emit_write_code_info_qstr(emit, scope->simple_name); emit_write_code_info_qstr(emit, scope->source_file); - // bytecode prelude: local state size and exception stack size; 16 bit uints for now + // bytecode prelude: 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 + { + for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) { + emit_write_bytecode_prealigned_ptr(emit, MP_OBJ_NEW_QSTR(scope->id_info[i].qst)); + } + } + + // bytecode prelude: local state size and exception stack size { mp_uint_t n_state = scope->num_locals + scope->stack_size; if (n_state == 0) { @@ -358,13 +374,9 @@ STATIC void emit_bc_end_pass(emit_t *emit) { emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size); } else if (emit->pass == MP_PASS_EMIT) { - qstr *arg_names = m_new(qstr, emit->scope->num_pos_args + emit->scope->num_kwonly_args); - for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) { - arg_names[i] = emit->scope->id_info[i].qst; - } mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base, emit->code_info_size + emit->bytecode_size, - emit->scope->num_pos_args, emit->scope->num_kwonly_args, arg_names, + emit->scope->num_pos_args, emit->scope->num_kwonly_args, emit->scope->scope_flags); } } diff --git a/py/emitglue.c b/py/emitglue.c index dd31de925b3e2353867c5c6b28b2f0c405fb1793..41a6720e7092b771f0b88dbadd451cc00854bfa5 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -55,26 +55,20 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) { return rc; } -void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags) { +void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags) { rc->kind = MP_CODE_BYTECODE; rc->scope_flags = scope_flags; rc->n_pos_args = n_pos_args; rc->n_kwonly_args = n_kwonly_args; - rc->arg_names = arg_names; rc->u_byte.code = code; rc->u_byte.len = len; #ifdef DEBUG_PRINT DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", code, len, n_pos_args, n_kwonly_args, (uint)scope_flags); - DEBUG_printf(" arg names:"); - for (int i = 0; i < n_pos_args + n_kwonly_args; i++) { - DEBUG_printf(" %s", qstr_str(arg_names[i])); - } - DEBUG_printf("\n"); #endif #if MICROPY_DEBUG_PRINTERS if (mp_verbose_flag > 0) { - mp_bytecode_print(rc, code, len); + mp_bytecode_print(rc, n_pos_args + n_kwonly_args, code, len); } #endif } @@ -121,7 +115,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp mp_obj_t fun; switch (rc->kind) { case MP_CODE_BYTECODE: - fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code); + fun = mp_obj_new_fun_bc(rc->scope_flags, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code); break; #if MICROPY_EMIT_NATIVE case MP_CODE_NATIVE_PY: diff --git a/py/emitglue.h b/py/emitglue.h index 91d5285ad5e13604c9a368d30847247efdda7beb..fd55af26a6dff651f1cf487f9584de2fc1c09733 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -40,7 +40,6 @@ typedef struct _mp_raw_code_t { mp_uint_t scope_flags : 7; mp_uint_t n_pos_args : 11; mp_uint_t n_kwonly_args : 11; - qstr *arg_names; union { struct { byte *code; @@ -55,7 +54,7 @@ typedef struct _mp_raw_code_t { mp_raw_code_t *mp_emit_glue_new_raw_code(void); -void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags); +void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, 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, mp_uint_t n_args, mp_uint_t type_sig); mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args); diff --git a/py/obj.h b/py/obj.h index 0ae9dc0303c944ca14c2d169fe53cb912f6f136e..4d4c73a00196587bc60f0b290344f82ec32cb66b 100644 --- a/py/obj.h +++ b/py/obj.h @@ -383,7 +383,7 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg); mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, mp_uint_t n_args, const mp_obj_t *args); mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg); mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) -mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code); +mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code); mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data); mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig); mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data); diff --git a/py/objfun.c b/py/objfun.c index e64d088bfa9091b9583aac12ffc0efaf5dc3e5fd..3adf05e3b0e410e9ff3fdbab6b1cb80859846477 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -173,7 +173,10 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t code_info_size = mp_decode_uint(&code_info); const byte *ip = self->bytecode + code_info_size; - // bytecode prelude: state size and exception stack size; 16 bit uints + // bytecode prelude: skip arg names + ip += (self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t); + + // bytecode prelude: state size and exception stack size mp_uint_t n_state = mp_decode_uint(&ip); mp_uint_t n_exc_stack = mp_decode_uint(&ip); @@ -268,7 +271,7 @@ const mp_obj_type_t mp_type_fun_bc = { .binary_op = mp_obj_fun_binary_op, }; -mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code) { +mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code) { mp_uint_t n_def_args = 0; mp_uint_t n_extra_args = 0; mp_obj_tuple_t *def_args = def_args_in; @@ -283,7 +286,6 @@ mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_ar 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->args = args; o->n_pos_args = n_pos_args; o->n_kwonly_args = n_kwonly_args; o->n_def_args = n_def_args; diff --git a/py/objfun.h b/py/objfun.h index cc8035ef37389c54e132ff2167eebe40fefbdb82..e23fe8d529db3af58c13af77fa719ce4c1cf84f3 100644 --- a/py/objfun.h +++ b/py/objfun.h @@ -27,14 +27,13 @@ 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 - mp_uint_t n_pos_args : 16; // number of arguments this function takes - mp_uint_t n_kwonly_args : 16; // number of arguments this function takes - mp_uint_t n_def_args : 16; // number of default arguments + mp_uint_t n_pos_args : 8; // number of arguments this function takes + mp_uint_t n_kwonly_args : 8; // number of keyword-only arguments this function takes + mp_uint_t n_def_args : 8; // number of default arguments mp_uint_t has_def_kw_args : 1; // set if this function has default keyword args mp_uint_t takes_var_args : 1; // set if this function takes variable args mp_uint_t takes_kw_args : 1; // set if this function takes keyword args const byte *bytecode; // bytecode for the function - qstr *args; // argument names (needed to resolve positional args passed as keywords) // the following extra_args array is allocated space to take (in order): // - values of positional default args (if any) // - a single slot for default kw args dict (if it has them) diff --git a/py/objgenerator.c b/py/objgenerator.c index 9d16d2bee06f172b5475e4b5ad5e9233267ef446..ce26cbce26523f1dd3f5c69e5eaa398d50134880 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -62,6 +62,9 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw mp_uint_t code_info_size = mp_decode_uint(&code_info); const byte *ip = self_fun->bytecode + code_info_size; + // bytecode prelude: skip arg names + ip += (self_fun->n_pos_args + self_fun->n_kwonly_args) * sizeof(mp_obj_t); + // bytecode prelude: get state size and exception stack size mp_uint_t n_state = mp_decode_uint(&ip); mp_uint_t n_exc_stack = mp_decode_uint(&ip); diff --git a/py/showbc.c b/py/showbc.c index 28fed14c9ebfa0d97d4ca40d8dbd42e834e166ce..13d257d304a06add44a3efcd1f60cb8e4e49b6ac 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -57,7 +57,7 @@ ip += sizeof(mp_uint_t); \ } while (0) -void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len) { +void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *ip, mp_uint_t len) { const byte *ip_start = ip; // get code info size @@ -80,6 +80,14 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len) { } printf("\n"); + // bytecode prelude: arg names (as qstr objects) + printf("arg names:"); + for (int i = 0; i < n_total_args; i++) { + printf(" %s", qstr_str(MP_OBJ_QSTR_VALUE(*(mp_obj_t*)ip))); + ip += sizeof(mp_obj_t); + } + printf("\n"); + // bytecode prelude: state size and exception stack size; 16 bit uints { uint n_state = mp_decode_uint(&ip);