From de991387a459f0bddf51f6ab92fbb54b85a25e26 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 18 Mar 2010 12:12:06 -0700 Subject: [PATCH] Bug 552586 - split JSVAL_SPECIAL into TT_SPECIAL and TT_VOID (r=dvander) --- js/src/jsbuiltins.cpp | 16 +-- js/src/jsbuiltins.h | 6 +- js/src/jsrecursion.cpp | 28 +++-- js/src/jstracer.cpp | 258 ++++++++++++++++++++++++----------------- js/src/jstracer.h | 13 ++- 5 files changed, 184 insertions(+), 137 deletions(-) diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp index f27c001bcad..49d77ce8948 100644 --- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -317,23 +317,13 @@ js_TypeOfBoolean(JSContext* cx, int32 unboxed) } JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfBoolean, CONTEXT, INT32, 1, ACC_NONE) -jsdouble FASTCALL -js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed) -{ - if (unboxed == JSVAL_TO_SPECIAL(JSVAL_VOID)) - return js_NaN; - JS_ASSERT(unboxed == JS_TRUE || unboxed == JS_FALSE); - return unboxed; -} -JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, ACC_NONE) - JSString* FASTCALL -js_BooleanOrUndefinedToString(JSContext *cx, int32 unboxed) +js_BooleanIntToString(JSContext *cx, int32 unboxed) { - JS_ASSERT(uint32(unboxed) <= 2); + JS_ASSERT(uint32(unboxed) <= 1); return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]); } -JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanOrUndefinedToString, CONTEXT, INT32, 1, ACC_NONE) +JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanIntToString, CONTEXT, INT32, 1, ACC_NONE) JSObject* FASTCALL js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent) diff --git a/js/src/jsbuiltins.h b/js/src/jsbuiltins.h index 80efbfe984b..fd115a42030 100644 --- a/js/src/jsbuiltins.h +++ b/js/src/jsbuiltins.h @@ -503,9 +503,6 @@ struct ClosureVarInfo; jsdouble FASTCALL js_StringToNumber(JSContext* cx, JSString* str); -jsdouble FASTCALL -js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed); - /* Extern version of SetBuiltinError. */ extern JS_FRIEND_API(void) js_SetTraceableNativeFailed(JSContext *cx); @@ -557,8 +554,7 @@ JS_DECLARE_CALLINFO(js_HasNamedProperty) JS_DECLARE_CALLINFO(js_HasNamedPropertyInt32) JS_DECLARE_CALLINFO(js_TypeOfObject) JS_DECLARE_CALLINFO(js_TypeOfBoolean) -JS_DECLARE_CALLINFO(js_BooleanOrUndefinedToNumber) -JS_DECLARE_CALLINFO(js_BooleanOrUndefinedToString) +JS_DECLARE_CALLINFO(js_BooleanIntToString) JS_DECLARE_CALLINFO(js_NewNullClosure) JS_DECLARE_CALLINFO(js_PopInterpFrame) JS_DECLARE_CALLINFO(js_ConcatN) diff --git a/js/src/jsrecursion.cpp b/js/src/jsrecursion.cpp index e737ec38d77..1a243df48e2 100644 --- a/js/src/jsrecursion.cpp +++ b/js/src/jsrecursion.cpp @@ -167,7 +167,7 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame) if (*cx->fp->regs->pc == JSOP_RETURN) exitTypeMap[downPostSlots] = determineSlotType(&stackval(-1)); else - exitTypeMap[downPostSlots] = TT_PSEUDOBOOLEAN; + exitTypeMap[downPostSlots] = TT_VOID; /* Add global types. */ determineGlobalTypes(&exitTypeMap[downPostSlots + 1]); @@ -314,7 +314,7 @@ TraceRecorder::upRecursion() NULL; JS_ASSERT(rval_ins); } else { - rval_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)); + rval_ins = INS_VOID(); } TraceType returnType = exit->stackTypeMap()[downPostSlots]; @@ -331,7 +331,7 @@ TraceRecorder::upRecursion() if (*cx->fp->regs->pc == JSOP_RETURN) slotMap.addSlot(&stackval(-1)); else - slotMap.addSlot(TT_PSEUDOBOOLEAN); + slotMap.addSlot(TT_VOID); VisitGlobalSlots(slotMap, cx, *tree->globalSlots); if (recursive_pc == (jsbytecode*)fragment->root->ip) { debug_only_print0(LC_TMTracer, "Compiling up-recursive loop...\n"); @@ -473,7 +473,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) if (*cx->fp->regs->pc == JSOP_RETURN) typeMap[downPostSlots] = determineSlotType(&stackval(-1)); else - typeMap[downPostSlots] = TT_PSEUDOBOOLEAN; + typeMap[downPostSlots] = TT_VOID; } else { typeMap[downPostSlots] = anchor->stackTypeMap()[anchor->numStackSlots - 1]; } @@ -510,7 +510,8 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) } else { switch (returnType) { - case TT_PSEUDOBOOLEAN: + case TT_SPECIAL: + case TT_VOID: case TT_INT32: rval_ins = lir->insLoad(LIR_ld, lirbuf->sp, offset); break; @@ -591,7 +592,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) if (*cx->fp->regs->pc == JSOP_RETURN) slotMap.addSlot(&stackval(-1), typeMap[downPostSlots]); else - slotMap.addSlot(TT_PSEUDOBOOLEAN); + slotMap.addSlot(TT_VOID); VisitGlobalSlots(slotMap, cx, *tree->globalSlots); debug_only_print0(LC_TMTracer, "Compiling up-recursive slurp...\n"); exit = copy(exit); @@ -721,7 +722,7 @@ TraceRecorder::slurpDoubleSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) } JS_REQUIRES_STACK LIns* -TraceRecorder::slurpBoolSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) +TraceRecorder::slurpSpecialSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) { guard(true, lir->ins2(LIR_peq, @@ -733,6 +734,13 @@ TraceRecorder::slurpBoolSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) return bool_ins; } +JS_REQUIRES_STACK LIns* +TraceRecorder::slurpVoidSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) +{ + guard(true, lir->ins2(LIR_peq, val_ins, INS_CONSTWORD(JSVAL_VOID)), exit); + return INS_VOID(); +} + JS_REQUIRES_STACK LIns* TraceRecorder::slurpStringSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) { @@ -801,8 +809,10 @@ TraceRecorder::slurpSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) { switch (exit->slurpType) { - case TT_PSEUDOBOOLEAN: - return slurpBoolSlot(val_ins, vp, exit); + case TT_SPECIAL: + return slurpSpecialSlot(val_ins, vp, exit); + case TT_VOID: + return slurpVoidSlot(val_ins, vp, exit); case TT_INT32: return slurpInt32Slot(val_ins, vp, exit); case TT_DOUBLE: diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 65146eeb095..ae2ac0c9a25 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -194,14 +194,6 @@ using namespace nanojit; #define RETURN_IF_XML_A(val) RETURN_VALUE_IF_XML(val, ARECORD_STOP) #define RETURN_IF_XML(val) RETURN_VALUE_IF_XML(val, RECORD_STOP) -/* - * Never use JSVAL_IS_BOOLEAN because it restricts the value (true, false) and - * the type. What you want to use is JSVAL_IS_SPECIAL(x) and then handle the - * undefined case properly (bug 457363). - */ -#undef JSVAL_IS_BOOLEAN -#define JSVAL_IS_BOOLEAN(x) JS_STATIC_ASSERT(0) - JS_STATIC_ASSERT(sizeof(TraceType) == 1); JS_STATIC_ASSERT(offsetof(TraceNativeStorage, stack_global_buf) % 16 == 0); @@ -1049,11 +1041,14 @@ GetPromotedType(jsval v) return TT_FUNCTION; return TT_OBJECT; } + /* N.B. void is JSVAL_SPECIAL. */ + if (JSVAL_IS_VOID(v)) + return TT_VOID; uint8_t tag = JSVAL_TAG(v); JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL); JS_STATIC_ASSERT(static_cast(TT_DOUBLE) == JSVAL_DOUBLE); JS_STATIC_ASSERT(static_cast(TT_STRING) == JSVAL_STRING); - JS_STATIC_ASSERT(static_cast(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL); + JS_STATIC_ASSERT(static_cast(TT_SPECIAL) == JSVAL_SPECIAL); return TraceType(tag); } @@ -1070,11 +1065,14 @@ getCoercedType(jsval v) return TT_FUNCTION; return TT_OBJECT; } + /* N.B. void is JSVAL_SPECIAL. */ + if (JSVAL_IS_VOID(v)) + return TT_VOID; uint8_t tag = JSVAL_TAG(v); JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL); JS_STATIC_ASSERT(static_cast(TT_DOUBLE) == JSVAL_DOUBLE); JS_STATIC_ASSERT(static_cast(TT_STRING) == JSVAL_STRING); - JS_STATIC_ASSERT(static_cast(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL); + JS_STATIC_ASSERT(static_cast(TT_SPECIAL) == JSVAL_SPECIAL); return TraceType(tag); } @@ -2597,11 +2595,16 @@ ValueToNative(JSContext* cx, jsval v, TraceType type, double* slot) debug_only_print0(LC_TMTracer, "null "); return; - case TT_PSEUDOBOOLEAN: - /* Watch out for pseudo-booleans. */ + case TT_SPECIAL: JS_ASSERT(tag == JSVAL_SPECIAL); *(JSBool*)slot = JSVAL_TO_SPECIAL(v); - debug_only_printf(LC_TMTracer, "pseudoboolean<%d> ", *(JSBool*)slot); + debug_only_printf(LC_TMTracer, "special<%d> ", *(JSBool*)slot); + return; + + case TT_VOID: + JS_ASSERT(JSVAL_IS_VOID(v)); + *(JSBool*)slot = JSVAL_TO_SPECIAL(JSVAL_VOID); + debug_only_print0(LC_TMTracer, "undefined "); return; case TT_FUNCTION: { @@ -2773,10 +2776,14 @@ NativeToValue(JSContext* cx, jsval& v, TraceType type, double* slot) debug_only_printf(LC_TMTracer, "null<%p> ", (void*)(*(JSObject**)slot)); break; - case TT_PSEUDOBOOLEAN: - /* Watch out for pseudo-booleans. */ + case TT_SPECIAL: v = SPECIAL_TO_JSVAL(*(JSBool*)slot); - debug_only_printf(LC_TMTracer, "boolean<%d> ", *(JSBool*)slot); + debug_only_printf(LC_TMTracer, "special<%d> ", *(JSBool*)slot); + break; + + case TT_VOID: + v = JSVAL_VOID; + debug_only_print0(LC_TMTracer, "undefined "); break; case TT_FUNCTION: { @@ -3322,8 +3329,10 @@ TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, TraceType t, JS_ASSERT_IF(t != TT_JSVAL, isNumber(*p) == (t == TT_DOUBLE)); if (t == TT_DOUBLE) { ins = lir->insLoad(LIR_ldf, base, offset); - } else if (t == TT_PSEUDOBOOLEAN) { + } else if (t == TT_SPECIAL) { ins = lir->insLoad(LIR_ld, base, offset); + } else if (t == TT_VOID) { + ins = INS_VOID(); } else { ins = lir->insLoad(LIR_ldp, base, offset); } @@ -3822,10 +3831,13 @@ TraceRecorder::determineSlotType(jsval* vp) m = TT_FUNCTION; else m = TT_OBJECT; + } else if (JSVAL_IS_VOID(*vp)) { + /* N.B. void is JSVAL_SPECIAL. */ + m = TT_VOID; } else { - JS_ASSERT(JSVAL_TAG(*vp) == JSVAL_STRING || JSVAL_IS_SPECIAL(*vp)); + JS_ASSERT(JSVAL_IS_STRING(*vp) || JSVAL_IS_SPECIAL(*vp)); JS_STATIC_ASSERT(static_cast(TT_STRING) == JSVAL_STRING); - JS_STATIC_ASSERT(static_cast(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL); + JS_STATIC_ASSERT(static_cast(TT_SPECIAL) == JSVAL_SPECIAL); m = TraceType(JSVAL_TAG(*vp)); } JS_ASSERT(m != TT_INT32 || isInt32(*vp)); @@ -6059,11 +6071,17 @@ IsEntryTypeCompatible(jsval* vp, TraceType* m) return true; debug_only_printf(LC_TMTracer, "null != tag%u ", tag); return false; - case TT_PSEUDOBOOLEAN: - if (tag == JSVAL_SPECIAL) + case TT_SPECIAL: + /* N.B. void is JSVAL_SPECIAL. */ + if (JSVAL_IS_SPECIAL(*vp) && !JSVAL_IS_VOID(*vp)) return true; debug_only_printf(LC_TMTracer, "bool != tag%u ", tag); return false; + case TT_VOID: + if (JSVAL_IS_VOID(*vp)) + return true; + debug_only_printf(LC_TMTracer, "undefined != tag%u ", tag); + return false; default: JS_ASSERT(*m == TT_FUNCTION); if (tag == JSVAL_OBJECT && !JSVAL_IS_NULL(*vp) && @@ -8132,6 +8150,12 @@ TraceRecorder::alu(LOpcode v, jsdouble v0, jsdouble v1, LIns* s0, LIns* s1) return lir->ins1(LIR_i2f, result); } +LIns* +TraceRecorder::i2f(LIns* i) +{ + return lir->ins1(LIR_i2f, i); +} + LIns* TraceRecorder::f2i(LIns* f) { @@ -8210,8 +8234,12 @@ TraceRecorder::stringify(jsval& v) const CallInfo* ci; if (JSVAL_IS_NUMBER(v)) { ci = &js_NumberToString_ci; + } else if (JSVAL_IS_VOID(v)) { + /* N.B. void is JSVAL_SPECIAL. */ + return INS_ATOM(cx->runtime->atomState.booleanAtoms[2]); } else if (JSVAL_IS_SPECIAL(v)) { - ci = &js_BooleanOrUndefinedToString_ci; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + ci = &js_BooleanIntToString_ci; } else { /* * Callers must deal with non-primitive (non-null object) values by @@ -8581,14 +8609,16 @@ TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins, */ if (GetPromotedType(l) == GetPromotedType(r)) { - if (JSVAL_TAG(l) == JSVAL_OBJECT || JSVAL_IS_SPECIAL(l)) { - if (JSVAL_TAG(l) == JSVAL_OBJECT && l) { - JSClass *clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(l)); - if ((clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*) clasp)->equality) - RETURN_STOP_A("Can't trace extended class equality operator"); - } - if (JSVAL_TAG(l) == JSVAL_OBJECT) - op = LIR_peq; + if (JSVAL_IS_VOID(l) || JSVAL_IS_NULL(l)) { + cond = true; + } else if (JSVAL_IS_OBJECT(l)) { + JSClass *clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(l)); + if ((clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*) clasp)->equality) + RETURN_STOP_A("Can't trace extended class equality operator"); + op = LIR_peq; + cond = (l == r); + } else if (JSVAL_IS_SPECIAL(l)) { + JS_ASSERT(JSVAL_IS_BOOLEAN(l) && JSVAL_IS_BOOLEAN(r)); cond = (l == r); } else if (JSVAL_IS_STRING(l)) { args[0] = r_ins, args[1] = l_ins; @@ -8600,12 +8630,12 @@ TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins, cond = (asNumber(l) == asNumber(r)); op = LIR_feq; } - } else if (JSVAL_IS_NULL(l) && JSVAL_IS_SPECIAL(r)) { + } else if (JSVAL_IS_NULL(l) && JSVAL_IS_VOID(r)) { l_ins = INS_VOID(); - cond = (r == JSVAL_VOID); - } else if (JSVAL_IS_SPECIAL(l) && JSVAL_IS_NULL(r)) { + cond = true; + } else if (JSVAL_IS_VOID(l) && JSVAL_IS_NULL(r)) { r_ins = INS_VOID(); - cond = (l == JSVAL_VOID); + cond = true; } else if (isNumber(l) && JSVAL_IS_STRING(r)) { args[0] = r_ins, args[1] = cx_ins; r_ins = lir->insCall(&js_StringToNumber_ci, args); @@ -8617,43 +8647,25 @@ TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins, cond = (js_StringToNumber(cx, JSVAL_TO_STRING(l)) == asNumber(r)); op = LIR_feq; } else { - if (JSVAL_IS_SPECIAL(l)) { - bool isVoid = !!JSVAL_IS_VOID(l); - guard(isVoid, - lir->ins2(LIR_eq, l_ins, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))), - BRANCH_EXIT); - if (!isVoid) { - args[0] = l_ins, args[1] = cx_ins; - l_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); - l = (l == JSVAL_VOID) - ? cx->runtime->NaNValue - : INT_TO_JSVAL(l == JSVAL_TRUE); - return equalityHelper(l, r, l_ins, r_ins, negate, - tryBranchAfterCond, rval); - } - } else if (JSVAL_IS_SPECIAL(r)) { - bool isVoid = !!JSVAL_IS_VOID(r); - guard(isVoid, - lir->ins2(LIR_eq, r_ins, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))), - BRANCH_EXIT); - if (!isVoid) { - args[0] = r_ins, args[1] = cx_ins; - r_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); - r = (r == JSVAL_VOID) - ? cx->runtime->NaNValue - : INT_TO_JSVAL(r == JSVAL_TRUE); - return equalityHelper(l, r, l_ins, r_ins, negate, - tryBranchAfterCond, rval); - } - } else { - if ((JSVAL_IS_STRING(l) || isNumber(l)) && !JSVAL_IS_PRIMITIVE(r)) { - RETURN_IF_XML_A(r); - return InjectStatus(call_imacro(equality_imacros.any_obj)); - } - if (!JSVAL_IS_PRIMITIVE(l) && (JSVAL_IS_STRING(r) || isNumber(r))) { - RETURN_IF_XML_A(l); - return InjectStatus(call_imacro(equality_imacros.obj_any)); - } + if (JSVAL_IS_BOOLEAN(l)) { + l_ins = i2f(l_ins); + l = INT_TO_JSVAL(l == JSVAL_TRUE); + return equalityHelper(l, r, l_ins, r_ins, negate, + tryBranchAfterCond, rval); + } + if (JSVAL_IS_BOOLEAN(r)) { + r_ins = i2f(r_ins); + r = INT_TO_JSVAL(r == JSVAL_TRUE); + return equalityHelper(l, r, l_ins, r_ins, negate, + tryBranchAfterCond, rval); + } + if ((JSVAL_IS_STRING(l) || isNumber(l)) && !JSVAL_IS_PRIMITIVE(r)) { + RETURN_IF_XML_A(r); + return InjectStatus(call_imacro(equality_imacros.any_obj)); + } + if (!JSVAL_IS_PRIMITIVE(l) && (JSVAL_IS_STRING(r) || isNumber(r))) { + RETURN_IF_XML_A(l); + return InjectStatus(call_imacro(equality_imacros.obj_any)); } l_ins = lir->insImm(0); @@ -8740,7 +8752,10 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) LIns* args[] = { l_ins, cx_ins }; switch (JSVAL_TAG(l)) { case JSVAL_SPECIAL: - l_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); + if (JSVAL_IS_VOID(l)) + l_ins = lir->insImmf(js_NaN); + else + l_ins = i2f(l_ins); break; case JSVAL_STRING: l_ins = lir->insCall(&js_StringToNumber_ci, args); @@ -8763,7 +8778,10 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) LIns* args[] = { r_ins, cx_ins }; switch (JSVAL_TAG(r)) { case JSVAL_SPECIAL: - r_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); + if (JSVAL_IS_VOID(r)) + r_ins = lir->insImmf(js_NaN); + else + r_ins = i2f(r_ins); break; case JSVAL_STRING: r_ins = lir->insCall(&js_StringToNumber_ci, args); @@ -8894,16 +8912,25 @@ TraceRecorder::binary(LOpcode op) rnum = js_StringToNumber(cx, JSVAL_TO_STRING(r)); rightIsNumber = true; } + /* N.B. void is JSVAL_SPECIAL. */ if (JSVAL_IS_SPECIAL(l)) { - LIns* args[] = { a, cx_ins }; - a = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); - lnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_SPECIAL(l)); + if (JSVAL_IS_VOID(l)) { + a = lir->insImmf(js_NaN); + lnum = js_NaN; + } else { + a = i2f(a); + lnum = JSVAL_TO_SPECIAL(l); + } leftIsNumber = true; } if (JSVAL_IS_SPECIAL(r)) { - LIns* args[] = { b, cx_ins }; - b = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); - rnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_SPECIAL(r)); + if (JSVAL_IS_VOID(r)) { + b = lir->insImmf(js_NaN); + rnum = js_NaN; + } else { + b = i2f(b); + rnum = JSVAL_TO_SPECIAL(r); + } rightIsNumber = true; } if (leftIsNumber && rightIsNumber) { @@ -9365,11 +9392,17 @@ TraceRecorder::unbox_jsval(jsval v, LIns* v_ins, VMSideExit* exit) } switch (JSVAL_TAG(v)) { case JSVAL_SPECIAL: + if (JSVAL_IS_VOID(v)) { + guard(true, lir->ins2(LIR_peq, v_ins, INS_CONSTWORD(JSVAL_VOID)), exit); + return INS_VOID(); + } guard(true, lir->ins2(LIR_peq, lir->ins2(LIR_piand, v_ins, INS_CONSTWORD(JSVAL_TAGMASK)), INS_CONSTWORD(JSVAL_SPECIAL)), exit); + assert(!v_ins->isconstp()); + guard(false, lir->ins2(LIR_peq, v_ins, INS_CONSTWORD(JSVAL_VOID)), exit); return p2i(lir->ins2i(LIR_pursh, v_ins, JSVAL_TAGBITS)); case JSVAL_OBJECT: @@ -9834,7 +9867,7 @@ TraceRecorder::record_LeaveFrame() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_PUSH() { - stack(0, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))); + stack(0, INS_VOID()); return ARECORD_CONTINUE; } @@ -10230,14 +10263,20 @@ TraceRecorder::record_JSOP_NEG() return ARECORD_CONTINUE; } - JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v)); + if (JSVAL_IS_VOID(v)) { + set(&v, lir->insImmf(js_NaN)); + return ARECORD_CONTINUE; + } - LIns* args[] = { get(&v), cx_ins }; - set(&v, lir->ins1(LIR_fneg, - lir->insCall(JSVAL_IS_STRING(v) - ? &js_StringToNumber_ci - : &js_BooleanOrUndefinedToNumber_ci, - args))); + if (JSVAL_IS_STRING(v)) { + LIns* args[] = { get(&v), cx_ins }; + set(&v, lir->ins1(LIR_fneg, + lir->insCall(&js_StringToNumber_ci, args))); + return ARECORD_CONTINUE; + } + + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + set(&v, i2f(get(&v))); return ARECORD_CONTINUE; } @@ -10258,14 +10297,19 @@ TraceRecorder::record_JSOP_POS() set(&v, lir->insImmf(0)); return ARECORD_CONTINUE; } + if (JSVAL_IS_VOID(v)) { + set(&v, lir->insImmf(js_NaN)); + return ARECORD_CONTINUE; + } - JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v)); + if (JSVAL_IS_STRING(v)) { + LIns* args[] = { get(&v), cx_ins }; + set(&v, lir->insCall(&js_StringToNumber_ci, args)); + return ARECORD_CONTINUE; + } - LIns* args[] = { get(&v), cx_ins }; - set(&v, lir->insCall(JSVAL_IS_STRING(v) - ? &js_StringToNumber_ci - : &js_BooleanOrUndefinedToNumber_ci, - args)); + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + set(&v, i2f(get(&v))); return ARECORD_CONTINUE; } @@ -10995,7 +11039,7 @@ TraceRecorder::record_JSOP_TYPEOF() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_VOID() { - stack(-1, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))); + stack(-1, INS_VOID()); return ARECORD_CONTINUE; } @@ -11987,13 +12031,14 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) if (!isNumber(v)) { if (JSVAL_IS_NULL(v)) { v_ins = INS_CONST(0); - } else if (JSVAL_IS_PRIMITIVE(v)) { - JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v)); + } else if (JSVAL_IS_VOID(v)) { + v_ins = lir->insImmf(js_NaN); + } else if (JSVAL_IS_STRING(v)) { LIns* args[] = { v_ins, cx_ins }; - v_ins = lir->insCall(JSVAL_IS_STRING(v) - ? &js_StringToNumber_ci - : &js_BooleanOrUndefinedToNumber_ci, - args); + v_ins = lir->insCall(&js_StringToNumber_ci, args); + } else if (JSVAL_IS_SPECIAL(v)) { + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + v_ins = i2f(v_ins); } else { v_ins = lir->insImmf(js_NaN); } @@ -12224,7 +12269,8 @@ LIns* TraceRecorder::stackLoad(LIns* base, uint8 type) loadOp = LIR_ldp; break; case TT_INT32: - case TT_PSEUDOBOOLEAN: + case TT_SPECIAL: + case TT_VOID: loadOp = LIR_ld; break; case TT_JSVAL: @@ -12384,7 +12430,7 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, * and does not call any TR::record_*CallComplete hook. */ if (fun->u.i.script->isEmpty()) { - LIns* rval_ins = constructing ? stack(-1 - argc) : INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)); + LIns* rval_ins = constructing ? stack(-1 - argc) : INS_VOID(); stack(-2 - argc, rval_ins); return RECORD_CONTINUE; } @@ -12787,7 +12833,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, } } while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit)); - set(outp, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))); + set(outp, INS_VOID()); return ARECORD_CONTINUE; } @@ -12985,7 +13031,7 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ lir->ins2i(LIR_pilsh, pidx_ins, (sizeof(jsval) == 4) ? 2 : 3)); v_ins = unbox_jsval(*vp, lir->insLoad(LIR_ldp, addr_ins, 0), exit); - if (JSVAL_IS_SPECIAL(*vp)) { + if (JSVAL_IS_SPECIAL(*vp) && !JSVAL_IS_VOID(*vp)) { /* * If we read a hole from the array, convert it to undefined and guard * that there are no indexed properties along the prototype chain. @@ -14625,7 +14671,7 @@ TraceRecorder::record_JSOP_STOP() JS_ASSERT(fp->thisv == fp->argv[-1]); rval_ins = get(&fp->argv[-1]); } else { - rval_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)); + rval_ins = INS_VOID(); } clearCurrentFrameSlotsFromTracker(nativeFrameTracker); return ARECORD_CONTINUE; @@ -14664,7 +14710,7 @@ TraceRecorder::record_JSOP_ENTERBLOCK() JSObject* obj; obj = cx->fp->script->getObject(getFullIndex(0)); - LIns* void_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)); + LIns* void_ins = INS_VOID(); for (int i = 0, n = OBJ_BLOCK_COUNT(cx, obj); i < n; i++) stack(i, void_ins); return ARECORD_CONTINUE; diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 78ec9f58937..924bdc209b4 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -348,9 +348,10 @@ enum TraceType_ TT_JSVAL = 3, /* arbitrary jsval */ TT_STRING = 4, /* pointer to JSString */ TT_NULL = 5, /* null */ - TT_PSEUDOBOOLEAN = 6, /* true, false, or undefined (0, 1, or 2) */ - TT_FUNCTION = 7, /* pointer to JSObject whose class is js_FunctionClass */ - TT_IGNORE = 8 + TT_SPECIAL = 6, /* true, false, hole, or areturn (0, 1, 6, or 8) */ + TT_VOID = 7, /* undefined (2) */ + TT_FUNCTION = 8, /* pointer to JSObject whose class is js_FunctionClass */ + TT_IGNORE = 9 } #if defined(__GNUC__) && defined(USE_TRACE_TYPE_ENUM) __attribute__((packed)) @@ -1096,7 +1097,9 @@ class TraceRecorder VMSideExit* exit); JS_REQUIRES_STACK nanojit::LIns* slurpNullSlot(nanojit::LIns* val_ins, jsval* vp, VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpBoolSlot(nanojit::LIns* val_ins, jsval* vp, + JS_REQUIRES_STACK nanojit::LIns* slurpSpecialSlot(nanojit::LIns* val_ins, jsval* vp, + VMSideExit* exit); + JS_REQUIRES_STACK nanojit::LIns* slurpVoidSlot(nanojit::LIns* val_ins, jsval* vp, VMSideExit* exit); JS_REQUIRES_STACK nanojit::LIns* slurpSlot(nanojit::LIns* val_ins, jsval* vp, VMSideExit* exit); @@ -1155,6 +1158,8 @@ class TraceRecorder JS_REQUIRES_STACK nanojit::LIns* alu(nanojit::LOpcode op, jsdouble v0, jsdouble v1, nanojit::LIns* s0, nanojit::LIns* s1); + + nanojit::LIns* i2f(nanojit::LIns* i); nanojit::LIns* f2i(nanojit::LIns* f); nanojit::LIns* f2u(nanojit::LIns* f); JS_REQUIRES_STACK nanojit::LIns* makeNumberInt32(nanojit::LIns* f);