fix crash related to allocating in context heap

This commit is contained in:
2026-02-06 12:43:19 -06:00
parent 32885a422f
commit 0a45394689

View File

@@ -30730,6 +30730,17 @@ typedef struct MachVarInfo {
int is_const; /* 1 for def, function args; 0 for var */
} MachVarInfo;
/* ---- Compile-time constant pool entry ---- */
/* Stores raw data during compilation; converted to JSValues when building JSCodeRegister */
typedef enum { MACH_CP_IMM, MACH_CP_STR } MachCPType;
typedef struct {
MachCPType type;
union {
JSValue val; /* immediate value (int, float) - no GC alloc */
char *str; /* owned C string */
};
} MachCPoolEntry;
/* ---- Compiler state ---- */
typedef struct MachCompState {
@@ -30740,8 +30751,8 @@ typedef struct MachCompState {
int code_count;
int code_capacity;
/* Constant pool */
JSValue *cpool;
/* Constant pool (raw entries, no GC objects) */
MachCPoolEntry *cpool;
int cpool_count;
int cpool_capacity;
@@ -30811,54 +30822,64 @@ static void mach_free_reg_to(MachCompState *cs, int saved) {
/* Add a constant to the pool, return its index */
static int mach_cpool_add(MachCompState *cs, JSValue val) {
/* Check for duplicates (simple linear scan) */
/* Check for duplicates (immediate values only) */
for (int i = 0; i < cs->cpool_count; i++) {
JSValue existing = cs->cpool[i];
/* Compare by tag and value */
if (JS_IsInt(val) && JS_IsInt(existing)) {
if (JS_VALUE_GET_INT(val) == JS_VALUE_GET_INT(existing))
MachCPoolEntry *e = &cs->cpool[i];
if (e->type != MACH_CP_IMM) continue;
if (JS_IsInt(val) && JS_IsInt(e->val)) {
if (JS_VALUE_GET_INT(val) == JS_VALUE_GET_INT(e->val))
return i;
} else if (e->val == val) {
return i;
} else if (JS_VALUE_IS_TEXT(val) && JS_VALUE_IS_TEXT(existing)) {
const char *a = JS_ToCString(cs->ctx, val);
const char *b = JS_ToCString(cs->ctx, existing);
int eq = a && b && strcmp(a, b) == 0;
JS_FreeCString(cs->ctx, a);
JS_FreeCString(cs->ctx, b);
if (eq) return i;
}
}
if (cs->cpool_count >= cs->cpool_capacity) {
int new_cap = cs->cpool_capacity ? cs->cpool_capacity * 2 : 16;
cs->cpool = sys_realloc(cs->cpool, new_cap * sizeof(JSValue));
cs->cpool = sys_realloc(cs->cpool, new_cap * sizeof(MachCPoolEntry));
cs->cpool_capacity = new_cap;
}
cs->cpool[cs->cpool_count] = val;
cs->cpool[cs->cpool_count] = (MachCPoolEntry){ .type = MACH_CP_IMM, .val = val };
return cs->cpool_count++;
}
/* Add a string constant, return its cpool index */
static int mach_cpool_add_str(MachCompState *cs, const char *str) {
/* Check for existing identical string first (before allocating) */
/* Check for existing identical string */
for (int i = 0; i < cs->cpool_count; i++) {
JSValue existing = cs->cpool[i];
if (JS_VALUE_IS_TEXT(existing)) {
const char *s = JS_ToCString(cs->ctx, existing);
int eq = s && strcmp(s, str) == 0;
JS_FreeCString(cs->ctx, s);
if (eq) return i;
MachCPoolEntry *e = &cs->cpool[i];
if (e->type == MACH_CP_STR && strcmp(e->str, str) == 0)
return i;
}
}
JSValue val = JS_NewString(cs->ctx, str);
if (cs->cpool_count >= cs->cpool_capacity) {
int new_cap = cs->cpool_capacity ? cs->cpool_capacity * 2 : 16;
cs->cpool = sys_realloc(cs->cpool, new_cap * sizeof(JSValue));
cs->cpool = sys_realloc(cs->cpool, new_cap * sizeof(MachCPoolEntry));
cs->cpool_capacity = new_cap;
}
cs->cpool[cs->cpool_count] = val;
char *dup = sys_malloc(strlen(str) + 1);
memcpy(dup, str, strlen(str) + 1);
cs->cpool[cs->cpool_count] = (MachCPoolEntry){ .type = MACH_CP_STR, .str = dup };
return cs->cpool_count++;
}
/* Convert compile-time cpool entries to JSValue array for JSCodeRegister.
Caller takes ownership of the returned array. Frees the raw entries.
Strings are interned into stone memory (no GC allocation). */
static JSValue *mach_materialize_cpool(JSContext *ctx, MachCPoolEntry *entries, int count) {
if (count == 0) { sys_free(entries); return NULL; }
JSValue *cpool = js_malloc_rt(count * sizeof(JSValue));
for (int i = 0; i < count; i++) {
if (entries[i].type == MACH_CP_STR) {
cpool[i] = js_key_new(ctx, entries[i].str);
sys_free(entries[i].str);
} else {
cpool[i] = entries[i].val;
}
}
sys_free(entries);
return cpool;
}
/* Add a variable */
static void mach_add_var(MachCompState *cs, const char *name, int slot, int is_const) {
if (cs->var_count >= cs->var_capacity) {
@@ -31450,14 +31471,13 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
fn_code->instr_count = child.code_count;
fn_code->instructions = child.code;
fn_code->cpool_count = child.cpool_count;
fn_code->cpool = child.cpool;
fn_code->cpool = mach_materialize_cpool(cs->ctx, child.cpool, child.cpool_count);
fn_code->func_count = child.func_count;
fn_code->functions = child.functions;
cJSON *fname = cJSON_GetObjectItem(node, "name");
if (fname && cJSON_IsString(fname)) {
fn_code->name = JS_NewString(cs->ctx, cJSON_GetStringValue(fname));
fn_code->name = JS_CellStone(cs->ctx, fn_code->name);
fn_code->name = js_key_new(cs->ctx, cJSON_GetStringValue(fname));
} else {
fn_code->name = JS_NULL;
}
@@ -31765,7 +31785,7 @@ static JSCodeRegister *mach_compile_program(MachCompState *cs, cJSON *ast, JSVal
code->instr_count = cs->code_count;
code->instructions = cs->code;
code->cpool_count = cs->cpool_count;
code->cpool = cs->cpool;
code->cpool = mach_materialize_cpool(cs->ctx, cs->cpool, cs->cpool_count);
code->func_count = cs->func_count;
code->functions = cs->functions;
code->name = JS_NULL;