From 523b575039d96d63669ad8c1fa318ba4db046aca Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 31 Mar 2014 11:59:23 +0100 Subject: [PATCH] py: Add LOAD_NULL bytecode and use it to simplify function calls. Adding this bytecode allows to remove 4 others related to function/method calls with * and ** support. Will also help with bytecodes that make functions/closures with default positional and keyword args. --- py/bc0.h | 21 +++++++--------- py/emitbc.c | 67 ++++++++++++++++++---------------------------------- py/runtime.c | 4 +++- py/runtime.h | 2 +- py/showbc.c | 20 ---------------- py/vm.c | 60 +++++++--------------------------------------- 6 files changed, 44 insertions(+), 130 deletions(-) diff --git a/py/bc0.h b/py/bc0.h index 3d4b106d32..80a8248de7 100644 --- a/py/bc0.h +++ b/py/bc0.h @@ -11,6 +11,7 @@ #define MP_BC_LOAD_CONST_ID (0x17) // qstr #define MP_BC_LOAD_CONST_BYTES (0x18) // qstr #define MP_BC_LOAD_CONST_STRING (0x19) // qstr +#define MP_BC_LOAD_NULL (0x1a) #define MP_BC_LOAD_FAST_0 (0x20) #define MP_BC_LOAD_FAST_1 (0x21) @@ -84,18 +85,14 @@ #define MP_BC_YIELD_VALUE (0x82) #define MP_BC_YIELD_FROM (0x83) -#define MP_BC_MAKE_FUNCTION (0x90) // uint -#define MP_BC_MAKE_CLOSURE (0x91) // uint -#define MP_BC_CALL_FUNCTION (0x92) // uint -#define MP_BC_CALL_FUNCTION_VAR (0x93) // uint -#define MP_BC_CALL_FUNCTION_KW (0x94) // uint -#define MP_BC_CALL_FUNCTION_VAR_KW (0x95) // uint -#define MP_BC_CALL_METHOD (0x96) // uint -#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_MAKE_CLOSURE_DEFARGS (0x9b) // uint +#define MP_BC_MAKE_FUNCTION (0x90) // uint +#define MP_BC_MAKE_FUNCTION_DEFARGS (0x91) // uint +#define MP_BC_MAKE_CLOSURE (0x92) // uint +#define MP_BC_MAKE_CLOSURE_DEFARGS (0x93) // uint +#define MP_BC_CALL_FUNCTION (0x94) // uint +#define MP_BC_CALL_FUNCTION_VAR_KW (0x95) // uint +#define MP_BC_CALL_METHOD (0x96) // uint +#define MP_BC_CALL_METHOD_VAR_KW (0x97) // uint #define MP_BC_IMPORT_NAME (0xe0) // qstr #define MP_BC_IMPORT_FROM (0xe1) // qstr diff --git a/py/emitbc.c b/py/emitbc.c index a149582c0d..595c7ac196 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -399,6 +399,11 @@ STATIC void emit_bc_load_const_verbatim_str(emit_t *emit, const char *str) { assert(0); } +STATIC void emit_bc_load_null(emit_t *emit) { + emit_bc_pre(emit, 1); + emit_write_byte_code_byte(emit, MP_BC_LOAD_NULL); +}; + STATIC void emit_bc_load_fast(emit_t *emit, qstr qstr, int local_num) { assert(local_num >= 0); emit_bc_pre(emit, 1); @@ -748,56 +753,30 @@ STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaul } } -STATIC void emit_bc_call_function(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { - int s = 0; - if (have_star_arg) { - s += 1; - } - if (have_dbl_star_arg) { - s += 1; - } - emit_bc_pre(emit, -n_positional - 2 * n_keyword - s); - int op; - if (have_star_arg) { - if (have_dbl_star_arg) { - op = MP_BC_CALL_FUNCTION_VAR_KW; - } else { - op = MP_BC_CALL_FUNCTION_VAR; +STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, uint bytecode_base, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { + if (have_star_arg || have_dbl_star_arg) { + if (!have_star_arg) { + // load dummy entry for non-existent pos_seq + emit_bc_load_null(emit); + emit_bc_rot_two(emit); + } else if (!have_dbl_star_arg) { + // load dummy entry for non-existent kw_dict + emit_bc_load_null(emit); } + emit_bc_pre(emit, stack_adj - n_positional - 2 * n_keyword - 2); + emit_write_byte_code_byte_uint(emit, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? } else { - if (have_dbl_star_arg) { - op = MP_BC_CALL_FUNCTION_KW; - } else { - op = MP_BC_CALL_FUNCTION; - } + emit_bc_pre(emit, stack_adj - n_positional - 2 * n_keyword); + emit_write_byte_code_byte_uint(emit, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? } - emit_write_byte_code_byte_uint(emit, op, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints +} + +STATIC void emit_bc_call_function(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { + emit_bc_call_function_method_helper(emit, 0, MP_BC_CALL_FUNCTION, n_positional, n_keyword, have_star_arg, have_dbl_star_arg); } STATIC void emit_bc_call_method(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { - int s = 0; - if (have_star_arg) { - s += 1; - } - if (have_dbl_star_arg) { - s += 1; - } - emit_bc_pre(emit, -1 - n_positional - 2 * n_keyword - s); - int op; - if (have_star_arg) { - if (have_dbl_star_arg) { - op = MP_BC_CALL_METHOD_VAR_KW; - } else { - op = MP_BC_CALL_METHOD_VAR; - } - } else { - if (have_dbl_star_arg) { - op = MP_BC_CALL_METHOD_KW; - } else { - op = MP_BC_CALL_METHOD; - } - } - emit_write_byte_code_byte_uint(emit, op, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints + emit_bc_call_function_method_helper(emit, -1, MP_BC_CALL_METHOD, n_positional, n_keyword, have_star_arg, have_dbl_star_arg); } STATIC void emit_bc_return_value(emit_t *emit) { diff --git a/py/runtime.c b/py/runtime.c index 4898864962..7e02879455 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -505,7 +505,7 @@ mp_obj_t mp_call_method_n_kw(uint n_args, uint n_kw, const mp_obj_t *args) { return mp_call_function_n_kw(args[0], n_args + adjust, n_kw, args + 2 - adjust); } -mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_t *args, mp_obj_t pos_seq, mp_obj_t kw_dict) { +mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_t *args) { mp_obj_t fun = *args++; mp_obj_t self = MP_OBJ_NULL; if (have_self) { @@ -513,6 +513,8 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_ } uint n_args = n_args_n_kw & 0xff; uint n_kw = (n_args_n_kw >> 8) & 0xff; + mp_obj_t pos_seq = args[n_args + 2 * n_kw]; // map be MP_OBJ_NULL + mp_obj_t kw_dict = args[n_args + 2 * n_kw + 1]; // map be MP_OBJ_NULL DEBUG_OP_printf("call method var (fun=%p, self=%p, n_args=%u, n_kw=%u, args=%p, seq=%p, dict=%p)\n", fun, self, n_args, n_kw, args, pos_seq, kw_dict); diff --git a/py/runtime.h b/py/runtime.h index f79cb2e306..d71e045b01 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -43,7 +43,7 @@ mp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); mp_obj_t mp_call_function_n_kw_for_native(mp_obj_t fun_in, uint n_args_kw, const mp_obj_t *args); mp_obj_t mp_call_function_n_kw(mp_obj_t fun, uint n_args, uint n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_n_kw(uint n_args, uint n_kw, const mp_obj_t *args); -mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_t *args, mp_obj_t pos_seq, mp_obj_t kw_dict); +mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_t *args); mp_obj_t mp_build_tuple(int n_args, mp_obj_t *items); mp_obj_t mp_build_list(int n_args, mp_obj_t *items); diff --git a/py/showbc.c b/py/showbc.c index 10b3e7490d..823769c0ef 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -399,16 +399,6 @@ void mp_byte_code_print(const byte *ip, int len) { printf("CALL_FUNCTION n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); break; - case MP_BC_CALL_FUNCTION_VAR: - DECODE_UINT; - printf("CALL_FUNCTION_VAR n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); - break; - - case MP_BC_CALL_FUNCTION_KW: - DECODE_UINT; - printf("CALL_FUNCTION_KW n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); - break; - case MP_BC_CALL_FUNCTION_VAR_KW: DECODE_UINT; printf("CALL_FUNCTION_VAR_KW n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); @@ -419,16 +409,6 @@ void mp_byte_code_print(const byte *ip, int len) { printf("CALL_METHOD n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); break; - case MP_BC_CALL_METHOD_VAR: - DECODE_UINT; - printf("CALL_METHOD_VAR n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); - break; - - case MP_BC_CALL_METHOD_KW: - DECODE_UINT; - printf("CALL_METHOD_KW n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); - break; - case MP_BC_CALL_METHOD_VAR_KW: DECODE_UINT; printf("CALL_METHOD_VAR_KW n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); diff --git a/py/vm.c b/py/vm.c index edcad39565..599a1d862e 100644 --- a/py/vm.c +++ b/py/vm.c @@ -220,6 +220,10 @@ dispatch_loop: PUSH(mp_load_const_str(qst)); break; + case MP_BC_LOAD_NULL: + PUSH(MP_OBJ_NULL); + break; + case MP_BC_LOAD_FAST_0: PUSH(fastn[0]); break; @@ -671,38 +675,14 @@ unwind_jump: SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); break; - case MP_BC_CALL_FUNCTION_VAR: - DECODE_UINT; - // unum & 0xff == n_positional - // (unum >> 8) & 0xff == n_keyword - // We have folowing stack layout here: - // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq <- TOS - obj1 = POP(); - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); - SET_TOP(mp_call_method_n_kw_var(false, unum, sp, obj1, MP_OBJ_NULL)); - break; - - case MP_BC_CALL_FUNCTION_KW: - DECODE_UINT; - // unum & 0xff == n_positional - // (unum >> 8) & 0xff == n_keyword - // We have folowing stack layout here: - // fun arg0 arg1 ... kw0 val0 kw1 val1 ... dict <- TOS - obj1 = POP(); - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); - SET_TOP(mp_call_method_n_kw_var(false, unum, sp, MP_OBJ_NULL, obj1)); - break; - case MP_BC_CALL_FUNCTION_VAR_KW: DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword // We have folowing stack layout here: // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS - obj2 = POP(); - obj1 = POP(); - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); - SET_TOP(mp_call_method_n_kw_var(false, unum, sp, obj1, obj2)); + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 2; + SET_TOP(mp_call_method_n_kw_var(false, unum, sp)); break; case MP_BC_CALL_METHOD: @@ -713,38 +693,14 @@ unwind_jump: SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); break; - case MP_BC_CALL_METHOD_VAR: - DECODE_UINT; - // unum & 0xff == n_positional - // (unum >> 8) & 0xff == n_keyword - // We have folowing stack layout here: - // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq <- TOS - obj1 = POP(); - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; - SET_TOP(mp_call_method_n_kw_var(true, unum, sp, obj1, MP_OBJ_NULL)); - break; - - case MP_BC_CALL_METHOD_KW: - DECODE_UINT; - // unum & 0xff == n_positional - // (unum >> 8) & 0xff == n_keyword - // We have folowing stack layout here: - // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... dict <- TOS - obj1 = POP(); - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; - SET_TOP(mp_call_method_n_kw_var(true, unum, sp, MP_OBJ_NULL, obj1)); - break; - case MP_BC_CALL_METHOD_VAR_KW: DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword // We have folowing stack layout here: // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS - obj2 = POP(); - obj1 = POP(); - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; - SET_TOP(mp_call_method_n_kw_var(true, unum, sp, obj1, obj2)); + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 3; + SET_TOP(mp_call_method_n_kw_var(true, unum, sp)); break; case MP_BC_RETURN_VALUE: