From 9ecbcfff994621aa17fdbb5bf2f0c6710e54ea4c Mon Sep 17 00:00:00 2001 From: Damien Date: Wed, 11 Dec 2013 00:41:43 +0000 Subject: [PATCH] py: work towards working closures. --- py/bc.h | 29 ++++++++++++---------- py/compile.c | 43 +++++++++++++++++++++++++++------ py/emit.h | 8 +++---- py/emitbc.c | 59 ++++++++++++++++++++++----------------------- py/emitcpy.c | 64 ++++++++++++++++++++++++------------------------- py/emitnative.c | 50 +++++++++++++++++++------------------- py/runtime.c | 53 ++++++++++++++++++++++++++++++++++++---- py/runtime.h | 8 ++++++- py/scope.c | 1 + py/scope.h | 6 ++++- py/vm.c | 21 ++++++++++++++++ 11 files changed, 224 insertions(+), 118 deletions(-) diff --git a/py/bc.h b/py/bc.h index 455d5054f6..6dc1dbbd4e 100644 --- a/py/bc.h +++ b/py/bc.h @@ -12,25 +12,28 @@ #define PYBC_LOAD_FAST_1 (0x21) #define PYBC_LOAD_FAST_2 (0x22) #define PYBC_LOAD_FAST_N (0x23) // uint -#define PYBC_LOAD_NAME (0x24) // qstr -#define PYBC_LOAD_GLOBAL (0x25) // qstr -#define PYBC_LOAD_ATTR (0x26) // qstr -#define PYBC_LOAD_METHOD (0x27) // qstr -#define PYBC_LOAD_BUILD_CLASS (0x28) +#define PYBC_LOAD_DEREF (0x24) // uint +#define PYBC_LOAD_CLOSURE (0x25) // uint +#define PYBC_LOAD_NAME (0x26) // qstr +#define PYBC_LOAD_GLOBAL (0x27) // qstr +#define PYBC_LOAD_ATTR (0x28) // qstr +#define PYBC_LOAD_METHOD (0x29) // qstr +#define PYBC_LOAD_BUILD_CLASS (0x2a) #define PYBC_STORE_FAST_0 (0x30) #define PYBC_STORE_FAST_1 (0x31) #define PYBC_STORE_FAST_2 (0x32) #define PYBC_STORE_FAST_N (0x33) // uint -#define PYBC_STORE_NAME (0x34) // qstr -#define PYBC_STORE_GLOBAL (0x35) // qstr -#define PYBC_STORE_ATTR (0x36) // qstr -#define PYBC_STORE_SUBSCR (0x37) +#define PYBC_STORE_DEREF (0x34) // uint +#define PYBC_STORE_NAME (0x35) // qstr +#define PYBC_STORE_GLOBAL (0x36) // qstr +#define PYBC_STORE_ATTR (0x37) // qstr +#define PYBC_STORE_SUBSCR (0x38) #define PYBC_DELETE_FAST_N (0x39) // uint -#define PYBC_DELETE_NAME (0x3a) // qstr -#define PYBC_DELETE_GLOBAL (0x3b) // qstr -#define PYBC_DELETE_DEREF (0x3c) // qstr +#define PYBC_DELETE_DEREF (0x3a) // uint +#define PYBC_DELETE_NAME (0x3b) // qstr +#define PYBC_DELETE_GLOBAL (0x3c) // qstr #define PYBC_DELETE_ATTR (0x3d) // qstr #define PYBC_DELETE_SUBSCR (0x3e) @@ -80,7 +83,7 @@ #define PYBC_YIELD_FROM (0x83) #define PYBC_MAKE_FUNCTION (0x90) // uint -#define PYBC_MAKE_CLOSURE (0x91) // uint? +#define PYBC_MAKE_CLOSURE (0x91) // uint #define PYBC_CALL_FUNCTION (0x92) // uint #define PYBC_CALL_FUNCTION_VAR (0x93) // uint #define PYBC_CALL_FUNCTION_KW (0x94) // uint diff --git a/py/compile.c b/py/compile.c index 17aa20d249..2fd0d6ed14 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2842,9 +2842,7 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { // in functions, turn implicit globals into explicit globals // compute num_locals, and the index of each local - // compute the index of free and cell vars (freevars[idx] in CPython) scope->num_locals = 0; - int num_closed = 0; for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; if (scope->kind == SCOPE_CLASS && id->qstr == comp->qstr___class__) { @@ -2854,16 +2852,47 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; } + // note: params always count for 1 local, even if they are a cell if (id->param || id->kind == ID_INFO_KIND_LOCAL) { id->local_num = scope->num_locals; scope->num_locals += 1; - } else if (id->kind == ID_INFO_KIND_CELL) { + } + } + + // compute the index of cell vars (freevars[idx] in CPython) + int num_closed = 0; + for (int i = 0; i < scope->id_info_len; i++) { + id_info_t *id = &scope->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL) { id->local_num = num_closed; +#if !MICROPY_EMIT_CPYTHON + // the cells come right after the fast locals (CPython doesn't add this offset) + id->local_num += scope->num_locals; +#endif num_closed += 1; - } else if (id->kind == ID_INFO_KIND_FREE) { - id_info_t *id_parent = scope_find_local_in_parent(scope, id->qstr); - assert(id_parent != NULL); // should never be NULL - id->local_num = id_parent->local_num; + } + } + scope->num_cells = num_closed; + + // compute the index of free vars (freevars[idx] in CPython) + // make sure they are in the order of the parent scope + if (scope->parent != NULL) { + int num_free = 0; + for (int i = 0; i < scope->parent->id_info_len; i++) { + id_info_t *id = &scope->parent->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) { + for (int j = 0; j < scope->id_info_len; j++) { + id_info_t *id2 = &scope->id_info[j]; + if (id2->kind == ID_INFO_KIND_FREE && id->qstr == id2->qstr) { + id2->local_num = num_closed + num_free; +#if !MICROPY_EMIT_CPYTHON + // the frees come right after the cells (CPython doesn't add this offset) + id2->local_num += scope->num_locals; +#endif + num_free += 1; + } + } + } } } diff --git a/py/emit.h b/py/emit.h index a04acf537d..fdfe76437b 100644 --- a/py/emit.h +++ b/py/emit.h @@ -45,24 +45,24 @@ typedef struct _emit_method_table_t { void (*load_const_verbatim_quoted_str)(emit_t *emit, qstr qstr, bool bytes); void (*load_const_verbatim_end)(emit_t *emit); void (*load_fast)(emit_t *emit, qstr qstr, int local_num); - void (*load_name)(emit_t *emit, qstr qstr); - void (*load_global)(emit_t *emit, qstr qstr); void (*load_deref)(emit_t *emit, qstr qstr, int local_num); void (*load_closure)(emit_t *emit, qstr qstr, int local_num); + void (*load_name)(emit_t *emit, qstr qstr); + void (*load_global)(emit_t *emit, qstr qstr); void (*load_attr)(emit_t *emit, qstr qstr); void (*load_method)(emit_t *emit, qstr qstr); void (*load_build_class)(emit_t *emit); void (*store_fast)(emit_t *emit, qstr qstr, int local_num); + void (*store_deref)(emit_t *emit, qstr qstr, int local_num); void (*store_name)(emit_t *emit, qstr qstr); void (*store_global)(emit_t *emit, qstr qstr); - void (*store_deref)(emit_t *emit, qstr qstr, int local_num); void (*store_attr)(emit_t *emit, qstr qstr); void (*store_subscr)(emit_t *emit); void (*store_locals)(emit_t *emit); void (*delete_fast)(emit_t *emit, qstr qstr, int local_num); + void (*delete_deref)(emit_t *emit, qstr qstr, int local_num); void (*delete_name)(emit_t *emit, qstr qstr); void (*delete_global)(emit_t *emit, qstr qstr); - void (*delete_deref)(emit_t *emit, qstr qstr, int local_num); void (*delete_attr)(emit_t *emit, qstr qstr); void (*delete_subscr)(emit_t *emit); void (*dup_top)(emit_t *emit); diff --git a/py/emitbc.c b/py/emitbc.c index 7d02e439e2..880c10807e 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -75,7 +75,7 @@ static void emit_bc_end_pass(emit_t *emit) { emit->code_base = m_new(byte, emit->code_size); } else if (emit->pass == PASS_3) { - rt_assign_byte_code(emit->scope->unique_code_id, emit->code_base, emit->code_size, emit->scope->num_params, emit->scope->num_locals, emit->scope->stack_size, (emit->scope->flags & SCOPE_FLAG_GENERATOR) != 0); + rt_assign_byte_code(emit->scope->unique_code_id, emit->code_base, emit->code_size, emit->scope->num_params, emit->scope->num_locals, emit->scope->num_cells, emit->scope->stack_size, (emit->scope->flags & SCOPE_FLAG_GENERATOR) != 0); } } @@ -302,6 +302,16 @@ static void emit_bc_load_fast(emit_t *emit, qstr qstr, int local_num) { } } +static void emit_bc_load_deref(emit_t *emit, qstr qstr, int local_num) { + emit_pre(emit, 1); + emit_write_byte_1_uint(emit, PYBC_LOAD_DEREF, local_num); +} + +static void emit_bc_load_closure(emit_t *emit, qstr qstr, int local_num) { + emit_pre(emit, 1); + emit_write_byte_1_uint(emit, PYBC_LOAD_CLOSURE, local_num); +} + static void emit_bc_load_name(emit_t *emit, qstr qstr) { emit_pre(emit, 1); emit_write_byte_1_qstr(emit, PYBC_LOAD_NAME, qstr); @@ -312,16 +322,6 @@ static void emit_bc_load_global(emit_t *emit, qstr qstr) { emit_write_byte_1_qstr(emit, PYBC_LOAD_GLOBAL, qstr); } -static void emit_bc_load_deref(emit_t *emit, qstr qstr, int local_num) { - emit_pre(emit, 1); - assert(0); -} - -static void emit_bc_load_closure(emit_t *emit, qstr qstr, int local_num) { - emit_pre(emit, 1); - assert(0); -} - static void emit_bc_load_attr(emit_t *emit, qstr qstr) { emit_pre(emit, 0); emit_write_byte_1_qstr(emit, PYBC_LOAD_ATTR, qstr); @@ -348,6 +348,11 @@ static void emit_bc_store_fast(emit_t *emit, qstr qstr, int local_num) { } } +static void emit_bc_store_deref(emit_t *emit, qstr qstr, int local_num) { + emit_pre(emit, -1); + emit_write_byte_1_uint(emit, PYBC_STORE_DEREF, local_num); +} + static void emit_bc_store_name(emit_t *emit, qstr qstr) { emit_pre(emit, -1); emit_write_byte_1_qstr(emit, PYBC_STORE_NAME, qstr); @@ -358,11 +363,6 @@ static void emit_bc_store_global(emit_t *emit, qstr qstr) { emit_write_byte_1_qstr(emit, PYBC_STORE_GLOBAL, qstr); } -static void emit_bc_store_deref(emit_t *emit, qstr qstr, int local_num) { - emit_pre(emit, -1); - assert(0); -} - static void emit_bc_store_attr(emit_t *emit, qstr qstr) { emit_pre(emit, -2); emit_write_byte_1_qstr(emit, PYBC_STORE_ATTR, qstr); @@ -385,6 +385,11 @@ static void emit_bc_delete_fast(emit_t *emit, qstr qstr, int local_num) { emit_write_byte_1_uint(emit, PYBC_DELETE_FAST_N, local_num); } +static void emit_bc_delete_deref(emit_t *emit, qstr qstr, int local_num) { + emit_pre(emit, 0); + emit_write_byte_1_qstr(emit, PYBC_DELETE_DEREF, local_num); +} + static void emit_bc_delete_name(emit_t *emit, qstr qstr) { emit_pre(emit, 0); emit_write_byte_1_qstr(emit, PYBC_DELETE_NAME, qstr); @@ -395,12 +400,6 @@ static void emit_bc_delete_global(emit_t *emit, qstr qstr) { emit_write_byte_1_qstr(emit, PYBC_DELETE_GLOBAL, qstr); } -static void emit_bc_delete_deref(emit_t *emit, qstr qstr, int local_num) { - emit_pre(emit, 0); - assert(0); - //emit_write_byte_1_qstr(emit, PYBC_DELETE_DEREF, qstr); -} - static void emit_bc_delete_attr(emit_t *emit, qstr qstr) { emit_pre(emit, -1); emit_write_byte_1_qstr(emit, PYBC_DELETE_ATTR, qstr); @@ -612,11 +611,9 @@ static void emit_bc_make_function(emit_t *emit, scope_t *scope, int n_dict_param } static void emit_bc_make_closure(emit_t *emit, scope_t *scope, int n_dict_params, int n_default_params) { - assert(0); - emit_pre(emit, -2 - n_default_params - 2 * n_dict_params); - if (emit->pass == PASS_3) { - printf("MAKE_CLOSURE %d\n", (n_dict_params << 8) | n_default_params); - } + assert(n_default_params == 0 && n_dict_params == 0); + emit_pre(emit, 0); + emit_write_byte_1_uint(emit, PYBC_MAKE_CLOSURE, scope->unique_code_id); } static void emit_bc_call_function(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { @@ -728,24 +725,24 @@ const emit_method_table_t emit_bc_method_table = { emit_bc_load_const_verbatim_quoted_str, emit_bc_load_const_verbatim_end, emit_bc_load_fast, - emit_bc_load_name, - emit_bc_load_global, emit_bc_load_deref, emit_bc_load_closure, + emit_bc_load_name, + emit_bc_load_global, emit_bc_load_attr, emit_bc_load_method, emit_bc_load_build_class, emit_bc_store_fast, + emit_bc_store_deref, emit_bc_store_name, emit_bc_store_global, - emit_bc_store_deref, emit_bc_store_attr, emit_bc_store_subscr, emit_bc_store_locals, emit_bc_delete_fast, + emit_bc_delete_deref, emit_bc_delete_name, emit_bc_delete_global, - emit_bc_delete_deref, emit_bc_delete_attr, emit_bc_delete_subscr, emit_bc_dup_top, diff --git a/py/emitcpy.c b/py/emitcpy.c index 428e6fd00a..a1d03ec4c1 100644 --- a/py/emitcpy.c +++ b/py/emitcpy.c @@ -265,20 +265,6 @@ static void emit_cpy_load_fast(emit_t *emit, qstr qstr, int local_num) { } } -static void emit_cpy_load_name(emit_t *emit, qstr qstr) { - emit_pre(emit, 1, 3); - if (emit->pass == PASS_3) { - printf("LOAD_NAME %s\n", qstr_str(qstr)); - } -} - -static void emit_cpy_load_global(emit_t *emit, qstr qstr) { - emit_pre(emit, 1, 3); - if (emit->pass == PASS_3) { - printf("LOAD_GLOBAL %s\n", qstr_str(qstr)); - } -} - static void emit_cpy_load_deref(emit_t *emit, qstr qstr, int local_num) { emit_pre(emit, 1, 3); if (emit->pass == PASS_3) { @@ -293,6 +279,20 @@ static void emit_cpy_load_closure(emit_t *emit, qstr qstr, int local_num) { } } +static void emit_cpy_load_name(emit_t *emit, qstr qstr) { + emit_pre(emit, 1, 3); + if (emit->pass == PASS_3) { + printf("LOAD_NAME %s\n", qstr_str(qstr)); + } +} + +static void emit_cpy_load_global(emit_t *emit, qstr qstr) { + emit_pre(emit, 1, 3); + if (emit->pass == PASS_3) { + printf("LOAD_GLOBAL %s\n", qstr_str(qstr)); + } +} + static void emit_cpy_load_attr(emit_t *emit, qstr qstr) { emit_pre(emit, 0, 3); if (emit->pass == PASS_3) { @@ -318,6 +318,13 @@ static void emit_cpy_store_fast(emit_t *emit, qstr qstr, int local_num) { } } +static void emit_cpy_store_deref(emit_t *emit, qstr qstr, int local_num) { + emit_pre(emit, -1, 3); + if (emit->pass == PASS_3) { + printf("STORE_DEREF %d %s\n", local_num, qstr_str(qstr)); + } +} + static void emit_cpy_store_name(emit_t *emit, qstr qstr) { emit_pre(emit, -1, 3); if (emit->pass == PASS_3) { @@ -332,13 +339,6 @@ static void emit_cpy_store_global(emit_t *emit, qstr qstr) { } } -static void emit_cpy_store_deref(emit_t *emit, qstr qstr, int local_num) { - emit_pre(emit, -1, 3); - if (emit->pass == PASS_3) { - printf("STORE_DEREF %d %s\n", local_num, qstr_str(qstr)); - } -} - static void emit_cpy_store_attr(emit_t *emit, qstr qstr) { emit_pre(emit, -2, 3); if (emit->pass == PASS_3) { @@ -367,6 +367,13 @@ static void emit_cpy_delete_fast(emit_t *emit, qstr qstr, int local_num) { } } +static void emit_cpy_delete_deref(emit_t *emit, qstr qstr, int local_num) { + emit_pre(emit, 0, 3); + if (emit->pass == PASS_3) { + printf("DELETE_DEREF %d %s\n", local_num, qstr_str(qstr)); + } +} + static void emit_cpy_delete_name(emit_t *emit, qstr qstr) { emit_pre(emit, 0, 3); if (emit->pass == PASS_3) { @@ -381,13 +388,6 @@ static void emit_cpy_delete_global(emit_t *emit, qstr qstr) { } } -static void emit_cpy_delete_deref(emit_t *emit, qstr qstr, int local_num) { - emit_pre(emit, 0, 3); - if (emit->pass == PASS_3) { - printf("DELETE_DEREF %d %s\n", local_num, qstr_str(qstr)); - } -} - static void emit_cpy_delete_attr(emit_t *emit, qstr qstr) { emit_pre(emit, -1, 3); if (emit->pass == PASS_3) { @@ -852,24 +852,24 @@ const emit_method_table_t emit_cpython_method_table = { emit_cpy_load_const_verbatim_quoted_str, emit_cpy_load_const_verbatim_end, emit_cpy_load_fast, - emit_cpy_load_name, - emit_cpy_load_global, emit_cpy_load_deref, emit_cpy_load_closure, + emit_cpy_load_name, + emit_cpy_load_global, emit_cpy_load_attr, emit_cpy_load_method, emit_cpy_load_build_class, emit_cpy_store_fast, + emit_cpy_store_deref, emit_cpy_store_name, emit_cpy_store_global, - emit_cpy_store_deref, emit_cpy_store_attr, emit_cpy_store_subscr, emit_cpy_store_locals, emit_cpy_delete_fast, + emit_cpy_delete_deref, emit_cpy_delete_name, emit_cpy_delete_global, - emit_cpy_delete_deref, emit_cpy_delete_attr, emit_cpy_delete_subscr, emit_cpy_dup_top, diff --git a/py/emitnative.c b/py/emitnative.c index 52805d90ce..29acee9e83 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -688,6 +688,17 @@ static void emit_native_load_fast(emit_t *emit, qstr qstr, int local_num) { #endif } +static void emit_native_load_deref(emit_t *emit, qstr qstr, int local_num) { + // not implemented + // in principle could support this quite easily (ldr r0, [r0, #0]) and then get closed over variables! + assert(0); +} + +static void emit_native_load_closure(emit_t *emit, qstr qstr, int local_num) { + // not implemented + assert(0); +} + static void emit_native_load_name(emit_t *emit, qstr qstr) { emit_pre(emit); emit_call_with_imm_arg(emit, RT_F_LOAD_NAME, rt_load_name, qstr, REG_ARG_1); @@ -700,17 +711,6 @@ static void emit_native_load_global(emit_t *emit, qstr qstr) { emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } -static void emit_native_load_deref(emit_t *emit, qstr qstr, int local_num) { - // not implemented - // in principle could support this quite easily (ldr r0, [r0, #0]) and then get closed over variables! - assert(0); -} - -static void emit_native_load_closure(emit_t *emit, qstr qstr, int local_num) { - // not implemented - assert(0); -} - static void emit_native_load_attr(emit_t *emit, qstr qstr) { // depends on type of subject: // - integer, function, pointer to integers: error @@ -771,6 +771,11 @@ static void emit_native_store_fast(emit_t *emit, qstr qstr, int local_num) { } } +static void emit_native_store_deref(emit_t *emit, qstr qstr, int local_num) { + // not implemented + assert(0); +} + static void emit_native_store_name(emit_t *emit, qstr qstr) { // rt_store_name, but needs conversion of object (maybe have rt_viper_store_name(obj, type)) vtype_kind_t vtype; @@ -785,11 +790,6 @@ static void emit_native_store_global(emit_t *emit, qstr qstr) { assert(0); } -static void emit_native_store_deref(emit_t *emit, qstr qstr, int local_num) { - // not implemented - assert(0); -} - static void emit_native_store_attr(emit_t *emit, qstr qstr) { vtype_kind_t vtype_base, vtype_val; emit_pre_pop_reg_reg(emit, &vtype_base, REG_ARG_1, &vtype_val, REG_ARG_3); // arg1 = base, arg3 = value @@ -825,6 +825,11 @@ static void emit_native_delete_fast(emit_t *emit, qstr qstr, int local_num) { assert(0); } +static void emit_native_delete_deref(emit_t *emit, qstr qstr, int local_num) { + // not supported + assert(0); +} + static void emit_native_delete_name(emit_t *emit, qstr qstr) { // not implemented // use rt_delete_name @@ -837,11 +842,6 @@ static void emit_native_delete_global(emit_t *emit, qstr qstr) { assert(0); } -static void emit_native_delete_deref(emit_t *emit, qstr qstr, int local_num) { - // not supported - assert(0); -} - static void emit_native_delete_attr(emit_t *emit, qstr qstr) { // not supported assert(0); @@ -1280,24 +1280,24 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_load_const_verbatim_quoted_str, emit_native_load_const_verbatim_end, emit_native_load_fast, - emit_native_load_name, - emit_native_load_global, emit_native_load_deref, emit_native_load_closure, + emit_native_load_name, + emit_native_load_global, emit_native_load_attr, emit_native_load_method, emit_native_load_build_class, emit_native_store_fast, + emit_native_store_deref, emit_native_store_name, emit_native_store_global, - emit_native_store_deref, emit_native_store_attr, emit_native_store_subscr, emit_native_store_locals, emit_native_delete_fast, + emit_native_delete_deref, emit_native_delete_name, emit_native_delete_global, - emit_native_delete_deref, emit_native_delete_attr, emit_native_delete_subscr, emit_native_dup_top, diff --git a/py/runtime.c b/py/runtime.c index df69ddf0dd..189d29fa22 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -43,6 +43,7 @@ typedef enum { O_FLOAT, O_COMPLEX, #endif + O_CELL, O_EXCEPTION_0, O_EXCEPTION_N, O_RANGE, @@ -57,6 +58,7 @@ typedef enum { O_GEN_WRAP, O_GEN_INSTANCE, O_BOUND_METH, + O_CLOSURE, O_TUPLE, O_LIST, O_TUPLE_IT, @@ -101,6 +103,7 @@ struct _py_obj_base_t { py_float_t imag; } u_complex; #endif + py_obj_t u_cell; // for O_CELL struct { // for O_EXCEPTION_0 qstr id; } u_exc0; @@ -148,6 +151,10 @@ struct _py_obj_base_t { py_obj_t meth; py_obj_t self; } u_bound_meth; + struct { // for O_CLOSURE + py_obj_t fun; + py_obj_t vars; + } u_closure; struct { // for O_TUPLE, O_LIST machine_uint_t alloc; machine_uint_t len; @@ -382,6 +389,13 @@ py_obj_t py_obj_new_complex(py_float_t real, py_float_t imag) { } #endif +py_obj_t py_obj_new_cell(py_obj_t val) { + py_obj_base_t *o = m_new(py_obj_base_t, 1); + o->kind = O_CELL; + o->u_cell = val; + return (py_obj_t)o; +} + py_obj_t py_obj_new_exception_0(qstr id) { py_obj_base_t *o = m_new(py_obj_base_t, 1); o->kind = O_EXCEPTION_0; @@ -585,6 +599,23 @@ qstr py_obj_get_qstr(py_obj_t arg) { } } +py_obj_t py_obj_get_cell(py_obj_t cell) { + if (IS_O(cell, O_CELL)) { + return ((py_obj_base_t*)cell)->u_cell; + } else { + assert(0); + return py_const_none; + } +} + +void py_obj_set_cell(py_obj_t cell, py_obj_t val) { + if (IS_O(cell, O_CELL)) { + ((py_obj_base_t*)cell)->u_cell = val; + } else { + assert(0); + } +} + py_obj_t *py_obj_get_array_fixed_n(py_obj_t o_in, machine_int_t n) { if (IS_O(o_in, O_TUPLE) || IS_O(o_in, O_LIST)) { py_obj_base_t *o = o_in; @@ -879,6 +910,7 @@ typedef struct _py_code_t { py_code_kind_t kind; int n_args; int n_locals; + int n_cells; int n_stack; bool is_generator; union { @@ -1078,19 +1110,20 @@ static void alloc_unique_codes(void) { } } -void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator) { +void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_cells, int n_stack, bool is_generator) { alloc_unique_codes(); assert(unique_code_id < next_unique_code_id); unique_codes[unique_code_id].kind = PY_CODE_BYTE; unique_codes[unique_code_id].n_args = n_args; unique_codes[unique_code_id].n_locals = n_locals; + unique_codes[unique_code_id].n_cells = n_cells; unique_codes[unique_code_id].n_stack = n_stack; unique_codes[unique_code_id].is_generator = is_generator; unique_codes[unique_code_id].u_byte.code = code; unique_codes[unique_code_id].u_byte.len = len; - printf("byte code: %d bytes\n", len); + //printf("byte code: %d bytes\n", len); #ifdef DEBUG_PRINT DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d\n", unique_code_id, code, len, n_args); @@ -1120,6 +1153,7 @@ void rt_assign_native_code(int unique_code_id, py_fun_t fun, uint len, int n_arg unique_codes[unique_code_id].kind = PY_CODE_NATIVE; unique_codes[unique_code_id].n_args = n_args; unique_codes[unique_code_id].n_locals = 0; + unique_codes[unique_code_id].n_cells = 0; unique_codes[unique_code_id].n_stack = 0; unique_codes[unique_code_id].is_generator = false; unique_codes[unique_code_id].u_native.fun = fun; @@ -1153,6 +1187,7 @@ void rt_assign_inline_asm_code(int unique_code_id, py_fun_t fun, uint len, int n unique_codes[unique_code_id].kind = PY_CODE_INLINE_ASM; unique_codes[unique_code_id].n_args = n_args; unique_codes[unique_code_id].n_locals = 0; + unique_codes[unique_code_id].n_cells = 0; unique_codes[unique_code_id].n_stack = 0; unique_codes[unique_code_id].is_generator = false; unique_codes[unique_code_id].u_inline_asm.fun = fun; @@ -1562,7 +1597,7 @@ py_obj_t rt_make_function_from_id(int unique_code_id) { case PY_CODE_BYTE: o->kind = O_FUN_BC; o->u_fun_bc.n_args = c->n_args; - o->u_fun_bc.n_state = c->n_locals + c->n_stack; + o->u_fun_bc.n_state = c->n_locals + c->n_cells + c->n_stack; o->u_fun_bc.code = c->u_byte.code; break; case PY_CODE_NATIVE: @@ -1588,7 +1623,7 @@ py_obj_t rt_make_function_from_id(int unique_code_id) { py_obj_base_t *o2 = m_new(py_obj_base_t, 1); o2->kind = O_GEN_WRAP; // we have at least 3 locals so the bc can write back fast[0,1,2] safely; should improve how this is done - o2->u_gen_wrap.n_state = (c->n_locals < 3 ? 3 : c->n_locals) + c->n_stack; + o2->u_gen_wrap.n_state = ((c->n_locals + c->n_cells) < 3 ? 3 : (c->n_locals + c->n_cells)) + c->n_stack; o2->u_gen_wrap.fun = o; o = o2; } @@ -1634,6 +1669,16 @@ py_obj_t rt_make_function_var(int n_fixed_args, py_fun_var_t f) { return o; } +py_obj_t rt_make_closure_from_id(int unique_code_id, py_obj_t closure_tuple) { + py_obj_t f = rt_make_function_from_id(unique_code_id); + // wrap function in closure object + py_obj_base_t *f2 = m_new(py_obj_base_t, 1); + f2->kind = O_CLOSURE; + f2->u_closure.fun = f; + f2->u_closure.vars = closure_tuple; + return f2; +} + py_obj_t rt_call_function_0(py_obj_t fun) { return rt_call_function_n(fun, 0, NULL); } diff --git a/py/runtime.h b/py/runtime.h index c1d1936bf2..c9b8be500d 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -94,18 +94,23 @@ extern py_obj_t py_const_stop_iteration; // special object indicating end of ite void rt_init(void); void rt_deinit(void); int rt_get_unique_code_id(bool is_main_module); -void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator); +void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_cells, int n_stack, bool is_generator); void rt_assign_native_code(int unique_code_id, py_fun_t f, uint len, int n_args); void rt_assign_inline_asm_code(int unique_code_id, py_fun_t f, uint len, int n_args); void py_obj_print(py_obj_t o); py_obj_t py_obj_new_int(machine_int_t value); py_obj_t py_obj_new_str(qstr qstr); +py_obj_t py_obj_new_cell(py_obj_t val); int rt_is_true(py_obj_t arg); machine_int_t py_obj_get_int(py_obj_t arg); machine_float_t py_obj_get_float(py_obj_t arg); qstr py_obj_get_qstr(py_obj_t arg); + +py_obj_t py_obj_get_cell(py_obj_t cell); +void py_obj_set_cell(py_obj_t cell, py_obj_t val); + py_obj_t *py_obj_get_array_fixed_n(py_obj_t o, machine_int_t n); py_obj_t rt_load_const_dec(qstr qstr); @@ -124,6 +129,7 @@ py_obj_t rt_make_function_1(py_fun_1_t f); py_obj_t rt_make_function_2(py_fun_2_t f); py_obj_t rt_make_function(int n_args, py_fun_t code); py_obj_t rt_make_function_var(int n_fixed_args, py_fun_var_t f); +py_obj_t rt_make_closure_from_id(int unique_code_id, py_obj_t closure_tuple); py_obj_t rt_call_function_0(py_obj_t fun); py_obj_t rt_call_function_1(py_obj_t fun, py_obj_t arg); py_obj_t rt_call_function_2(py_obj_t fun, py_obj_t arg1, py_obj_t arg2); diff --git a/py/scope.c b/py/scope.c index 7f844108e3..d72d130f28 100644 --- a/py/scope.c +++ b/py/scope.c @@ -52,6 +52,7 @@ scope_t *scope_new(scope_kind_t kind, py_parse_node_t pn, uint unique_code_id, u scope->num_dict_params = 0; */ scope->num_locals = 0; + scope->num_cells = 0; scope->unique_code_id = unique_code_id; scope->emit_options = emit_options; diff --git a/py/scope.h b/py/scope.h index 9a04c56f61..f560e3d21a 100644 --- a/py/scope.h +++ b/py/scope.h @@ -11,7 +11,10 @@ typedef struct _id_info_t { bool param; int kind; qstr qstr; - int local_num; // when it's an ID_INFO_KIND_LOCAL this is the unique number of the local + + // when it's an ID_INFO_KIND_LOCAL this is the unique number of the local + // whet it's an ID_INFO_KIND_CELL/FREE this is the unique number of the closed over variable + int local_num; } id_info_t; // taken from python source, Include/code.h @@ -46,6 +49,7 @@ typedef struct _scope_t { int num_dict_params; */ int num_locals; + int num_cells; int stack_size; uint unique_code_id; uint emit_options; diff --git a/py/vm.c b/py/vm.c index fabed0f02e..55c7bd30cd 100644 --- a/py/vm.c +++ b/py/vm.c @@ -120,6 +120,16 @@ bool py_execute_byte_code_2(const byte **ip_in_out, py_obj_t *fastn, py_obj_t ** PUSH(fastn[unum]); break; + case PYBC_LOAD_DEREF: + DECODE_UINT; + PUSH(py_obj_get_cell(fastn[unum])); + break; + + case PYBC_LOAD_CLOSURE: + DECODE_UINT; + PUSH(fastn[unum]); + break; + case PYBC_LOAD_NAME: DECODE_QSTR; PUSH(rt_load_name(qstr)); @@ -162,6 +172,11 @@ bool py_execute_byte_code_2(const byte **ip_in_out, py_obj_t *fastn, py_obj_t ** fastn[unum] = POP(); break; + case PYBC_STORE_DEREF: + DECODE_UINT; + py_obj_set_cell(fastn[unum], POP()); + break; + case PYBC_STORE_NAME: DECODE_QSTR; rt_store_name(qstr, POP()); @@ -382,6 +397,12 @@ bool py_execute_byte_code_2(const byte **ip_in_out, py_obj_t *fastn, py_obj_t ** PUSH(rt_make_function_from_id(unum)); break; + case PYBC_MAKE_CLOSURE: + DECODE_UINT; + obj1 = POP(); + PUSH(rt_make_closure_from_id(unum, obj1)); + break; + case PYBC_CALL_FUNCTION: DECODE_UINT; assert((unum & 0xff00) == 0); // n_keyword