зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1004198. Improve codegen in testValueTruthyKernel to emit as few tests as we can get away with given our type inference information. r=jandem
This commit is contained in:
Родитель
13ecba6a77
Коммит
2be1743b63
|
@ -508,52 +508,122 @@ CodeGenerator::testValueTruthyKernel(const ValueOperand &value,
|
|||
const LDefinition *scratch1, const LDefinition *scratch2,
|
||||
FloatRegister fr,
|
||||
Label *ifTruthy, Label *ifFalsy,
|
||||
OutOfLineTestObject *ool)
|
||||
OutOfLineTestObject *ool,
|
||||
MDefinition *valueMIR)
|
||||
{
|
||||
Register tag = masm.splitTagForTest(value);
|
||||
// Count the number of possible type tags we might have, so we'll know when
|
||||
// we've checked them all and hence can avoid emitting a tag check for the
|
||||
// last one. In particular, whenever tagCount is 1 that means we've tried
|
||||
// all but one of them already so we know exactly what's left based on the
|
||||
// mightBe* booleans.
|
||||
bool mightBeUndefined = valueMIR->mightBeType(MIRType_Undefined);
|
||||
bool mightBeNull = valueMIR->mightBeType(MIRType_Null);
|
||||
bool mightBeBoolean = valueMIR->mightBeType(MIRType_Boolean);
|
||||
bool mightBeInt32 = valueMIR->mightBeType(MIRType_Int32);
|
||||
bool mightBeObject = valueMIR->mightBeType(MIRType_Object);
|
||||
bool mightBeString = valueMIR->mightBeType(MIRType_String);
|
||||
bool mightBeDouble = valueMIR->mightBeType(MIRType_Double);
|
||||
int tagCount = int(mightBeUndefined) + int(mightBeNull) +
|
||||
int(mightBeBoolean) + int(mightBeInt32) + int(mightBeObject) +
|
||||
int(mightBeString) + int(mightBeDouble);
|
||||
|
||||
// Eventually we will want some sort of type filter here. For now, just
|
||||
// emit all easy cases. For speed we use the cached tag for all comparison,
|
||||
// except for doubles, which we test last (as the operation can clobber the
|
||||
// tag, which may be in ScratchReg).
|
||||
masm.branchTestUndefined(Assembler::Equal, tag, ifFalsy);
|
||||
masm.branchTestNull(Assembler::Equal, tag, ifFalsy);
|
||||
MOZ_ASSERT_IF(!valueMIR->emptyResultTypeSet(), tagCount > 0);
|
||||
|
||||
Label notBoolean;
|
||||
masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean);
|
||||
masm.branchTestBooleanTruthy(false, value, ifFalsy);
|
||||
masm.jump(ifTruthy);
|
||||
masm.bind(¬Boolean);
|
||||
|
||||
Label notInt32;
|
||||
masm.branchTestInt32(Assembler::NotEqual, tag, ¬Int32);
|
||||
masm.branchTestInt32Truthy(false, value, ifFalsy);
|
||||
masm.jump(ifTruthy);
|
||||
masm.bind(¬Int32);
|
||||
|
||||
if (ool) {
|
||||
Label notObject;
|
||||
|
||||
masm.branchTestObject(Assembler::NotEqual, tag, ¬Object);
|
||||
|
||||
Register objreg = masm.extractObject(value, ToRegister(scratch1));
|
||||
testObjectEmulatesUndefined(objreg, ifFalsy, ifTruthy, ToRegister(scratch2), ool);
|
||||
|
||||
masm.bind(¬Object);
|
||||
} else {
|
||||
masm.branchTestObject(Assembler::Equal, tag, ifTruthy);
|
||||
// If we know we're null or undefined, we're definitely falsy, no
|
||||
// need to even check the tag.
|
||||
if (int(mightBeNull) + int(mightBeUndefined) == tagCount) {
|
||||
masm.jump(ifFalsy);
|
||||
return;
|
||||
}
|
||||
|
||||
// Test if a string is non-empty.
|
||||
Label notString;
|
||||
masm.branchTestString(Assembler::NotEqual, tag, ¬String);
|
||||
masm.branchTestStringTruthy(false, value, ifFalsy);
|
||||
masm.jump(ifTruthy);
|
||||
masm.bind(¬String);
|
||||
Register tag = masm.splitTagForTest(value);
|
||||
|
||||
// If we reach here the value is a double.
|
||||
masm.unboxDouble(value, fr);
|
||||
masm.branchTestDoubleTruthy(false, fr, ifFalsy);
|
||||
if (mightBeUndefined) {
|
||||
MOZ_ASSERT(tagCount > 1);
|
||||
masm.branchTestUndefined(Assembler::Equal, tag, ifFalsy);
|
||||
--tagCount;
|
||||
}
|
||||
|
||||
if (mightBeNull) {
|
||||
MOZ_ASSERT(tagCount > 1);
|
||||
masm.branchTestNull(Assembler::Equal, tag, ifFalsy);
|
||||
--tagCount;
|
||||
}
|
||||
|
||||
if (mightBeBoolean) {
|
||||
MOZ_ASSERT(tagCount != 0);
|
||||
Label notBoolean;
|
||||
if (tagCount != 1)
|
||||
masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean);
|
||||
masm.branchTestBooleanTruthy(false, value, ifFalsy);
|
||||
if (tagCount != 1)
|
||||
masm.jump(ifTruthy);
|
||||
// Else just fall through to truthiness.
|
||||
masm.bind(¬Boolean);
|
||||
--tagCount;
|
||||
}
|
||||
|
||||
if (mightBeInt32) {
|
||||
MOZ_ASSERT(tagCount != 0);
|
||||
Label notInt32;
|
||||
if (tagCount != 1)
|
||||
masm.branchTestInt32(Assembler::NotEqual, tag, ¬Int32);
|
||||
masm.branchTestInt32Truthy(false, value, ifFalsy);
|
||||
if (tagCount != 1)
|
||||
masm.jump(ifTruthy);
|
||||
// Else just fall through to truthiness.
|
||||
masm.bind(¬Int32);
|
||||
--tagCount;
|
||||
}
|
||||
|
||||
if (mightBeObject) {
|
||||
MOZ_ASSERT(tagCount != 0);
|
||||
if (ool) {
|
||||
Label notObject;
|
||||
|
||||
if (tagCount != 1)
|
||||
masm.branchTestObject(Assembler::NotEqual, tag, ¬Object);
|
||||
|
||||
Register objreg = masm.extractObject(value, ToRegister(scratch1));
|
||||
testObjectEmulatesUndefined(objreg, ifFalsy, ifTruthy, ToRegister(scratch2), ool);
|
||||
|
||||
masm.bind(¬Object);
|
||||
} else {
|
||||
if (tagCount != 1)
|
||||
masm.branchTestObject(Assembler::Equal, tag, ifTruthy);
|
||||
// Else just fall through to truthiness.
|
||||
}
|
||||
--tagCount;
|
||||
} else {
|
||||
MOZ_ASSERT(!ool,
|
||||
"We better not have an unused OOL path, since the code generator will try to "
|
||||
"generate code for it but we never set up its labels, which will cause null "
|
||||
"derefs of those labels.");
|
||||
}
|
||||
|
||||
if (mightBeString) {
|
||||
// Test if a string is non-empty.
|
||||
MOZ_ASSERT(tagCount != 0);
|
||||
Label notString;
|
||||
if (tagCount != 1)
|
||||
masm.branchTestString(Assembler::NotEqual, tag, ¬String);
|
||||
masm.branchTestStringTruthy(false, value, ifFalsy);
|
||||
if (tagCount != 1)
|
||||
masm.jump(ifTruthy);
|
||||
// Else just fall through to truthiness.
|
||||
masm.bind(¬String);
|
||||
--tagCount;
|
||||
}
|
||||
|
||||
if (mightBeDouble) {
|
||||
MOZ_ASSERT(tagCount == 1);
|
||||
// If we reach here the value is a double.
|
||||
masm.unboxDouble(value, fr);
|
||||
masm.branchTestDoubleTruthy(false, fr, ifFalsy);
|
||||
--tagCount;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(tagCount == 0);
|
||||
|
||||
// Fall through for truthy.
|
||||
}
|
||||
|
@ -563,9 +633,10 @@ CodeGenerator::testValueTruthy(const ValueOperand &value,
|
|||
const LDefinition *scratch1, const LDefinition *scratch2,
|
||||
FloatRegister fr,
|
||||
Label *ifTruthy, Label *ifFalsy,
|
||||
OutOfLineTestObject *ool)
|
||||
OutOfLineTestObject *ool,
|
||||
MDefinition *valueMIR)
|
||||
{
|
||||
testValueTruthyKernel(value, scratch1, scratch2, fr, ifTruthy, ifFalsy, ool);
|
||||
testValueTruthyKernel(value, scratch1, scratch2, fr, ifTruthy, ifFalsy, ool, valueMIR);
|
||||
masm.jump(ifTruthy);
|
||||
}
|
||||
|
||||
|
@ -612,7 +683,11 @@ bool
|
|||
CodeGenerator::visitTestVAndBranch(LTestVAndBranch *lir)
|
||||
{
|
||||
OutOfLineTestObject *ool = nullptr;
|
||||
if (lir->mir()->operandMightEmulateUndefined()) {
|
||||
// XXXbz operandMightEmulateUndefined lies a lot. See bug 1004169. In
|
||||
// practice, we don't need the OutOfLineTestObject if the input to our test
|
||||
// is not an object.
|
||||
MDefinition* input = lir->mir()->input();
|
||||
if (lir->mir()->operandMightEmulateUndefined() && input->mightBeType(MIRType_Object)) {
|
||||
ool = new(alloc()) OutOfLineTestObject();
|
||||
if (!addOutOfLineCode(ool))
|
||||
return false;
|
||||
|
@ -624,7 +699,7 @@ CodeGenerator::visitTestVAndBranch(LTestVAndBranch *lir)
|
|||
testValueTruthy(ToValue(lir, LTestVAndBranch::Input),
|
||||
lir->temp1(), lir->temp2(),
|
||||
ToFloatRegister(lir->tempFloat()),
|
||||
truthy, falsy, ool);
|
||||
truthy, falsy, ool, input);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5291,6 +5366,7 @@ CodeGenerator::visitNotV(LNotV *lir)
|
|||
|
||||
OutOfLineTestObjectWithLabels *ool = nullptr;
|
||||
if (lir->mir()->operandMightEmulateUndefined()) {
|
||||
MOZ_ASSERT(lir->mir()->operand()->mightBeType(MIRType_Object));
|
||||
ool = new(alloc()) OutOfLineTestObjectWithLabels();
|
||||
if (!addOutOfLineCode(ool))
|
||||
return false;
|
||||
|
@ -5305,7 +5381,7 @@ CodeGenerator::visitNotV(LNotV *lir)
|
|||
|
||||
testValueTruthyKernel(ToValue(lir, LNotV::Input), lir->temp1(), lir->temp2(),
|
||||
ToFloatRegister(lir->tempFloat()),
|
||||
ifTruthy, ifFalsy, ool);
|
||||
ifTruthy, ifFalsy, ool, lir->mir()->operand());
|
||||
|
||||
Label join;
|
||||
Register output = ToRegister(lir->output());
|
||||
|
|
|
@ -389,7 +389,8 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
const LDefinition *scratch1, const LDefinition *scratch2,
|
||||
FloatRegister fr,
|
||||
Label *ifTruthy, Label *ifFalsy,
|
||||
OutOfLineTestObject *ool);
|
||||
OutOfLineTestObject *ool,
|
||||
MDefinition *valueMIR);
|
||||
|
||||
// Test whether value is truthy or not and jump to the corresponding label.
|
||||
// If the value can be an object that emulates |undefined|, |ool| must be
|
||||
|
@ -400,7 +401,8 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
const LDefinition *scratch1, const LDefinition *scratch2,
|
||||
FloatRegister fr,
|
||||
Label *ifTruthy, Label *ifFalsy,
|
||||
OutOfLineTestObject *ool);
|
||||
OutOfLineTestObject *ool,
|
||||
MDefinition *valueMIR);
|
||||
|
||||
// This function behaves like testObjectEmulatesUndefined with the exception
|
||||
// that it can choose to let control flow fall through when the object
|
||||
|
|
Загрузка…
Ссылка в новой задаче