vm: Initial support for calling bytecode functions w/o C stack ("stackless").
This commit is contained in:
parent
f88eec0de2
commit
2039757b85
3
py/bc.c
3
py/bc.c
|
@ -86,6 +86,9 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
|
|||
mp_obj_fun_bc_t *self = self_in;
|
||||
mp_uint_t n_state = code_state->n_state;
|
||||
|
||||
#if MICROPY_STACKLESS
|
||||
code_state->prev = NULL;
|
||||
#endif
|
||||
code_state->code_info = self->bytecode;
|
||||
code_state->sp = &code_state->state[0] - 1;
|
||||
code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
|
||||
|
|
4
py/bc.h
4
py/bc.h
|
@ -46,6 +46,9 @@ typedef struct _mp_code_state {
|
|||
// bit 0 is saved currently_in_except_block value
|
||||
mp_exc_stack_t *exc_sp;
|
||||
mp_obj_dict_t *old_globals;
|
||||
#if MICROPY_STACKLESS
|
||||
struct _mp_code_state *prev;
|
||||
#endif
|
||||
mp_uint_t n_state;
|
||||
// Variable-length
|
||||
mp_obj_t state[0];
|
||||
|
@ -56,6 +59,7 @@ typedef struct _mp_code_state {
|
|||
mp_uint_t mp_decode_uint(const byte **ptr);
|
||||
|
||||
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc);
|
||||
mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
|
||||
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);
|
||||
void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *code, mp_uint_t len);
|
||||
void mp_bytecode_print2(const byte *code, mp_uint_t len);
|
||||
|
|
|
@ -125,6 +125,11 @@
|
|||
#define MICROPY_QSTR_BYTES_IN_LEN (1)
|
||||
#endif
|
||||
|
||||
// Avoid using C stack when making Python function calls.
|
||||
#ifndef MICROPY_STACKLESS
|
||||
#define MICROPY_STACKLESS (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Micro Python emitters */
|
||||
|
||||
|
|
32
py/objfun.c
32
py/objfun.c
|
@ -142,6 +142,38 @@ STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) {
|
|||
// Set this to enable a simple stack overflow check.
|
||||
#define VM_DETECT_STACK_OVERFLOW (0)
|
||||
|
||||
mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
MP_STACK_CHECK();
|
||||
mp_obj_fun_bc_t *self = self_in;
|
||||
|
||||
// skip code-info block
|
||||
const byte *code_info = self->bytecode;
|
||||
mp_uint_t code_info_size = mp_decode_uint(&code_info);
|
||||
const byte *ip = self->bytecode + code_info_size;
|
||||
|
||||
// bytecode prelude: skip arg names
|
||||
ip += (self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t);
|
||||
|
||||
// bytecode prelude: state size and exception stack size
|
||||
mp_uint_t n_state = mp_decode_uint(&ip);
|
||||
mp_uint_t n_exc_stack = mp_decode_uint(&ip);
|
||||
|
||||
// allocate state for locals and stack
|
||||
mp_uint_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t);
|
||||
mp_code_state *code_state;
|
||||
code_state = m_new_obj_var(mp_code_state, byte, state_size);
|
||||
|
||||
code_state->n_state = n_state;
|
||||
code_state->ip = ip;
|
||||
mp_setup_code_state(code_state, self_in, n_args, n_kw, args);
|
||||
|
||||
// execute the byte code with the correct globals context
|
||||
code_state->old_globals = mp_globals_get();
|
||||
mp_globals_set(self->globals);
|
||||
|
||||
return code_state;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
MP_STACK_CHECK();
|
||||
|
||||
|
|
43
py/vm.c
43
py/vm.c
|
@ -129,9 +129,12 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
|
|||
// loop and the exception handler, leading to very obscure bugs.
|
||||
#define RAISE(o) do { nlr_pop(); nlr.ret_val = o; goto exception_handler; } while(0)
|
||||
|
||||
#if MICROPY_STACKLESS
|
||||
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);
|
||||
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);
|
||||
|
||||
// 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
|
||||
|
@ -865,6 +868,18 @@ unwind_jump:;
|
|||
// unum & 0xff == n_positional
|
||||
// (unum >> 8) & 0xff == n_keyword
|
||||
sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe);
|
||||
#if MICROPY_STACKLESS
|
||||
if (mp_obj_get_type(*sp) == &mp_type_fun_bc) {
|
||||
code_state->ip = ip;
|
||||
code_state->sp = sp;
|
||||
code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block);
|
||||
mp_code_state *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1);
|
||||
new_state->prev = code_state;
|
||||
code_state = new_state;
|
||||
nlr_pop();
|
||||
goto run_code_state;
|
||||
}
|
||||
#endif
|
||||
SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1));
|
||||
DISPATCH();
|
||||
}
|
||||
|
@ -925,6 +940,15 @@ unwind_return:
|
|||
nlr_pop();
|
||||
code_state->sp = sp;
|
||||
assert(exc_sp == exc_stack - 1);
|
||||
#if MICROPY_STACKLESS
|
||||
if (code_state->prev != NULL) {
|
||||
mp_obj_t res = *sp;
|
||||
mp_globals_set(code_state->old_globals);
|
||||
code_state = code_state->prev;
|
||||
*code_state->sp = res;
|
||||
goto run_code_state;
|
||||
}
|
||||
#endif
|
||||
return MP_VM_RETURN_NORMAL;
|
||||
|
||||
ENTRY(MP_BC_RAISE_VARARGS): {
|
||||
|
@ -1122,6 +1146,9 @@ exception_handler:
|
|||
goto outer_dispatch_loop; // continue with dispatch loop
|
||||
}
|
||||
|
||||
#if MICROPY_STACKLESS
|
||||
unwind_loop:
|
||||
#endif
|
||||
// set file and line number that the exception occurred at
|
||||
// TODO: don't set traceback for exceptions re-raised by END_FINALLY.
|
||||
// But consider how to handle nested exceptions.
|
||||
|
@ -1185,6 +1212,18 @@ exception_handler:
|
|||
PUSH(mp_obj_get_type(nlr.ret_val));
|
||||
code_state->sp = sp;
|
||||
|
||||
#if MICROPY_STACKLESS
|
||||
} 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);
|
||||
// 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
|
||||
goto unwind_loop;
|
||||
|
||||
#endif
|
||||
} else {
|
||||
// propagate exception to higher level
|
||||
// TODO what to do about ip and sp? they don't really make sense at this point
|
||||
|
|
Loading…
Reference in New Issue