summaryrefslogtreecommitdiff
path: root/py/objgenerator.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-10-01 13:07:04 +1000
committerDamien George <damien.p.george@gmail.com>2018-10-01 13:31:11 +1000
commitcc2bd63c57a72ec37d839965c6bb61cd1fa202fc (patch)
tree44acc885421554921db85273aed4d1b1de4ecbf8 /py/objgenerator.c
parent8fec6f543411dc16b42e9850af0cc3a1097162a7 (diff)
py/emitnative: Implement yield and yield-from in native emitter.
This commit adds first class support for yield and yield-from in the native emitter, including send and throw support, and yields enclosed in exception handlers (which requires pulling down the NLR stack before yielding, then rebuilding it when resuming). This has been fully tested and is working on unix x86 and x86-64, and stm32. Also basic tests have been done with the esp8266 port. Performance of existing native code is unchanged.
Diffstat (limited to 'py/objgenerator.c')
-rw-r--r--py/objgenerator.c64
1 files changed, 63 insertions, 1 deletions
diff --git a/py/objgenerator.c b/py/objgenerator.c
index 58a33d40b..348d2d79d 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -74,6 +74,53 @@ const mp_obj_type_t mp_type_gen_wrap = {
};
/******************************************************************************/
+// native generator wrapper
+
+#if MICROPY_EMIT_NATIVE
+
+STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // The state for a native generating function is held in the same struct as a bytecode function
+ mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in);
+
+ // Determine start of prelude, and extract n_state from it
+ uintptr_t prelude_offset = ((uintptr_t*)self_fun->bytecode)[0];
+ size_t n_state = mp_decode_uint_value(self_fun->bytecode + prelude_offset);
+ size_t n_exc_stack = 0;
+
+ // Allocate the generator object, with room for local stack and exception stack
+ mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte,
+ n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t));
+ o->base.type = &mp_type_gen_instance;
+
+ // Parse the input arguments and set up the code state
+ o->globals = self_fun->globals;
+ o->code_state.fun_bc = self_fun;
+ o->code_state.ip = (const byte*)prelude_offset;
+ mp_setup_code_state(&o->code_state, n_args, n_kw, args);
+
+ // Indicate we are a native function, which doesn't use this variable
+ o->code_state.exc_sp = NULL;
+
+ // Prepare the generator instance for execution
+ uintptr_t start_offset = ((uintptr_t*)self_fun->bytecode)[1];
+ o->code_state.ip = MICROPY_MAKE_POINTER_CALLABLE((void*)(self_fun->bytecode + start_offset));
+
+ return MP_OBJ_FROM_PTR(o);
+}
+
+const mp_obj_type_t mp_type_native_gen_wrap = {
+ { &mp_type_type },
+ .name = MP_QSTR_generator,
+ .call = native_gen_wrap_call,
+ .unary_op = mp_generic_unary_op,
+ #if MICROPY_PY_FUNCTION_ATTRS
+ .attr = mp_obj_fun_bc_attr,
+ #endif
+};
+
+#endif // MICROPY_EMIT_NATIVE
+
+/******************************************************************************/
/* generator instance */
STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
@@ -118,7 +165,22 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
self->code_state.old_globals = mp_globals_get();
mp_globals_set(self->globals);
self->globals = NULL;
- mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value);
+
+ mp_vm_return_kind_t ret_kind;
+
+ #if MICROPY_EMIT_NATIVE
+ if (self->code_state.exc_sp == NULL) {
+ // A native generator, with entry point 2 words into the "bytecode" pointer
+ typedef uintptr_t (*mp_fun_native_gen_t)(void*, mp_obj_t);
+ mp_fun_native_gen_t fun = MICROPY_MAKE_POINTER_CALLABLE((const void*)(self->code_state.fun_bc->bytecode + 2 * sizeof(uintptr_t)));
+ ret_kind = fun((void*)&self->code_state, throw_value);
+ } else
+ #endif
+ {
+ // A bytecode generator
+ ret_kind = mp_execute_bytecode(&self->code_state, throw_value);
+ }
+
self->globals = mp_globals_get();
mp_globals_set(self->code_state.old_globals);