diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/bc.h | 2 | ||||
-rw-r--r-- | py/bc0.h | 2 | ||||
-rw-r--r-- | py/compile.c | 2 | ||||
-rw-r--r-- | py/emitbc.c | 59 | ||||
-rw-r--r-- | py/obj.h | 2 | ||||
-rw-r--r-- | py/objfun.c | 36 | ||||
-rw-r--r-- | py/runtime.c | 6 | ||||
-rw-r--r-- | py/runtime.h | 2 | ||||
-rw-r--r-- | py/showbc.c | 5 | ||||
-rw-r--r-- | py/vm.c | 17 |
10 files changed, 86 insertions, 47 deletions
@@ -1,3 +1,3 @@ -mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, uint n_state); +mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, uint n_state); bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out); void mp_byte_code_print(const byte *code, int len); @@ -94,7 +94,9 @@ #define MP_BC_CALL_METHOD_VAR (0x97) // uint #define MP_BC_CALL_METHOD_KW (0x98) // uint #define MP_BC_CALL_METHOD_VAR_KW (0x99) // uint +#define MP_BC_MAKE_FUNCTION_DEFARGS (0x9a) // uint #define MP_BC_IMPORT_NAME (0xe0) // qstr #define MP_BC_IMPORT_FROM (0xe1) // qstr #define MP_BC_IMPORT_STAR (0xe2) + diff --git a/py/compile.c b/py/compile.c index c1a7955dcd..c4b582e2ae 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3212,7 +3212,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) { return mp_const_true; #else // return function that executes the outer module - return rt_make_function_from_id(unique_code_id); + return rt_make_function_from_id(unique_code_id, MP_OBJ_NULL); #endif } } diff --git a/py/emitbc.c b/py/emitbc.c index d74b065253..117a08cda5 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -107,6 +107,22 @@ static void emit_write_byte_code_byte_byte(emit_t* emit, byte b1, uint b2) { c[1] = b2; } +static void emit_write_byte_code_uint(emit_t* emit, uint num) { + if (num <= 127) { // fits in 0x7f + // fit argument in single byte + byte* c = emit_get_cur_to_write_byte_code(emit, 1); + c[0] = num; + } else if (num <= 16383) { // fits in 0x3fff + // fit argument in two bytes + byte* c = emit_get_cur_to_write_byte_code(emit, 2); + c[0] = (num >> 8) | 0x80; + c[1] = num; + } else { + // larger numbers not implemented/supported + assert(0); + } +} + // integers (for small ints) are stored as 24 bits, in excess static void emit_write_byte_code_byte_int(emit_t* emit, byte b1, machine_int_t num) { num += 0x800000; @@ -118,26 +134,21 @@ static void emit_write_byte_code_byte_int(emit_t* emit, byte b1, machine_int_t n c[3] = num >> 16; } -static void emit_write_byte_code_byte_uint(emit_t* emit, byte b1, uint num) { - if (num <= 127) { // fits in 0x7f - // fit argument in single byte - byte* c = emit_get_cur_to_write_byte_code(emit, 2); - c[0] = b1; - c[1] = num; - } else if (num <= 16383) { // fits in 0x3fff - // fit argument in two bytes - byte* c = emit_get_cur_to_write_byte_code(emit, 3); - c[0] = b1; - c[1] = (num >> 8) | 0x80; - c[2] = num; - } else { - // larger numbers not implemented/supported - assert(0); - } +static void emit_write_byte_code_byte_uint(emit_t* emit, byte b, uint num) { + emit_write_byte_code_byte(emit, b); + emit_write_byte_code_uint(emit, num); +} + +/* currently unused +static void emit_write_byte_code_byte_uint_uint(emit_t* emit, byte b, uint num1, uint num2) { + emit_write_byte_code_byte(emit, b); + emit_write_byte_code_byte_uint(emit, num1); + emit_write_byte_code_byte_uint(emit, num2); } +*/ -static void emit_write_byte_code_byte_qstr(emit_t* emit, byte b1, qstr qstr) { - emit_write_byte_code_byte_uint(emit, b1, qstr); +static void emit_write_byte_code_byte_qstr(emit_t* emit, byte b, qstr qstr) { + emit_write_byte_code_byte_uint(emit, b, qstr); } // unsigned labels are relative to ip following this instruction, stored as 16 bits @@ -664,9 +675,15 @@ static void emit_bc_unpack_ex(emit_t *emit, int n_left, int n_right) { } static void emit_bc_make_function(emit_t *emit, scope_t *scope, int n_dict_params, int n_default_params) { - assert(n_default_params == 0 && n_dict_params == 0); - emit_pre(emit, 1); - emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION, scope->unique_code_id); + assert(n_dict_params == 0); + if (n_default_params == 0) { + emit_pre(emit, 1); + emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION, scope->unique_code_id); + } else { + emit_bc_build_tuple(emit, n_default_params); + emit_pre(emit, 0); + emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->unique_code_id); + } } static void emit_bc_make_closure(emit_t *emit, scope_t *scope, int n_dict_params, int n_default_params) { @@ -221,7 +221,7 @@ mp_obj_t mp_obj_new_exception_msg_2_args(qstr id, const char *fmt, const char *a mp_obj_t mp_obj_new_exception_msg_varg(qstr id, 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_range(int start, int stop, int step); mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step); -mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code); +mp_obj_t mp_obj_new_fun_bc(int n_args, mp_obj_t def_args, uint n_state, const byte *code); mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun); mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args); diff --git a/py/objfun.c b/py/objfun.c index fe4f49430e..fbc0cab118 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -8,6 +8,7 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "objtuple.h" #include "map.h" #include "runtime.h" #include "bc.h" @@ -136,32 +137,30 @@ mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var typedef struct _mp_obj_fun_bc_t { mp_obj_base_t base; mp_map_t *globals; // the context within which this function was defined - int n_args; // number of arguments this function takes + short n_args; // number of arguments this function takes + short n_def_args; // number of default arguments uint n_state; // total state size for the executing function (incl args, locals, stack) const byte *bytecode; // bytecode for the function + mp_obj_t def_args[]; // values of default args, if any } mp_obj_fun_bc_t; mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { mp_obj_fun_bc_t *self = self_in; - if (n_args != self->n_args) { + if (n_args < self->n_args - self->n_def_args || n_args > self->n_args) { nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args, (const char*)(machine_int_t)n_args)); } if (n_kw != 0) { nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments")); } - // optimisation: allow the compiler to optimise this tail call for - // the common case when the globals don't need to be changed + uint use_def_args = self->n_args - n_args; mp_map_t *old_globals = rt_globals_get(); - if (self->globals == old_globals) { - return mp_execute_byte_code(self->bytecode, args, n_args, self->n_state); - } else { - rt_globals_set(self->globals); - mp_obj_t result = mp_execute_byte_code(self->bytecode, args, n_args, self->n_state); - rt_globals_set(old_globals); - return result; - } + rt_globals_set(self->globals); + mp_obj_t result = mp_execute_byte_code(self->bytecode, args, n_args, self->def_args + self->n_def_args - use_def_args, use_def_args, self->n_state); + rt_globals_set(old_globals); + + return result; } const mp_obj_type_t fun_bc_type = { @@ -170,13 +169,22 @@ const mp_obj_type_t fun_bc_type = { .call = fun_bc_call, }; -mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code) { - mp_obj_fun_bc_t *o = m_new_obj(mp_obj_fun_bc_t); +mp_obj_t mp_obj_new_fun_bc(int n_args, mp_obj_t def_args_in, uint n_state, const byte *code) { + int n_def_args = 0; + mp_obj_tuple_t *def_args = def_args_in; + if (def_args != MP_OBJ_NULL) { + n_def_args = def_args->len; + } + mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_def_args); o->base.type = &fun_bc_type; o->globals = rt_globals_get(); o->n_args = n_args; + o->n_def_args = n_def_args; o->n_state = n_state; o->bytecode = code; + if (def_args != MP_OBJ_NULL) { + memcpy(o->def_args, def_args->items, n_def_args * sizeof(*o->def_args)); + } return o; } diff --git a/py/runtime.c b/py/runtime.c index ee8d720c22..77e596c5d0 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -674,7 +674,7 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { return mp_const_none; } -mp_obj_t rt_make_function_from_id(int unique_code_id) { +mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) { DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id); if (unique_code_id < 1 || unique_code_id >= next_unique_code_id) { // illegal code id @@ -686,7 +686,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) { mp_obj_t fun; switch (c->kind) { case MP_CODE_BYTE: - fun = mp_obj_new_fun_bc(c->n_args, c->n_state, c->u_byte.code); + fun = mp_obj_new_fun_bc(c->n_args, def_args, c->n_state, c->u_byte.code); break; case MP_CODE_NATIVE: fun = rt_make_function_n(c->n_args, c->u_native.fun); @@ -710,7 +710,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) { mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple) { DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id); // make function object - mp_obj_t ffun = rt_make_function_from_id(unique_code_id); + mp_obj_t ffun = rt_make_function_from_id(unique_code_id, MP_OBJ_NULL); // wrap function in closure object return mp_obj_new_closure(ffun, closure_tuple); } diff --git a/py/runtime.h b/py/runtime.h index c8113f4a7d..10c262a606 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -12,7 +12,7 @@ void rt_store_name(qstr qstr, mp_obj_t obj); void rt_store_global(qstr qstr, mp_obj_t obj); mp_obj_t rt_unary_op(int op, mp_obj_t arg); mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs); -mp_obj_t rt_make_function_from_id(int unique_code_id); +mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args); mp_obj_t rt_make_function_n(int n_args, void *fun); // fun must have the correct signature for n_args fixed arguments mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun); mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun); // min and max are inclusive diff --git a/py/showbc.c b/py/showbc.c index 8a12302531..53a1826045 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -339,6 +339,11 @@ void mp_byte_code_print(const byte *ip, int len) { printf("MAKE_FUNCTION " UINT_FMT, unum); break; + case MP_BC_MAKE_FUNCTION_DEFARGS: + DECODE_UINT; + printf("MAKE_FUNCTION_DEFARGS " UINT_FMT, unum); + break; + case MP_BC_MAKE_CLOSURE: DECODE_UINT; printf("MAKE_CLOSURE " UINT_FMT, unum); @@ -46,7 +46,7 @@ typedef enum { #define TOP() (*sp) #define SET_TOP(val) *sp = (val) -mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, uint n_state) { +mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, uint n_state) { // allocate state for locals and stack mp_obj_t temp_state[10]; mp_obj_t *state = &temp_state[0]; @@ -56,10 +56,12 @@ mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_arg mp_obj_t *sp = &state[0] - 1; // init args - for (int i = 0; i < n_args; i++) { - assert(i < 8); + for (uint i = 0; i < n_args; i++) { state[n_state - 1 - i] = args[i]; } + for (uint i = 0; i < n_args2; i++) { + state[n_state - 1 - n_args - i] = args2[i]; + } const byte *ip = code; @@ -71,7 +73,7 @@ mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_arg { for (uint n_local = *ip++; n_local > 0; n_local--) { uint local_num = *ip++; - if (local_num < n_args) { + if (local_num < n_args + n_args2) { state[n_state - 1 - local_num] = mp_obj_new_cell(state[n_state - 1 - local_num]); } else { state[n_state - 1 - local_num] = mp_obj_new_cell(MP_OBJ_NULL); @@ -497,7 +499,12 @@ dispatch_loop: case MP_BC_MAKE_FUNCTION: DECODE_UINT; - PUSH(rt_make_function_from_id(unum)); + PUSH(rt_make_function_from_id(unum, MP_OBJ_NULL)); + break; + + case MP_BC_MAKE_FUNCTION_DEFARGS: + DECODE_UINT; + SET_TOP(rt_make_function_from_id(unum, TOP())); break; case MP_BC_MAKE_CLOSURE: |