diff options
author | Damien George <damien.p.george@gmail.com> | 2014-10-25 15:07:02 +0100 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2014-10-25 20:23:13 +0100 |
commit | 1084b0f9c21b093618da4494508dec9ca8467e35 (patch) | |
tree | e21a6e19240346b6a449b432cbf961d7839fba4b /py/bc.c | |
parent | fcff4663dd5bd33eed931c7731fd133f49551b4b (diff) |
py: Store bytecode arg names in bytecode (were in own array).
This saves a lot of RAM for 2 reasons:
1. For functions that don't have default values, var args or var kw
args (which is a large number of functions in the general case), the
mp_obj_fun_bc_t type now fits in 1 GC block (previously needed 2 because
of the extra pointer to point to the arg_names array). So this saves 16
bytes per function (32 bytes on 64-bit machines).
2. Combining separate memory regions generally saves RAM because the
unused bytes at the end of the GC block are saved for 1 of the blocks
(since that block doesn't exist on its own anymore). So generally this
saves 8 bytes per function.
Tested by importing lots of modules:
- 64-bit Linux gave about an 8% RAM saving for 86k of used RAM.
- pyboard gave about a 6% RAM saving for 31k of used RAM.
Diffstat (limited to 'py/bc.c')
-rw-r--r-- | py/bc.c | 20 |
1 files changed, 14 insertions, 6 deletions
@@ -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]); |