py/emitnative: Make viper funcs run with their correct globals context.
Viper functions will now capture the globals at the point they were defined and use these globals when executing.pull/1/head
parent
f12e039c2b
commit
93d71c5436
|
@ -3287,7 +3287,12 @@ STATIC void scope_compute_things(scope_t *scope) {
|
|||
#if MICROPY_EMIT_NATIVE
|
||||
if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
|
||||
// This function makes a reference to a global variable
|
||||
scope->scope_flags |= MP_SCOPE_FLAG_REFGLOBALS;
|
||||
if (scope->emit_options == MP_EMIT_OPT_VIPER
|
||||
&& mp_native_type_from_qstr(id->qst) >= MP_NATIVE_TYPE_INT) {
|
||||
// A casting operator in viper mode, not a real global reference
|
||||
} else {
|
||||
scope->scope_flags |= MP_SCOPE_FLAG_REFGLOBALS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// params always count for 1 local, even if they are a cell
|
||||
|
|
|
@ -66,7 +66,8 @@
|
|||
// locals (reversed, L0 at end) |
|
||||
//
|
||||
// C stack layout for viper functions:
|
||||
// 0 = emit->stack_start: nlr_buf_t [optional] |
|
||||
// 0 fun_obj, old_globals [optional]
|
||||
// emit->stack_start: nlr_buf_t [optional] |
|
||||
// Python object stack | emit->n_state
|
||||
// locals (reversed, L0 at end) |
|
||||
// (L0-L2 may be in regs instead)
|
||||
|
@ -76,7 +77,7 @@
|
|||
|
||||
// Whether the native/viper function needs to be wrapped in an exception handler
|
||||
#define NEED_GLOBAL_EXC_HANDLER(emit) ((emit)->scope->exc_stack_size > 0 \
|
||||
|| (!(emit)->do_viper_types && ((emit)->scope->scope_flags & MP_SCOPE_FLAG_REFGLOBALS)))
|
||||
|| ((emit)->scope->scope_flags & MP_SCOPE_FLAG_REFGLOBALS))
|
||||
|
||||
// Whether registers can be used to store locals (only true if there are no
|
||||
// exception handlers, because otherwise an nlr_jump will restore registers to
|
||||
|
@ -312,8 +313,13 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
|||
}
|
||||
}
|
||||
|
||||
// The locals and stack start at the beginning of the C stack
|
||||
emit->stack_start = 0;
|
||||
// Work out where the locals and Python stack start within the C stack
|
||||
if (NEED_GLOBAL_EXC_HANDLER(emit)) {
|
||||
// Reserve 2 words for function object and old globals
|
||||
emit->stack_start = 2;
|
||||
} else {
|
||||
emit->stack_start = 0;
|
||||
}
|
||||
|
||||
// Entry to function
|
||||
ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs);
|
||||
|
@ -325,6 +331,14 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
|||
asm_arm_mov_reg_i32(emit->as, ASM_ARM_REG_R7, (mp_uint_t)mp_fun_table);
|
||||
#endif
|
||||
|
||||
// Store function object (passed as first arg) to stack if needed
|
||||
if (NEED_GLOBAL_EXC_HANDLER(emit)) {
|
||||
#if N_X86
|
||||
asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1);
|
||||
#endif
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_ARG_1);
|
||||
}
|
||||
|
||||
// Put n_args in REG_ARG_1, n_kw in REG_ARG_2, args array in REG_LOCAL_3
|
||||
#if N_X86
|
||||
asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_1);
|
||||
|
@ -931,15 +945,13 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) {
|
|||
mp_uint_t start_label = *emit->label_slot + 2;
|
||||
mp_uint_t global_except_label = *emit->label_slot + 3;
|
||||
|
||||
if (!emit->do_viper_types) {
|
||||
// Set new globals
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_FUN_OBJ(emit));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t));
|
||||
emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
|
||||
// Set new globals
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_FUN_OBJ(emit));
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t));
|
||||
emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
|
||||
|
||||
// Save old globals (or NULL if globals didn't change)
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_OLD_GLOBALS(emit), REG_RET);
|
||||
}
|
||||
// Save old globals (or NULL if globals didn't change)
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_OLD_GLOBALS(emit), REG_RET);
|
||||
|
||||
if (emit->scope->exc_stack_size == 0) {
|
||||
// Optimisation: if globals didn't change don't push the nlr context
|
||||
|
@ -976,11 +988,9 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) {
|
|||
ASM_JUMP_IF_REG_NONZERO(emit->as, REG_LOCAL_1, nlr_label, false);
|
||||
}
|
||||
|
||||
if (!emit->do_viper_types) {
|
||||
// Restore old globals
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit));
|
||||
emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
|
||||
}
|
||||
// Restore old globals
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit));
|
||||
emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
|
||||
|
||||
// Re-raise exception out to caller
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit));
|
||||
|
@ -996,19 +1006,17 @@ STATIC void emit_native_global_exc_exit(emit_t *emit) {
|
|||
emit_native_label_assign(emit, emit->exit_label);
|
||||
|
||||
if (NEED_GLOBAL_EXC_HANDLER(emit)) {
|
||||
if (!emit->do_viper_types) {
|
||||
// Get old globals
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit));
|
||||
// Get old globals
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit));
|
||||
|
||||
if (emit->scope->exc_stack_size == 0) {
|
||||
// Optimisation: if globals didn't change then don't restore them and don't do nlr_pop
|
||||
ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, emit->exit_label + 1, false);
|
||||
}
|
||||
|
||||
// Restore old globals
|
||||
emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
|
||||
if (emit->scope->exc_stack_size == 0) {
|
||||
// Optimisation: if globals didn't change then don't restore them and don't do nlr_pop
|
||||
ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, emit->exit_label + 1, false);
|
||||
}
|
||||
|
||||
// Restore old globals
|
||||
emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
|
||||
|
||||
// Pop the nlr context
|
||||
emit_call(emit, MP_F_NLR_POP);
|
||||
adjust_stack(emit, -(mp_int_t)(sizeof(nlr_buf_t) / sizeof(uintptr_t)));
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# test that viper functions capture their globals context
|
||||
|
||||
gl = {}
|
||||
|
||||
exec("""
|
||||
@micropython.viper
|
||||
def f():
|
||||
return x
|
||||
""", gl)
|
||||
|
||||
# x is not yet in the globals, f should not see it
|
||||
try:
|
||||
print(gl['f']())
|
||||
except NameError:
|
||||
print('NameError')
|
||||
|
||||
# x is in globals, f should now see it
|
||||
gl['x'] = 123
|
||||
print(gl['f']())
|
|
@ -0,0 +1,2 @@
|
|||
NameError
|
||||
123
|
Loading…
Reference in New Issue