diff options
Diffstat (limited to 'py/vm.c')
-rw-r--r-- | py/vm.c | 150 |
1 files changed, 115 insertions, 35 deletions
@@ -38,8 +38,7 @@ #include "py/bc.h" #if 0 -//#define TRACE(ip) printf("sp=" INT_FMT " ", sp - code_state->sp); mp_bytecode_print2(ip, 1); -#define TRACE(ip) printf("sp=%d ", sp - code_state->sp); mp_bytecode_print2(ip, 1); +#define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(ip, 1, code_state->fun_bc->const_table); #else #define TRACE(ip) #endif @@ -64,8 +63,8 @@ typedef enum { do { \ unum = (unum << 7) + (*ip & 0x7f); \ } while ((*ip++ & 0x80) != 0) -#define DECODE_ULABEL mp_uint_t ulab = (ip[0] | (ip[1] << 8)); ip += 2 -#define DECODE_SLABEL mp_uint_t slab = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2 +#define DECODE_ULABEL size_t ulab = (ip[0] | (ip[1] << 8)); ip += 2 +#define DECODE_SLABEL size_t slab = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2 #if MICROPY_PERSISTENT_CODE @@ -74,10 +73,10 @@ typedef enum { ip += 2; #define DECODE_PTR \ DECODE_UINT; \ - void *ptr = (void*)(uintptr_t)code_state->const_table[unum] + void *ptr = (void*)(uintptr_t)code_state->fun_bc->const_table[unum] #define DECODE_OBJ \ DECODE_UINT; \ - mp_obj_t obj = (mp_obj_t)code_state->const_table[unum] + mp_obj_t obj = (mp_obj_t)code_state->fun_bc->const_table[unum] #else @@ -163,13 +162,20 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp run_code_state: ; #endif // Pointers which are constant for particular invocation of mp_execute_bytecode() - mp_obj_t * /*const*/ fastn = &code_state->state[code_state->n_state - 1]; - mp_exc_stack_t * /*const*/ exc_stack = (mp_exc_stack_t*)(code_state->state + code_state->n_state); + size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); + mp_obj_t * /*const*/ fastn = &code_state->state[n_state - 1]; + mp_exc_stack_t * /*const*/ exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) volatile bool currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack + #if MICROPY_PY_THREAD_GIL && MICROPY_PY_THREAD_GIL_VM_DIVISOR + // This needs to be volatile and outside the VM loop so it persists across handling + // of any exceptions. Otherwise it's possible that the VM never gives up the GIL. + volatile int gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; + #endif + // outer exception handling loop for (;;) { nlr_buf_t nlr; @@ -279,12 +285,12 @@ dispatch_loop: DECODE_QSTR; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); mp_uint_t x = *ip; - if (x < MP_STATE_CTX(dict_locals)->map.alloc && MP_STATE_CTX(dict_locals)->map.table[x].key == key) { - PUSH(MP_STATE_CTX(dict_locals)->map.table[x].value); + if (x < mp_locals_get()->map.alloc && mp_locals_get()->map.table[x].key == key) { + PUSH(mp_locals_get()->map.table[x].value); } else { - mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_CTX(dict_locals)->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem != NULL) { - *(byte*)ip = (elem - &MP_STATE_CTX(dict_locals)->map.table[0]) & 0xff; + *(byte*)ip = (elem - &mp_locals_get()->map.table[0]) & 0xff; PUSH(elem->value); } else { PUSH(mp_load_name(MP_OBJ_QSTR_VALUE(key))); @@ -308,12 +314,12 @@ dispatch_loop: DECODE_QSTR; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); mp_uint_t x = *ip; - if (x < MP_STATE_CTX(dict_globals)->map.alloc && MP_STATE_CTX(dict_globals)->map.table[x].key == key) { - PUSH(MP_STATE_CTX(dict_globals)->map.table[x].value); + if (x < mp_globals_get()->map.alloc && mp_globals_get()->map.table[x].key == key) { + PUSH(mp_globals_get()->map.table[x].value); } else { - mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_CTX(dict_globals)->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem != NULL) { - *(byte*)ip = (elem - &MP_STATE_CTX(dict_globals)->map.table[0]) & 0xff; + *(byte*)ip = (elem - &mp_globals_get()->map.table[0]) & 0xff; PUSH(elem->value); } else { PUSH(mp_load_global(MP_OBJ_QSTR_VALUE(key))); @@ -370,6 +376,14 @@ dispatch_loop: DISPATCH(); } + ENTRY(MP_BC_LOAD_SUPER_METHOD): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + sp -= 1; + mp_load_super_method(qst, sp - 1); + DISPATCH(); + } + ENTRY(MP_BC_LOAD_BUILD_CLASS): MARK_EXC_IP_SELECTIVE(); PUSH(mp_load_build_class()); @@ -676,7 +690,8 @@ unwind_jump:; } ip = (const byte*)MP_OBJ_TO_PTR(POP()); // pop destination ip for jump if (unum != 0) { - sp--; + // pop the exhausted iterator + sp -= MP_OBJ_ITER_BUF_NSLOTS; } DISPATCH_WITH_PEND_EXC_CHECK(); } @@ -718,17 +733,40 @@ unwind_jump:; ENTRY(MP_BC_GET_ITER): MARK_EXC_IP_SELECTIVE(); - SET_TOP(mp_getiter(TOP())); + SET_TOP(mp_getiter(TOP(), NULL)); DISPATCH(); + // An iterator for a for-loop takes MP_OBJ_ITER_BUF_NSLOTS slots on + // the Python value stack. These slots are either used to store the + // iterator object itself, or the first slot is MP_OBJ_NULL and + // the second slot holds a reference to the iterator object. + ENTRY(MP_BC_GET_ITER_STACK): { + MARK_EXC_IP_SELECTIVE(); + mp_obj_t obj = TOP(); + mp_obj_iter_buf_t *iter_buf = (mp_obj_iter_buf_t*)sp; + sp += MP_OBJ_ITER_BUF_NSLOTS - 1; + obj = mp_getiter(obj, iter_buf); + if (obj != MP_OBJ_FROM_PTR(iter_buf)) { + // Iterator didn't use the stack so indicate that with MP_OBJ_NULL. + sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] = MP_OBJ_NULL; + sp[-MP_OBJ_ITER_BUF_NSLOTS + 2] = obj; + } + DISPATCH(); + } + ENTRY(MP_BC_FOR_ITER): { MARK_EXC_IP_SELECTIVE(); DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward code_state->sp = sp; - assert(TOP()); - mp_obj_t value = mp_iternext_allow_raise(TOP()); + mp_obj_t obj; + if (sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] == MP_OBJ_NULL) { + obj = sp[-MP_OBJ_ITER_BUF_NSLOTS + 2]; + } else { + obj = MP_OBJ_FROM_PTR(&sp[-MP_OBJ_ITER_BUF_NSLOTS + 1]); + } + mp_obj_t value = mp_iternext_allow_raise(obj); if (value == MP_OBJ_STOP_ITERATION) { - --sp; // pop the exhausted iterator + sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator ip += ulab; // jump to after for-block } else { PUSH(value); // push the next iteration value @@ -858,7 +896,7 @@ unwind_jump:; ENTRY(MP_BC_MAKE_CLOSURE): { DECODE_PTR; - mp_uint_t n_closed_over = *ip++; + size_t n_closed_over = *ip++; // Stack layout: closed_overs <- TOS sp -= n_closed_over - 1; SET_TOP(mp_make_closure_from_raw_code(ptr, n_closed_over, sp)); @@ -867,7 +905,7 @@ unwind_jump:; ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS): { DECODE_PTR; - mp_uint_t n_closed_over = *ip++; + size_t n_closed_over = *ip++; // Stack layout: def_tuple def_dict closed_overs <- TOS sp -= 2 + n_closed_over - 1; SET_TOP(mp_make_closure_from_raw_code(ptr, 0x100 | n_closed_over, sp)); @@ -953,8 +991,8 @@ unwind_jump:; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); - mp_uint_t n_args = unum & 0xff; - mp_uint_t n_kw = (unum >> 8) & 0xff; + size_t n_args = unum & 0xff; + size_t n_kw = (unum >> 8) & 0xff; int adjust = (sp[1] == MP_OBJ_NULL) ? 0 : 1; mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust); @@ -1237,16 +1275,50 @@ yield: pending_exception_check: MICROPY_VM_HOOK_LOOP + + #if MICROPY_ENABLE_SCHEDULER + // This is an inlined variant of mp_handle_pending + if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { + MARK_EXC_IP_SELECTIVE(); + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + if (obj != MP_OBJ_NULL) { + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + if (!mp_sched_num_pending()) { + MP_STATE_VM(sched_state) = MP_SCHED_IDLE; + } + MICROPY_END_ATOMIC_SECTION(atomic_state); + RAISE(obj); + } + mp_handle_pending_tail(atomic_state); + } + #else + // This is an inlined variant of mp_handle_pending if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { MARK_EXC_IP_SELECTIVE(); mp_obj_t obj = MP_STATE_VM(mp_pending_exception); MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; RAISE(obj); } + #endif - // TODO make GIL release more efficient - MP_THREAD_GIL_EXIT(); - MP_THREAD_GIL_ENTER(); + #if MICROPY_PY_THREAD_GIL + #if MICROPY_PY_THREAD_GIL_VM_DIVISOR + if (--gil_divisor == 0) { + gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; + #else + { + #endif + #if MICROPY_ENABLE_SCHEDULER + // can only switch threads if the scheduler is unlocked + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) + #endif + { + MP_THREAD_GIL_EXIT(); + MP_THREAD_GIL_ENTER(); + } + } + #endif } // for loop @@ -1270,7 +1342,7 @@ exception_handler: const byte *ip = code_state->ip + 1; DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward code_state->ip = ip + ulab; // jump to after for-block - code_state->sp -= 1; // pop the exhausted iterator + code_state->sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator goto outer_dispatch_loop; // continue with dispatch loop } else if (*code_state->ip == MP_BC_YIELD_FROM) { // StopIteration inside yield from call means return a value of @@ -1290,8 +1362,16 @@ unwind_loop: // But consider how to handle nested exceptions. // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj) if (nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) { - const byte *ip = code_state->code_info; - mp_uint_t code_info_size = mp_decode_uint(&ip); + const byte *ip = code_state->fun_bc->bytecode; + mp_decode_uint(&ip); // skip n_state + mp_decode_uint(&ip); // skip n_exc_stack + ip++; // skip scope_params + ip++; // skip n_pos_args + ip++; // skip n_kwonly_args + ip++; // skip n_def_pos_args + size_t bc = code_state->ip - ip; + size_t code_info_size = mp_decode_uint(&ip); + bc -= code_info_size; #if MICROPY_PERSISTENT_CODE qstr block_name = ip[0] | (ip[1] << 8); qstr source_file = ip[2] | (ip[3] << 8); @@ -1300,11 +1380,10 @@ unwind_loop: qstr block_name = mp_decode_uint(&ip); qstr source_file = mp_decode_uint(&ip); #endif - size_t bc = code_state->ip - code_state->code_info - code_info_size; size_t source_line = 1; size_t c; while ((c = *ip)) { - mp_uint_t b, l; + size_t b, l; if ((c & 0x80) == 0) { // 0b0LLBBBBB encoding b = c & 0x1f; @@ -1356,8 +1435,9 @@ unwind_loop: } else if (code_state->prev != NULL) { mp_globals_set(code_state->old_globals); code_state = code_state->prev; - fastn = &code_state->state[code_state->n_state - 1]; - exc_stack = (mp_exc_stack_t*)(code_state->state + code_state->n_state); + size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); + fastn = &code_state->state[n_state - 1]; + exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack |