diff --git a/source/quickjs.c b/source/quickjs.c index 20110436..aa356991 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -33002,6 +33002,7 @@ static const char *mach_gen_binop_to_string (const char *kind) { if (strcmp (kind, "<=") == 0) return "le"; if (strcmp (kind, ">") == 0) return "gt"; if (strcmp (kind, ">=") == 0) return "ge"; + if (strcmp (kind, "**") == 0) return "pow"; if (strcmp (kind, "in") == 0) return "in"; return "add"; } @@ -34379,15 +34380,15 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, JSValue right = frame->slots[(int)a3->valuedouble]; if (JS_VALUE_IS_BOTH_INT(left, right)) { int32_t ia = JS_VALUE_GET_INT(left), ib = JS_VALUE_GET_INT(right); - if (ib == 0) { goto disrupt; } - if (ia % ib == 0) frame->slots[dest] = JS_NewInt32(ctx, ia / ib); + if (ib == 0) { frame->slots[dest] = JS_NULL; } + else if (ia % ib == 0) frame->slots[dest] = JS_NewInt32(ctx, ia / ib); else frame->slots[dest] = JS_NewFloat64(ctx, (double)ia / (double)ib); } else if (JS_IsNumber(left) && JS_IsNumber(right)) { double a, b; JS_ToFloat64(ctx, &a, left); JS_ToFloat64(ctx, &b, right); - if (b == 0.0) { goto disrupt; } - frame->slots[dest] = JS_NewFloat64(ctx, a / b); + if (b == 0.0) { frame->slots[dest] = JS_NULL; } + else frame->slots[dest] = JS_NewFloat64(ctx, a / b); } else { goto disrupt; } } else if (strcmp(op, "integer_divide") == 0) { @@ -34396,14 +34397,14 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, JSValue right = frame->slots[(int)a3->valuedouble]; if (JS_VALUE_IS_BOTH_INT(left, right)) { int32_t ib = JS_VALUE_GET_INT(right); - if (ib == 0) { goto disrupt; } - frame->slots[dest] = JS_NewInt32(ctx, JS_VALUE_GET_INT(left) / ib); + if (ib == 0) { frame->slots[dest] = JS_NULL; } + else frame->slots[dest] = JS_NewInt32(ctx, JS_VALUE_GET_INT(left) / ib); } else if (JS_IsNumber(left) && JS_IsNumber(right)) { double a, b; JS_ToFloat64(ctx, &a, left); JS_ToFloat64(ctx, &b, right); - if (b == 0.0) { goto disrupt; } - frame->slots[dest] = JS_NewInt32(ctx, (int32_t)(a / b)); + if (b == 0.0) { frame->slots[dest] = JS_NULL; } + else frame->slots[dest] = JS_NewInt32(ctx, (int32_t)(a / b)); } else { goto disrupt; } } else if (strcmp(op, "modulo") == 0) { @@ -34412,14 +34413,14 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, JSValue right = frame->slots[(int)a3->valuedouble]; if (JS_VALUE_IS_BOTH_INT(left, right)) { int32_t ib = JS_VALUE_GET_INT(right); - if (ib == 0) { goto disrupt; } - frame->slots[dest] = JS_NewInt32(ctx, JS_VALUE_GET_INT(left) % ib); + if (ib == 0) { frame->slots[dest] = JS_NULL; } + else frame->slots[dest] = JS_NewInt32(ctx, JS_VALUE_GET_INT(left) % ib); } else if (JS_IsNumber(left) && JS_IsNumber(right)) { double a, b; JS_ToFloat64(ctx, &a, left); JS_ToFloat64(ctx, &b, right); - if (b == 0.0) { goto disrupt; } - frame->slots[dest] = JS_NewFloat64(ctx, fmod(a, b)); + if (b == 0.0) { frame->slots[dest] = JS_NULL; } + else frame->slots[dest] = JS_NewFloat64(ctx, fmod(a, b)); } else { goto disrupt; } } else if (strcmp(op, "remainder") == 0) { @@ -34428,14 +34429,25 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, JSValue right = frame->slots[(int)a3->valuedouble]; if (JS_VALUE_IS_BOTH_INT(left, right)) { int32_t ib = JS_VALUE_GET_INT(right); - if (ib == 0) { goto disrupt; } - frame->slots[dest] = JS_NewInt32(ctx, JS_VALUE_GET_INT(left) % ib); + if (ib == 0) { frame->slots[dest] = JS_NULL; } + else frame->slots[dest] = JS_NewInt32(ctx, JS_VALUE_GET_INT(left) % ib); } else if (JS_IsNumber(left) && JS_IsNumber(right)) { double a, b; JS_ToFloat64(ctx, &a, left); JS_ToFloat64(ctx, &b, right); - if (b == 0.0) { goto disrupt; } - frame->slots[dest] = JS_NewFloat64(ctx, remainder(a, b)); + if (b == 0.0) { frame->slots[dest] = JS_NULL; } + else frame->slots[dest] = JS_NewFloat64(ctx, remainder(a, b)); + } else { goto disrupt; } + } + else if (strcmp(op, "pow") == 0) { + int dest = (int)a1->valuedouble; + JSValue left = frame->slots[(int)a2->valuedouble]; + JSValue right = frame->slots[(int)a3->valuedouble]; + if (JS_IsNumber(left) && JS_IsNumber(right)) { + double a, b; + JS_ToFloat64(ctx, &a, left); + JS_ToFloat64(ctx, &b, right); + frame->slots[dest] = JS_NewFloat64(ctx, pow(a, b)); } else { goto disrupt; } } else if (strcmp(op, "max") == 0) { @@ -34740,6 +34752,17 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, } else { goto disrupt; } } + /* ---- in operator ---- */ + else if (strcmp(op, "in") == 0) { + int dest = (int)a1->valuedouble; + JSValue left = frame->slots[(int)a2->valuedouble]; + JSValue right = frame->slots[(int)a3->valuedouble]; + int ret = JS_HasPropertyKey(ctx, right, left); + frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); + if (ret < 0) { goto disrupt; } + frame->slots[dest] = JS_NewBool(ctx, ret); + } + /* ---- Sensory (type checks) ---- */ else if (strcmp(op, "text?") == 0) { int dest = (int)a1->valuedouble; @@ -35366,23 +35389,32 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, 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; + /* Search frame chain for a disruption handler. + Use frame_pc to track each frame's execution point: + - For the faulting frame, it's the current pc. + - For unwound caller frames, read from frame->address. */ + { + uint32_t frame_pc = pc; + for (;;) { + JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function); + JSMCode *fn_code = fn->u.mcode.code; + /* Only enter handler if we're not already inside it */ + if (fn_code->disruption_pc > 0 && frame_pc < fn_code->disruption_pc) { + code = fn_code; + pc = fn_code->disruption_pc; + break; + } + if (JS_IsNull(frame->caller)) { + result = JS_NULL; + goto done; + } + /* Unwind one frame — read caller's saved pc from its address field */ + JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller); + frame->caller = JS_NULL; + frame = caller; + frame_ref.val = JS_MKPTR(frame); + frame_pc = (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16); } - 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); } } @@ -35478,6 +35510,8 @@ JSValue JS_CallMcode(JSContext *ctx, const char *mcode_json) { /* Execute with global_obj as this */ JSValue result = mcode_exec(ctx, code, ctx->global_obj, 0, NULL, JS_NULL); + /* Clear frame ref before freeing mcode — stack trace data is inside code */ + ctx->reg_current_frame = JS_NULL; jsmcode_free(code); return result; }