summaryrefslogtreecommitdiffstatshomepage
path: root/py/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'py/vm.c')
-rw-r--r--py/vm.c150
1 files changed, 115 insertions, 35 deletions
diff --git a/py/vm.c b/py/vm.c
index 363824e5f1..5094e3e450 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -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