fix functions and closures in mach

This commit is contained in:
2026-02-06 18:30:26 -06:00
parent 8cf98d8a9e
commit e2bc5948c1

View File

@@ -2126,10 +2126,18 @@ void *js_malloc (JSContext *ctx, size_t size) {
JS_ThrowOutOfMemory(ctx);
return NULL;
}
/* Check if we have space after GC */
/* Check if we have space after GC — the GC may have doubled
next_block_size but allocated the old size. Fall through to
the normal grow path so we get a bigger block. */
if ((uint8_t *)ctx->heap_free + size > (uint8_t *)ctx->heap_end) {
JS_ThrowOutOfMemory(ctx);
return NULL;
if (ctx_gc(ctx, 1) < 0) {
JS_ThrowOutOfMemory(ctx);
return NULL;
}
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 */
@@ -31459,6 +31467,7 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
/* Register parameters */
cJSON *params = cJSON_GetObjectItem(node, "params");
if (!params) params = cJSON_GetObjectItem(node, "parameters");
if (!params) params = cJSON_GetObjectItem(node, "list");
int nparams = params ? cJSON_GetArraySize(params) : 0;
child.nr_args = nparams;
for (int i = 0; i < nparams; i++) {
@@ -31476,7 +31485,8 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
/* Compile body */
cJSON *body = cJSON_GetObjectItem(node, "body");
if (body) {
if (!body) body = node; /* statements may be directly on the function node */
{
cJSON *stmts = cJSON_GetObjectItem(body, "statements");
if (!stmts) stmts = body; /* body might be the statements array directly */
if (cJSON_IsArray(stmts)) {
@@ -31557,6 +31567,19 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
return;
}
/* Function declaration statement */
if (strcmp(kind, "function") == 0) {
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(stmt, "name"));
if (!name) return;
int slot = mach_find_var(cs, name);
if (slot < 0) {
slot = mach_reserve_reg(cs);
mach_add_var(cs, name, slot, 1);
}
mach_compile_expr(cs, stmt, slot);
return;
}
/* Expression statement (call) */
if (strcmp(kind, "call") == 0) {
cJSON *expr = cJSON_GetObjectItem(stmt, "expression");
@@ -31796,6 +31819,20 @@ static MachCode *mach_compile_program(MachCompState *cs, cJSON *ast) {
/* Scan scope record for declarations */
mach_scan_scope(cs);
/* Hoist function declarations */
cJSON *functions = cJSON_GetObjectItem(ast, "functions");
if (functions && cJSON_IsArray(functions)) {
int fcount = cJSON_GetArraySize(functions);
for (int i = 0; i < fcount; i++) {
cJSON *fn_node = cJSON_GetArrayItem(functions, i);
const char *fn_name = cJSON_GetStringValue(cJSON_GetObjectItem(fn_node, "name"));
if (!fn_name) continue;
int slot = mach_find_var(cs, fn_name);
if (slot < 0) continue;
mach_compile_expr(cs, fn_node, slot);
}
}
/* Compile each statement */
int count = cJSON_GetArraySize(stmts);
for (int i = 0; i < count; i++) {
@@ -32092,7 +32129,11 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JS_AddGCRef(ctx, &frame_ref);
frame_ref.val = JS_MKPTR(frame);
/* Setup initial frame */
/* Setup initial frame — wrap top-level code in a function object so that
returning from a called register function can read code/env from frame */
JSValue top_fn = js_new_register_function(ctx, code, env, outer_frame);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
frame->function = top_fn;
frame->slots[0] = this_obj; /* slot 0 = this */
/* Copy arguments */
@@ -32116,11 +32157,11 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
if (JS_IsNull(frame->caller)) goto done;
/* Pop frame */
int ret_info = JS_VALUE_GET_INT(frame->address);
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
frame->caller = JS_NULL;
frame = caller;
frame_ref.val = JS_MKPTR(frame);
int ret_info = JS_VALUE_GET_INT(frame->address);
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
code = fn->u.reg.code;
env = fn->u.reg.env_record;
@@ -32420,7 +32461,10 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JSCodeRegister *fn_code = fn->u.reg.code;
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots);
if (!new_frame) { result = JS_EXCEPTION; goto done; }
/* Re-read pointers — GC may have moved them */
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
func_val = frame->slots[base];
fn = JS_VALUE_GET_FUNCTION(func_val);
new_frame->function = func_val;
new_frame->slots[0] = JS_NULL; /* this */
for (int i = 0; i < nargs && i < fn_code->arity; i++)
@@ -32450,11 +32494,11 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
result = frame->slots[a];
if (JS_IsNull(frame->caller)) goto done;
{
int ret_info = JS_VALUE_GET_INT(frame->address);
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
frame->caller = JS_NULL;
frame = caller;
frame_ref.val = JS_MKPTR(frame);
int ret_info = JS_VALUE_GET_INT(frame->address);
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
code = fn->u.reg.code;
env = fn->u.reg.env_record;
@@ -32468,11 +32512,11 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
result = JS_NULL;
if (JS_IsNull(frame->caller)) goto done;
{
int ret_info = JS_VALUE_GET_INT(frame->address);
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
frame->caller = JS_NULL;
frame = caller;
frame_ref.val = JS_MKPTR(frame);
int ret_info = JS_VALUE_GET_INT(frame->address);
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
code = fn->u.reg.code;
env = fn->u.reg.env_record;