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.

add promise assimilation helper, adjust GC thresholds, and optimize numeric string formatting for performance

+98 -23
+1
include/ant.h
··· 189 189 void js_set_finalizer(ant_value_t obj, js_finalizer_fn fn); 190 190 191 191 ant_value_t js_get_slot(ant_value_t obj, internal_slot_t slot); 192 + ant_value_t js_promise_assimilate_awaitable(ant_t *js, ant_value_t value); 192 193 ant_value_t js_promise_then(ant_t *js, ant_value_t promise, ant_value_t on_fulfilled, ant_value_t on_rejected); 193 194 194 195 void js_set_slot(ant_value_t obj, internal_slot_t slot, ant_value_t value);
+3 -2
include/gc.h
··· 10 10 #define GC_FORCE_INTERVAL_MS 50 11 11 #define GC_MAJOR_EVERY_N_MINOR 8 12 12 13 - #define GC_HEAP_GROWTH(n) ((n) + (n) / 2) 14 - 15 13 #define GC_OBJ_TYPE_MASK (JS_TPFLG(T_OBJ) \ 16 14 | JS_TPFLG(T_ARR) \ 17 15 | JS_TPFLG(T_PROMISE) \ ··· 30 28 void gc_run_minor(ant_t *js); 31 29 void gc_maybe(ant_t *js); 32 30 void gc_remember_add(ant_t *js, ant_object_t *obj); 31 + 32 + size_t gc_live_major_threshold(ant_t *js); 33 + size_t gc_pool_major_threshold(ant_t *js); 33 34 34 35 void gc_func_mark_profile_enable(bool enabled); 35 36 void gc_func_mark_profile_reset(void);
+47 -12
src/ant.c
··· 394 394 } 395 395 396 396 static ant_object_t *obj_alloc(ant_t *js, uint8_t type_tag, uint8_t inobj_limit) { 397 - size_t threshold = GC_HEAP_GROWTH(js->gc_last_live); 398 - 399 - if (threshold < 2048) threshold = 2048; 397 + size_t threshold = gc_live_major_threshold(js); 400 398 if (js->obj_arena.live_count >= threshold) gc_run(js); 401 399 402 400 ant_object_t *obj = (ant_object_t *)fixed_arena_alloc(&js->obj_arena); ··· 1859 1857 return n; 1860 1858 } 1861 1859 1860 + static size_t strnum_safe_integer(double dv, char *buf, size_t len) { 1861 + char temp[32]; 1862 + size_t pos = sizeof(temp); 1863 + uint64_t value = 0; 1864 + bool negative = signbit(dv) != 0; 1865 + 1866 + if (negative) dv = -dv; 1867 + value = (uint64_t)dv; 1868 + 1869 + do { 1870 + temp[--pos] = (char)('0' + (value % 10u)); 1871 + value /= 10u; 1872 + } while (value != 0); 1873 + 1874 + if (negative) temp[--pos] = '-'; 1875 + return cpy(buf, len, temp + pos, sizeof(temp) - pos); 1876 + } 1877 + 1862 1878 static size_t strnum(ant_value_t value, char *buf, size_t len) { 1863 1879 double dv = tod(value); 1864 - 1865 - if (isnan(dv)) return cpy(buf, len, "NaN", 3); 1866 - if (isinf(dv)) return cpy(buf, len, dv > 0 ? "Infinity" : "-Infinity", dv > 0 ? 8 : 9); 1867 1880 if (dv == 0.0) return cpy(buf, len, "0", 1); 1881 + 1882 + if (__builtin_expect(isnan(dv), 0)) 1883 + return cpy(buf, len, "NaN", 3); 1884 + if (__builtin_expect(isinf(dv), 0)) 1885 + return cpy(buf, len, dv > 0 ? "Infinity" : "-Infinity", dv > 0 ? 8 : 9); 1868 1886 1869 1887 char temp[64]; 1870 1888 int sign = dv < 0 ? 1 : 0; ··· 1873 1891 double iv; 1874 1892 double frac = modf(adv, &iv); 1875 1893 if (frac == 0.0 && adv < 9007199254740992.0) { 1876 - int result = snprintf(temp, sizeof(temp), "%.0f", dv); 1877 - fix_exponent(temp, (size_t)result); 1878 - return cpy(buf, len, temp, strlen(temp)); 1894 + return strnum_safe_integer(dv, buf, len); 1879 1895 } 1880 1896 1881 1897 for (int prec = 1; prec <= 17; prec++) { ··· 1885 1901 fix_exponent(temp, (size_t)n); 1886 1902 return cpy(buf, len, temp, strlen(temp)); 1887 1903 } 1888 - (void)n; 1889 1904 } 1890 1905 1891 1906 int result = snprintf(temp, sizeof(temp), "%.17g", dv); ··· 8053 8068 elem_str = (const char *)(uintptr_t)(soff); 8054 8069 elem_len = slen; 8055 8070 } else if (et == T_NUM) { 8056 - snprintf(numstr, sizeof(numstr), "%g", tod(elem)); 8071 + elem_len = strnum(elem, numstr, sizeof(numstr)); 8057 8072 elem_str = numstr; 8058 - elem_len = strlen(numstr); 8059 8073 } else if (et == T_BOOL) { 8060 8074 elem_str = vdata(elem) ? "true" : "false"; 8061 8075 elem_len = strlen(elem_str); ··· 11284 11298 static inline ant_value_t js_get_thenable_then(ant_t *js, ant_value_t value) { 11285 11299 if (!is_object_type(value)) return js_mkundef(); 11286 11300 return js_getprop_fallback(js, value, "then"); 11301 + } 11302 + 11303 + ant_value_t js_promise_assimilate_awaitable(ant_t *js, ant_value_t value) { 11304 + if (vtype(value) == T_PROMISE || !is_object_type(value)) return value; 11305 + 11306 + GC_ROOT_SAVE(root_mark, js); 11307 + GC_ROOT_PIN(js, value); 11308 + 11309 + ant_value_t then_prop = js_get_thenable_then(js, value); 11310 + GC_ROOT_PIN(js, then_prop); 11311 + 11312 + if (vtype(then_prop) == T_FUNC || vtype(then_prop) == T_CFUNC) { 11313 + ant_value_t promise = js_mkpromise(js); 11314 + GC_ROOT_PIN(js, promise); 11315 + js_resolve_promise(js, promise, value); 11316 + GC_ROOT_RESTORE(js, root_mark); 11317 + return promise; 11318 + } 11319 + 11320 + GC_ROOT_RESTORE(js, root_mark); 11321 + return value; 11287 11322 } 11288 11323 11289 11324 js_await_result_t js_promise_await_coroutine(ant_t *js, ant_value_t promise, coroutine_t *coro) {
+40 -4
src/gc/gc.c
··· 16 16 static size_t gc_nursery_threshold = GC_NURSERY_THRESHOLD; 17 17 static uint32_t gc_major_every_n = GC_MAJOR_EVERY_N_MINOR; 18 18 19 + static uint32_t gc_major_live_growth_x256 = 384; 20 + static uint32_t gc_major_pool_growth_x256 = 384; 21 + 19 22 static uint32_t gc_minor_surv_ewma = 128; 20 23 static uint32_t gc_major_recl_ewma = 26; 21 24 ··· 25 28 return (uint64_t)ts.tv_sec * 1000ULL + (uint64_t)ts.tv_nsec / 1000000ULL; 26 29 } 27 30 31 + static size_t gc_scaled_threshold(size_t base_live, uint32_t growth_x256, size_t floor) { 32 + size_t scaled = (base_live * (size_t)growth_x256) / 256u; 33 + if (scaled < floor) scaled = floor; 34 + return scaled; 35 + } 36 + 37 + size_t gc_live_major_threshold(ant_t *js) { 38 + size_t base_live = js ? js->gc_last_live : 0; 39 + return gc_scaled_threshold(base_live, gc_major_live_growth_x256, 2048u); 40 + } 41 + 42 + size_t gc_pool_major_threshold(ant_t *js) { 43 + size_t base_live = js ? js->gc_pool_last_live : 0; 44 + return gc_scaled_threshold(base_live, gc_major_pool_growth_x256, 4u * 1024u * 1024u); 45 + } 46 + 28 47 static void gc_adapt_nursery(size_t young_before, size_t survivors) { 29 48 if (young_before == 0) return; 30 49 uint32_t rate = (uint32_t)((survivors * 256) / young_before); ··· 49 68 if (gc_major_every_n > 2) gc_major_every_n--; 50 69 } else if (!gen_ineffective && low_reclaim) { 51 70 if (gc_major_every_n < GC_MAJOR_EVERY_N_MINOR * 4) gc_major_every_n++; 71 + } 72 + 73 + if (gen_ineffective && low_reclaim) { 74 + if (gc_major_live_growth_x256 < 1024) gc_major_live_growth_x256 += 96; 75 + if (gc_major_pool_growth_x256 < 1536) gc_major_pool_growth_x256 += 128; 76 + } else if (low_reclaim) { 77 + if (gc_major_live_growth_x256 < 896) gc_major_live_growth_x256 += 48; 78 + if (gc_major_pool_growth_x256 < 1280) gc_major_pool_growth_x256 += 64; 79 + } else if (high_reclaim) { 80 + if (gc_major_live_growth_x256 > 320) gc_major_live_growth_x256 -= 32; 81 + if (gc_major_pool_growth_x256 > 320) gc_major_pool_growth_x256 -= 32; 82 + } else { 83 + if (gc_major_live_growth_x256 > 384) gc_major_live_growth_x256 -= 16; 84 + else if (gc_major_live_growth_x256 < 384) gc_major_live_growth_x256 += 16; 85 + if (gc_major_pool_growth_x256 > 384) gc_major_pool_growth_x256 -= 16; 86 + else if (gc_major_pool_growth_x256 < 384) gc_major_pool_growth_x256 += 16; 52 87 } 53 88 } 54 89 ··· 153 188 gc_tick = 0; 154 189 gc_run_minor(js); 155 190 if (js->minor_gc_count >= gc_major_every_n) { 156 - js->minor_gc_count = 0; gc_run(js); 191 + js->minor_gc_count = 0; 192 + gc_run(js); 157 193 } 158 194 return; 159 195 } 160 196 161 - size_t threshold = GC_HEAP_GROWTH(js->gc_last_live); 162 - if (threshold < 2048) threshold = 2048; 197 + size_t threshold = gc_live_major_threshold(js); 163 198 164 199 if (live >= threshold) { 165 - gc_tick = 0; gc_run(js); 200 + gc_tick = 0; 201 + gc_run(js); 166 202 return; 167 203 } 168 204
+1
src/gc/objects.c
··· 320 320 gc_mark_value(js, frame->super_val); 321 321 gc_mark_value(js, frame->with_obj); 322 322 gc_mark_value(js, frame->completion.value); 323 + gc_mark_value(js, frame->arguments_obj); 323 324 } 324 325 325 326 for (sv_upvalue_t *uv = vm->open_upvalues; uv; uv = uv->next) {
+1 -3
src/pool.c
··· 307 307 if (align == 0) align = sizeof(void *); 308 308 309 309 js->gc_pool_alloc += size; 310 - size_t pool_threshold = GC_HEAP_GROWTH(js->gc_pool_last_live); 311 - 312 - if (pool_threshold < (4u * 1024u * 1024u)) pool_threshold = 4u * 1024u * 1024u; 310 + size_t pool_threshold = gc_pool_major_threshold(js); 313 311 if (js->gc_pool_alloc >= pool_threshold) gc_run(js); 314 312 if (kind == ANT_ALLOC_STRING) return string_pool_alloc(js, size, align); 315 313
+5 -2
src/silver/ops/async.h
··· 66 66 ); 67 67 68 68 ant_value_t promise = ctx->coro->async_promise; 69 + if (vm && vm->suspended) return; 69 70 70 71 if (is_err(result)) { 71 72 ant_value_t reject_value = js->thrown_exists ? js->thrown_value : result; ··· 95 96 96 97 ant_value_t result = sv_execute_entry(vm, ctx->func, ctx->this_val, NULL, 0); 97 98 ant_value_t promise = ctx->coro->async_promise; 99 + if (vm && vm->suspended) return; 98 100 99 101 if (is_err(result)) { 100 102 ant_value_t reject_value = js->thrown_exists ? js->thrown_value : result; ··· 501 503 } 502 504 503 505 static inline ant_value_t sv_await_value(ant_t *js, ant_value_t value) { 506 + value = js_promise_assimilate_awaitable(js, value); 507 + if (is_err(value)) return value; 504 508 if (vtype(value) != T_PROMISE) return value; 505 509 506 510 mco_coro *current_mco = mco_running(); 507 - if (!current_mco) 508 - current_mco = NULL; 511 + if (!current_mco) current_mco = NULL; 509 512 510 513 coroutine_t *coro = NULL; 511 514 if (current_mco) {