зеркало из https://github.com/mozilla/gecko-dev.git
Bug 559006 - Wrong behavior with JSClass::convert hook and JIT. r=mrbkap.
This commit is contained in:
Родитель
2d0cad7e4d
Коммит
5cd6cfd465
|
@ -56,6 +56,7 @@ CPPSRCS = \
|
|||
testIsAboutToBeFinalized.cpp \
|
||||
testLookup.cpp \
|
||||
testNewObject.cpp \
|
||||
testOps.cpp \
|
||||
testPropCache.cpp \
|
||||
testTrap.cpp \
|
||||
testSameValue.cpp \
|
||||
|
|
|
@ -8660,7 +8660,7 @@ TraceRecorder::equality(bool negate, bool tryBranchAfterCond)
|
|||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins,
|
||||
TraceRecorder::equalityHelper(jsval& l, jsval& r, LIns* l_ins, LIns* r_ins,
|
||||
bool negate, bool tryBranchAfterCond,
|
||||
jsval& rval)
|
||||
{
|
||||
|
@ -8720,24 +8720,28 @@ 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 {
|
||||
// Below we may assign to l or r, which modifies the interpreter state.
|
||||
// This is fine as long as we also update the tracker.
|
||||
if (JSVAL_IS_BOOLEAN(l)) {
|
||||
l_ins = i2f(l_ins);
|
||||
set(&l, 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);
|
||||
set(&r, 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);
|
||||
CHECK_STATUS_A(guardNativeConversion(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);
|
||||
CHECK_STATUS_A(guardNativeConversion(l));
|
||||
return InjectStatus(call_imacro(equality_imacros.obj_any));
|
||||
}
|
||||
|
||||
|
@ -8799,15 +8803,15 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond)
|
|||
* properties, abort.
|
||||
*/
|
||||
if (!JSVAL_IS_PRIMITIVE(l)) {
|
||||
RETURN_IF_XML_A(l);
|
||||
CHECK_STATUS_A(guardNativeConversion(l));
|
||||
if (!JSVAL_IS_PRIMITIVE(r)) {
|
||||
RETURN_IF_XML_A(r);
|
||||
CHECK_STATUS_A(guardNativeConversion(r));
|
||||
return InjectStatus(call_imacro(binary_imacros.obj_obj));
|
||||
}
|
||||
return InjectStatus(call_imacro(binary_imacros.obj_any));
|
||||
}
|
||||
if (!JSVAL_IS_PRIMITIVE(r)) {
|
||||
RETURN_IF_XML_A(r);
|
||||
CHECK_STATUS_A(guardNativeConversion(r));
|
||||
return InjectStatus(call_imacro(binary_imacros.any_obj));
|
||||
}
|
||||
|
||||
|
@ -8948,15 +8952,15 @@ TraceRecorder::binary(LOpcode op)
|
|||
jsval& l = stackval(-2);
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(l)) {
|
||||
RETURN_IF_XML(l);
|
||||
CHECK_STATUS(guardNativeConversion(l));
|
||||
if (!JSVAL_IS_PRIMITIVE(r)) {
|
||||
RETURN_IF_XML(r);
|
||||
CHECK_STATUS(guardNativeConversion(r));
|
||||
return call_imacro(binary_imacros.obj_obj);
|
||||
}
|
||||
return call_imacro(binary_imacros.obj_any);
|
||||
}
|
||||
if (!JSVAL_IS_PRIMITIVE(r)) {
|
||||
RETURN_IF_XML(r);
|
||||
CHECK_STATUS(guardNativeConversion(r));
|
||||
return call_imacro(binary_imacros.any_obj);
|
||||
}
|
||||
|
||||
|
@ -9586,6 +9590,39 @@ TraceRecorder::guardPrototypeHasNoIndexedProperties(JSObject* obj, LIns* obj_ins
|
|||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard that the object stored in v has the ECMA standard [[DefaultValue]]
|
||||
* method. Several imacros require this.
|
||||
*/
|
||||
JS_REQUIRES_STACK RecordingStatus
|
||||
TraceRecorder::guardNativeConversion(jsval& v)
|
||||
{
|
||||
JSObject* obj = JSVAL_TO_OBJECT(v);
|
||||
LIns* obj_ins = get(&v);
|
||||
|
||||
if (obj->map->ops->defaultValue != js_DefaultValue)
|
||||
RETURN_STOP("operand has non-native defaultValue op");
|
||||
JSConvertOp convert = obj->getClass()->convert;
|
||||
if (convert != JS_ConvertStub && convert != js_TryValueOf)
|
||||
RETURN_STOP("operand has convert hook");
|
||||
|
||||
VMSideExit* exit = snapshot(BRANCH_EXIT);
|
||||
if (obj->isNative()) {
|
||||
// The common case. Guard on shape rather than class because it'll
|
||||
// often be free: we're about to do a shape guard anyway to get the
|
||||
// .valueOf property of this object, and this guard will be cached.
|
||||
CHECK_STATUS(guardShape(obj_ins, obj, obj->shape(),
|
||||
"guardNativeConversion", exit));
|
||||
} else {
|
||||
// Guard that the defaultValue hook is native at run time,
|
||||
// even though other ops are not. This has overhead.
|
||||
LIns* ops_ins;
|
||||
JS_ALWAYS_TRUE(map_is_native(obj->map, map(obj_ins), ops_ins,
|
||||
offsetof(JSObjectOps, defaultValue)));
|
||||
}
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
// Helper for clearXEntryFrameSlotsFromTracker.
|
||||
// Clear out slots of the given frame in the NativeFrameTracker. All argument slots
|
||||
// are cleared. |nslots| local slots are cleared.
|
||||
|
@ -10147,15 +10184,15 @@ TraceRecorder::record_JSOP_ADD()
|
|||
jsval& l = stackval(-2);
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(l)) {
|
||||
RETURN_IF_XML_A(l);
|
||||
CHECK_STATUS_A(guardNativeConversion(l));
|
||||
if (!JSVAL_IS_PRIMITIVE(r)) {
|
||||
RETURN_IF_XML_A(r);
|
||||
CHECK_STATUS_A(guardNativeConversion(r));
|
||||
return InjectStatus(call_imacro(add_imacros.obj_obj));
|
||||
}
|
||||
return InjectStatus(call_imacro(add_imacros.obj_any));
|
||||
}
|
||||
if (!JSVAL_IS_PRIMITIVE(r)) {
|
||||
RETURN_IF_XML_A(r);
|
||||
CHECK_STATUS_A(guardNativeConversion(r));
|
||||
return InjectStatus(call_imacro(add_imacros.any_obj));
|
||||
}
|
||||
|
||||
|
@ -10230,7 +10267,7 @@ TraceRecorder::record_JSOP_NEG()
|
|||
jsval& v = stackval(-1);
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(v)) {
|
||||
RETURN_IF_XML_A(v);
|
||||
CHECK_STATUS_A(guardNativeConversion(v));
|
||||
return InjectStatus(call_imacro(unary_imacros.sign));
|
||||
}
|
||||
|
||||
|
@ -10290,7 +10327,7 @@ TraceRecorder::record_JSOP_POS()
|
|||
jsval& v = stackval(-1);
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(v)) {
|
||||
RETURN_IF_XML_A(v);
|
||||
CHECK_STATUS_A(guardNativeConversion(v));
|
||||
return InjectStatus(call_imacro(unary_imacros.sign));
|
||||
}
|
||||
|
||||
|
@ -10407,7 +10444,7 @@ TraceRecorder::newString(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval)
|
|||
JS_ASSERT(argc == 1);
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(argv[0])) {
|
||||
RETURN_IF_XML(argv[0]);
|
||||
CHECK_STATUS(guardNativeConversion(argv[0]));
|
||||
return call_imacro(new_imacros.String);
|
||||
}
|
||||
|
||||
|
@ -10976,7 +11013,7 @@ TraceRecorder::functionCall(uintN argc, JSOp mode)
|
|||
if (mode == JSOP_NEW)
|
||||
return newString(JSVAL_TO_OBJECT(fval), 1, argv, &fval);
|
||||
if (!JSVAL_IS_PRIMITIVE(argv[0])) {
|
||||
RETURN_IF_XML(argv[0]);
|
||||
CHECK_STATUS(guardNativeConversion(argv[0]));
|
||||
return call_imacro(call_imacros.String);
|
||||
}
|
||||
set(&fval, stringify(argv[0]));
|
||||
|
@ -15096,6 +15133,7 @@ TraceRecorder::record_JSOP_OBJTOSTR()
|
|||
*cx->fp->imacpc == JSOP_OBJTOSTR);
|
||||
if (JSVAL_IS_PRIMITIVE(v))
|
||||
return ARECORD_CONTINUE;
|
||||
CHECK_STATUS_A(guardNativeConversion(v));
|
||||
return InjectStatus(call_imacro(objtostr_imacros.toString));
|
||||
}
|
||||
|
||||
|
|
|
@ -1185,7 +1185,7 @@ class TraceRecorder
|
|||
|
||||
JS_REQUIRES_STACK void strictEquality(bool equal, bool cmpCase);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus equality(bool negate, bool tryBranchAfterCond);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus equalityHelper(jsval l, jsval r,
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus equalityHelper(jsval& l, jsval& r,
|
||||
nanojit::LIns* l_ins, nanojit::LIns* r_ins,
|
||||
bool negate, bool tryBranchAfterCond,
|
||||
jsval& rval);
|
||||
|
@ -1305,6 +1305,7 @@ class TraceRecorder
|
|||
JS_REQUIRES_STACK RecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj,
|
||||
nanojit::LIns* obj_ins,
|
||||
ExitType exitType);
|
||||
JS_REQUIRES_STACK RecordingStatus guardNativeConversion(jsval& v);
|
||||
JS_REQUIRES_STACK JSStackFrame* entryFrame() const;
|
||||
JS_REQUIRES_STACK void clearEntryFrameSlotsFromTracker(Tracker& which);
|
||||
JS_REQUIRES_STACK void clearCurrentFrameSlotsFromTracker(Tracker& which);
|
||||
|
|
Загрузка…
Ссылка в новой задаче