fix mach vm suite errors
This commit is contained in:
@@ -1707,20 +1707,24 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
/* ---- Link pass: resolve GETNAME to GETINTRINSIC or GETENV ---- */
|
/* ---- Link pass: resolve GETNAME to GETINTRINSIC or GETENV ---- */
|
||||||
|
|
||||||
static void mach_link_code(JSContext *ctx, JSCodeRegister *code, JSValue env) {
|
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++) {
|
for (uint32_t i = 0; i < code->instr_count; i++) {
|
||||||
MachInstr32 instr = code->instructions[i];
|
MachInstr32 instr = code->instructions[i];
|
||||||
if (MACH_GET_OP(instr) != MACH_GETNAME) continue;
|
if (MACH_GET_OP(instr) != MACH_GETNAME) continue;
|
||||||
int a = MACH_GET_A(instr);
|
int a = MACH_GET_A(instr);
|
||||||
int bx = MACH_GET_Bx(instr);
|
int bx = MACH_GET_Bx(instr);
|
||||||
int in_env = 0;
|
int in_env = 0;
|
||||||
if (!JS_IsNull(env) && (uint32_t)bx < code->cpool_count) {
|
if (!JS_IsNull(env_ref.val) && (uint32_t)bx < code->cpool_count) {
|
||||||
JSValue val = JS_GetProperty(ctx, env, code->cpool[bx]);
|
JSValue val = JS_GetProperty(ctx, env_ref.val, code->cpool[bx]);
|
||||||
in_env = !JS_IsNull(val) && !JS_IsException(val);
|
in_env = !JS_IsNull(val) && !JS_IsException(val);
|
||||||
}
|
}
|
||||||
code->instructions[i] = MACH_ABx(in_env ? MACH_GETENV : MACH_GETINTRINSIC, a, bx);
|
code->instructions[i] = MACH_ABx(in_env ? MACH_GETENV : MACH_GETINTRINSIC, a, bx);
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < code->func_count; i++)
|
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 ---- */
|
/* ---- Top-level compiler ---- */
|
||||||
@@ -1832,6 +1836,11 @@ void JS_FreeMachCode(MachCode *mc) {
|
|||||||
|
|
||||||
/* Load a MachCode into a JSCodeRegister (materializes JSValues, needs ctx) */
|
/* Load a MachCode into a JSCodeRegister (materializes JSValues, needs ctx) */
|
||||||
JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env) {
|
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));
|
JSCodeRegister *code = js_mallocz_rt(sizeof(JSCodeRegister));
|
||||||
code->arity = mc->arity;
|
code->arity = mc->arity;
|
||||||
code->nr_close_slots = mc->nr_close_slots;
|
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) {
|
if (mc->func_count > 0) {
|
||||||
code->functions = js_malloc_rt(mc->func_count * sizeof(JSCodeRegister *));
|
code->functions = js_malloc_rt(mc->func_count * sizeof(JSCodeRegister *));
|
||||||
for (uint32_t i = 0; i < mc->func_count; i++)
|
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 {
|
} else {
|
||||||
code->functions = NULL;
|
code->functions = NULL;
|
||||||
}
|
}
|
||||||
@@ -1866,8 +1875,9 @@ JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env) {
|
|||||||
code->disruption_pc = mc->disruption_pc;
|
code->disruption_pc = mc->disruption_pc;
|
||||||
|
|
||||||
/* Link: resolve GETNAME to GETENV/GETINTRINSIC */
|
/* 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;
|
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 */
|
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);
|
JSValue top_fn = js_new_register_function(ctx, code, env_gc.val, of_gc.val);
|
||||||
JS_PopGCRef(ctx, &of_gc);
|
JS_PopGCRef(ctx, &of_gc);
|
||||||
|
env = env_gc.val; /* refresh — GC may have moved env during allocation */
|
||||||
JS_PopGCRef(ctx, &env_gc);
|
JS_PopGCRef(ctx, &env_gc);
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
frame->function = top_fn;
|
frame->function = top_fn;
|
||||||
@@ -2499,9 +2510,11 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case MACH_GETENV: {
|
case MACH_GETENV: {
|
||||||
|
/* Read env fresh from frame->function — C local env can go stale after GC */
|
||||||
int bx = MACH_GET_Bx(instr);
|
int bx = MACH_GET_Bx(instr);
|
||||||
JSValue key = code->cpool[bx];
|
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 = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
frame->slots[a] = val;
|
frame->slots[a] = val;
|
||||||
break;
|
break;
|
||||||
@@ -2512,8 +2525,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
int bx = MACH_GET_Bx(instr);
|
int bx = MACH_GET_Bx(instr);
|
||||||
JSValue key = code->cpool[bx];
|
JSValue key = code->cpool[bx];
|
||||||
JSValue val = JS_NULL;
|
JSValue val = JS_NULL;
|
||||||
if (!JS_IsNull(env)) {
|
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.reg.env_record;
|
||||||
val = JS_GetProperty(ctx, env, key);
|
if (!JS_IsNull(cur_env)) {
|
||||||
|
val = JS_GetProperty(ctx, cur_env, key);
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
}
|
}
|
||||||
if (JS_IsNull(val) || JS_IsException(val)) {
|
if (JS_IsNull(val) || JS_IsException(val)) {
|
||||||
@@ -2661,8 +2675,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
JS_PushGCRef(ctx, &key_ref);
|
JS_PushGCRef(ctx, &key_ref);
|
||||||
key_ref.val = (c == 0xFF) ? frame->slots[base + 1] : code->cpool[c];
|
key_ref.val = (c == 0xFF) ? frame->slots[base + 1] : code->cpool[c];
|
||||||
|
|
||||||
if (JS_IsFunction(frame->slots[base]) && JS_IsText(key_ref.val)) {
|
if (JS_IsFunction(frame->slots[base]) && JS_IsText(key_ref.val) &&
|
||||||
/* Proxy call: obj(name, [args...]) */
|
JS_VALUE_GET_FUNCTION(frame->slots[base])->length == 2) {
|
||||||
|
/* Proxy call (arity-2 functions only): obj(name, [args...]) */
|
||||||
JSValue arr = JS_NewArray(ctx);
|
JSValue arr = JS_NewArray(ctx);
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
if (JS_IsException(arr)) { JS_PopGCRef(ctx, &key_ref); goto disrupt; }
|
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);
|
int bx = MACH_GET_Bx(instr);
|
||||||
if ((uint32_t)bx < code->func_count) {
|
if ((uint32_t)bx < code->func_count) {
|
||||||
JSCodeRegister *fn_code = code->functions[bx];
|
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 = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
frame->slots[a] = fn_val;
|
frame->slots[a] = fn_val;
|
||||||
} else {
|
} 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");
|
return JS_ThrowSyntaxError(ctx, "failed to compile AST to MACH bytecode");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSCodeRegister *code = JS_LoadMachCode(ctx, mc, env);
|
/* Protect env from GC — JS_LoadMachCode allocates on GC heap */
|
||||||
JSValue result = JS_CallRegisterVM(ctx, code, ctx->global_obj, 0, NULL, env, JS_NULL);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3061,8 +3061,9 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
|||||||
nargs -= 2;
|
nargs -= 2;
|
||||||
if (nargs < 0) nargs = 0;
|
if (nargs < 0) nargs = 0;
|
||||||
|
|
||||||
if (JS_IsFunction(obj) && JS_VALUE_IS_TEXT(key)) {
|
if (JS_IsFunction(obj) && JS_VALUE_IS_TEXT(key) &&
|
||||||
/* Proxy call: obj(key, [args...]) */
|
JS_VALUE_GET_FUNCTION(obj)->length == 2) {
|
||||||
|
/* Proxy call (arity-2 functions only): obj(key, [args...]) */
|
||||||
int vs_base = ctx->value_stack_top;
|
int vs_base = ctx->value_stack_top;
|
||||||
ctx->value_stack[vs_base] = key; /* protect key on value stack */
|
ctx->value_stack[vs_base] = key; /* protect key on value stack */
|
||||||
ctx->value_stack_top = vs_base + 1; /* protect key from GC */
|
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;
|
if (JS_IsException(ret)) goto disrupt;
|
||||||
frame->slots[dest] = ret;
|
frame->slots[dest] = ret;
|
||||||
} else if (JS_IsFunction(obj)) {
|
} 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);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
goto disrupt;
|
goto disrupt;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -5974,7 +5974,7 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
|
|||||||
int64_t i, len;
|
int64_t i, len;
|
||||||
int ret;
|
int ret;
|
||||||
BOOL has_content;
|
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 */
|
/* Root all values that can be heap pointers and survive across GC points */
|
||||||
JS_PushGCRef (ctx, &val_ref);
|
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, &sep1_ref);
|
||||||
JS_PushGCRef (ctx, &tab_ref);
|
JS_PushGCRef (ctx, &tab_ref);
|
||||||
JS_PushGCRef (ctx, &prop_ref);
|
JS_PushGCRef (ctx, &prop_ref);
|
||||||
|
JS_PushGCRef (ctx, &v_ref);
|
||||||
|
|
||||||
val_ref.val = val;
|
val_ref.val = val;
|
||||||
indent_ref.val = indent;
|
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;
|
sep1_ref.val = JS_NULL;
|
||||||
tab_ref.val = JS_NULL;
|
tab_ref.val = JS_NULL;
|
||||||
prop_ref.val = JS_NULL;
|
prop_ref.val = JS_NULL;
|
||||||
|
v_ref.val = JS_NULL;
|
||||||
|
|
||||||
if (js_check_stack_overflow (ctx, 0)) {
|
if (js_check_stack_overflow (ctx, 0)) {
|
||||||
JS_ThrowStackOverflow (ctx);
|
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);
|
JSC_B_CONCAT (jsc, sep_ref.val);
|
||||||
v = JS_GetPropertyInt64 (ctx, val_ref.val, i);
|
v = JS_GetPropertyInt64 (ctx, val_ref.val, i);
|
||||||
if (JS_IsException (v)) goto exception;
|
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 */
|
/* XXX: could do this string conversion only when needed */
|
||||||
prop_ref.val = JS_ToString (ctx, JS_NewInt64 (ctx, i));
|
prop_ref.val = JS_ToString (ctx, JS_NewInt64 (ctx, i));
|
||||||
if (JS_IsException (prop_ref.val)) goto exception;
|
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;
|
prop_ref.val = JS_NULL;
|
||||||
if (JS_IsException (v)) goto exception;
|
if (JS_IsException (v)) goto exception;
|
||||||
if (JS_IsNull (v)) v = JS_NULL;
|
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);
|
v = js_json_check (ctx, jsc, val_ref.val, v, prop_ref.val);
|
||||||
if (JS_IsException (v)) goto exception;
|
if (JS_IsException (v)) goto exception;
|
||||||
if (!JS_IsNull (v)) {
|
if (!JS_IsNull (v)) {
|
||||||
|
v_ref.val = v; /* root v — allocations below can trigger GC */
|
||||||
if (has_content) {
|
if (has_content) {
|
||||||
JSC_B_PUTC (jsc, ',');
|
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_CONCAT (jsc, prop_ref.val);
|
||||||
JSC_B_PUTC (jsc, ':');
|
JSC_B_PUTC (jsc, ':');
|
||||||
JSC_B_CONCAT (jsc, sep1_ref.val);
|
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;
|
has_content = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6116,6 +6120,7 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
JS_PopGCRef (ctx, &v_ref);
|
||||||
JS_PopGCRef (ctx, &prop_ref);
|
JS_PopGCRef (ctx, &prop_ref);
|
||||||
JS_PopGCRef (ctx, &tab_ref);
|
JS_PopGCRef (ctx, &tab_ref);
|
||||||
JS_PopGCRef (ctx, &sep1_ref);
|
JS_PopGCRef (ctx, &sep1_ref);
|
||||||
@@ -6126,6 +6131,7 @@ done:
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exception_ret:
|
exception_ret:
|
||||||
|
JS_PopGCRef (ctx, &v_ref);
|
||||||
JS_PopGCRef (ctx, &prop_ref);
|
JS_PopGCRef (ctx, &prop_ref);
|
||||||
JS_PopGCRef (ctx, &tab_ref);
|
JS_PopGCRef (ctx, &tab_ref);
|
||||||
JS_PopGCRef (ctx, &sep1_ref);
|
JS_PopGCRef (ctx, &sep1_ref);
|
||||||
|
|||||||
@@ -2926,15 +2926,6 @@ run("array map with exit", function() {
|
|||||||
if (length(result) != 5) fail("array map with exit length unexpected")
|
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
|
// STRING METHOD EDGE CASES
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user