Try converting known doubles to integers in GETELEM/SETELEM paths, bug 678687. r=dvander

This commit is contained in:
Brian Hackett 2011-11-03 09:24:40 -07:00
parent a9d4865e7b
commit 72819628ee
2 changed files with 61 additions and 6 deletions

View File

@ -601,6 +601,12 @@ private:
/* Convert fe from a double to integer (per ValueToECMAInt32) in place. */
void truncateDoubleToInt32(FrameEntry *fe, Uses uses);
/*
* Try to convert a double fe to an integer, with no truncation performed,
* or jump to the slow path per uses.
*/
void tryConvertInteger(FrameEntry *fe, Uses uses);
/* Opcode handlers. */
bool jumpAndTrace(Jump j, jsbytecode *target, Jump *slow = NULL, bool *trampoline = NULL);
bool startLoop(jsbytecode *head, Jump entry, jsbytecode *entryTarget);

View File

@ -1038,9 +1038,11 @@ IsCacheableSetElem(FrameEntry *obj, FrameEntry *id, FrameEntry *value)
{
if (obj->isNotType(JSVAL_TYPE_OBJECT))
return false;
if (id->isNotType(JSVAL_TYPE_INT32))
if (id->isNotType(JSVAL_TYPE_INT32) && id->isNotType(JSVAL_TYPE_DOUBLE))
return false;
if (id->isConstant()) {
if (id->isNotType(JSVAL_TYPE_INT32))
return false;
if (id->getValue().toInt32() < 0)
return false;
if (id->getValue().toInt32() + 1 < 0) // watch for overflow in hole paths
@ -1070,6 +1072,9 @@ mjit::Compiler::jsop_setelem_dense()
stubcc.linkExit(guard, Uses(3));
}
if (id->isType(JSVAL_TYPE_DOUBLE))
tryConvertInteger(id, Uses(2));
// Test for integer index.
if (!id->isTypeKnown()) {
Jump guard = frame.testInt32(Assembler::NotEqual, id);
@ -1354,6 +1359,9 @@ mjit::Compiler::jsop_setelem_typed(int atype)
stubcc.linkExit(guard, Uses(3));
}
if (id->isType(JSVAL_TYPE_DOUBLE))
tryConvertInteger(id, Uses(2));
// Test for integer index.
if (!id->isTypeKnown()) {
Jump guard = frame.testInt32(Assembler::NotEqual, id);
@ -1433,6 +1441,22 @@ mjit::Compiler::jsop_setelem_typed(int atype)
}
#endif /* JS_METHODJIT_TYPED_ARRAY */
void
mjit::Compiler::tryConvertInteger(FrameEntry *fe, Uses uses)
{
JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
JumpList isDouble;
FPRegisterID fpreg = frame.tempFPRegForData(fe);
RegisterID reg = frame.allocReg();
masm.branchConvertDoubleToInt32(fpreg, reg, isDouble, Registers::FPConversionTemp);
Jump j = masm.jump();
isDouble.linkTo(masm.label(), &masm);
stubcc.linkExit(masm.jump(), uses);
j.linkTo(masm.label(), &masm);
frame.learnType(fe, JSVAL_TYPE_INT32, reg);
}
bool
mjit::Compiler::jsop_setelem(bool popGuaranteed)
{
@ -1449,7 +1473,7 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
// If the object is definitely a dense array or a typed array we can generate
// code directly without using an inline cache.
if (cx->typeInferenceEnabled() && id->mightBeType(JSVAL_TYPE_INT32)) {
if (cx->typeInferenceEnabled()) {
types::TypeSet *types = analysis->poppedTypes(PC, 2);
if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
@ -1472,6 +1496,11 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
#endif
}
if (id->isType(JSVAL_TYPE_DOUBLE)) {
jsop_setelem_slow();
return true;
}
SetElementICInfo ic = SetElementICInfo(JSOp(*PC));
// One by one, check if the most important stack entries have registers,
@ -1631,15 +1660,18 @@ static inline bool
IsCacheableGetElem(FrameEntry *obj, FrameEntry *id)
{
if (id->isTypeKnown() &&
!(id->getKnownType() == JSVAL_TYPE_INT32
!(id->isType(JSVAL_TYPE_INT32) || id->isType(JSVAL_TYPE_DOUBLE)
#if defined JS_POLYIC
|| id->getKnownType() == JSVAL_TYPE_STRING
|| id->isType(JSVAL_TYPE_STRING)
#endif
)) {
return false;
}
if (id->isTypeKnown() && id->getKnownType() == JSVAL_TYPE_INT32 && id->isConstant() &&
if (id->isType(JSVAL_TYPE_DOUBLE) && id->isConstant())
return false;
if (id->isType(JSVAL_TYPE_INT32) && id->isConstant() &&
id->getValue().toInt32() < 0) {
return false;
}
@ -1664,6 +1696,9 @@ mjit::Compiler::jsop_getelem_dense(bool isPacked)
stubcc.linkExit(guard, Uses(2));
}
if (id->isType(JSVAL_TYPE_DOUBLE))
tryConvertInteger(id, Uses(2));
// Test for integer index.
if (!id->isTypeKnown()) {
Jump guard = frame.testInt32(Assembler::NotEqual, id);
@ -1780,6 +1815,9 @@ mjit::Compiler::jsop_getelem_args()
{
FrameEntry *id = frame.peek(-1);
if (id->isType(JSVAL_TYPE_DOUBLE))
tryConvertInteger(id, Uses(2));
// Test for integer index.
if (!id->isTypeKnown()) {
Jump guard = frame.testInt32(Assembler::NotEqual, id);
@ -1887,6 +1925,9 @@ mjit::Compiler::jsop_getelem_typed(int atype)
stubcc.linkExit(guard, Uses(2));
}
if (id->isType(JSVAL_TYPE_DOUBLE))
tryConvertInteger(id, Uses(2));
// Test for integer index.
if (!id->isTypeKnown()) {
Jump guard = frame.testInt32(Assembler::NotEqual, id);
@ -2007,7 +2048,7 @@ mjit::Compiler::jsop_getelem(bool isCall)
// If the object is definitely an arguments object, a dense array or a typed array
// we can generate code directly without using an inline cache.
if (cx->typeInferenceEnabled() && id->mightBeType(JSVAL_TYPE_INT32) && !isCall) {
if (cx->typeInferenceEnabled() && !id->isType(JSVAL_TYPE_STRING) && !isCall) {
types::TypeSet *types = analysis->poppedTypes(PC, 1);
if (types->isLazyArguments(cx) && !outerScript->analysis()->modifiesArguments()) {
// Inline arguments path.
@ -2040,6 +2081,14 @@ mjit::Compiler::jsop_getelem(bool isCall)
frame.forgetMismatchedObject(obj);
if (id->isType(JSVAL_TYPE_DOUBLE)) {
if (isCall)
jsop_callelem_slow();
else
jsop_getelem_slow();
return true;
}
GetElementICInfo ic = GetElementICInfo(JSOp(*PC));
// Pin the top of the stack to avoid spills, before allocating registers.