faster gc
This commit is contained in:
@@ -1082,6 +1082,11 @@ struct JSContext {
|
||||
uint8_t *heap_end; /* end of block */
|
||||
size_t current_block_size; /* current block size (64KB initially) */
|
||||
size_t next_block_size; /* doubles if <10% recovered after GC */
|
||||
int gc_poor_streak; /* consecutive poor-recovery GC cycles */
|
||||
|
||||
/* GC stats (lightweight, always on) */
|
||||
uint64_t gc_count; /* number of GC cycles */
|
||||
uint64_t gc_bytes_copied; /* total bytes copied across all GCs */
|
||||
|
||||
/* Constant text pool — compilation constants */
|
||||
uint8_t *ct_base; /* pool base */
|
||||
|
||||
@@ -1678,6 +1678,10 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
|
||||
/* Update context with new block */
|
||||
size_t new_used = to_free - to_base;
|
||||
|
||||
/* Update GC stats */
|
||||
ctx->gc_count++;
|
||||
ctx->gc_bytes_copied += new_used;
|
||||
size_t recovered = old_used > new_used ? old_used - new_used : 0;
|
||||
|
||||
ctx->heap_base = to_base;
|
||||
@@ -1697,19 +1701,23 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If <20% recovered, double next block size for future allocations
|
||||
But only if allow_grow is set (i.e., GC was triggered due to low space) */
|
||||
/* If <40% recovered, grow next block size for future allocations.
|
||||
First poor recovery: double. Consecutive poor: quadruple. */
|
||||
#ifdef DUMP_GC
|
||||
int will_grow = 0;
|
||||
#endif
|
||||
if (allow_grow && recovered > 0 && old_used > 0 && recovered < old_used / 5) {
|
||||
size_t doubled = new_size * 2;
|
||||
if (doubled <= buddy_max_block(&ctx->rt->buddy)) {
|
||||
ctx->next_block_size = doubled;
|
||||
if (allow_grow && recovered > 0 && old_used > 0 && recovered < old_used * 2 / 5) {
|
||||
size_t factor = ctx->gc_poor_streak >= 1 ? 4 : 2;
|
||||
size_t grown = new_size * factor;
|
||||
if (grown <= buddy_max_block(&ctx->rt->buddy)) {
|
||||
ctx->next_block_size = grown;
|
||||
#ifdef DUMP_GC
|
||||
will_grow = 1;
|
||||
#endif
|
||||
}
|
||||
ctx->gc_poor_streak++;
|
||||
} else {
|
||||
ctx->gc_poor_streak = 0;
|
||||
}
|
||||
|
||||
#ifdef DUMP_GC
|
||||
@@ -1855,6 +1863,20 @@ JSContext *JS_NewContextRawWithHeapSize (JSRuntime *rt, size_t heap_size) {
|
||||
/* Initialize per-context execution state (moved from JSRuntime) */
|
||||
ctx->current_exception = JS_NULL;
|
||||
|
||||
/* Initialize constant text pool (avoids overflow pages for common case) */
|
||||
{
|
||||
size_t ct_pool_size = 64 * 1024; /* 64KB initial CT pool */
|
||||
ctx->ct_base = js_malloc_rt (ct_pool_size);
|
||||
if (!ctx->ct_base) {
|
||||
js_free_rt (ctx->class_array);
|
||||
js_free_rt (ctx->class_proto);
|
||||
js_free_rt (ctx);
|
||||
return NULL;
|
||||
}
|
||||
ctx->ct_free = ctx->ct_base;
|
||||
ctx->ct_end = ctx->ct_base + ct_pool_size;
|
||||
}
|
||||
|
||||
/* Initialize constant text intern table */
|
||||
ctx->ct_pages = NULL;
|
||||
ctx->ct_array = NULL;
|
||||
@@ -1944,6 +1966,7 @@ void JS_FreeContext (JSContext *ctx) {
|
||||
|
||||
/* Free constant text pool and intern table */
|
||||
ct_free_all (ctx);
|
||||
if (ctx->ct_base) js_free_rt (ctx->ct_base);
|
||||
js_free_rt (ctx->ct_hash);
|
||||
js_free_rt (ctx->ct_array);
|
||||
|
||||
@@ -9757,6 +9780,22 @@ static JSValue js_mach_dump_mcode (JSContext *ctx, JSValue this_val, int argc, J
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
/* gc_stats() — return {count, bytes_copied, heap_size, ct_pages} and reset counters */
|
||||
static JSValue js_gc_stats (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||
JSValue obj = JS_NewObject (ctx);
|
||||
if (JS_IsException (obj)) return obj;
|
||||
JS_SetPropertyStr (ctx, obj, "count", JS_NewInt64 (ctx, (int64_t)ctx->gc_count));
|
||||
JS_SetPropertyStr (ctx, obj, "bytes_copied", JS_NewInt64 (ctx, (int64_t)ctx->gc_bytes_copied));
|
||||
JS_SetPropertyStr (ctx, obj, "heap_size", JS_NewInt64 (ctx, (int64_t)ctx->current_block_size));
|
||||
/* Count CT overflow pages */
|
||||
int ct_page_count = 0;
|
||||
for (CTPage *p = (CTPage *)ctx->ct_pages; p; p = p->next) ct_page_count++;
|
||||
JS_SetPropertyStr (ctx, obj, "ct_pages", JS_NewInt32 (ctx, ct_page_count));
|
||||
ctx->gc_count = 0;
|
||||
ctx->gc_bytes_copied = 0;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* mach_compile_mcode_bin(name, mcode_json) - compile mcode IR to serialized binary blob */
|
||||
static JSValue js_mach_compile_mcode_bin (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||
if (argc < 2 || !JS_IsText (argv[0]) || !JS_IsText (argv[1]))
|
||||
@@ -10849,6 +10888,7 @@ static void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
|
||||
js_set_global_cfunc(ctx, "mach_eval_mcode", js_mach_eval_mcode, 3);
|
||||
js_set_global_cfunc(ctx, "mach_dump_mcode", js_mach_dump_mcode, 3);
|
||||
js_set_global_cfunc(ctx, "mach_compile_mcode_bin", js_mach_compile_mcode_bin, 2);
|
||||
js_set_global_cfunc(ctx, "gc_stats", js_gc_stats, 0);
|
||||
js_set_global_cfunc(ctx, "stone", js_cell_stone, 1);
|
||||
js_set_global_cfunc(ctx, "length", js_cell_length, 1);
|
||||
js_set_global_cfunc(ctx, "call", js_cell_call, 3);
|
||||
|
||||
Reference in New Issue
Block a user