diff --git a/ports/webassembly/main.c b/ports/webassembly/main.c index 23d12b6db..fd331f8dc 100644 --- a/ports/webassembly/main.c +++ b/ports/webassembly/main.c @@ -44,6 +44,19 @@ #include "library.h" #include "proxy_c.h" +// This counter tracks the current depth of calls into C code that originated +// externally, ie from JavaScript. When the counter is 0 that corresponds to +// the top-level call into C. +static size_t external_call_depth = 0; + +void external_call_depth_inc(void) { + ++external_call_depth; +} + +void external_call_depth_dec(void) { + --external_call_depth; +} + void mp_js_init(int heap_size) { #if MICROPY_ENABLE_GC char *heap = (char *)malloc(heap_size * sizeof(char)); @@ -79,6 +92,7 @@ void mp_js_register_js_module(const char *name, uint32_t *value) { } void mp_js_do_import(const char *name, uint32_t *out) { + external_call_depth_inc(); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t ret = mp_import_name(qstr_from_str(name), mp_const_none, MP_OBJ_NEW_SMALL_INT(0)); @@ -97,9 +111,11 @@ void mp_js_do_import(const char *name, uint32_t *out) { } } nlr_pop(); + external_call_depth_dec(); proxy_convert_mp_to_js_obj_cside(ret, out); } else { // uncaught exception + external_call_depth_dec(); proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); } } @@ -109,6 +125,7 @@ void mp_js_do_exec(const char *src, size_t len, uint32_t *out) { gc_collect_start(); gc_collect_end(); + external_call_depth_inc(); mp_parse_input_kind_t input_kind = MP_PARSE_FILE_INPUT; nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { @@ -118,9 +135,11 @@ void mp_js_do_exec(const char *src, size_t len, uint32_t *out) { mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); mp_obj_t ret = mp_call_function_0(module_fun); nlr_pop(); + external_call_depth_dec(); proxy_convert_mp_to_js_obj_cside(ret, out); } else { // uncaught exception + external_call_depth_dec(); proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); } } @@ -136,7 +155,10 @@ void mp_js_repl_init(void) { } int mp_js_repl_process_char(int c) { - return pyexec_event_repl_process_char(c); + external_call_depth_inc(); + int ret = pyexec_event_repl_process_char(c); + external_call_depth_dec(); + return ret; } #if MICROPY_GC_SPLIT_HEAP_AUTO diff --git a/ports/webassembly/proxy_c.c b/ports/webassembly/proxy_c.c index 2ab92303d..22f879177 100644 --- a/ports/webassembly/proxy_c.c +++ b/ports/webassembly/proxy_c.c @@ -176,6 +176,7 @@ void proxy_convert_mp_to_js_exc_cside(void *exc, uint32_t *out) { } void proxy_c_to_js_call(uint32_t c_ref, uint32_t n_args, uint32_t *args_value, uint32_t *out) { + external_call_depth_inc(); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t args[n_args]; @@ -185,14 +186,17 @@ void proxy_c_to_js_call(uint32_t c_ref, uint32_t n_args, uint32_t *args_value, u mp_obj_t obj = proxy_c_get_obj(c_ref); mp_obj_t member = mp_call_function_n_kw(obj, n_args, 0, args); nlr_pop(); + external_call_depth_dec(); proxy_convert_mp_to_js_obj_cside(member, out); } else { // uncaught exception + external_call_depth_dec(); proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); } } void proxy_c_to_js_dir(uint32_t c_ref, uint32_t *out) { + external_call_depth_inc(); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t obj = proxy_c_get_obj(c_ref); @@ -210,9 +214,11 @@ void proxy_c_to_js_dir(uint32_t c_ref, uint32_t *out) { dir = mp_builtin_dir_obj.fun.var(1, args); } nlr_pop(); + external_call_depth_dec(); proxy_convert_mp_to_js_obj_cside(dir, out); } else { // uncaught exception + external_call_depth_dec(); proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); } } @@ -235,6 +241,7 @@ bool proxy_c_to_js_has_attr(uint32_t c_ref, const char *attr_in) { } void proxy_c_to_js_lookup_attr(uint32_t c_ref, const char *attr_in, uint32_t *out) { + external_call_depth_inc(); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t obj = proxy_c_get_obj(c_ref); @@ -255,19 +262,27 @@ void proxy_c_to_js_lookup_attr(uint32_t c_ref, const char *attr_in, uint32_t *ou member = mp_load_attr(obj, attr); } nlr_pop(); + external_call_depth_dec(); proxy_convert_mp_to_js_obj_cside(member, out); } else { // uncaught exception + external_call_depth_dec(); proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); } } -static bool proxy_c_to_js_store_helper(uint32_t c_ref, const char *attr_in, mp_obj_t value) { - mp_obj_t obj = proxy_c_get_obj(c_ref); - qstr attr = qstr_from_str(attr_in); - +static bool proxy_c_to_js_store_helper(uint32_t c_ref, const char *attr_in, uint32_t *value_in) { + external_call_depth_inc(); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + qstr attr = qstr_from_str(attr_in); + + mp_obj_t value = MP_OBJ_NULL; + if (value_in != NULL) { + value = proxy_convert_js_to_mp_obj_cside(value_in); + } + if (mp_obj_is_dict_or_ordereddict(obj)) { if (value == MP_OBJ_NULL) { mp_obj_dict_delete(obj, MP_OBJ_NEW_QSTR(attr)); @@ -278,20 +293,21 @@ static bool proxy_c_to_js_store_helper(uint32_t c_ref, const char *attr_in, mp_o mp_store_attr(obj, attr, value); } nlr_pop(); + external_call_depth_dec(); return true; } else { // uncaught exception + external_call_depth_dec(); return false; } } bool proxy_c_to_js_store_attr(uint32_t c_ref, const char *attr_in, uint32_t *value_in) { - mp_obj_t value = proxy_convert_js_to_mp_obj_cside(value_in); - return proxy_c_to_js_store_helper(c_ref, attr_in, value); + return proxy_c_to_js_store_helper(c_ref, attr_in, value_in); } bool proxy_c_to_js_delete_attr(uint32_t c_ref, const char *attr_in) { - return proxy_c_to_js_store_helper(c_ref, attr_in, MP_OBJ_NULL); + return proxy_c_to_js_store_helper(c_ref, attr_in, NULL); } uint32_t proxy_c_to_js_get_type(uint32_t c_ref) { @@ -352,18 +368,22 @@ uint32_t proxy_c_to_js_get_iter(uint32_t c_ref) { } bool proxy_c_to_js_iternext(uint32_t c_ref, uint32_t *out) { - mp_obj_t obj = proxy_c_get_obj(c_ref); + external_call_depth_inc(); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + mp_obj_t obj = proxy_c_get_obj(c_ref); mp_obj_t iter = mp_iternext_allow_raise(obj); if (iter == MP_OBJ_STOP_ITERATION) { + external_call_depth_dec(); nlr_pop(); return false; } nlr_pop(); + external_call_depth_dec(); proxy_convert_mp_to_js_obj_cside(iter, out); return true; } else { + external_call_depth_dec(); if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { return false; } else { @@ -475,6 +495,7 @@ static mp_obj_t resume_fun(size_t n_args, const mp_obj_t *args) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(resume_obj, 5, 5, resume_fun); void proxy_c_to_js_resume(uint32_t c_ref, uint32_t *args) { + external_call_depth_inc(); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t obj = proxy_c_get_obj(c_ref); @@ -482,9 +503,11 @@ void proxy_c_to_js_resume(uint32_t c_ref, uint32_t *args) { mp_obj_t reject = proxy_convert_js_to_mp_obj_cside(args + 2 * 3); mp_obj_t ret = proxy_resume_execute(obj, mp_const_none, mp_const_none, resolve, reject); nlr_pop(); + external_call_depth_dec(); proxy_convert_mp_to_js_obj_cside(ret, args); } else { // uncaught exception + external_call_depth_dec(); proxy_convert_mp_to_js_exc_cside(nlr.ret_val, args); } } diff --git a/ports/webassembly/proxy_c.h b/ports/webassembly/proxy_c.h index 751d14332..d3567c195 100644 --- a/ports/webassembly/proxy_c.h +++ b/ports/webassembly/proxy_c.h @@ -39,6 +39,9 @@ typedef struct _mp_obj_jsproxy_t { extern const mp_obj_type_t mp_type_jsproxy; extern const mp_obj_type_t mp_type_JsException; +void external_call_depth_inc(void); +void external_call_depth_dec(void); + void proxy_c_init(void); mp_obj_t proxy_convert_js_to_mp_obj_cside(uint32_t *value); void proxy_convert_mp_to_js_obj_cside(mp_obj_t obj, uint32_t *out);