diff --git a/py/compile.c b/py/compile.c index 4d07f2e74..b3a83715e 100644 --- a/py/compile.c +++ b/py/compile.c @@ -13,6 +13,7 @@ #include "scope.h" #include "runtime0.h" #include "emit.h" +#include "emitglue.h" #include "obj.h" #include "compile.h" #include "runtime.h" @@ -213,7 +214,7 @@ STATIC void compile_decrease_except_level(compiler_t *comp) { } STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) { - scope_t *scope = scope_new(kind, pn, comp->source_file, rt_get_unique_code_id(), emit_options); + scope_t *scope = scope_new(kind, pn, comp->source_file, mp_emit_glue_get_unique_code_id(), emit_options); scope->parent = comp->scope_cur; scope->next = NULL; if (comp->scope_head == NULL) { @@ -1149,14 +1150,14 @@ void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->break_label == 0) { - printf("ERROR: cannot break from here\n"); + compile_syntax_error(comp, "'break' outside loop"); } EMIT_ARG(break_loop, comp->break_label, comp->cur_except_level - comp->break_continue_except_level); } void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->continue_label == 0) { - printf("ERROR: cannot continue from here\n"); + compile_syntax_error(comp, "'continue' outside loop"); } EMIT_ARG(continue_loop, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level); } diff --git a/py/emit.h b/py/emit.h index ce0c98ba7..26149983b 100644 --- a/py/emit.h +++ b/py/emit.h @@ -79,7 +79,7 @@ typedef struct _emit_method_table_t { void (*setup_except)(emit_t *emit, int label); void (*setup_finally)(emit_t *emit, int label); void (*end_finally)(emit_t *emit); - void (*get_iter)(emit_t *emit); // tos = getiter(tos) + void (*get_iter)(emit_t *emit); void (*for_iter)(emit_t *emit, int label); void (*for_iter_end)(emit_t *emit); void (*pop_block)(emit_t *emit); diff --git a/py/emitbc.c b/py/emitbc.c index 1516b41e5..ac3fc8009 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -12,6 +12,7 @@ #include "scope.h" #include "runtime0.h" #include "emit.h" +#include "emitglue.h" #include "bc0.h" struct _emit_t { @@ -271,9 +272,9 @@ STATIC void emit_bc_end_pass(emit_t *emit) { for (int i = 0; i < emit->scope->num_params; i++) { arg_names[i] = emit->scope->id_info[i].qstr; } - rt_assign_byte_code(emit->scope->unique_code_id, emit->code_base, + mp_emit_glue_assign_byte_code(emit->scope->unique_code_id, emit->code_base, emit->code_info_size + emit->byte_code_size, - emit->scope->num_params, emit->scope->num_locals, emit->scope->stack_size, + emit->scope->num_params, emit->scope->num_locals, emit->scope->scope_flags, arg_names); } } diff --git a/py/emitglue.c b/py/emitglue.c new file mode 100644 index 000000000..0ab909092 --- /dev/null +++ b/py/emitglue.c @@ -0,0 +1,206 @@ +// This code glues the code emitters to the runtime. + +#include +#include + +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "runtime0.h" +#include "runtime.h" +#include "emitglue.h" + +#if 0 // print debugging info +#define DEBUG_PRINT (1) +#define WRITE_CODE (1) +#define DEBUG_printf DEBUG_printf +#define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__) +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#define DEBUG_OP_printf(...) (void)0 +#endif + +typedef enum { + MP_CODE_NONE, + MP_CODE_BYTE, + MP_CODE_NATIVE, + MP_CODE_INLINE_ASM, +} mp_code_kind_t; + +typedef struct _mp_code_t { + mp_code_kind_t kind : 8; + uint scope_flags : 8; + uint n_args : 16; + union { + struct { + byte *code; + uint len; + } u_byte; + struct { + mp_fun_t fun; + } u_native; + struct { + void *fun; + } u_inline_asm; + }; + qstr *arg_names; +} mp_code_t; + +STATIC machine_uint_t unique_codes_alloc = 0; +STATIC mp_code_t *unique_codes = NULL; +STATIC uint next_unique_code_id; + +void mp_emit_glue_init(void) { + next_unique_code_id = 0; + unique_codes_alloc = 0; + unique_codes = NULL; +} + +void mp_emit_glue_deinit(void) { + m_del(mp_code_t, unique_codes, unique_codes_alloc); +} + +uint mp_emit_glue_get_unique_code_id(void) { + return next_unique_code_id++; +} + +STATIC void mp_emit_glue_alloc_unique_codes(void) { + if (next_unique_code_id > unique_codes_alloc) { + DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id); + // increase size of unique_codes table + unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, next_unique_code_id); + for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) { + unique_codes[i].kind = MP_CODE_NONE; + } + unique_codes_alloc = next_unique_code_id; + } +} + +void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names) { + mp_emit_glue_alloc_unique_codes(); + + assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); + unique_codes[unique_code_id].kind = MP_CODE_BYTE; + unique_codes[unique_code_id].scope_flags = scope_flags; + unique_codes[unique_code_id].n_args = n_args; + unique_codes[unique_code_id].u_byte.code = code; + unique_codes[unique_code_id].u_byte.len = len; + unique_codes[unique_code_id].arg_names = arg_names; + + //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_locals=%d\n", unique_code_id, code, len, n_args, n_locals); + for (int i = 0; i < 128 && i < len; i++) { + if (i > 0 && i % 16 == 0) { + DEBUG_printf("\n"); + } + DEBUG_printf(" %02x", code[i]); + } + DEBUG_printf("\n"); +#if MICROPY_DEBUG_PRINTERS + mp_byte_code_print(code, len); +#endif +#endif +} + +void mp_emit_glue_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) { + mp_emit_glue_alloc_unique_codes(); + + assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); + unique_codes[unique_code_id].kind = MP_CODE_NATIVE; + unique_codes[unique_code_id].scope_flags = 0; + unique_codes[unique_code_id].n_args = n_args; + unique_codes[unique_code_id].u_native.fun = fun; + + //printf("native code: %d bytes\n", len); + +#ifdef DEBUG_PRINT + DEBUG_printf("assign native code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args); + byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code + for (int i = 0; i < 128 && i < len; i++) { + if (i > 0 && i % 16 == 0) { + DEBUG_printf("\n"); + } + DEBUG_printf(" %02x", fun_data[i]); + } + DEBUG_printf("\n"); + +#ifdef WRITE_CODE + if (fp_write_code != NULL) { + fwrite(fun_data, len, 1, fp_write_code); + fflush(fp_write_code); + } +#endif +#endif +} + +void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) { + mp_emit_glue_alloc_unique_codes(); + + assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); + unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM; + unique_codes[unique_code_id].scope_flags = 0; + unique_codes[unique_code_id].n_args = n_args; + unique_codes[unique_code_id].u_inline_asm.fun = fun; + +#ifdef DEBUG_PRINT + DEBUG_printf("assign inline asm code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args); + byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code + for (int i = 0; i < 128 && i < len; i++) { + if (i > 0 && i % 16 == 0) { + DEBUG_printf("\n"); + } + DEBUG_printf(" %02x", fun_data[i]); + } + DEBUG_printf("\n"); + +#ifdef WRITE_CODE + if (fp_write_code != NULL) { + fwrite(fun_data, len, 1, fp_write_code); + } +#endif +#endif +} + +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 >= next_unique_code_id) { + // illegal code id + return mp_const_none; + } + + // make the function, depending on the code kind + mp_code_t *c = &unique_codes[unique_code_id]; + mp_obj_t fun; + switch (c->kind) { + case MP_CODE_BYTE: + fun = mp_obj_new_fun_bc(c->scope_flags, c->arg_names, c->n_args, def_args, c->u_byte.code); + break; + case MP_CODE_NATIVE: + fun = rt_make_function_n(c->n_args, c->u_native.fun); + break; + case MP_CODE_INLINE_ASM: + fun = mp_obj_new_fun_asm(c->n_args, c->u_inline_asm.fun); + break; + default: + assert(0); + fun = mp_const_none; + } + + // check for generator functions and if so wrap in generator object + if ((c->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) { + fun = mp_obj_new_gen_wrap(fun); + } + + return fun; +} + +mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) { + 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, def_args); + // wrap function in closure object + return mp_obj_new_closure(ffun, closure_tuple); +} diff --git a/py/emitglue.h b/py/emitglue.h new file mode 100644 index 000000000..e06578e22 --- /dev/null +++ b/py/emitglue.h @@ -0,0 +1,9 @@ +// These variables and functions glue the code emitters to the runtime. + +void mp_emit_glue_init(void); +void mp_emit_glue_deinit(void); +uint mp_emit_glue_get_unique_code_id(void); +uint mp_emit_glue_get_unique_code(uint unique_code_id); +void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names); +void mp_emit_glue_assign_native_code(uint unique_code_id, void *f, uint len, int n_args); +void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args); diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 55af97f83..9ea2cc24b 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -11,6 +11,7 @@ #include "scope.h" #include "runtime0.h" #include "emit.h" +#include "emitglue.h" #include "asmthumb.h" #if MICROPY_EMIT_INLINE_THUMB @@ -51,7 +52,7 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) { if (emit->pass == PASS_3) { void *f = asm_thumb_get_code(emit->as); - rt_assign_inline_asm_code(emit->scope->unique_code_id, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params); + mp_emit_glue_assign_inline_asm_code(emit->scope->unique_code_id, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params); } } diff --git a/py/emitnative.c b/py/emitnative.c index 75086de15..743c32111 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -30,6 +30,7 @@ #include "scope.h" #include "runtime0.h" #include "emit.h" +#include "emitglue.h" #include "obj.h" #include "runtime.h" @@ -275,10 +276,10 @@ STATIC void emit_native_end_pass(emit_t *emit) { if (emit->pass == PASS_3) { #if N_X64 void *f = asm_x64_get_code(emit->as); - rt_assign_native_code(emit->scope->unique_code_id, f, asm_x64_get_code_size(emit->as), emit->scope->num_params); + mp_emit_glue_assign_native_code(emit->scope->unique_code_id, f, asm_x64_get_code_size(emit->as), emit->scope->num_params); #elif N_THUMB void *f = asm_thumb_get_code(emit->as); - rt_assign_native_code(emit->scope->unique_code_id, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params); + mp_emit_glue_assign_native_code(emit->scope->unique_code_id, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params); #endif } } diff --git a/py/py.mk b/py/py.mk index 2247b6bab..3905aa77d 100644 --- a/py/py.mk +++ b/py/py.mk @@ -35,6 +35,7 @@ PY_O_BASENAME = \ formatfloat.o \ parsenumbase.o \ parsenum.o \ + emitglue.o \ runtime.o \ map.o \ obj.o \ diff --git a/py/runtime.c b/py/runtime.c index 60e975687..762924c20 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1,11 +1,6 @@ -// in principle, rt_xxx functions are called only by vm/native/viper and make assumptions about args -// mp_xxx functions are safer and can be called by anyone -// note that rt_assign_xxx are called only from emit*, and maybe we can rename them to reflect this - #include #include #include -#include #include "nlr.h" #include "misc.h" @@ -16,6 +11,7 @@ #include "parsenum.h" #include "runtime0.h" #include "runtime.h" +#include "emitglue.h" #include "map.h" #include "builtin.h" #include "builtintables.h" @@ -37,36 +33,6 @@ STATIC mp_map_t *map_locals; STATIC mp_map_t *map_globals; STATIC mp_map_t map_builtins; -typedef enum { - MP_CODE_NONE, - MP_CODE_BYTE, - MP_CODE_NATIVE, - MP_CODE_INLINE_ASM, -} mp_code_kind_t; - -typedef struct _mp_code_t { - mp_code_kind_t kind : 8; - uint scope_flags : 8; - uint n_args : 16; - union { - struct { - byte *code; - uint len; - } u_byte; - struct { - mp_fun_t fun; - } u_native; - struct { - void *fun; - } u_inline_asm; - }; - qstr *arg_names; -} mp_code_t; - -STATIC uint next_unique_code_id; -STATIC machine_uint_t unique_codes_alloc = 0; -STATIC mp_code_t *unique_codes = NULL; - #ifdef WRITE_CODE FILE *fp_write_code = NULL; #endif @@ -77,6 +43,8 @@ STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) { } void rt_init(void) { + mp_emit_glue_init(); + // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) map_locals = map_globals = mp_map_new(1); @@ -101,129 +69,21 @@ void rt_init(void) { //sys_path = mp_obj_new_list(0, NULL); //rt_store_attr(m_sys, MP_QSTR_path, sys_path); - // TODO: wastes one mp_code_t structure in mem - next_unique_code_id = 1; // 0 indicates "no code" - unique_codes_alloc = 0; - unique_codes = NULL; - #ifdef WRITE_CODE fp_write_code = fopen("out-code", "wb"); #endif } void rt_deinit(void) { - m_del(mp_code_t, unique_codes, unique_codes_alloc); - mp_map_free(map_globals); - mp_map_deinit(&map_builtins); - mp_module_deinit(); #ifdef WRITE_CODE if (fp_write_code != NULL) { fclose(fp_write_code); } #endif -} - -uint rt_get_unique_code_id(void) { - return next_unique_code_id++; -} - -STATIC void alloc_unique_codes(void) { - if (next_unique_code_id > unique_codes_alloc) { - DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id); - // increase size of unique_codes table - unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, next_unique_code_id); - for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) { - unique_codes[i].kind = MP_CODE_NONE; - } - unique_codes_alloc = next_unique_code_id; - } -} - -void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, uint scope_flags, qstr *arg_names) { - alloc_unique_codes(); - - assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); - unique_codes[unique_code_id].kind = MP_CODE_BYTE; - unique_codes[unique_code_id].scope_flags = scope_flags; - unique_codes[unique_code_id].n_args = n_args; - unique_codes[unique_code_id].u_byte.code = code; - unique_codes[unique_code_id].u_byte.len = len; - unique_codes[unique_code_id].arg_names = arg_names; - - //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_locals=%d n_stack=%d\n", unique_code_id, code, len, n_args, n_locals, n_stack); - for (int i = 0; i < 128 && i < len; i++) { - if (i > 0 && i % 16 == 0) { - DEBUG_printf("\n"); - } - DEBUG_printf(" %02x", code[i]); - } - DEBUG_printf("\n"); -#if MICROPY_DEBUG_PRINTERS - mp_byte_code_print(code, len); -#endif -#endif -} - -void rt_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) { - alloc_unique_codes(); - - assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); - unique_codes[unique_code_id].kind = MP_CODE_NATIVE; - unique_codes[unique_code_id].scope_flags = 0; - unique_codes[unique_code_id].n_args = n_args; - unique_codes[unique_code_id].u_native.fun = fun; - - //printf("native code: %d bytes\n", len); - -#ifdef DEBUG_PRINT - DEBUG_printf("assign native code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args); - byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code - for (int i = 0; i < 128 && i < len; i++) { - if (i > 0 && i % 16 == 0) { - DEBUG_printf("\n"); - } - DEBUG_printf(" %02x", fun_data[i]); - } - DEBUG_printf("\n"); - -#ifdef WRITE_CODE - if (fp_write_code != NULL) { - fwrite(fun_data, len, 1, fp_write_code); - fflush(fp_write_code); - } -#endif -#endif -} - -void rt_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) { - alloc_unique_codes(); - - assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); - unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM; - unique_codes[unique_code_id].scope_flags = 0; - unique_codes[unique_code_id].n_args = n_args; - unique_codes[unique_code_id].u_inline_asm.fun = fun; - -#ifdef DEBUG_PRINT - DEBUG_printf("assign inline asm code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args); - byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code - for (int i = 0; i < 128 && i < len; i++) { - if (i > 0 && i % 16 == 0) { - DEBUG_printf("\n"); - } - DEBUG_printf(" %02x", fun_data[i]); - } - DEBUG_printf("\n"); - -#ifdef WRITE_CODE - if (fp_write_code != NULL) { - fwrite(fun_data, len, 1, fp_write_code); - } -#endif -#endif + mp_map_free(map_globals); + mp_map_deinit(&map_builtins); + mp_module_deinit(); + mp_emit_glue_deinit(); } int rt_is_true(mp_obj_t arg) { @@ -646,47 +506,6 @@ generic_binary_op: return mp_const_none; } -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 - return mp_const_none; - } - - // make the function, depending on the code kind - mp_code_t *c = &unique_codes[unique_code_id]; - mp_obj_t fun; - switch (c->kind) { - case MP_CODE_BYTE: - fun = mp_obj_new_fun_bc(c->scope_flags, c->arg_names, c->n_args, def_args, c->u_byte.code); - break; - case MP_CODE_NATIVE: - fun = rt_make_function_n(c->n_args, c->u_native.fun); - break; - case MP_CODE_INLINE_ASM: - fun = mp_obj_new_fun_asm(c->n_args, c->u_inline_asm.fun); - break; - default: - assert(0); - fun = mp_const_none; - } - - // check for generator functions and if so wrap in generator object - if ((c->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) { - fun = mp_obj_new_gen_wrap(fun); - } - - return fun; -} - -mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) { - 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, def_args); - // wrap function in closure object - return mp_obj_new_closure(ffun, closure_tuple); -} - mp_obj_t rt_call_function_0(mp_obj_t fun) { return rt_call_function_n_kw(fun, 0, 0, NULL); } diff --git a/py/runtime.h b/py/runtime.h index 553a83468..b27d12ff1 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -1,3 +1,6 @@ +void rt_init(void); +void rt_deinit(void); + void rt_check_nargs(int n_args, machine_uint_t n_args_min, machine_uint_t n_args_max, int n_kw, bool is_kw); int rt_is_true(mp_obj_t arg); diff --git a/py/runtime0.h b/py/runtime0.h index 07fcf0705..a650e704a 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -93,10 +93,3 @@ typedef enum { } rt_fun_kind_t; extern void *const rt_fun_table[RT_F_NUMBER_OF]; - -void rt_init(void); -void rt_deinit(void); -uint rt_get_unique_code_id(void); -void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, uint scope_flags, qstr *arg_names); -void rt_assign_native_code(uint unique_code_id, void *f, uint len, int n_args); -void rt_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args); diff --git a/unix-cpy/main.c b/unix-cpy/main.c index 52d63273c..7e2703139 100644 --- a/unix-cpy/main.c +++ b/unix-cpy/main.c @@ -12,7 +12,7 @@ #include "obj.h" #include "parsehelper.h" #include "compile.h" -#include "runtime0.h" +#include "runtime.h" void do_file(const char *file) { mp_lexer_t *lex = mp_lexer_new_from_file(file);