diff --git a/source/quickjs.c b/source/quickjs.c index d76ecbf9..1a27bcd1 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -31982,16 +31982,26 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) { cJSON *elems = cJSON_GetObjectItem(node, "list"); int count = elems ? cJSON_GetArraySize(elems) : 0; - /* Reserve consecutive regs for elements starting at dest+1 */ + /* Reserve consecutive regs for elements starting at arr_base+1. + If dest is below freereg, other temps occupy dest+1..freereg-1 + so we must use a fresh base to avoid clobbering them. */ int save = cs->freereg; - cs->freereg = dest + 1; + int arr_base; + if (dest + 1 >= cs->freereg) { + arr_base = dest; + cs->freereg = dest + 1; + } else { + arr_base = mach_reserve_reg(cs); + } for (int i = 0; i < count; i++) { int er = mach_reserve_reg(cs); cJSON *elem = cJSON_GetArrayItem(elems, i); int r = mach_compile_expr(cs, elem, er); if (r != er) mach_emit(cs, MACH_ABC(MACH_MOVE, er, r, 0)); } - mach_emit(cs, MACH_ABC(MACH_NEWARRAY, dest, count, 0)); + mach_emit(cs, MACH_ABC(MACH_NEWARRAY, arr_base, count, 0)); + if (arr_base != dest) + mach_emit(cs, MACH_ABC(MACH_MOVE, dest, arr_base, 0)); mach_free_reg_to(cs, save); return dest; } @@ -32903,10 +32913,14 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) { /* Comparison ops allow mixed types — return false for mismatches */ if (op >= MACH_EQ && op <= MACH_GE) { - /* Fast path: bitwise-identical values (same object/pointer) */ - if (a == b) { - if (op == MACH_EQ || op == MACH_LE || op == MACH_GE) return JS_TRUE; - if (op == MACH_NEQ) return JS_FALSE; + /* Fast path: identical values (chase pointers for forwarded objects) */ + { + JSValue ca = JS_IsPtr(a) ? JS_MKPTR(chase(a)) : a; + JSValue cb = JS_IsPtr(b) ? JS_MKPTR(chase(b)) : b; + if (ca == cb) { + if (op == MACH_EQ || op == MACH_LE || op == MACH_GE) return JS_TRUE; + if (op == MACH_NEQ) return JS_FALSE; + } } if (JS_IsNumber(a) && JS_IsNumber(b)) { double da, db;