mach disrupt support
This commit is contained in:
210
source/quickjs.c
210
source/quickjs.c
@@ -556,7 +556,7 @@ typedef enum MachOpcode {
|
||||
|
||||
/* Special */
|
||||
MACH_TYPEOF, /* R(A) = typeof R(B) */
|
||||
MACH_THROW, /* throw R(A) */
|
||||
MACH_THROW, /* disrupt — trigger disruption */
|
||||
|
||||
MACH_NOP,
|
||||
|
||||
@@ -613,7 +613,7 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
[MACH_NEWARRAY] = "newarray",
|
||||
[MACH_CLOSURE] = "closure",
|
||||
[MACH_TYPEOF] = "typeof",
|
||||
[MACH_THROW] = "throw",
|
||||
[MACH_THROW] = "disrupt",
|
||||
[MACH_NOP] = "nop",
|
||||
};
|
||||
|
||||
@@ -642,6 +642,7 @@ typedef struct JSCodeRegister {
|
||||
MachLineEntry *line_table; /* [instr_count], parallel to instructions[] */
|
||||
char *filename_cstr; /* plain C string for stack trace (js_malloc_rt) */
|
||||
char *name_cstr; /* plain C string for stack trace (js_malloc_rt) */
|
||||
uint16_t disruption_pc; /* start of disruption handler (0 = none) */
|
||||
} JSCodeRegister;
|
||||
|
||||
/* Pre-parsed MCODE for a single function (off-heap, never GC'd).
|
||||
@@ -664,6 +665,7 @@ typedef struct JSMCode {
|
||||
MachLineEntry *line_table; /* [instr_count], parallel to instrs[] */
|
||||
const char *name; /* function name (points into cJSON tree) */
|
||||
const char *filename; /* source filename (points into cJSON tree) */
|
||||
uint16_t disruption_pc; /* start of disruption handler (0 = none) */
|
||||
} JSMCode;
|
||||
|
||||
/* Frame for closures - used by link-time relocation model where closures
|
||||
@@ -30632,6 +30634,7 @@ typedef struct MachCode {
|
||||
char *name; /* owned C string, or NULL */
|
||||
MachLineEntry *line_table; /* [instr_count], parallel to instructions[] */
|
||||
char *filename; /* source filename (sys_malloc'd) */
|
||||
uint16_t disruption_pc; /* start of disruption handler (0 = none) */
|
||||
} MachCode;
|
||||
|
||||
/* ---- Compiler state ---- */
|
||||
@@ -31384,6 +31387,17 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
/* Implicit return null */
|
||||
mach_emit(&child, MACH_ABC(MACH_RETNIL, 0, 0, 0));
|
||||
|
||||
/* Disruption clause — emitted after body, recorded as disruption_pc */
|
||||
int disruption_start = 0;
|
||||
cJSON *disruption = cJSON_GetObjectItem(node, "disruption");
|
||||
if (disruption && cJSON_IsArray(disruption)) {
|
||||
disruption_start = mach_current_pc(&child);
|
||||
int dcount = cJSON_GetArraySize(disruption);
|
||||
for (int i = 0; i < dcount; i++)
|
||||
mach_compile_stmt(&child, cJSON_GetArrayItem(disruption, i));
|
||||
mach_emit(&child, MACH_ABC(MACH_RETNIL, 0, 0, 0));
|
||||
}
|
||||
|
||||
/* Build MachCode for the child function */
|
||||
cJSON *fn_scope = mach_find_scope_record(cs->scopes, child.function_nr);
|
||||
cJSON *fn_ncs = fn_scope ? cJSON_GetObjectItem(fn_scope, "nr_close_slots") : NULL;
|
||||
@@ -31401,6 +31415,7 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
fn_code->functions = child.functions;
|
||||
fn_code->line_table = child.line_info;
|
||||
fn_code->filename = cs->filename ? strdup(cs->filename) : NULL;
|
||||
fn_code->disruption_pc = disruption_start;
|
||||
|
||||
cJSON *fname = cJSON_GetObjectItem(node, "name");
|
||||
if (fname && cJSON_IsString(fname)) {
|
||||
@@ -31823,6 +31838,8 @@ JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env) {
|
||||
code->filename_cstr = mc->filename ? js_strdup_rt(mc->filename) : NULL;
|
||||
code->name_cstr = mc->name ? js_strdup_rt(mc->name) : NULL;
|
||||
|
||||
code->disruption_pc = mc->disruption_pc;
|
||||
|
||||
/* Link: resolve GETNAME to GETENV/GETINTRINSIC */
|
||||
mach_link_code(ctx, code, env);
|
||||
|
||||
@@ -31960,42 +31977,45 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Float operations */
|
||||
double da, db;
|
||||
if (JS_ToFloat64(ctx, &da, a) || JS_ToFloat64(ctx, &db, b))
|
||||
return JS_EXCEPTION;
|
||||
/* String concat for ADD */
|
||||
if (op == MACH_ADD && JS_IsText(a) && JS_IsText(b))
|
||||
return JS_ConcatString(ctx, a, b);
|
||||
|
||||
/* Comparison ops allow mixed types — return false for mismatches */
|
||||
if (op >= MACH_EQ && op <= MACH_GE) {
|
||||
if (JS_IsNumber(a) && JS_IsNumber(b)) {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, a);
|
||||
JS_ToFloat64(ctx, &db, b);
|
||||
switch (op) {
|
||||
case MACH_ADD:
|
||||
return JS_NewFloat64(ctx, da + db);
|
||||
case MACH_SUB:
|
||||
return JS_NewFloat64(ctx, da - db);
|
||||
case MACH_MUL:
|
||||
return JS_NewFloat64(ctx, da * db);
|
||||
case MACH_DIV:
|
||||
return JS_NewFloat64(ctx, da / db);
|
||||
case MACH_MOD:
|
||||
return JS_NewFloat64(ctx, fmod(da, db));
|
||||
case MACH_POW:
|
||||
return JS_NewFloat64(ctx, pow(da, db));
|
||||
case MACH_EQ:
|
||||
return JS_NewBool(ctx, da == db);
|
||||
case MACH_NEQ:
|
||||
return JS_NewBool(ctx, da != db);
|
||||
case MACH_LT:
|
||||
return JS_NewBool(ctx, da < db);
|
||||
case MACH_LE:
|
||||
return JS_NewBool(ctx, da <= db);
|
||||
case MACH_GT:
|
||||
return JS_NewBool(ctx, da > db);
|
||||
case MACH_GE:
|
||||
return JS_NewBool(ctx, da >= db);
|
||||
case MACH_BAND:
|
||||
case MACH_BOR:
|
||||
case MACH_BXOR:
|
||||
case MACH_SHL:
|
||||
case MACH_SHR:
|
||||
case MACH_USHR: {
|
||||
case MACH_EQ: return JS_NewBool(ctx, da == db);
|
||||
case MACH_NEQ: return JS_NewBool(ctx, da != db);
|
||||
case MACH_LT: return JS_NewBool(ctx, da < db);
|
||||
case MACH_LE: return JS_NewBool(ctx, da <= db);
|
||||
case MACH_GT: return JS_NewBool(ctx, da > db);
|
||||
case MACH_GE: return JS_NewBool(ctx, da >= db);
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
/* Different types: EQ→false, NEQ→true, others→false */
|
||||
if (op == MACH_NEQ) return JS_NewBool(ctx, 1);
|
||||
return JS_NewBool(ctx, 0);
|
||||
}
|
||||
|
||||
/* Numeric operations — both must be numeric */
|
||||
if (JS_IsNumber(a) && JS_IsNumber(b)) {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, a);
|
||||
JS_ToFloat64(ctx, &db, b);
|
||||
switch (op) {
|
||||
case MACH_ADD: return JS_NewFloat64(ctx, da + db);
|
||||
case MACH_SUB: return JS_NewFloat64(ctx, da - db);
|
||||
case MACH_MUL: return JS_NewFloat64(ctx, da * db);
|
||||
case MACH_DIV: return JS_NewFloat64(ctx, da / db);
|
||||
case MACH_MOD: return JS_NewFloat64(ctx, fmod(da, db));
|
||||
case MACH_POW: return JS_NewFloat64(ctx, pow(da, db));
|
||||
case MACH_BAND: case MACH_BOR: case MACH_BXOR:
|
||||
case MACH_SHL: case MACH_SHR: case MACH_USHR: {
|
||||
int32_t ia = (int32_t)da;
|
||||
int32_t ib = (int32_t)db;
|
||||
switch (op) {
|
||||
@@ -32008,11 +32028,12 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) {
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_NULL;
|
||||
/* Type mismatch — disrupt */
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
/* Check for interrupt */
|
||||
@@ -32132,6 +32153,7 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
JSValue right = frame->slots[c];
|
||||
JSValue res = reg_vm_binop(ctx, op, left, right);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[a] = res;
|
||||
break;
|
||||
}
|
||||
@@ -32358,8 +32380,7 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
JSValue func_val = frame->slots[base];
|
||||
|
||||
if (!JS_IsFunction(func_val)) {
|
||||
result = JS_ThrowTypeError(ctx, "not a function");
|
||||
goto done;
|
||||
goto disrupt;
|
||||
}
|
||||
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val);
|
||||
@@ -32370,13 +32391,13 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, &frame->slots[base + 1]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
ctx->reg_current_frame = JS_NULL;
|
||||
if (JS_IsException(ret)) { result = ret; goto done; }
|
||||
if (JS_IsException(ret)) { goto disrupt; }
|
||||
if (nresults > 0) frame->slots[base] = ret;
|
||||
} else if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
||||
/* Register function: allocate frame, copy args, switch */
|
||||
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; }
|
||||
if (!new_frame) { goto disrupt; }
|
||||
/* Re-read pointers — GC may have moved them */
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
func_val = frame->slots[base];
|
||||
@@ -32400,7 +32421,7 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
/* Other function kinds (bytecode) — call via C bridge */
|
||||
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, &frame->slots[base + 1]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(ret)) { result = ret; goto done; }
|
||||
if (JS_IsException(ret)) { goto disrupt; }
|
||||
if (nresults > 0) frame->slots[base] = ret;
|
||||
}
|
||||
break;
|
||||
@@ -32445,7 +32466,7 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
case MACH_NEWOBJECT: {
|
||||
JSValue obj = JS_NewObject(ctx);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(obj)) { result = obj; goto done; }
|
||||
if (JS_IsException(obj)) { goto disrupt; }
|
||||
frame->slots[a] = obj;
|
||||
break;
|
||||
}
|
||||
@@ -32454,7 +32475,7 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
int count = b;
|
||||
JSValue arr = JS_NewArray(ctx);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(arr)) { result = arr; goto done; }
|
||||
if (JS_IsException(arr)) { goto disrupt; }
|
||||
for (int i = 0; i < count; i++) {
|
||||
JS_SetPropertyUint32(ctx, arr, i, frame->slots[a + 1 + i]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
@@ -32477,13 +32498,34 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
}
|
||||
|
||||
case MACH_THROW:
|
||||
result = JS_Throw(ctx, frame->slots[a]);
|
||||
goto done;
|
||||
goto disrupt;
|
||||
|
||||
default:
|
||||
result = JS_ThrowInternalError(ctx, "unknown register VM opcode %d", op);
|
||||
goto done;
|
||||
}
|
||||
continue;
|
||||
|
||||
disrupt:
|
||||
/* Search frame chain for a disruption handler */
|
||||
for (;;) {
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = fn->u.reg.code;
|
||||
if (code->disruption_pc > 0) {
|
||||
env = fn->u.reg.env_record;
|
||||
pc = code->disruption_pc;
|
||||
break;
|
||||
}
|
||||
if (JS_IsNull(frame->caller)) {
|
||||
result = JS_NULL;
|
||||
goto done;
|
||||
}
|
||||
/* Unwind one frame */
|
||||
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
|
||||
frame->caller = JS_NULL;
|
||||
frame = caller;
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -33735,10 +33777,14 @@ static cJSON *mach_gen_function (MachGenState *parent, cJSON *func_node) {
|
||||
mach_gen_emit_0 (&s, "return_undef");
|
||||
|
||||
/* Compile disruption clause if present */
|
||||
int disruption_start = 0;
|
||||
cJSON *disruption = cJSON_GetObjectItem (func_node, "disruption");
|
||||
if (disruption && cJSON_IsArray (disruption)) {
|
||||
disruption_start = cJSON_GetArraySize (s.instructions);
|
||||
cJSON_ArrayForEach (stmt, disruption) { mach_gen_statement (&s, stmt); }
|
||||
mach_gen_emit_0 (&s, "return_undef");
|
||||
}
|
||||
cJSON_AddNumberToObject (result, "disruption_pc", disruption_start);
|
||||
|
||||
cJSON *fn_scope = mach_find_scope_record (s.scopes, s.function_nr);
|
||||
cJSON *fn_ncs = fn_scope ? cJSON_GetObjectItem (fn_scope, "nr_close_slots") : NULL;
|
||||
@@ -33956,6 +34002,10 @@ static JSMCode *jsmcode_parse_one(cJSON *func_def) {
|
||||
code->name = cJSON_GetStringValue(cJSON_GetObjectItem(func_def, "name"));
|
||||
code->filename = cJSON_GetStringValue(cJSON_GetObjectItem(func_def, "filename"));
|
||||
|
||||
/* Extract disruption_pc */
|
||||
cJSON *dpc = cJSON_GetObjectItem(func_def, "disruption_pc");
|
||||
code->disruption_pc = dpc ? (uint16_t)cJSON_GetNumberValue(dpc) : 0;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
@@ -34137,9 +34187,9 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
int dest = (int)a1->valuedouble;
|
||||
JSValue left = frame->slots[(int)a2->valuedouble];
|
||||
JSValue right = frame->slots[(int)a3->valuedouble];
|
||||
/* Use the same binop helper as the register VM for correct int/float handling */
|
||||
JSValue res = reg_vm_binop(ctx, MACH_ADD, left, right);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "sub") == 0) {
|
||||
@@ -34148,6 +34198,7 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
JSValue right = frame->slots[(int)a3->valuedouble];
|
||||
JSValue res = reg_vm_binop(ctx, MACH_SUB, left, right);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "mul") == 0) {
|
||||
@@ -34156,6 +34207,7 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
JSValue right = frame->slots[(int)a3->valuedouble];
|
||||
JSValue res = reg_vm_binop(ctx, MACH_MUL, left, right);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "div") == 0) {
|
||||
@@ -34164,6 +34216,7 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
JSValue right = frame->slots[(int)a3->valuedouble];
|
||||
JSValue res = reg_vm_binop(ctx, MACH_DIV, left, right);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "mod") == 0) {
|
||||
@@ -34172,6 +34225,7 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
JSValue right = frame->slots[(int)a3->valuedouble];
|
||||
JSValue res = reg_vm_binop(ctx, MACH_MOD, left, right);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "pow") == 0) {
|
||||
@@ -34180,6 +34234,7 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
JSValue right = frame->slots[(int)a3->valuedouble];
|
||||
JSValue res = reg_vm_binop(ctx, MACH_POW, left, right);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "neg") == 0) {
|
||||
@@ -34337,36 +34392,42 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
int dest = (int)a1->valuedouble;
|
||||
JSValue res = reg_vm_binop(ctx, MACH_BAND, frame->slots[(int)a2->valuedouble], frame->slots[(int)a3->valuedouble]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "bitor") == 0) {
|
||||
int dest = (int)a1->valuedouble;
|
||||
JSValue res = reg_vm_binop(ctx, MACH_BOR, frame->slots[(int)a2->valuedouble], frame->slots[(int)a3->valuedouble]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "bitxor") == 0) {
|
||||
int dest = (int)a1->valuedouble;
|
||||
JSValue res = reg_vm_binop(ctx, MACH_BXOR, frame->slots[(int)a2->valuedouble], frame->slots[(int)a3->valuedouble]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "shl") == 0) {
|
||||
int dest = (int)a1->valuedouble;
|
||||
JSValue res = reg_vm_binop(ctx, MACH_SHL, frame->slots[(int)a2->valuedouble], frame->slots[(int)a3->valuedouble]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "shr") == 0) {
|
||||
int dest = (int)a1->valuedouble;
|
||||
JSValue res = reg_vm_binop(ctx, MACH_SHR, frame->slots[(int)a2->valuedouble], frame->slots[(int)a3->valuedouble]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
else if (strcmp(op, "ushr") == 0) {
|
||||
int dest = (int)a1->valuedouble;
|
||||
JSValue res = reg_vm_binop(ctx, MACH_USHR, frame->slots[(int)a2->valuedouble], frame->slots[(int)a3->valuedouble]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(res)) { goto disrupt; }
|
||||
frame->slots[dest] = res;
|
||||
}
|
||||
|
||||
@@ -34541,15 +34602,14 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
int call_argc = a3 ? (int)a3->valuedouble : 0;
|
||||
|
||||
if (!JS_IsFunction(func_val)) {
|
||||
result = JS_ThrowTypeError(ctx, "not a function");
|
||||
goto done;
|
||||
goto disrupt;
|
||||
}
|
||||
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val);
|
||||
if (fn->kind == JS_FUNC_KIND_MCODE) {
|
||||
JSMCode *fn_code = fn->u.mcode.code;
|
||||
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots);
|
||||
if (!new_frame) { result = JS_EXCEPTION; goto done; }
|
||||
if (!new_frame) { goto disrupt; }
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
/* Re-read func_val after GC may have moved it */
|
||||
func_val = frame->slots[(int)a2->valuedouble];
|
||||
@@ -34602,7 +34662,7 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
JSValue this_val = JS_NULL;
|
||||
result = JS_Call(ctx, target, this_val, c_argc, c_argv);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(result)) goto done;
|
||||
if (JS_IsException(result)) goto disrupt;
|
||||
frame->slots[ret_reg] = result;
|
||||
} else {
|
||||
/* MCODE function — switch frames */
|
||||
@@ -34632,7 +34692,7 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
JSValue c_result = js_call_c_function(ctx, new_frame->function, new_frame->slots[0], c_argc, c_argv);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
ctx->reg_current_frame = JS_NULL;
|
||||
if (JS_IsException(c_result)) { result = c_result; goto done; }
|
||||
if (JS_IsException(c_result)) { goto disrupt; }
|
||||
frame->slots[ret_reg] = c_result;
|
||||
} else {
|
||||
/* Bytecode interop — use JS_Call */
|
||||
@@ -34641,7 +34701,7 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
/* TODO: proper arg count */
|
||||
JSValue bc_result = JS_Call(ctx, new_frame->function, new_frame->slots[0], bc_argc, bc_argv);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(bc_result)) { result = bc_result; goto done; }
|
||||
if (JS_IsException(bc_result)) { goto disrupt; }
|
||||
frame->slots[ret_reg] = bc_result;
|
||||
}
|
||||
}
|
||||
@@ -34654,14 +34714,13 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
JSValue func_val = frame->slots[func_reg];
|
||||
|
||||
if (!JS_IsFunction(func_val)) {
|
||||
result = JS_ThrowTypeError(ctx, "not a function");
|
||||
goto done;
|
||||
goto disrupt;
|
||||
}
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val);
|
||||
if (fn->kind == JS_FUNC_KIND_MCODE) {
|
||||
JSMCode *fn_code = fn->u.mcode.code;
|
||||
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots);
|
||||
if (!new_frame) { result = JS_EXCEPTION; goto done; }
|
||||
if (!new_frame) { goto disrupt; }
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
func_val = frame->slots[func_reg]; /* re-read after GC */
|
||||
new_frame->function = func_val;
|
||||
@@ -34677,15 +34736,14 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
|
||||
if (JS_IsFunction(target)) {
|
||||
result = JS_ThrowInternalError(ctx, "C function tail call not supported in MCODE");
|
||||
goto done;
|
||||
goto disrupt;
|
||||
}
|
||||
|
||||
JSFrameRegister *new_frame = (JSFrameRegister *)JS_VALUE_GET_PTR(target);
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(new_frame->function);
|
||||
|
||||
if (fn->kind != JS_FUNC_KIND_MCODE) {
|
||||
result = JS_ThrowInternalError(ctx, "non-mcode function in goinvoke");
|
||||
goto done;
|
||||
goto disrupt;
|
||||
}
|
||||
|
||||
/* Tail call — bypass current frame */
|
||||
@@ -34738,14 +34796,14 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
int dest = (int)a1->valuedouble;
|
||||
JSValue rec = JS_NewObject(ctx);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(rec)) { result = rec; goto done; }
|
||||
if (JS_IsException(rec)) { goto disrupt; }
|
||||
frame->slots[dest] = rec;
|
||||
}
|
||||
else if (strcmp(op, "mkarray") == 0) {
|
||||
int dest = (int)a1->valuedouble;
|
||||
JSValue arr = JS_NewArray(ctx);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(arr)) { result = arr; goto done; }
|
||||
if (JS_IsException(arr)) { goto disrupt; }
|
||||
frame->slots[dest] = arr;
|
||||
}
|
||||
else if (strcmp(op, "mkfunc") == 0) {
|
||||
@@ -34779,8 +34837,7 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
|
||||
/* ---- Disruption ---- */
|
||||
else if (strcmp(op, "disrupt") == 0) {
|
||||
result = JS_Throw(ctx, JS_NULL);
|
||||
goto done;
|
||||
goto disrupt;
|
||||
}
|
||||
|
||||
/* ---- Unknown opcode ---- */
|
||||
@@ -34788,6 +34845,27 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
result = JS_ThrowInternalError(ctx, "unknown MCODE opcode: %s", op);
|
||||
goto done;
|
||||
}
|
||||
continue;
|
||||
|
||||
disrupt:
|
||||
/* Search frame chain for a disruption handler */
|
||||
for (;;) {
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
JSMCode *fn_code = fn->u.mcode.code;
|
||||
if (fn_code->disruption_pc > 0) {
|
||||
code = fn_code;
|
||||
pc = fn_code->disruption_pc;
|
||||
break;
|
||||
}
|
||||
if (JS_IsNull(frame->caller)) {
|
||||
result = JS_NULL;
|
||||
goto done;
|
||||
}
|
||||
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
|
||||
frame->caller = JS_NULL;
|
||||
frame = caller;
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -34963,6 +35041,8 @@ static void dump_register_code(JSContext *ctx, JSCodeRegister *code, int indent)
|
||||
if (!JS_IsNull(code->name)) {
|
||||
JS_FreeCString(ctx, name);
|
||||
}
|
||||
if (code->disruption_pc > 0)
|
||||
printf("%s Disruption handler at: %d\n", pad, code->disruption_pc);
|
||||
|
||||
/* Constant pool */
|
||||
if (code->cpool_count > 0) {
|
||||
|
||||
Reference in New Issue
Block a user