mach disrupt support

This commit is contained in:
2026-02-06 21:09:18 -06:00
parent 77ae133747
commit 6571262af0

View File

@@ -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,59 +31977,63 @@ 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);
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: {
int32_t ia = (int32_t)da;
int32_t ib = (int32_t)db;
/* 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_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_BAND: return JS_NewInt32(ctx, ia & ib);
case MACH_BOR: return JS_NewInt32(ctx, ia | ib);
case MACH_BXOR: return JS_NewInt32(ctx, ia ^ ib);
case MACH_SHL: return JS_NewInt32(ctx, ia << (ib & 31));
case MACH_SHR: return JS_NewInt32(ctx, ia >> (ib & 31));
case MACH_USHR: return JS_NewInt32(ctx, (uint32_t)ia >> (ib & 31));
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) {
case MACH_BAND: return JS_NewInt32(ctx, ia & ib);
case MACH_BOR: return JS_NewInt32(ctx, ia | ib);
case MACH_BXOR: return JS_NewInt32(ctx, ia ^ ib);
case MACH_SHL: return JS_NewInt32(ctx, ia << (ib & 31));
case MACH_SHR: return JS_NewInt32(ctx, ia >> (ib & 31));
case MACH_USHR: return JS_NewInt32(ctx, (uint32_t)ia >> (ib & 31));
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) {