Bug 552586 - split JSVAL_SPECIAL into TT_SPECIAL and TT_VOID (r=dvander)

This commit is contained in:
Luke Wagner 2010-03-18 12:12:06 -07:00
parent c841a2ef46
commit de991387a4
5 changed files with 184 additions and 137 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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<jsvaltag>(TT_DOUBLE) == JSVAL_DOUBLE);
JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_STRING) == JSVAL_STRING);
JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL);
JS_STATIC_ASSERT(static_cast<jsvaltag>(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<jsvaltag>(TT_DOUBLE) == JSVAL_DOUBLE);
JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_STRING) == JSVAL_STRING);
JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL);
JS_STATIC_ASSERT(static_cast<jsvaltag>(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<jsvaltag>(TT_STRING) == JSVAL_STRING);
JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL);
JS_STATIC_ASSERT(static_cast<jsvaltag>(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;

View File

@ -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);