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.

enable GC throttling during server response handling

+82 -48
+17 -7
include/gc.h
··· 17 17 jsval_t cached; 18 18 } rope_node_t; 19 19 20 - #define GC_FWD_LOAD_FACTOR 70 21 - #define GC_ROOTS_INITIAL_CAP 32 22 - 23 - #define GC_FWD_ARGS jsval_t (*fwd_val)(void *ctx, jsval_t old), void *ctx 24 - #define GC_UPDATE_ARGS ant_t *js, jsoff_t (*fwd_off)(void *ctx, jsoff_t old), GC_FWD_ARGS 25 - #define GC_OP_VAL_ARGS void (*op_val)(void *ctx, jsval_t *val), void *ctx 20 + #define GC_FWD_LOAD_FACTOR 70 21 + #define GC_ROOTS_INITIAL_CAP 32 22 + #define GC_CB(ret, name, arg) ret (*name)(void *ctx, arg old) 26 23 27 - void js_maybe_gc(ant_t *js); 28 24 size_t js_gc_compact(ant_t *js); 25 + 26 + #define GC_CTX void *ctx 27 + #define GC_FWD_OFF GC_CB(jsoff_t, fwd_off, jsoff_t) 28 + #define GC_FWD_VAL GC_CB(jsval_t, fwd_val, jsval_t) 29 + #define GC_WEAK_OFF GC_CB(jsoff_t, weak_off, jsoff_t) 30 + #define GC_OP_VAL void (*op_val)(void *ctx, jsval_t *val) 31 + 32 + #define GC_FWD_ARGS GC_FWD_VAL, GC_CTX 33 + #define GC_RESERVE_ARGS ant_t *js, GC_FWD_OFF, GC_FWD_ARGS 34 + #define GC_UPDATE_ARGS ant_t *js, GC_FWD_OFF, GC_WEAK_OFF, GC_FWD_ARGS 35 + #define GC_OP_VAL_ARGS GC_OP_VAL, GC_CTX 36 + 37 + void js_gc_maybe(ant_t *js); 38 + void js_gc_throttle(bool enabled); 29 39 30 40 #endif
+1 -1
include/internal.h
··· 114 114 bool is_internal_prop(const char *key, jsoff_t klen); 115 115 size_t uint_to_str(char *buf, size_t bufsize, uint64_t val); 116 116 117 - void js_gc_reserve_roots(GC_UPDATE_ARGS); 117 + void js_gc_reserve_roots(GC_RESERVE_ARGS); 118 118 void js_gc_update_roots(GC_UPDATE_ARGS); 119 119 120 120 jsoff_t esize(jsoff_t w);
+29 -28
src/ant.c
··· 11019 11019 pos4 = js->pos; 11020 11020 11021 11021 while (!(flags & F_NOEXEC)) { 11022 - js_maybe_gc(js); 11022 + js_gc_maybe(js); 11023 11023 js->flags = flags, js->pos = pos1, js->consumed = 1; 11024 11024 if (next(js) != TOK_SEMICOLON) { 11025 11025 v = resolveprop(js, js_expr(js)); ··· 11128 11128 11129 11129 if (exe) { 11130 11130 while (true) { 11131 - js_maybe_gc(js); 11131 + js_gc_maybe(js); 11132 11132 js->flags = flags; 11133 11133 js->pos = cond_start; 11134 11134 js->consumed = 1; ··· 11224 11224 11225 11225 if (exe) { 11226 11226 do { 11227 - js_maybe_gc(js); 11227 + js_gc_maybe(js); 11228 11228 js->pos = body_start; 11229 11229 js->consumed = 1; 11230 11230 js->flags = (flags & ~F_NOEXEC) | F_LOOP; ··· 22474 22474 if (c->js->ascii_cache_init) for (int i = 0; i < 128; i++) op_val(c, &c->js->ascii_char_cache[i]); 22475 22475 } 22476 22476 22477 - void js_gc_reserve_roots(GC_UPDATE_ARGS) { 22477 + void js_gc_reserve_roots(GC_RESERVE_ARGS) { 22478 22478 #define RSV_OFF(x) ((x) ? (void)fwd_off(ctx, x) : (void)0) 22479 22479 #define RSV_VAL(x) (void)fwd_val(ctx, x) 22480 22480 ··· 22484 22484 22485 22485 promise_data_entry_t *pd, *pd_tmp; 22486 22486 HASH_ITER(hh, promise_registry, pd, pd_tmp) { 22487 - (void)fwd_off(ctx, pd->obj_offset); 22487 + bool can_collect = (pd->state != 0) && (utarray_len(pd->handlers) == 0); 22488 + if (can_collect) continue; 22488 22489 RSV_VAL(pd->value); 22489 22490 UTARRAY_EACH(pd->handlers, promise_handler_t, h) { 22490 - RSV_VAL(h->onFulfilled); RSV_VAL(h->onRejected); RSV_VAL(h->nextPromise); 22491 + RSV_VAL(h->onFulfilled); 22492 + RSV_VAL(h->onRejected); 22493 + RSV_VAL(h->nextPromise); 22491 22494 } 22492 22495 } 22493 - 22494 - // accessor registry is a weak reference 22495 - // objects only survive if reachable from other roots 22496 - (void)accessor_registry; 22497 - 22496 + 22498 22497 proxy_data_t *proxy, *proxy_tmp; 22499 22498 HASH_ITER(hh, proxy_registry, proxy, proxy_tmp) { 22500 22499 RSV_VAL(proxy->target); 22501 22500 RSV_VAL(proxy->handler); 22502 22501 } 22503 22502 22504 - descriptor_entry_t *desc, *desc_tmp; 22505 - HASH_ITER(hh, desc_registry, desc, desc_tmp) { 22506 - if (desc->has_getter) RSV_VAL(desc->getter); 22507 - if (desc->has_setter) RSV_VAL(desc->setter); 22508 - } 22503 + // accessor/descriptor registry are weak references 22504 + // objects only survive if reachable from other roots 22505 + (void)accessor_registry; 22506 + (void)desc_registry; 22509 22507 22510 22508 #undef RSV_OFF 22511 22509 #undef RSV_VAL ··· 22514 22512 void js_gc_update_roots(GC_UPDATE_ARGS) { 22515 22513 #define FWD_OFF(x) ((x) ? ((x) = fwd_off(ctx, x)) : 0) 22516 22514 #define FWD_VAL(x) ((x) = fwd_val(ctx, x)) 22515 + #define IS_UNREACHABLE(old, new) ((new) == (old) && (old) != 0 && (old) < js->brk) 22517 22516 22518 22517 gc_cb_ctx_t cb_ctx = { fwd_off, fwd_val, ctx, js }; 22519 22518 gc_roots_common(gc_update_off_cb, gc_update_val_cb, &cb_ctx); ··· 22530 22529 HASH_FIND(hh_unhandled, unhandled_rejections, &pd->promise_id, sizeof(uint32_t), in_unhandled); 22531 22530 if (in_unhandled) HASH_DELETE(hh_unhandled, unhandled_rejections, pd); 22532 22531 22533 - jsoff_t new_off = fwd_off(ctx, pd->obj_offset); 22534 - if (new_off == 0) { utarray_free(pd->handlers); free(pd); continue; } 22532 + jsoff_t new_off = weak_off(ctx, pd->obj_offset); 22533 + if (new_off == (jsoff_t)~0) { utarray_free(pd->handlers); free(pd); continue; } 22534 + 22535 + bool can_collect = (pd->state != 0) && (utarray_len(pd->handlers) == 0); 22536 + if (can_collect) { utarray_free(pd->handlers); free(pd); continue; } 22535 22537 22536 22538 pd->obj_offset = new_off; 22537 22539 FWD_VAL(pd->value); 22538 22540 UTARRAY_EACH(pd->handlers, promise_handler_t, h) { 22539 - FWD_VAL(h->onFulfilled); FWD_VAL(h->onRejected); FWD_VAL(h->nextPromise); 22541 + FWD_VAL(h->onFulfilled); 22542 + FWD_VAL(h->onRejected); 22543 + FWD_VAL(h->nextPromise); 22540 22544 } 22541 22545 22542 22546 HASH_ADD(hh, new_promise_registry, promise_id, sizeof(uint32_t), pd); ··· 22547 22551 for (proxy_data_t *new_proxy_registry = NULL, *_once = NULL; !_once; _once = (void*)1, proxy_registry = new_proxy_registry) 22548 22552 HASH_ITER(hh, proxy_registry, proxy, proxy_tmp) { 22549 22553 HASH_DEL(proxy_registry, proxy); 22550 - jsoff_t old_off = proxy->obj_offset; 22551 - jsoff_t new_off = fwd_off(ctx, old_off); 22552 - if (new_off == 0) { free(proxy); continue; } 22554 + jsoff_t new_off = weak_off(ctx, proxy->obj_offset); 22555 + if (new_off == (jsoff_t)~0) { free(proxy); continue; } 22553 22556 proxy->obj_offset = new_off; 22554 22557 FWD_VAL(proxy->target); FWD_VAL(proxy->handler); 22555 22558 HASH_ADD(hh, new_proxy_registry, obj_offset, sizeof(jsoff_t), proxy); ··· 22559 22562 for (dynamic_accessors_t *new_acc_registry = NULL, *_once = NULL; !_once; _once = (void*)1, accessor_registry = new_acc_registry) 22560 22563 HASH_ITER(hh, accessor_registry, acc, acc_tmp) { 22561 22564 HASH_DEL(accessor_registry, acc); 22562 - jsoff_t old_off = acc->obj_offset; 22563 - jsoff_t new_off = fwd_off(ctx, old_off); 22564 - if (new_off == 0) { free(acc); continue; } 22565 + jsoff_t new_off = weak_off(ctx, acc->obj_offset); 22566 + if (new_off == (jsoff_t)~0) { free(acc); continue; } 22565 22567 acc->obj_offset = new_off; 22566 22568 HASH_ADD(hh, new_acc_registry, obj_offset, sizeof(jsoff_t), acc); 22567 22569 } ··· 22570 22572 for (descriptor_entry_t *new_desc_registry = NULL, *_once = NULL; !_once; _once = (void*)1, desc_registry = new_desc_registry) 22571 22573 HASH_ITER(hh, desc_registry, desc, desc_tmp) { 22572 22574 HASH_DEL(desc_registry, desc); 22573 - jsoff_t old_off = (jsoff_t)(desc->key >> 32); 22574 - jsoff_t new_off = fwd_off(ctx, old_off); 22575 - if (new_off == 0) { free(desc->prop_name); free(desc); continue; } 22575 + jsoff_t new_off = weak_off(ctx, (jsoff_t)(desc->key >> 32)); 22576 + if (new_off == (jsoff_t)~0) { free(desc); continue; } 22576 22577 if (desc->has_getter) FWD_VAL(desc->getter); 22577 22578 if (desc->has_setter) FWD_VAL(desc->setter); 22578 22579 desc->key = ((uint64_t)new_off << 32) | (uint32_t)(desc->key & 0xFFFFFFFF);
+25 -9
src/gc.c
··· 35 35 static size_t gc_scratch_size = 0; 36 36 static time_t gc_last_run_time = 0; 37 37 38 + static bool gc_throttled = false; 39 + void js_gc_throttle(bool enabled) { gc_throttled = enabled; } 40 + 38 41 #define FWD_EMPTY ((jsoff_t)~0) 39 42 #define FWD_TOMBSTONE ((jsoff_t)~1) 40 43 ··· 560 563 return gc_apply_val(ctx, val); 561 564 } 562 565 566 + static jsoff_t gc_weak_off_callback(void *ctx_ptr, jsoff_t old_off) { 567 + gc_ctx_t *ctx = (gc_ctx_t *)ctx_ptr; 568 + if (old_off >= ctx->js->brk) return old_off; 569 + return fwd_lookup(&ctx->fwd, old_off); 570 + } 571 + 563 572 size_t js_gc_compact(ant_t *js) { 564 573 if (!js || js->brk == 0) return 0; 565 574 if (js->brk < 2 * 1024 * 1024) return 0; ··· 630 639 if ((header_at_0 & 3) == T_OBJ) gc_reserve_object(&ctx, 0); 631 640 } 632 641 633 - js_gc_reserve_roots( 634 - js, 635 - gc_fwd_off_callback, 642 + js_gc_reserve_roots(js, 643 + gc_fwd_off_callback, 636 644 gc_fwd_val_callback, 637 645 &ctx 638 - ); 639 - 640 - gc_drain_work_queue(&ctx); 646 + ); gc_drain_work_queue(&ctx); 641 647 642 648 if (ctx.failed) { 643 649 free(mark_bits); ··· 647 653 } 648 654 649 655 js_gc_update_roots(js, 650 - gc_apply_off_callback, 656 + gc_apply_off_callback, 657 + gc_weak_off_callback, 651 658 gc_apply_val_callback, 652 659 &ctx); 653 660 ··· 676 683 677 684 void js_maybe_gc(ant_t *js) { 678 685 jsoff_t thresh = js->brk / 4; 679 - if (thresh < 2 * 1024 * 1024) thresh = 2 * 1024 * 1024; 680 - if (thresh > 16 * 1024 * 1024) thresh = 16 * 1024 * 1024; 686 + 687 + jsoff_t min_thresh = gc_throttled 688 + ? 8 * 1024 * 1024 689 + : 2 * 1024 * 1024; 690 + 691 + jsoff_t max_thresh = gc_throttled 692 + ? 64 * 1024 * 1024 693 + : 16 * 1024 * 1024; 694 + 695 + if (thresh < min_thresh) thresh = min_thresh; 696 + if (thresh > max_thresh) thresh = max_thresh; 681 697 682 698 if (js->gc_alloc_since > thresh || js->needs_gc) { 683 699 js->needs_gc = false;
+9 -2
src/modules/server.c
··· 960 960 } 961 961 962 962 server->pending_responses = NULL; 963 + js_gc_throttle(true); 964 + 963 965 js_reactor_set_poll_hook( 964 - (reactor_poll_hook_t)check_pending_responses, server 965 - ); js_run_event_loop(js); 966 + (reactor_poll_hook_t) 967 + check_pending_responses, 968 + server 969 + ); 970 + 971 + js_run_event_loop(js); 972 + js_gc_throttle(false); 966 973 967 974 return js_mknum(1); 968 975 }
+1 -1
src/reactor.c
··· 81 81 82 82 if (work & WORK_BLOCKING) uv_run(uv_default_loop(), UV_RUN_NOWAIT); 83 83 else if ((work & WORK_ASYNC) || uv_alive) { 84 - js_maybe_gc(js); 84 + js_gc_maybe(js); 85 85 uv_run(uv_default_loop(), UV_RUN_ONCE); 86 86 } else if (work & WORK_COROUTINES) break; 87 87 }