fix mach vm suite errors

This commit is contained in:
2026-02-09 18:12:44 -06:00
parent d5209e1d59
commit 7f691fd52b
4 changed files with 50 additions and 28 deletions

View File

@@ -1707,20 +1707,24 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
/* ---- Link pass: resolve GETNAME to GETINTRINSIC or GETENV ---- */
static void mach_link_code(JSContext *ctx, JSCodeRegister *code, JSValue env) {
JSGCRef env_ref;
JS_PushGCRef(ctx, &env_ref);
env_ref.val = env;
for (uint32_t i = 0; i < code->instr_count; i++) {
MachInstr32 instr = code->instructions[i];
if (MACH_GET_OP(instr) != MACH_GETNAME) continue;
int a = MACH_GET_A(instr);
int bx = MACH_GET_Bx(instr);
int in_env = 0;
if (!JS_IsNull(env) && (uint32_t)bx < code->cpool_count) {
JSValue val = JS_GetProperty(ctx, env, code->cpool[bx]);
if (!JS_IsNull(env_ref.val) && (uint32_t)bx < code->cpool_count) {
JSValue val = JS_GetProperty(ctx, env_ref.val, code->cpool[bx]);
in_env = !JS_IsNull(val) && !JS_IsException(val);
}
code->instructions[i] = MACH_ABx(in_env ? MACH_GETENV : MACH_GETINTRINSIC, a, bx);
}
for (uint32_t i = 0; i < code->func_count; i++)
if (code->functions[i]) mach_link_code(ctx, code->functions[i], env);
if (code->functions[i]) mach_link_code(ctx, code->functions[i], env_ref.val);
JS_PopGCRef(ctx, &env_ref);
}
/* ---- Top-level compiler ---- */
@@ -1832,6 +1836,11 @@ void JS_FreeMachCode(MachCode *mc) {
/* Load a MachCode into a JSCodeRegister (materializes JSValues, needs ctx) */
JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env) {
/* Protect env from GC — materialize/link calls can trigger collection */
JSGCRef env_ref;
JS_PushGCRef(ctx, &env_ref);
env_ref.val = env;
JSCodeRegister *code = js_mallocz_rt(sizeof(JSCodeRegister));
code->arity = mc->arity;
code->nr_close_slots = mc->nr_close_slots;
@@ -1849,7 +1858,7 @@ JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env) {
if (mc->func_count > 0) {
code->functions = js_malloc_rt(mc->func_count * sizeof(JSCodeRegister *));
for (uint32_t i = 0; i < mc->func_count; i++)
code->functions[i] = JS_LoadMachCode(ctx, mc->functions[i], env);
code->functions[i] = JS_LoadMachCode(ctx, mc->functions[i], env_ref.val);
} else {
code->functions = NULL;
}
@@ -1866,8 +1875,9 @@ JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env) {
code->disruption_pc = mc->disruption_pc;
/* Link: resolve GETNAME to GETENV/GETINTRINSIC */
mach_link_code(ctx, code, env);
mach_link_code(ctx, code, env_ref.val);
JS_PopGCRef(ctx, &env_ref);
return code;
}
@@ -2229,6 +2239,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
returning from a called register function can read code/env from frame */
JSValue top_fn = js_new_register_function(ctx, code, env_gc.val, of_gc.val);
JS_PopGCRef(ctx, &of_gc);
env = env_gc.val; /* refresh — GC may have moved env during allocation */
JS_PopGCRef(ctx, &env_gc);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
frame->function = top_fn;
@@ -2499,9 +2510,11 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
}
case MACH_GETENV: {
/* Read env fresh from frame->function — C local env can go stale after GC */
int bx = MACH_GET_Bx(instr);
JSValue key = code->cpool[bx];
JSValue val = JS_GetProperty(ctx, env, key);
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.reg.env_record;
JSValue val = JS_GetProperty(ctx, cur_env, key);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
frame->slots[a] = val;
break;
@@ -2512,8 +2525,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
int bx = MACH_GET_Bx(instr);
JSValue key = code->cpool[bx];
JSValue val = JS_NULL;
if (!JS_IsNull(env)) {
val = JS_GetProperty(ctx, env, key);
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.reg.env_record;
if (!JS_IsNull(cur_env)) {
val = JS_GetProperty(ctx, cur_env, key);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
}
if (JS_IsNull(val) || JS_IsException(val)) {
@@ -2661,8 +2675,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JS_PushGCRef(ctx, &key_ref);
key_ref.val = (c == 0xFF) ? frame->slots[base + 1] : code->cpool[c];
if (JS_IsFunction(frame->slots[base]) && JS_IsText(key_ref.val)) {
/* Proxy call: obj(name, [args...]) */
if (JS_IsFunction(frame->slots[base]) && JS_IsText(key_ref.val) &&
JS_VALUE_GET_FUNCTION(frame->slots[base])->length == 2) {
/* Proxy call (arity-2 functions only): obj(name, [args...]) */
JSValue arr = JS_NewArray(ctx);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
if (JS_IsException(arr)) { JS_PopGCRef(ctx, &key_ref); goto disrupt; }
@@ -2816,7 +2831,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
int bx = MACH_GET_Bx(instr);
if ((uint32_t)bx < code->func_count) {
JSCodeRegister *fn_code = code->functions[bx];
JSValue fn_val = js_new_register_function(ctx, fn_code, env, frame_ref.val);
/* Read env fresh from frame->function — C local can be stale */
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.reg.env_record;
JSValue fn_val = js_new_register_function(ctx, fn_code, cur_env, frame_ref.val);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
frame->slots[a] = fn_val;
} else {
@@ -3251,8 +3268,14 @@ JSValue JS_RunMachTree(JSContext *ctx, cJSON *ast, JSValue env) {
return JS_ThrowSyntaxError(ctx, "failed to compile AST to MACH bytecode");
}
JSCodeRegister *code = JS_LoadMachCode(ctx, mc, env);
JSValue result = JS_CallRegisterVM(ctx, code, ctx->global_obj, 0, NULL, env, JS_NULL);
/* Protect env from GC — JS_LoadMachCode allocates on GC heap */
JSGCRef env_ref;
JS_PushGCRef(ctx, &env_ref);
env_ref.val = env;
JSCodeRegister *code = JS_LoadMachCode(ctx, mc, env_ref.val);
JSValue result = JS_CallRegisterVM(ctx, code, ctx->global_obj, 0, NULL, env_ref.val, JS_NULL);
JS_PopGCRef(ctx, &env_ref);
return result;
}

View File

@@ -3061,8 +3061,9 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
nargs -= 2;
if (nargs < 0) nargs = 0;
if (JS_IsFunction(obj) && JS_VALUE_IS_TEXT(key)) {
/* Proxy call: obj(key, [args...]) */
if (JS_IsFunction(obj) && JS_VALUE_IS_TEXT(key) &&
JS_VALUE_GET_FUNCTION(obj)->length == 2) {
/* Proxy call (arity-2 functions only): obj(key, [args...]) */
int vs_base = ctx->value_stack_top;
ctx->value_stack[vs_base] = key; /* protect key on value stack */
ctx->value_stack_top = vs_base + 1; /* protect key from GC */
@@ -3087,7 +3088,8 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
if (JS_IsException(ret)) goto disrupt;
frame->slots[dest] = ret;
} else if (JS_IsFunction(obj)) {
JS_ThrowTypeError(ctx, "cannot use non-text bracket notation on function");
/* Non-proxy function: bracket access not allowed */
JS_ThrowTypeError(ctx, "cannot use bracket notation on non-proxy function");
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
goto disrupt;
} else {

View File

@@ -5974,7 +5974,7 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
int64_t i, len;
int ret;
BOOL has_content;
JSGCRef val_ref, indent_ref, indent1_ref, sep_ref, sep1_ref, tab_ref, prop_ref;
JSGCRef val_ref, indent_ref, indent1_ref, sep_ref, sep1_ref, tab_ref, prop_ref, v_ref;
/* Root all values that can be heap pointers and survive across GC points */
JS_PushGCRef (ctx, &val_ref);
@@ -5984,6 +5984,7 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
JS_PushGCRef (ctx, &sep1_ref);
JS_PushGCRef (ctx, &tab_ref);
JS_PushGCRef (ctx, &prop_ref);
JS_PushGCRef (ctx, &v_ref);
val_ref.val = val;
indent_ref.val = indent;
@@ -5992,6 +5993,7 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
sep1_ref.val = JS_NULL;
tab_ref.val = JS_NULL;
prop_ref.val = JS_NULL;
v_ref.val = JS_NULL;
if (js_check_stack_overflow (ctx, 0)) {
JS_ThrowStackOverflow (ctx);
@@ -6038,10 +6040,11 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
JSC_B_CONCAT (jsc, sep_ref.val);
v = JS_GetPropertyInt64 (ctx, val_ref.val, i);
if (JS_IsException (v)) goto exception;
v_ref.val = v; /* root v — JS_ToString below can trigger GC */
/* XXX: could do this string conversion only when needed */
prop_ref.val = JS_ToString (ctx, JS_NewInt64 (ctx, i));
if (JS_IsException (prop_ref.val)) goto exception;
v = js_json_check (ctx, jsc, val_ref.val, v, prop_ref.val);
v = js_json_check (ctx, jsc, val_ref.val, v_ref.val, prop_ref.val);
prop_ref.val = JS_NULL;
if (JS_IsException (v)) goto exception;
if (JS_IsNull (v)) v = JS_NULL;
@@ -6069,6 +6072,7 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
v = js_json_check (ctx, jsc, val_ref.val, v, prop_ref.val);
if (JS_IsException (v)) goto exception;
if (!JS_IsNull (v)) {
v_ref.val = v; /* root v — allocations below can trigger GC */
if (has_content) {
JSC_B_PUTC (jsc, ',');
}
@@ -6080,7 +6084,7 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
JSC_B_CONCAT (jsc, prop_ref.val);
JSC_B_PUTC (jsc, ':');
JSC_B_CONCAT (jsc, sep1_ref.val);
if (js_json_to_str (ctx, jsc, val_ref.val, v, indent1_ref.val)) goto exception;
if (js_json_to_str (ctx, jsc, val_ref.val, v_ref.val, indent1_ref.val)) goto exception;
has_content = TRUE;
}
}
@@ -6116,6 +6120,7 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
}
done:
JS_PopGCRef (ctx, &v_ref);
JS_PopGCRef (ctx, &prop_ref);
JS_PopGCRef (ctx, &tab_ref);
JS_PopGCRef (ctx, &sep1_ref);
@@ -6126,6 +6131,7 @@ done:
return 0;
exception_ret:
JS_PopGCRef (ctx, &v_ref);
JS_PopGCRef (ctx, &prop_ref);
JS_PopGCRef (ctx, &tab_ref);
JS_PopGCRef (ctx, &sep1_ref);

View File

@@ -2926,15 +2926,6 @@ run("array map with exit", function() {
if (length(result) != 5) fail("array map with exit length unexpected")
})
// ============================================================================
// ERROR OBJECTS
// ============================================================================
run("error creation", function() {
var e = Error("test message")
if (e.message != "test message") fail("Error creation failed")
})
// ============================================================================
// STRING METHOD EDGE CASES
// ============================================================================