MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix promise handling and state management

+109 -69
+1 -1
meson.build
··· 79 79 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 80 80 81 81 version_conf = configuration_data() 82 - version_conf.set('ANT_VERSION', '0.2.2.28') 82 + version_conf.set('ANT_VERSION', '0.2.2.29') 83 83 version_conf.set('ANT_GIT_HASH', git_hash) 84 84 version_conf.set('ANT_BUILD_DATE', build_date) 85 85
+108 -68
src/ant.c
··· 231 231 static const char *INTERN_ARGUMENTS = NULL; 232 232 static const char *INTERN_CALLEE = NULL; 233 233 static const char *INTERN_IDX[10] = {NULL}; 234 + static const char *INTERN_STATE = NULL; 235 + static const char *INTERN_PVALUE = NULL; 236 + static const char *INTERN_PROMISE = NULL; 234 237 235 238 #define INTERN_PROP_CACHE_SIZE 4096 236 239 typedef struct { ··· 239 242 jsoff_t prop_off; 240 243 } intern_prop_cache_entry_t; 241 244 static intern_prop_cache_entry_t intern_prop_cache[INTERN_PROP_CACHE_SIZE]; 245 + 246 + typedef struct promise_handler { 247 + jsval_t onFulfilled; 248 + jsval_t onRejected; 249 + jsval_t nextPromise; 250 + } promise_handler_t; 251 + 252 + static const UT_icd promise_handler_icd = { 253 + .sz = sizeof(promise_handler_t), 254 + .init = NULL, 255 + .copy = NULL, 256 + .dtor = NULL, 257 + }; 258 + 259 + typedef struct promise_handlers_entry { 260 + jsoff_t promise_off; // key 261 + UT_array *handlers; 262 + UT_hash_handle hh; 263 + } promise_handlers_entry_t; 264 + 265 + static promise_handlers_entry_t *promise_handlers_registry = NULL; 242 266 243 267 typedef struct map_entry { 244 268 char *key; ··· 789 813 790 814 static void free_coroutine(coroutine_t *coro); 791 815 static bool has_ready_coroutines(void); 816 + static bool coro_stack_size_initialized = false; 792 817 793 - // reserve large virtual stack (1MB) but only ~4-8KB physical per coroutine 794 818 static size_t calculate_coro_stack_size(void) { 819 + if (coro_stack_size_initialized) return 0; 820 + coro_stack_size_initialized = true; 795 821 const char *env_stack = getenv("ANT_CORO_STACK_SIZE"); 796 822 if (env_stack) { 797 823 size_t size = (size_t)atoi(env_stack) * 1024; ··· 2786 2812 INTERN_THIS = intern_string("__this", 6); 2787 2813 INTERN_NATIVE_FUNC = intern_string("__native_func", 13); 2788 2814 INTERN_ASYNC = intern_string("__async", 7); 2815 + INTERN_STATE = intern_string("__state", 7); 2816 + INTERN_PVALUE = intern_string("__value", 7); 2817 + INTERN_PROMISE = intern_string("promise", 7); 2789 2818 INTERN_BOUND_THIS = intern_string("__bound_this", 12); 2790 2819 INTERN_BOUND_ARGS = intern_string("__bound_args", 12); 2791 2820 INTERN_TARGET_FUNC = intern_string("__target_func", 13); ··· 17502 17531 } 17503 17532 } 17504 17533 17534 + static UT_array *get_promise_handlers(jsoff_t promise_off, bool create) { 17535 + promise_handlers_entry_t *entry = NULL; 17536 + HASH_FIND(hh, promise_handlers_registry, &promise_off, sizeof(jsoff_t), entry); 17537 + if (entry) return entry->handlers; 17538 + if (!create) return NULL; 17539 + 17540 + entry = (promise_handlers_entry_t *)malloc(sizeof(promise_handlers_entry_t)); 17541 + entry->promise_off = promise_off; 17542 + utarray_new(entry->handlers, &promise_handler_icd); 17543 + HASH_ADD(hh, promise_handlers_registry, promise_off, sizeof(jsoff_t), entry); 17544 + return entry->handlers; 17545 + } 17546 + 17505 17547 static jsval_t mkpromise(struct js *js) { 17506 17548 jsval_t obj = mkobj(js, 0); 17507 17549 if (is_err(obj)) return obj; 17508 - setprop(js, obj, js_mkstr(js, "__state", 7), tov(0.0)); 17509 - setprop(js, obj, js_mkstr(js, "__value", 7), js_mkundef()); 17510 - setprop(js, obj, js_mkstr(js, "__handlers", 10), mkarr(js)); 17511 - return mkval(T_PROMISE, vdata(obj)); 17550 + setprop_fast(js, obj, "__state", 7, tov(0.0)); 17551 + setprop_fast(js, obj, "__value", 7, js_mkundef()); 17552 + 17553 + jsoff_t obj_off = vdata(obj); 17554 + get_promise_handlers(obj_off, true); 17555 + return mkval(T_PROMISE, obj_off); 17512 17556 } 17513 17557 17514 17558 static jsval_t builtin_trigger_handler_wrapper(struct js *js, jsval_t *args, int nargs); 17515 17559 17516 17560 static void trigger_handlers(struct js *js, jsval_t p) { 17517 17561 jsval_t wrapper_obj = mkobj(js, 0); 17518 - setprop(js, wrapper_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_trigger_handler_wrapper)); 17519 - setprop(js, wrapper_obj, js_mkstr(js, "promise", 7), p); 17562 + setprop_fast(js, wrapper_obj, "__native_func", 13, js_mkfun(builtin_trigger_handler_wrapper)); 17563 + setprop_fast(js, wrapper_obj, "promise", 7, p); 17520 17564 jsval_t wrapper_fn = mkval(T_FUNC, vdata(wrapper_obj)); 17521 17565 queue_microtask(js, wrapper_fn); 17522 17566 } 17523 17567 17524 17568 static jsval_t builtin_trigger_handler_wrapper(struct js *js, jsval_t *args, int nargs) { 17525 17569 jsval_t me = js->current_func; 17526 - jsval_t p = js_get(js, me, "promise"); 17570 + jsoff_t promise_prop_off = lkp_interned(js, me, INTERN_PROMISE, 7); 17571 + if (promise_prop_off == 0) return js_mkundef(); 17572 + jsval_t p = resolveprop(js, mkval(T_PROP, promise_prop_off)); 17527 17573 if (vtype(p) != T_PROMISE) return js_mkundef(); 17528 17574 17529 - jsval_t p_obj = mkval(T_OBJ, vdata(p)); 17530 - jsoff_t state_off = lkp(js, p_obj, "__state", 7); 17575 + jsoff_t promise_off = vdata(p); 17576 + jsval_t p_obj = mkval(T_OBJ, promise_off); 17577 + jsoff_t state_off = lkp_interned(js, p_obj, INTERN_STATE, 7); 17531 17578 int state = (int)tod(resolveprop(js, mkval(T_PROP, state_off))); 17532 17579 17533 - jsoff_t val_off = lkp(js, p_obj, "__value", 7); 17580 + jsoff_t val_off = lkp_interned(js, p_obj, INTERN_PVALUE, 7); 17534 17581 jsval_t val = resolveprop(js, mkval(T_PROP, val_off)); 17535 17582 17536 - jsoff_t handlers_off = lkp(js, p_obj, "__handlers", 10); 17537 - jsval_t handlers_arr = resolveprop(js, mkval(T_PROP, handlers_off)); 17583 + UT_array *handlers = get_promise_handlers(promise_off, false); 17584 + if (!handlers) return js_mkundef(); 17538 17585 17539 - jsoff_t len_off = lkp_interned(js, handlers_arr, INTERN_LENGTH, 6); 17540 - int len = (int)tod(resolveprop(js, mkval(T_PROP, len_off))); 17541 - 17542 - for (int i = 0; i < len; i += 3) { 17543 - char idx1[16], idx2[16], idx3[16]; 17544 - snprintf(idx1, sizeof(idx1), "%d", i); 17545 - snprintf(idx2, sizeof(idx2), "%d", i+1); 17546 - snprintf(idx3, sizeof(idx3), "%d", i+2); 17547 - 17548 - jsval_t onFulfilled = resolveprop(js, js_get(js, handlers_arr, idx1)); 17549 - jsval_t onRejected = resolveprop(js, js_get(js, handlers_arr, idx2)); 17550 - jsval_t nextPromise = resolveprop(js, js_get(js, handlers_arr, idx3)); 17551 - 17552 - jsval_t handler = (state == 1) ? onFulfilled : onRejected; 17586 + unsigned int len = utarray_len(handlers); 17587 + for (unsigned int i = 0; i < len; i++) { 17588 + promise_handler_t *h = (promise_handler_t *)utarray_eltptr(handlers, i); 17589 + jsval_t handler = (state == 1) ? h->onFulfilled : h->onRejected; 17553 17590 17554 17591 if (vtype(handler) == T_FUNC || vtype(handler) == T_CFUNC) { 17555 - jsval_t res; 17556 - if (vtype(handler) == T_CFUNC) { 17557 - jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(handler); 17558 - res = fn(js, &val, 1); 17559 - } else { 17560 - jsval_t args[] = { val }; 17561 - res = js_call(js, handler, args, 1); 17562 - } 17592 + jsval_t res; 17593 + if (vtype(handler) == T_CFUNC) { 17594 + jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(handler); 17595 + res = fn(js, &val, 1); 17596 + } else { 17597 + jsval_t call_args[] = { val }; 17598 + res = js_call(js, handler, call_args, 1); 17599 + } 17563 17600 17564 - if (is_err(res)) { 17565 - jsval_t err_str = js_mkstr(js, js->errmsg, strlen(js->errmsg)); 17566 - reject_promise(js, nextPromise, err_str); 17567 - } else { 17568 - resolve_promise(js, nextPromise, res); 17569 - } 17601 + if (is_err(res)) { 17602 + jsval_t err_str = js_mkstr(js, js->errmsg, strlen(js->errmsg)); 17603 + reject_promise(js, h->nextPromise, err_str); 17604 + } else resolve_promise(js, h->nextPromise, res); 17570 17605 } else { 17571 - if (state == 1) resolve_promise(js, nextPromise, val); 17572 - else reject_promise(js, nextPromise, val); 17606 + if (state == 1) resolve_promise(js, h->nextPromise, val); 17607 + else reject_promise(js, h->nextPromise, val); 17573 17608 } 17574 17609 } 17575 - setprop(js, p_obj, js_mkstr(js, "__handlers", 10), mkarr(js)); 17610 + 17611 + utarray_clear(handlers); 17576 17612 return js_mkundef(); 17577 17613 } 17578 17614 17579 17615 static void resolve_promise(struct js *js, jsval_t p, jsval_t val) { 17580 17616 jsval_t p_obj = mkval(T_OBJ, vdata(p)); 17581 - jsoff_t state_off = lkp(js, p_obj, "__state", 7); 17582 - if (state_off == 0) { 17583 - return; 17584 - } 17617 + jsoff_t state_off = lkp_interned(js, p_obj, INTERN_STATE, 7); 17618 + if (state_off == 0) return; 17585 17619 jsval_t state_val = resolveprop(js, mkval(T_PROP, state_off)); 17586 - if ((int)tod(state_val) != 0) { 17587 - return; 17588 - } 17620 + if ((int)tod(state_val) != 0) return; 17589 17621 17590 17622 if (vtype(val) == T_PROMISE) { 17591 17623 if (vdata(val) == vdata(p)) { ··· 17594 17626 } 17595 17627 17596 17628 jsval_t res_obj = mkobj(js, 0); 17597 - setprop(js, res_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_resolve_internal)); 17598 - setprop(js, res_obj, js_mkstr(js, "promise", 7), p); 17629 + setprop_fast(js, res_obj, "__native_func", 13, js_mkfun(builtin_resolve_internal)); 17630 + setprop_fast(js, res_obj, "promise", 7, p); 17599 17631 jsval_t res_fn = mkval(T_FUNC, vdata(res_obj)); 17600 17632 17601 17633 jsval_t rej_obj = mkobj(js, 0); 17602 - setprop(js, rej_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_reject_internal)); 17603 - setprop(js, rej_obj, js_mkstr(js, "promise", 7), p); 17634 + setprop_fast(js, rej_obj, "__native_func", 13, js_mkfun(builtin_reject_internal)); 17635 + setprop_fast(js, rej_obj, "promise", 7, p); 17604 17636 jsval_t rej_fn = mkval(T_FUNC, vdata(rej_obj)); 17605 17637 17606 17638 jsval_t args[] = { res_fn, rej_fn }; ··· 17611 17643 } 17612 17644 } 17613 17645 17614 - setprop(js, p_obj, js_mkstr(js, "__state", 7), tov(1.0)); 17615 - setprop(js, p_obj, js_mkstr(js, "__value", 7), val); 17646 + saveval(js, state_off + sizeof(jsoff_t) * 2, tov(1.0)); 17647 + jsoff_t val_off = lkp_interned(js, p_obj, INTERN_PVALUE, 7); 17648 + if (val_off != 0) { 17649 + saveval(js, val_off + sizeof(jsoff_t) * 2, val); 17650 + } 17616 17651 trigger_handlers(js, p); 17617 17652 } 17618 17653 17619 17654 static void reject_promise(struct js *js, jsval_t p, jsval_t val) { 17620 17655 jsval_t p_obj = mkval(T_OBJ, vdata(p)); 17621 - jsoff_t state_off = lkp(js, p_obj, "__state", 7); 17656 + jsoff_t state_off = lkp_interned(js, p_obj, INTERN_STATE, 7); 17622 17657 if (state_off == 0) return; 17623 17658 jsval_t state_val = resolveprop(js, mkval(T_PROP, state_off)); 17624 17659 if ((int)tod(state_val) != 0) return; 17625 17660 17626 - setprop(js, p_obj, js_mkstr(js, "__state", 7), tov(2.0)); 17627 - setprop(js, p_obj, js_mkstr(js, "__value", 7), val); 17661 + saveval(js, state_off + sizeof(jsoff_t) * 2, tov(2.0)); 17662 + jsoff_t val_off = lkp_interned(js, p_obj, INTERN_PVALUE, 7); 17663 + if (val_off != 0) { 17664 + saveval(js, val_off + sizeof(jsoff_t) * 2, val); 17665 + } 17628 17666 trigger_handlers(js, p); 17629 17667 } 17630 17668 ··· 17682 17720 jsval_t nextP = mkpromise(js); 17683 17721 jsval_t onFulfilled = nargs > 0 ? args[0] : js_mkundef(); 17684 17722 jsval_t onRejected = nargs > 1 ? args[1] : js_mkundef(); 17685 - jsval_t p_obj = mkval(T_OBJ, vdata(p)); 17686 - jsval_t handlers = resolveprop(js, js_get(js, p_obj, "__handlers")); 17687 - jsval_t push_args[] = { onFulfilled, onRejected, nextP }; 17688 - jsval_t saved_this = js->this_val; 17689 - js->this_val = handlers; 17690 - builtin_array_push(js, push_args, 3); 17691 - js->this_val = saved_this; 17692 - jsoff_t state_off = lkp(js, p_obj, "__state", 7); 17723 + 17724 + jsoff_t promise_off = vdata(p); 17725 + UT_array *handlers = get_promise_handlers(promise_off, true); 17726 + if (handlers) { 17727 + promise_handler_t h = { onFulfilled, onRejected, nextP }; 17728 + utarray_push_back(handlers, &h); 17729 + } 17730 + 17731 + jsval_t p_obj = mkval(T_OBJ, promise_off); 17732 + jsoff_t state_off = lkp_interned(js, p_obj, INTERN_STATE, 7); 17693 17733 int state = (int)tod(resolveprop(js, mkval(T_PROP, state_off))); 17694 17734 if (state != 0) trigger_handlers(js, p); 17695 17735 return nextP;