add FORCE_GC_AT_MALLOC logic

This commit is contained in:
2026-02-03 03:00:46 -06:00
parent 16c26e4bf2
commit 522ae6128a

View File

@@ -82,7 +82,7 @@
*/
// #define DUMP_BYTECODE (1)
/* dump GC summary: old/new heap, recovery %, heap growth */
#define DUMP_GC
//#define DUMP_GC
/* dump detailed GC: roots, scanning, object traversal (implies DUMP_GC) */
// #define DUMP_GC_DETAIL
#ifdef DUMP_GC_DETAIL
@@ -97,7 +97,7 @@
// #define DUMP_ROPE_REBALANCE
/* test the GC by forcing it before each object allocation */
// #define FORCE_GC_AT_MALLOC
#define FORCE_GC_AT_MALLOC
#define POISON_HEAP
/* POISON_HEAP: Use ASan's memory poisoning to detect stale pointer access */
@@ -1055,7 +1055,7 @@ void *js_realloc (JSContext *ctx, void *ptr, size_t size) {
============================================================ */
/* Forward declaration for ctx_gc */
static int ctx_gc (JSContext *ctx);
static int ctx_gc (JSContext *ctx, int allow_grow);
/* JS_MarkValue - mark a value during GC traversal.
With copying GC, this is a no-op as we discover live objects by tracing. */
@@ -1912,10 +1912,23 @@ void *js_malloc (JSContext *ctx, size_t size) {
/* Align size to 8 bytes */
size = (size + 7) & ~7;
#ifdef FORCE_GC_AT_MALLOC
/* Force GC on every allocation for testing - but don't grow heap unless needed */
int need_space = (uint8_t *)ctx->heap_free + size > (uint8_t *)ctx->heap_end;
if (ctx_gc(ctx, need_space) < 0) {
JS_ThrowOutOfMemory(ctx);
return NULL;
}
/* Check if we have space after GC */
if ((uint8_t *)ctx->heap_free + size > (uint8_t *)ctx->heap_end) {
JS_ThrowOutOfMemory(ctx);
return NULL;
}
#else
/* Check if we have space in current block */
if ((uint8_t *)ctx->heap_free + size > (uint8_t *)ctx->heap_end) {
/* Trigger GC to reclaim memory */
if (ctx_gc (ctx) < 0) {
if (ctx_gc (ctx, 1) < 0) {
JS_ThrowOutOfMemory (ctx);
return NULL;
}
@@ -1925,6 +1938,7 @@ void *js_malloc (JSContext *ctx, size_t size) {
return NULL;
}
}
#endif
void *ptr = ctx->heap_free;
ctx->heap_free = (uint8_t *)ctx->heap_free + size;
@@ -2266,7 +2280,7 @@ static void heap_block_free(JSRuntime *rt, void *ptr, size_t size) {
============================================================ */
/* Forward declarations for GC helpers */
static int ctx_gc (JSContext *ctx);
static int ctx_gc (JSContext *ctx, int allow_grow);
static JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *from_end, uint8_t *to_base, uint8_t **to_free, uint8_t *to_end);
static void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8_t *from_end, uint8_t *to_base, uint8_t **to_free, uint8_t *to_end);
static size_t gc_object_size (void *ptr);
@@ -2432,8 +2446,9 @@ static void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8
}
}
/* Cheney copying GC - collect garbage and compact live objects */
static int ctx_gc (JSContext *ctx) {
/* Cheney copying GC - collect garbage and compact live objects
allow_grow: if true, grow heap when <20% recovered; if false, keep same size */
static int ctx_gc (JSContext *ctx, int allow_grow) {
JSRuntime *rt = ctx->rt;
size_t old_used = ctx->heap_free - ctx->heap_base;
size_t old_heap_size = ctx->current_block_size;
@@ -2588,9 +2603,10 @@ static int ctx_gc (JSContext *ctx) {
}
#endif
/* If <20% recovered, double next block size for future allocations */
/* 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) */
int will_grow = 0;
if (old_used > 0 && recovered < old_used / 5) {
if (allow_grow && old_used > 0 && recovered < old_used / 5) {
size_t doubled = new_size * 2;
if (doubled <= (1ULL << BUDDY_MAX_ORDER)) {
ctx->next_block_size = doubled;