From 9988618e0e0f5c319e31b135d993e22efb593093 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 6 Apr 2015 22:38:53 +0100 Subject: [PATCH] py: Implement full func arg passing for native emitter. This patch gets full function argument passing working with native emitter. Includes named args, keyword args, default args, var args and var keyword args. Fully Python compliant. It reuses the bytecode mp_setup_code_state function to do all the hard work. This function is slightly adjusted to accommodate native calls, and the native emitter is forced a bit to emit similar prelude and code-info as bytecode. --- py/asmthumb.c | 4 + py/asmthumb.h | 1 + py/asmx64.c | 19 +++ py/asmx64.h | 4 + py/asmx86.c | 27 +++- py/asmx86.h | 6 + py/bc.c | 13 +- py/emitglue.c | 11 +- py/emitglue.h | 2 +- py/emitinlinethumb.c | 2 +- py/emitnative.c | 358 +++++++++++++++++++++++-------------------- py/nativeglue.c | 2 + py/obj.h | 2 +- py/objfun.c | 62 +++----- py/objgenerator.c | 3 +- py/runtime0.h | 1 + tests/run-tests | 25 +-- 17 files changed, 307 insertions(+), 235 deletions(-) diff --git a/py/asmthumb.c b/py/asmthumb.c index 5bf2d80bb4..16337f4d5e 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -106,6 +106,10 @@ STATIC byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int num_bytes_to_ } } +uint asm_thumb_get_code_pos(asm_thumb_t *as) { + return as->code_offset; +} + uint asm_thumb_get_code_size(asm_thumb_t *as) { return as->code_size; } diff --git a/py/asmthumb.h b/py/asmthumb.h index 1ce91d38d6..e40f956543 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -70,6 +70,7 @@ asm_thumb_t *asm_thumb_new(uint max_num_labels); void asm_thumb_free(asm_thumb_t *as, bool free_code); void asm_thumb_start_pass(asm_thumb_t *as, uint pass); void asm_thumb_end_pass(asm_thumb_t *as); +uint asm_thumb_get_code_pos(asm_thumb_t *as); uint asm_thumb_get_code_size(asm_thumb_t *as); void *asm_thumb_get_code(asm_thumb_t *as); diff --git a/py/asmx64.c b/py/asmx64.c index d501d2cc8c..05aa0c2f14 100644 --- a/py/asmx64.c +++ b/py/asmx64.c @@ -176,6 +176,10 @@ STATIC byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int num_bytes_to_writ } } +mp_uint_t asm_x64_get_code_pos(asm_x64_t *as) { + return as->code_offset; +} + mp_uint_t asm_x64_get_code_size(asm_x64_t *as) { return as->code_size; } @@ -222,6 +226,21 @@ STATIC void asm_x64_write_word64(asm_x64_t *as, int64_t w64) { c[7] = IMM64_L7(w64); } +// align must be a multiple of 2 +void asm_x64_align(asm_x64_t* as, mp_uint_t align) { + // TODO fill unused data with NOPs? + as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); +} + +void asm_x64_data(asm_x64_t* as, mp_uint_t bytesize, mp_uint_t val) { + byte *c = asm_x64_get_cur_to_write_bytes(as, bytesize); + // machine is little endian + for (uint i = 0; i < bytesize; i++) { + *c++ = val; + val >>= 8; + } +} + /* unused STATIC void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) { byte* c; diff --git a/py/asmx64.h b/py/asmx64.h index cb021b2f3c..0d3af9aa18 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -78,9 +78,13 @@ asm_x64_t* asm_x64_new(mp_uint_t max_num_labels); void asm_x64_free(asm_x64_t* as, bool free_code); void asm_x64_start_pass(asm_x64_t *as, uint pass); void asm_x64_end_pass(asm_x64_t *as); +mp_uint_t asm_x64_get_code_pos(asm_x64_t *as); mp_uint_t asm_x64_get_code_size(asm_x64_t* as); void* asm_x64_get_code(asm_x64_t* as); +void asm_x64_align(asm_x64_t *as, mp_uint_t align); +void asm_x64_data(asm_x64_t *as, mp_uint_t bytesize, mp_uint_t val); + void asm_x64_nop(asm_x64_t* as); void asm_x64_push_r64(asm_x64_t* as, int src_r64); void asm_x64_pop_r64(asm_x64_t* as, int dest_r64); diff --git a/py/asmx86.c b/py/asmx86.c index 3de2f12aa4..8a4383c82d 100644 --- a/py/asmx86.c +++ b/py/asmx86.c @@ -162,6 +162,10 @@ STATIC byte *asm_x86_get_cur_to_write_bytes(asm_x86_t *as, int num_bytes_to_writ } } +mp_uint_t asm_x86_get_code_pos(asm_x86_t *as) { + return as->code_offset; +} + mp_uint_t asm_x86_get_code_size(asm_x86_t *as) { return as->code_size; } @@ -196,6 +200,21 @@ STATIC void asm_x86_write_word32(asm_x86_t *as, int w32) { c[3] = IMM32_L3(w32); } +// align must be a multiple of 2 +void asm_x86_align(asm_x86_t* as, mp_uint_t align) { + // TODO fill unused data with NOPs? + as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); +} + +void asm_x86_data(asm_x86_t* as, mp_uint_t bytesize, mp_uint_t val) { + byte *c = asm_x86_get_cur_to_write_bytes(as, bytesize); + // machine is little endian + for (uint i = 0; i < bytesize; i++) { + *c++ = val; + val >>= 8; + } +} + STATIC void asm_x86_write_r32_disp(asm_x86_t *as, int r32, int disp_r32, int disp_offset) { assert(disp_r32 != ASM_X86_REG_ESP); @@ -541,7 +560,13 @@ void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32) void asm_x86_call_ind(asm_x86_t *as, void *ptr, mp_uint_t n_args, int temp_r32) { // TODO align stack on 16-byte boundary before the call - assert(n_args <= 3); + assert(n_args <= 5); + if (n_args > 4) { + asm_x86_push_r32(as, ASM_X86_REG_ARG_5); + } + if (n_args > 3) { + asm_x86_push_r32(as, ASM_X86_REG_ARG_4); + } if (n_args > 2) { asm_x86_push_r32(as, ASM_X86_REG_ARG_3); } diff --git a/py/asmx86.h b/py/asmx86.h index 544786cf7f..cb245f37d9 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -61,6 +61,8 @@ #define ASM_X86_REG_ARG_1 ASM_X86_REG_EAX #define ASM_X86_REG_ARG_2 ASM_X86_REG_ECX #define ASM_X86_REG_ARG_3 ASM_X86_REG_EDX +#define ASM_X86_REG_ARG_4 ASM_X86_REG_EBX +#define ASM_X86_REG_ARG_5 ASM_X86_REG_ESI // condition codes, used for jcc and setcc (despite their j-name!) #define ASM_X86_CC_JB (0x2) // below, unsigned @@ -79,9 +81,13 @@ asm_x86_t* asm_x86_new(mp_uint_t max_num_labels); void asm_x86_free(asm_x86_t* as, bool free_code); void asm_x86_start_pass(asm_x86_t *as, mp_uint_t pass); void asm_x86_end_pass(asm_x86_t *as); +mp_uint_t asm_x86_get_code_pos(asm_x86_t *as); mp_uint_t asm_x86_get_code_size(asm_x86_t* as); void* asm_x86_get_code(asm_x86_t* as); +void asm_x86_align(asm_x86_t *as, mp_uint_t align); +void asm_x86_data(asm_x86_t *as, mp_uint_t bytesize, mp_uint_t val); + void asm_x86_mov_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32); void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32); diff --git a/py/bc.c b/py/bc.c index 865065ab19..613cce7956 100644 --- a/py/bc.c +++ b/py/bc.c @@ -78,8 +78,13 @@ STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) { #define dump_args(...) (void)0 #endif -// code_state should have ->ip filled in (pointing past code info block), -// as well as ->n_state. +// On entry code_state should be allocated somewhere (stack/heap) and +// contain the following valid entries: +// - code_state->code_info should be the offset in bytes from the start of +// the bytecode chunk to the start of the code-info within the bytecode +// - code_state->ip should contain the offset in bytes from the start of +// the bytecode chunk to the start of the prelude within the bytecode +// - code_state->n_state should be set to the state size (locals plus stack) void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { // This function is pretty complicated. It's main aim is to be efficient in speed and RAM // usage for the common case of positional only args. @@ -89,7 +94,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t #if MICROPY_STACKLESS code_state->prev = NULL; #endif - code_state->code_info = self->bytecode; + code_state->code_info = self->bytecode + (mp_uint_t)code_state->code_info; code_state->sp = &code_state->state[0] - 1; code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1; @@ -227,7 +232,7 @@ continue2:; } // bytecode prelude: initialise closed over variables - const byte *ip = code_state->ip; + const byte *ip = self->bytecode + (mp_uint_t)code_state->ip; mp_uint_t local_num; while ((local_num = *ip++) != 255) { code_state->state[n_state - 1 - local_num] = diff --git a/py/emitglue.c b/py/emitglue.c index b3e8495d94..610e76d534 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -86,16 +86,17 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, } #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB -void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig) { +void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags, mp_uint_t type_sig) { assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM); rc->kind = kind; - rc->scope_flags = 0; - rc->n_pos_args = n_args; + rc->scope_flags = scope_flags; + rc->n_pos_args = n_pos_args; + rc->n_kwonly_args = n_kwonly_args; rc->data.u_native.fun_data = fun_data; rc->data.u_native.type_sig = type_sig; #ifdef DEBUG_PRINT - DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_args=" UINT_FMT "\n", kind, fun_data, fun_len, n_args); + DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, n_kwonly_args, (uint)scope_flags); for (mp_uint_t i = 0; i < fun_len; i++) { if (i > 0 && i % 16 == 0) { DEBUG_printf("\n"); @@ -134,7 +135,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp break; #if MICROPY_EMIT_NATIVE case MP_CODE_NATIVE_PY: - fun = mp_obj_new_fun_native(rc->n_pos_args, rc->data.u_native.fun_data); + fun = mp_obj_new_fun_native(rc->scope_flags, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->data.u_native.fun_data); break; case MP_CODE_NATIVE_VIPER: fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig); diff --git a/py/emitglue.h b/py/emitglue.h index 4e915df2d5..97e680b4c4 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -44,7 +44,7 @@ typedef struct _mp_raw_code_t mp_raw_code_t; mp_raw_code_t *mp_emit_glue_new_raw_code(void); void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags); -void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig); +void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags, mp_uint_t type_sig); mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args); mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args); diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 220ff12c71..59cdc3aca6 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -90,7 +90,7 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) { if (emit->pass == MP_PASS_EMIT) { void *f = asm_thumb_get_code(emit->as); - mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0); + mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0, 0, 0); } } diff --git a/py/emitnative.c b/py/emitnative.c index f72112ba07..ff57ef1a36 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -48,6 +48,7 @@ #include "py/nlr.h" #include "py/emit.h" +#include "py/bc.h" #if 0 // print debugging info #define DEBUG_PRINT (1) @@ -70,11 +71,14 @@ #define EXPORT_FUN(name) emit_native_x64_##name +#define ASM_WORD_SIZE (8) + #define REG_RET ASM_X64_REG_RAX #define REG_ARG_1 ASM_X64_REG_RDI #define REG_ARG_2 ASM_X64_REG_RSI #define REG_ARG_3 ASM_X64_REG_RDX #define REG_ARG_4 ASM_X64_REG_RCX +#define REG_ARG_5 ASM_X64_REG_R08 // caller-save #define REG_TEMP0 ASM_X64_REG_RAX @@ -94,12 +98,16 @@ #define ASM_NEW asm_x64_new #define ASM_FREE asm_x64_free #define ASM_GET_CODE asm_x64_get_code +#define ASM_GET_CODE_POS asm_x64_get_code_pos #define ASM_GET_CODE_SIZE asm_x64_get_code_size #define ASM_START_PASS asm_x64_start_pass #define ASM_END_PASS asm_x64_end_pass #define ASM_ENTRY asm_x64_entry #define ASM_EXIT asm_x64_exit +#define ASM_ALIGN asm_x64_align +#define ASM_DATA asm_x64_data + #define ASM_LABEL_ASSIGN asm_x64_label_assign #define ASM_JUMP asm_x64_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ @@ -202,14 +210,19 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { [MP_F_DELETE_GLOBAL] = 1, [MP_F_NEW_CELL] = 1, [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3, + [MP_F_SETUP_CODE_STATE] = 5, }; #define EXPORT_FUN(name) emit_native_x86_##name +#define ASM_WORD_SIZE (4) + #define REG_RET ASM_X86_REG_EAX #define REG_ARG_1 ASM_X86_REG_ARG_1 #define REG_ARG_2 ASM_X86_REG_ARG_2 #define REG_ARG_3 ASM_X86_REG_ARG_3 +#define REG_ARG_4 ASM_X86_REG_ARG_4 +#define REG_ARG_5 ASM_X86_REG_ARG_5 // caller-save, so can be used as temporaries #define REG_TEMP0 ASM_X86_REG_EAX @@ -229,12 +242,16 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { #define ASM_NEW asm_x86_new #define ASM_FREE asm_x86_free #define ASM_GET_CODE asm_x86_get_code +#define ASM_GET_CODE_POS asm_x86_get_code_pos #define ASM_GET_CODE_SIZE asm_x86_get_code_size #define ASM_START_PASS asm_x86_start_pass #define ASM_END_PASS asm_x86_end_pass #define ASM_ENTRY asm_x86_entry #define ASM_EXIT asm_x86_exit +#define ASM_ALIGN asm_x86_align +#define ASM_DATA asm_x86_data + #define ASM_LABEL_ASSIGN asm_x86_label_assign #define ASM_JUMP asm_x86_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ @@ -292,11 +309,14 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { #define EXPORT_FUN(name) emit_native_thumb_##name +#define ASM_WORD_SIZE (4) + #define REG_RET ASM_THUMB_REG_R0 #define REG_ARG_1 ASM_THUMB_REG_R0 #define REG_ARG_2 ASM_THUMB_REG_R1 #define REG_ARG_3 ASM_THUMB_REG_R2 #define REG_ARG_4 ASM_THUMB_REG_R3 +// rest of args go on stack #define REG_TEMP0 ASM_THUMB_REG_R0 #define REG_TEMP1 ASM_THUMB_REG_R1 @@ -314,12 +334,16 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { #define ASM_NEW asm_thumb_new #define ASM_FREE asm_thumb_free #define ASM_GET_CODE asm_thumb_get_code +#define ASM_GET_CODE_POS asm_thumb_get_code_pos #define ASM_GET_CODE_SIZE asm_thumb_get_code_size #define ASM_START_PASS asm_thumb_start_pass #define ASM_END_PASS asm_thumb_end_pass #define ASM_ENTRY asm_thumb_entry #define ASM_EXIT asm_thumb_exit +#define ASM_ALIGN asm_thumb_align +#define ASM_DATA asm_thumb_data + #define ASM_LABEL_ASSIGN asm_thumb_label_assign #define ASM_JUMP asm_thumb_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ @@ -504,6 +528,10 @@ struct _emit_t { stack_info_t *stack_info; vtype_kind_t saved_stack_vtype; + int code_info_size; + int code_info_offset; + int prelude_offset; + int n_state; int stack_start; int stack_size; @@ -561,6 +589,8 @@ STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg); STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num); STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num); +#define STATE_START (sizeof(mp_code_state) / sizeof(mp_uint_t)) + STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope); @@ -584,14 +614,23 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc); } - // set default type for return and arguments + // set default type for return emit->return_vtype = VTYPE_PYOBJ; - for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) { + + // set default type for arguments + mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_kwonly_args; + if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) { + num_args += 1; + } + if (scope->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) { + num_args += 1; + } + for (mp_uint_t i = 0; i < num_args; i++) { emit->local_vtype[i] = VTYPE_PYOBJ; } // local variables begin unbound, and have unknown type - for (mp_uint_t i = emit->scope->num_pos_args; i < emit->local_vtype_alloc; i++) { + for (mp_uint_t i = num_args; i < emit->local_vtype_alloc; i++) { emit->local_vtype[i] = VTYPE_UNBOUND; } @@ -603,107 +642,157 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop ASM_START_PASS(emit->as, pass == MP_PASS_EMIT ? ASM_PASS_EMIT : ASM_PASS_COMPUTE); - // entry to function - int num_locals = 0; - if (pass > MP_PASS_SCOPE) { - num_locals = scope->num_locals - REG_LOCAL_NUM; - if (num_locals < 0) { - num_locals = 0; - } - emit->stack_start = num_locals; - num_locals += scope->stack_size; - } - ASM_ENTRY(emit->as, num_locals); + // generate code for entry to function - // initialise locals from parameters -#if N_X64 - for (int i = 0; i < scope->num_pos_args; i++) { - if (i == 0) { - ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1); - } else if (i == 1) { - ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2); - } else if (i == 2) { - ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3); - } else if (i == 3) { - asm_x64_mov_r64_to_local(emit->as, REG_ARG_4, i - REG_LOCAL_NUM); - } else { - // TODO not implemented - assert(0); + if (emit->do_viper_types) { + + // entry to function + int num_locals = 0; + if (pass > MP_PASS_SCOPE) { + num_locals = scope->num_locals - REG_LOCAL_NUM; + if (num_locals < 0) { + num_locals = 0; + } + emit->stack_start = num_locals; + num_locals += scope->stack_size; } - } -#elif N_X86 - for (int i = 0; i < scope->num_pos_args; i++) { - if (i == 0) { - asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_1); - } else if (i == 1) { - asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_2); - } else if (i == 2) { - asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_3); - } else { - asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0); - asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, i - REG_LOCAL_NUM); + ASM_ENTRY(emit->as, num_locals); + + #if N_X86 + for (int i = 0; i < scope->num_pos_args; i++) { + if (i == 0) { + asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_1); + } else if (i == 1) { + asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_2); + } else if (i == 2) { + asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_3); + } else { + asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0); + asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, i - REG_LOCAL_NUM); + } } - } -#elif N_THUMB - for (int i = 0; i < scope->num_pos_args; i++) { - if (i == 0) { - ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1); - } else if (i == 1) { - ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2); - } else if (i == 2) { - ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3); - } else if (i == 3) { - asm_thumb_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4); - } else { - // TODO not implemented - assert(0); + #else + for (int i = 0; i < scope->num_pos_args; i++) { + if (i == 0) { + ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1); + } else if (i == 1) { + ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2); + } else if (i == 2) { + ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3); + } else if (i == 3) { + ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_4, i - REG_LOCAL_NUM); + } else { + // TODO not implemented + assert(0); + } + } + #endif + + } else { + // work out size of state (locals plus stack) + emit->n_state = scope->num_locals + scope->stack_size; + + // allocate space on C-stack for code_state structure, which includes state + ASM_ENTRY(emit->as, STATE_START + emit->n_state); + + // prepare incoming arguments for call to mp_setup_code_state + #if N_X86 + asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_2); + asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_3); + asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_4); + asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_5); + #else + #if N_THUMB + ASM_MOV_REG_REG(emit->as, ASM_THUMB_REG_R4, REG_ARG_4); + #else + ASM_MOV_REG_REG(emit->as, REG_ARG_5, REG_ARG_4); + #endif + ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_ARG_3); + ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_ARG_2); + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_ARG_1); + #endif + + // set code_state.code_info (offset from start of this function to code_info data) + // XXX this encoding may change size + ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->code_info_offset, offsetof(mp_code_state, code_info) / sizeof(mp_uint_t), REG_ARG_1); + + // set code_state.ip (offset from start of this function to prelude info) + // XXX this encoding may change size + ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state, ip) / sizeof(mp_uint_t), REG_ARG_1); + + // set code_state.n_state + ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->n_state, offsetof(mp_code_state, n_state) / sizeof(mp_uint_t), REG_ARG_1); + + // put address of code_state into first arg + ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1); + + // call mp_setup_code_state to prepare code_state structure + #if N_THUMB + asm_thumb_op16(emit->as, 0xb400 | (1 << ASM_THUMB_REG_R4)); // push 5th arg + asm_thumb_bl_ind(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4); + asm_thumb_op16(emit->as, 0xbc00 | (1 << REG_RET)); // pop dummy (was 5th arg) + #else + ASM_CALL_IND(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE); + #endif + + // cache some locals in registers + if (scope->num_locals > 0) { + ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 0, REG_LOCAL_1); + if (scope->num_locals > 1) { + ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 1, REG_LOCAL_2); + if (scope->num_locals > 2) { + ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 2, REG_LOCAL_3); + } + } + } + + // set the type of closed over variables + for (mp_uint_t i = 0; i < scope->id_info_len; i++) { + id_info_t *id = &scope->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL) { + emit->local_vtype[id->local_num] = VTYPE_PYOBJ; + } } } + #if N_THUMB // TODO don't load r7 if we don't need it asm_thumb_mov_reg_i32(emit->as, ASM_THUMB_REG_R7, (mp_uint_t)mp_fun_table); -#elif N_ARM - for (int i = 0; i < scope->num_pos_args; i++) { - if (i == 0) { - ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1); - } else if (i == 1) { - ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2); - } else if (i == 2) { - ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3); - } else if (i == 3) { - asm_arm_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4); - } else { - // TODO not implemented - assert(0); - } - } + #endif + #if N_ARM // TODO don't load r7 if we don't need it asm_arm_mov_reg_i32(emit->as, ASM_ARM_REG_R7, (mp_uint_t)mp_fun_table); -#else - #error not implemented -#endif - - // initialise closed over variables - 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) { - if (emit->local_vtype[id->local_num] != VTYPE_UNBOUND) { - emit_native_load_fast(emit, id->qst, id->local_num); - vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, REG_ARG_1); - } - ASM_CALL_IND(emit->as, mp_fun_table[MP_F_NEW_CELL], MP_F_NEW_CELL); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); - emit_native_store_fast(emit, id->qst, id->local_num); - } - } + #endif } STATIC void emit_native_end_pass(emit_t *emit) { if (!emit->last_emit_was_return_value) { ASM_EXIT(emit->as); } + + if (!emit->do_viper_types) { + // write dummy code info (for mp_setup_code_state to parse) and arg names + emit->code_info_offset = ASM_GET_CODE_POS(emit->as); + ASM_DATA(emit->as, 1, emit->code_info_size); + ASM_ALIGN(emit->as, ASM_WORD_SIZE); + emit->code_info_size = ASM_GET_CODE_POS(emit->as) - emit->code_info_offset; + for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) { + ASM_DATA(emit->as, ASM_WORD_SIZE, (mp_uint_t)MP_OBJ_NEW_QSTR(emit->scope->id_info[i].qst)); + } + + // bytecode prelude: initialise closed over variables + emit->prelude_offset = ASM_GET_CODE_POS(emit->as); + for (int i = 0; i < emit->scope->id_info_len; i++) { + id_info_t *id = &emit->scope->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL) { + assert(id->local_num < 255); + ASM_DATA(emit->as, 1, id->local_num); // write the local which should be converted to a cell + } + } + ASM_DATA(emit->as, 1, 255); // end of list sentinel + } + ASM_END_PASS(emit->as); // check stack is back to zero size @@ -722,7 +811,10 @@ STATIC void emit_native_end_pass(emit_t *emit) { type_sig |= (emit->local_vtype[i] & 3) << (i * 2 + 2); } - mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, f_len, emit->scope->num_pos_args, type_sig); + mp_emit_glue_assign_native(emit->scope->raw_code, + emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, + f, f_len, emit->scope->num_pos_args, emit->scope->num_kwonly_args, + emit->scope->scope_flags, type_sig); } } @@ -1199,7 +1291,6 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { printf("ViperTypeError: local %s used before type known\n", qstr_str(qst)); } emit_native_pre(emit); -#if N_X64 if (local_num == 0) { emit_post_push_reg(emit, vtype, REG_LOCAL_1); } else if (local_num == 1) { @@ -1208,48 +1299,13 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { emit_post_push_reg(emit, vtype, REG_LOCAL_3); } else { need_reg_single(emit, REG_TEMP0, 0); - asm_x64_mov_local_to_r64(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); + if (emit->do_viper_types) { + ASM_MOV_LOCAL_TO_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); + } else { + ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0); + } emit_post_push_reg(emit, vtype, REG_TEMP0); } -#elif N_X86 - if (local_num == 0) { - emit_post_push_reg(emit, vtype, REG_LOCAL_1); - } else if (local_num == 1) { - emit_post_push_reg(emit, vtype, REG_LOCAL_2); - } else if (local_num == 2) { - emit_post_push_reg(emit, vtype, REG_LOCAL_3); - } else { - need_reg_single(emit, REG_TEMP0, 0); - asm_x86_mov_local_to_r32(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); - emit_post_push_reg(emit, vtype, REG_TEMP0); - } -#elif N_THUMB - if (local_num == 0) { - emit_post_push_reg(emit, vtype, REG_LOCAL_1); - } else if (local_num == 1) { - emit_post_push_reg(emit, vtype, REG_LOCAL_2); - } else if (local_num == 2) { - emit_post_push_reg(emit, vtype, REG_LOCAL_3); - } else { - need_reg_single(emit, REG_TEMP0, 0); - asm_thumb_mov_reg_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); - emit_post_push_reg(emit, vtype, REG_TEMP0); - } -#elif N_ARM - if (local_num == 0) { - emit_post_push_reg(emit, vtype, REG_LOCAL_1); - } else if (local_num == 1) { - emit_post_push_reg(emit, vtype, REG_LOCAL_2); - } else if (local_num == 2) { - emit_post_push_reg(emit, vtype, REG_LOCAL_3); - } else { - need_reg_single(emit, REG_TEMP0, 0); - asm_arm_mov_reg_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); - emit_post_push_reg(emit, vtype, REG_TEMP0); - } -#else - #error not implemented -#endif } STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { @@ -1417,7 +1473,6 @@ STATIC void emit_native_load_subscr(emit_t *emit) { STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { vtype_kind_t vtype; -#if N_X64 if (local_num == 0) { emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1); } else if (local_num == 1) { @@ -1426,45 +1481,12 @@ STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3); } else { emit_pre_pop_reg(emit, &vtype, REG_TEMP0); - asm_x64_mov_r64_to_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); + if (emit->do_viper_types) { + ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); + } else { + ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num); + } } -#elif N_X86 - if (local_num == 0) { - emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1); - } else if (local_num == 1) { - emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2); - } else if (local_num == 2) { - emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3); - } else { - emit_pre_pop_reg(emit, &vtype, REG_TEMP0); - asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); - } -#elif N_THUMB - if (local_num == 0) { - emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1); - } else if (local_num == 1) { - emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2); - } else if (local_num == 2) { - emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3); - } else { - emit_pre_pop_reg(emit, &vtype, REG_TEMP0); - asm_thumb_mov_local_reg(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); - } -#elif N_ARM - if (local_num == 0) { - emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1); - } else if (local_num == 1) { - emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2); - } else if (local_num == 2) { - emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3); - } else { - emit_pre_pop_reg(emit, &vtype, REG_TEMP0); - asm_arm_mov_local_reg(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); - } -#else - #error not implemented -#endif - emit_post(emit); // check types diff --git a/py/nativeglue.c b/py/nativeglue.c index ab4063014c..d0896eedd3 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -32,6 +32,7 @@ #include "py/runtime0.h" #include "py/runtime.h" #include "py/emitglue.h" +#include "py/bc.h" #if MICROPY_EMIT_NATIVE @@ -135,6 +136,7 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_delete_global, mp_obj_new_cell, mp_make_closure_from_raw_code, + mp_setup_code_state, }; /* diff --git a/py/obj.h b/py/obj.h index b1f173080d..448db762af 100644 --- a/py/obj.h +++ b/py/obj.h @@ -469,7 +469,7 @@ mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, mp_uint_t n_ar mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg); mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, 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_fun_bc(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code); -mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data); +mp_obj_t mp_obj_new_fun_native(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data); mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig); mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data); mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); diff --git a/py/objfun.c b/py/objfun.c index 25a835e9b5..48c51053df 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -108,8 +108,18 @@ qstr mp_obj_code_get_name(const byte *code_info) { return mp_decode_uint(&code_info); } +#if MICROPY_EMIT_NATIVE +STATIC const mp_obj_type_t mp_type_fun_native; +#endif + qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) { const mp_obj_fun_bc_t *fun = fun_in; + #if MICROPY_EMIT_NATIVE + if (fun->base.type == &mp_type_fun_native) { + // TODO native functions don't have name stored + return MP_QSTR_; + } + #endif const byte *code_info = fun->bytecode; return mp_obj_code_get_name(code_info); } @@ -168,7 +178,8 @@ mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, mp_uint_t n_arg } code_state->n_state = n_state; - code_state->ip = ip; + code_state->code_info = 0; // offset to code-info + code_state->ip = ip - self->bytecode; // offset to prelude mp_setup_code_state(code_state, self_in, n_args, n_kw, args); // execute the byte code with the correct globals context @@ -216,7 +227,8 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, } code_state->n_state = n_state; - code_state->ip = ip; + code_state->code_info = 0; // offset to code-info + code_state->ip = (byte*)(ip - self->bytecode); // offset to prelude mp_setup_code_state(code_state, self_in, n_args, n_kw, args); // execute the byte code with the correct globals context @@ -339,42 +351,11 @@ mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_ #if MICROPY_EMIT_NATIVE -typedef struct _mp_obj_fun_native_t { - mp_obj_base_t base; - mp_uint_t n_args; - void *fun_data; // GC must be able to trace this pointer - // TODO add mp_map_t *globals -} mp_obj_fun_native_t; - -typedef mp_obj_t (*native_fun_0_t)(void); -typedef mp_obj_t (*native_fun_1_t)(mp_obj_t); -typedef mp_obj_t (*native_fun_2_t)(mp_obj_t, mp_obj_t); -typedef mp_obj_t (*native_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t); - STATIC mp_obj_t fun_native_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { - mp_obj_fun_native_t *self = self_in; - - mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false); - - void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data); - - switch (n_args) { - case 0: - return ((native_fun_0_t)fun)(); - - case 1: - return ((native_fun_1_t)fun)(args[0]); - - case 2: - return ((native_fun_2_t)fun)(args[0], args[1]); - - case 3: - return ((native_fun_3_t)fun)(args[0], args[1], args[2]); - - default: - assert(0); - return mp_const_none; - } + MP_STACK_CHECK(); + mp_obj_fun_bc_t *self = self_in; + mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void*)self->bytecode); + return fun(self_in, n_args, n_kw, args); } STATIC const mp_obj_type_t mp_type_fun_native = { @@ -383,12 +364,9 @@ STATIC const mp_obj_type_t mp_type_fun_native = { .call = fun_native_call, }; -mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data) { - assert(0 <= n_args && n_args <= 3); - mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t); +mp_obj_t mp_obj_new_fun_native(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data) { + mp_obj_fun_bc_t *o = mp_obj_new_fun_bc(scope_flags, n_pos_args, n_kwonly_args, def_args_in, def_kw_args, (const byte*)fun_data); o->base.type = &mp_type_fun_native; - o->n_args = n_args; - o->fun_data = fun_data; return o; } diff --git a/py/objgenerator.c b/py/objgenerator.c index 112becb46b..f672b8d99d 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -73,7 +73,8 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw o->globals = self_fun->globals; o->code_state.n_state = n_state; - o->code_state.ip = ip; + o->code_state.code_info = 0; // offset to code-info + o->code_state.ip = (byte*)(ip - self_fun->bytecode); // offset to prelude mp_setup_code_state(&o->code_state, self_fun, n_args, n_kw, args); return o; } diff --git a/py/runtime0.h b/py/runtime0.h index 7ee8c9aa49..be9fc8d524 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -151,6 +151,7 @@ typedef enum { MP_F_DELETE_GLOBAL, MP_F_NEW_CELL, MP_F_MAKE_CLOSURE_FROM_RAW_CODE, + MP_F_SETUP_CODE_STATE, MP_F_NUMBER_OF, } mp_fun_kind_t; diff --git a/tests/run-tests b/tests/run-tests index c64d347e8f..ebe295c7df 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -154,19 +154,22 @@ def run_tests(pyb, tests, args): # Some tests are known to fail with native emitter # Remove them from the below when they work if args.emit == 'native': - skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class closure_defargs del_deref del_local fun3 fun_calldblstar fun_callstar fun_callstardblstar fun_defargs fun_defargs2 fun_kwargs fun_kwonly fun_kwonlydef fun_kwvarargs fun_varargs gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_throw generator1 generator2 generator_args generator_close generator_closure generator_exc generator_return generator_send globals_del string_format string_join subclass_native2_list subclass_native2_tuple try_finally_loops try_finally_return try_reraise try_reraise2 unboundlocal with1 with_break with_continue with_return'.split()}) + skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_throw generator1 generator2 generator_args generator_close generator_closure generator_exc generator_return generator_send'.split()}) # require yield + skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class globals_del string_join'.split()}) # require yield + skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs + skip_tests.update({'basics/%s.py' % t for t in 'with1 with_break with_continue with_return'.split()}) # require with skip_tests.add('basics/array_construct2.py') # requires generators skip_tests.add('basics/bool1.py') # seems to randomly fail - skip_tests.add('basics/boundmeth1.py') # requires support for many args - skip_tests.add('basics/closure_manyvars.py') # requires closures - skip_tests.add('float/string_format.py') - skip_tests.add('import/gen_context.py') - skip_tests.add('io/file_with.py') - skip_tests.add('io/stringio_with.py') - skip_tests.add('micropython/heapalloc.py') - skip_tests.add('misc/features.py') - skip_tests.add('misc/recursion.py') - skip_tests.add('misc/rge_sm.py') + skip_tests.add('basics/del_deref.py') # requires checking for unbound local + skip_tests.add('basics/del_local.py') # requires checking for unbound local + skip_tests.add('basics/try_finally_loops.py') # requires proper try finally code + skip_tests.add('basics/try_finally_return.py') # requires proper try finally code + skip_tests.add('basics/unboundlocal.py') # requires checking for unbound local + skip_tests.add('import/gen_context.py') # requires yield_value + skip_tests.add('io/file_with.py') # requires with + skip_tests.add('io/stringio_with.py') # requires with + skip_tests.add('misc/features.py') # requires raise_varargs + skip_tests.add('misc/rge_sm.py') # requires yield skip_tests.add('misc/print_exception.py') # because native doesn't have proper traceback info for test_file in tests: