diff --git a/source/quickjs.c b/source/quickjs.c index 74e14fb0..b9962661 100644 --- a/source/quickjs.c +++ b/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,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) {