summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/bc.c3
-rw-r--r--py/bc.h4
-rw-r--r--py/mpconfig.h5
-rw-r--r--py/objfun.c32
-rw-r--r--py/vm.c43
5 files changed, 85 insertions, 2 deletions
diff --git a/py/bc.c b/py/bc.c
index 3a8dc5e04f..af855e9474 100644
--- a/py/bc.c
+++ b/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;
diff --git a/py/bc.h b/py/bc.h
index f3885587a9..b4b4d8c550 100644
--- a/py/bc.h
+++ b/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);
diff --git a/py/mpconfig.h b/py/mpconfig.h
index ae5e776256..94e2737de0 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -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 */
diff --git a/py/objfun.c b/py/objfun.c
index d8ea22f394..187bb5a59e 100644
--- a/py/objfun.c
+++ b/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();
diff --git a/py/vm.c b/py/vm.c
index 29a9e4f6d6..3a7a816977 100644
--- a/py/vm.c
+++ b/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