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.

introduce controlled GC safepoints

+46 -14
+6
include/gc.h
··· 37 37 void js_gc_maybe(ant_t *js); 38 38 void js_gc_throttle(bool enabled); 39 39 40 + #define js_gc_safepoint(js) do { \ 41 + (js)->gc_safe = true; \ 42 + js_gc_maybe(js); \ 43 + (js)->gc_safe = false; \ 44 + } while (0) 45 + 40 46 #endif
+1
include/internal.h
··· 60 60 bool is_hoisting; // true during function declaration hoisting pass 61 61 uint64_t sym_counter; // counter for generating unique symbol IDs 62 62 bool needs_gc; // deferred GC flag, checked at statement boundaries 63 + bool gc_safe; // true when GC is allowed to run (at safe points only) 63 64 jsoff_t gc_alloc_since; // bytes allocated since last GC 64 65 int eval_depth; // recursion depth of js_eval calls 65 66 int parse_depth; // recursion depth of parser (for stack overflow protection)
+16 -7
src/ant.c
··· 7384 7384 if (is_non_numeric(lu) || is_non_numeric(ru) || (vtype(lu) == T_STR && vtype(ru) == T_STR)) { 7385 7385 jsval_t l_str = coerce_to_str_concat(js, l); 7386 7386 if (is_err(l_str)) return l_str; 7387 + jshdl_t lh = js_root(js, l_str); 7387 7388 jsval_t r_str = coerce_to_str_concat(js, r); 7389 + l_str = js_deref(js, lh); js_unroot(js, lh); 7388 7390 if (is_err(r_str)) return r_str; 7389 7391 return do_string_op(js, op, l_str, r_str); 7390 7392 } ··· 9517 9519 goto *dispatch[tok]; 9518 9520 9519 9521 do_binop: { 9522 + jshdl_t lh = js_root(js, lhs); 9520 9523 jsval_t rhs = js_expr_bp(js, bp + 1); 9524 + lhs = js_deref(js, lh); js_unroot(js, lh); 9521 9525 if (is_err(rhs)) return rhs; 9522 9526 lhs = do_op(js, tok, lhs, rhs); 9523 9527 goto loop; 9524 9528 } 9525 9529 9526 9530 do_exp: { 9531 + jshdl_t lh = js_root(js, lhs); 9527 9532 jsval_t rhs = js_expr_bp(js, bp); 9533 + lhs = js_deref(js, lh); js_unroot(js, lh); 9528 9534 if (is_err(rhs)) return rhs; 9529 9535 lhs = do_op(js, TOK_EXP, lhs, rhs); 9530 9536 goto loop; ··· 9534 9540 uint8_t flags = js->flags; 9535 9541 lhs = resolveprop(js, lhs); 9536 9542 if (js_truthy(js, lhs)) js->flags |= F_NOEXEC; 9543 + jshdl_t lh = js_root(js, lhs); 9537 9544 jsval_t rhs = js_expr_bp(js, bp); 9545 + lhs = js_deref(js, lh); js_unroot(js, lh); 9538 9546 if (!(flags & F_NOEXEC) && !js_truthy(js, lhs)) lhs = rhs; 9539 9547 js->flags = flags; 9540 9548 if (is_err(rhs)) return rhs; ··· 9545 9553 uint8_t flags = js->flags; 9546 9554 lhs = resolveprop(js, lhs); 9547 9555 if (!js_truthy(js, lhs)) js->flags |= F_NOEXEC; 9556 + jshdl_t lh = js_root(js, lhs); 9548 9557 jsval_t rhs = js_expr_bp(js, bp); 9558 + lhs = js_deref(js, lh); js_unroot(js, lh); 9549 9559 if (!(flags & F_NOEXEC) && js_truthy(js, lhs)) lhs = rhs; 9550 9560 js->flags = flags; 9551 9561 if (is_err(rhs)) return rhs; ··· 9557 9567 lhs = resolveprop(js, lhs); 9558 9568 uint8_t lhs_type = vtype(lhs); 9559 9569 if (lhs_type != T_NULL && lhs_type != T_UNDEF) js->flags |= F_NOEXEC; 9570 + jshdl_t lh = js_root(js, lhs); 9560 9571 jsval_t rhs = js_expr_bp(js, bp); 9572 + lhs = js_deref(js, lh); js_unroot(js, lh); 9561 9573 if (!(flags & F_NOEXEC) && (lhs_type == T_NULL || lhs_type == T_UNDEF)) lhs = rhs; 9562 9574 js->flags = flags; 9563 9575 if (is_err(rhs)) return rhs; ··· 11023 11035 pos4 = js->pos; 11024 11036 11025 11037 while (!(flags & F_NOEXEC)) { 11026 - js_gc_maybe(js); 11038 + js_gc_safepoint(js); 11027 11039 js->flags = flags, js->pos = pos1, js->consumed = 1; 11028 11040 if (next(js) != TOK_SEMICOLON) { 11029 11041 v = resolveprop(js, js_expr(js)); ··· 11132 11144 11133 11145 if (exe) { 11134 11146 while (true) { 11135 - js_gc_maybe(js); 11147 + js_gc_safepoint(js); 11136 11148 js->flags = flags; 11137 11149 js->pos = cond_start; 11138 11150 js->consumed = 1; ··· 11228 11240 11229 11241 if (exe) { 11230 11242 do { 11231 - js_gc_maybe(js); 11243 + js_gc_safepoint(js); 11232 11244 js->pos = body_start; 11233 11245 js->consumed = 1; 11234 11246 js->flags = (flags & ~F_NOEXEC) | F_LOOP; ··· 22682 22694 22683 22695 while (next(js) != TOK_EOF && !is_err(res)) { 22684 22696 res = js_stmt(js); 22685 - if (js->needs_gc && js->eval_depth == 1) { 22686 - js->needs_gc = false; 22687 - if (js_gc_compact(js) > 0) js->gc_alloc_since = 0; 22688 - } 22697 + if (js->needs_gc && js->eval_depth == 1) js_gc_safepoint(js); 22689 22698 if (js->flags & F_RETURN) break; 22690 22699 } 22691 22700
+5
src/gc.c
··· 573 573 if (!js || js->brk == 0) return 0; 574 574 if (js->brk < 2 * 1024 * 1024) return 0; 575 575 576 + if (!js->gc_safe) { 577 + js->needs_gc = true; 578 + return 0; 579 + } 580 + 576 581 mco_coro *running = mco_running(); 577 582 int in_coroutine = (running != NULL && running->stack_base != NULL); 578 583
+2 -6
src/reactor.c
··· 45 45 } else free_coroutine(temp); 46 46 } 47 47 48 - if (js->needs_gc) { 49 - js->needs_gc = false; 50 - if (js_gc_compact(js) > 0) js->gc_alloc_since = 0; 51 - } 52 - 48 + if (js->needs_gc) js_gc_safepoint(js); 53 49 if (g_poll_hook) g_poll_hook(g_poll_hook_data); 54 50 } 55 51 ··· 80 76 81 77 if (work & WORK_BLOCKING) uv_run(uv_default_loop(), UV_RUN_NOWAIT); 82 78 else if ((work & WORK_ASYNC) || uv_alive) { 83 - js_gc_maybe(js); 79 + js_gc_safepoint(js); 84 80 uv_run(uv_default_loop(), UV_RUN_ONCE); 85 81 } else if (work & WORK_COROUTINES) break; 86 82 }
+1 -1
src/sugar.c
··· 251 251 if (mco_status(mco) == MCO_DEAD) { 252 252 remove_coroutine(coro); 253 253 free_coroutine(coro); 254 - js_gc_maybe(js); 254 + js_gc_safepoint(js); 255 255 } 256 256 257 257 return promise;
+15
tests/test_gc_stress7.js
··· 1 + // Minimal crash: pad() + string concat in a nested loop 2 + function pad(s, n) { 3 + while (s.length < n) s += ' '; 4 + return s; 5 + } 6 + 7 + let sink = []; 8 + for (let i = 0; i < 10000; i++) { 9 + for (let j = 0; j < 5; j++) { 10 + sink.push(pad('INFO', 5) + ' ' + pad('hello', 15)); 11 + } 12 + if (sink.length > 100) sink = []; 13 + } 14 + 15 + console.log('OK');