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.

reduce GC overhead in microtask-heavy workloads

+44 -21
+2
include/ant.h
··· 149 149 void js_resolve_promise(struct js *js, jsval_t promise, jsval_t value); 150 150 void js_reject_promise(struct js *js, jsval_t promise, jsval_t value); 151 151 void js_check_unhandled_rejections(struct js *js); 152 + void js_process_promise_handlers(struct js *js, uint32_t promise_id); 152 153 153 154 void js_run_event_loop(struct js *js); 154 155 void js_poll_events(struct js *js); ··· 180 181 181 182 void js_print_stack_trace(FILE *stream); 182 183 void js_set_needs_gc(struct js *js, bool needs); 184 + void js_set_gc_suppress(struct js *js, bool suppress); 183 185 184 186 size_t js_gc_compact(struct js *js); 185 187
+1
include/internal.h
··· 45 45 bool is_hoisting; // true during function declaration hoisting pass 46 46 uint64_t sym_counter; // counter for generating unique symbol IDs 47 47 bool needs_gc; // deferred GC flag, checked at statement boundaries 48 + bool gc_suppress; // suppress GC during microtask batch processing 48 49 int eval_depth; // recursion depth of js_eval calls 49 50 int parse_depth; // recursion depth of parser (for stack overflow protection) 50 51 };
+1
include/modules/timer.h
··· 8 8 void process_microtasks(struct js *js); 9 9 void process_immediates(struct js *js); 10 10 void queue_microtask(struct js *js, jsval_t callback); 11 + void queue_promise_trigger(uint32_t promise_id); 11 12 void timer_gc_update_roots(GC_FWD_ARGS); 12 13 13 14 int has_pending_timers(void);
+11 -18
src/ant.c
··· 554 554 js->needs_gc = needs; 555 555 } 556 556 557 + void js_set_gc_suppress(struct js *js, bool suppress) { 558 + js->gc_suppress = suppress; 559 + } 560 + 557 561 uint8_t vtype(jsval_t v) { 558 562 return is_tagged(v) ? ((v >> NANBOX_TYPE_SHIFT) & NANBOX_TYPE_MASK) : (uint8_t)T_NUM; 559 563 } ··· 18883 18887 return mkval(T_PROMISE, vdata(obj)); 18884 18888 } 18885 18889 18886 - static jsval_t builtin_trigger_handler_wrapper(struct js *js, jsval_t *args, int nargs); 18887 - 18888 - static void trigger_handlers(struct js *js, jsval_t p) { 18889 - jsval_t wrapper_obj = mkobj(js, 0); 18890 - set_slot(js, wrapper_obj, SLOT_CFUNC, js_mkfun(builtin_trigger_handler_wrapper)); 18891 - set_slot(js, wrapper_obj, SLOT_DATA, p); 18892 - jsval_t wrapper_fn = mkval(T_FUNC, vdata(wrapper_obj)); 18893 - queue_microtask(js, wrapper_fn); 18890 + static inline void trigger_handlers(struct js *js, jsval_t p) { 18891 + uint32_t pid = get_promise_id(js, p); 18892 + queue_promise_trigger(pid); 18894 18893 } 18895 18894 18896 - static jsval_t builtin_trigger_handler_wrapper(struct js *js, jsval_t *args, int nargs) { 18897 - jsval_t me = js->current_func; 18898 - jsval_t p = get_slot(js, me, SLOT_DATA); 18899 - if (vtype(p) != T_PROMISE) return js_mkundef(); 18900 - 18901 - uint32_t pid = get_promise_id(js, p); 18895 + void js_process_promise_handlers(struct js *js, uint32_t pid) { 18902 18896 promise_data_entry_t *pd = get_promise_data(pid, false); 18903 - if (!pd) return js_mkundef(); 18897 + if (!pd) return; 18904 18898 18905 18899 int state = pd->state; 18906 18900 jsval_t val = pd->value; ··· 18934 18928 } 18935 18929 } 18936 18930 18937 - utarray_clear(pd->handlers); 18938 - return js_mkundef(); 18931 + utarray_clear(pd->handlers); 18939 18932 } 18940 18933 18941 18934 static void resolve_promise(struct js *js, jsval_t p, jsval_t val) { ··· 22538 22531 22539 22532 while (next(js) != TOK_EOF && !is_err(res)) { 22540 22533 res = js_stmt(js); 22541 - if (js->needs_gc && js->eval_depth == 1) { 22534 + if (js->needs_gc && js->eval_depth == 1 && !js->gc_suppress) { 22542 22535 js->needs_gc = false; 22543 22536 js_gc_compact(js); 22544 22537 }
+29 -3
src/modules/timer.c
··· 27 27 28 28 typedef struct microtask_entry { 29 29 jsval_t callback; 30 + uint32_t promise_id; 30 31 struct microtask_entry *next; 31 32 } microtask_entry_t; 32 33 ··· 195 196 if (entry == NULL) return; 196 197 197 198 entry->callback = callback; 199 + entry->promise_id = 0; 200 + entry->next = NULL; 201 + 202 + if (timer_state.microtasks_tail == NULL) { 203 + timer_state.microtasks = entry; 204 + timer_state.microtasks_tail = entry; 205 + } else { 206 + timer_state.microtasks_tail->next = entry; 207 + timer_state.microtasks_tail = entry; 208 + } 209 + } 210 + 211 + void queue_promise_trigger(uint32_t promise_id) { 212 + microtask_entry_t *entry = ANT_GC_MALLOC(sizeof(microtask_entry_t)); 213 + if (entry == NULL) return; 214 + 215 + entry->callback = 0; 216 + entry->promise_id = promise_id; 198 217 entry->next = NULL; 199 218 200 219 if (timer_state.microtasks_tail == NULL) { ··· 207 226 } 208 227 209 228 void process_microtasks(struct js *js) { 229 + js_set_gc_suppress(js, true); 230 + 210 231 while (timer_state.microtasks != NULL) { 211 232 microtask_entry_t *entry = timer_state.microtasks; 212 233 timer_state.microtasks = entry->next; ··· 215 236 timer_state.microtasks_tail = NULL; 216 237 } 217 238 218 - jsval_t args[0]; 219 - js_call(js, entry->callback, args, 0); 239 + if (entry->promise_id != 0) { 240 + js_process_promise_handlers(js, entry->promise_id); 241 + } else { 242 + jsval_t args[0]; 243 + js_call(js, entry->callback, args, 0); 244 + } 220 245 221 246 ANT_GC_FREE(entry); 222 247 } 223 248 249 + js_set_gc_suppress(js, false); 224 250 js_check_unhandled_rejections(js); 225 251 } 226 252 ··· 343 369 t->callback = fwd_val(ctx, t->callback); 344 370 } 345 371 for (microtask_entry_t *m = timer_state.microtasks; m; m = m->next) { 346 - m->callback = fwd_val(ctx, m->callback); 372 + if (m->promise_id == 0) m->callback = fwd_val(ctx, m->callback); 347 373 } 348 374 for (immediate_entry_t *i = timer_state.immediates; i; i = i->next) { 349 375 i->callback = fwd_val(ctx, i->callback);