mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1131403 - Optimize uses of ObjectOrNull properties of unboxed objects better, r=jandem.
This commit is contained in:
parent
0784d3889f
commit
6a09ea4902
17
js/src/jit-test/tests/ion/bailout-with-object-or-null.js
Normal file
17
js/src/jit-test/tests/ion/bailout-with-object-or-null.js
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
function foo(p) {
|
||||
this.f = p;
|
||||
}
|
||||
function use(v, a, b) {
|
||||
var f = v.f;
|
||||
g = f;
|
||||
g = a + b;
|
||||
if (f != null)
|
||||
return;
|
||||
}
|
||||
|
||||
with({}){}
|
||||
|
||||
for (var i = 0; i < 2000; i++)
|
||||
use(new foo(i % 2 ? {} : null), 1, 2);
|
||||
use(new foo(null), 2147483548, 1000);
|
@ -2209,13 +2209,17 @@ CodeGenerator::visitStoreSlotT(LStoreSlotT *lir)
|
||||
emitPreBarrier(dest);
|
||||
|
||||
MIRType valueType = lir->mir()->value()->type();
|
||||
ConstantOrRegister value;
|
||||
if (lir->value()->isConstant())
|
||||
value = ConstantOrRegister(*lir->value()->toConstant());
|
||||
else
|
||||
value = TypedOrValueRegister(valueType, ToAnyRegister(lir->value()));
|
||||
|
||||
masm.storeUnboxedValue(value, valueType, dest, lir->mir()->slotType());
|
||||
if (valueType == MIRType_ObjectOrNull) {
|
||||
masm.storeObjectOrNull(ToRegister(lir->value()), dest);
|
||||
} else {
|
||||
ConstantOrRegister value;
|
||||
if (lir->value()->isConstant())
|
||||
value = ConstantOrRegister(*lir->value()->toConstant());
|
||||
else
|
||||
value = TypedOrValueRegister(valueType, ToAnyRegister(lir->value()));
|
||||
masm.storeUnboxedValue(value, valueType, dest, lir->mir()->slotType());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -3731,7 +3735,7 @@ CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mi
|
||||
// We have a result TypeSet, assert this object is in it.
|
||||
Label miss, ok;
|
||||
if (mir->type() == MIRType_ObjectOrNull)
|
||||
masm.branchPtr(Assembler::NotEqual, output, ImmWord(0), &ok);
|
||||
masm.branchPtr(Assembler::Equal, output, ImmWord(0), &ok);
|
||||
if (mir->resultTypeSet()->getObjectCount() > 0)
|
||||
masm.guardObjectType(output, mir->resultTypeSet(), temp, &miss);
|
||||
else
|
||||
@ -5335,14 +5339,14 @@ CodeGenerator::visitCompareVM(LCompareVM *lir)
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir)
|
||||
CodeGenerator::visitIsNullOrLikeUndefinedV(LIsNullOrLikeUndefinedV *lir)
|
||||
{
|
||||
JSOp op = lir->mir()->jsop();
|
||||
MCompare::CompareType compareType = lir->mir()->compareType();
|
||||
MOZ_ASSERT(compareType == MCompare::Compare_Undefined ||
|
||||
compareType == MCompare::Compare_Null);
|
||||
|
||||
const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefined::Value);
|
||||
const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefinedV::Value);
|
||||
Register output = ToRegister(lir->output());
|
||||
|
||||
if (op == JSOP_EQ || op == JSOP_NE) {
|
||||
@ -5409,14 +5413,14 @@ CodeGenerator::visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir)
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBranch *lir)
|
||||
CodeGenerator::visitIsNullOrLikeUndefinedAndBranchV(LIsNullOrLikeUndefinedAndBranchV *lir)
|
||||
{
|
||||
JSOp op = lir->cmpMir()->jsop();
|
||||
MCompare::CompareType compareType = lir->cmpMir()->compareType();
|
||||
MOZ_ASSERT(compareType == MCompare::Compare_Undefined ||
|
||||
compareType == MCompare::Compare_Null);
|
||||
|
||||
const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefinedAndBranch::Value);
|
||||
const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefinedAndBranchV::Value);
|
||||
|
||||
if (op == JSOP_EQ || op == JSOP_NE) {
|
||||
MBasicBlock *ifTrue;
|
||||
@ -5476,76 +5480,110 @@ CodeGenerator::visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBran
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitEmulatesUndefined(LEmulatesUndefined *lir)
|
||||
CodeGenerator::visitIsNullOrLikeUndefinedT(LIsNullOrLikeUndefinedT * lir)
|
||||
{
|
||||
MOZ_ASSERT(lir->mir()->compareType() == MCompare::Compare_Undefined ||
|
||||
lir->mir()->compareType() == MCompare::Compare_Null);
|
||||
MOZ_ASSERT(lir->mir()->lhs()->type() == MIRType_Object);
|
||||
MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(),
|
||||
"If the object couldn't emulate undefined, this should have been folded.");
|
||||
|
||||
MIRType lhsType = lir->mir()->lhs()->type();
|
||||
MOZ_ASSERT(lhsType == MIRType_Object || lhsType == MIRType_ObjectOrNull);
|
||||
|
||||
JSOp op = lir->mir()->jsop();
|
||||
MOZ_ASSERT(op == JSOP_EQ || op == JSOP_NE, "Strict equality should have been folded");
|
||||
MOZ_ASSERT(lhsType == MIRType_ObjectOrNull || op == JSOP_EQ || op == JSOP_NE,
|
||||
"Strict equality should have been folded");
|
||||
|
||||
OutOfLineTestObjectWithLabels *ool = new(alloc()) OutOfLineTestObjectWithLabels();
|
||||
addOutOfLineCode(ool, lir->mir());
|
||||
|
||||
Label *emulatesUndefined = ool->label1();
|
||||
Label *doesntEmulateUndefined = ool->label2();
|
||||
MOZ_ASSERT(lhsType == MIRType_ObjectOrNull || lir->mir()->operandMightEmulateUndefined(),
|
||||
"If the object couldn't emulate undefined, this should have been folded.");
|
||||
|
||||
Register objreg = ToRegister(lir->input());
|
||||
Register output = ToRegister(lir->output());
|
||||
branchTestObjectEmulatesUndefined(objreg, emulatesUndefined, doesntEmulateUndefined,
|
||||
output, ool);
|
||||
|
||||
Label done;
|
||||
if ((op == JSOP_EQ || op == JSOP_NE) && lir->mir()->operandMightEmulateUndefined()) {
|
||||
OutOfLineTestObjectWithLabels *ool = new(alloc()) OutOfLineTestObjectWithLabels();
|
||||
addOutOfLineCode(ool, lir->mir());
|
||||
|
||||
masm.move32(Imm32(op == JSOP_NE), output);
|
||||
masm.jump(&done);
|
||||
Label *emulatesUndefined = ool->label1();
|
||||
Label *doesntEmulateUndefined = ool->label2();
|
||||
|
||||
masm.bind(emulatesUndefined);
|
||||
masm.move32(Imm32(op == JSOP_EQ), output);
|
||||
masm.bind(&done);
|
||||
if (lhsType == MIRType_ObjectOrNull)
|
||||
masm.branchTestPtr(Assembler::Zero, objreg, objreg, emulatesUndefined);
|
||||
|
||||
branchTestObjectEmulatesUndefined(objreg, emulatesUndefined, doesntEmulateUndefined,
|
||||
output, ool);
|
||||
|
||||
Label done;
|
||||
|
||||
masm.move32(Imm32(op == JSOP_NE), output);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(emulatesUndefined);
|
||||
masm.move32(Imm32(op == JSOP_EQ), output);
|
||||
masm.bind(&done);
|
||||
} else {
|
||||
MOZ_ASSERT(lhsType == MIRType_ObjectOrNull);
|
||||
|
||||
Label isNull, done;
|
||||
|
||||
masm.branchTestPtr(Assembler::Zero, objreg, objreg, &isNull);
|
||||
|
||||
masm.move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), output);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&isNull);
|
||||
masm.move32(Imm32(op == JSOP_EQ || op == JSOP_STRICTEQ), output);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitEmulatesUndefinedAndBranch(LEmulatesUndefinedAndBranch *lir)
|
||||
CodeGenerator::visitIsNullOrLikeUndefinedAndBranchT(LIsNullOrLikeUndefinedAndBranchT *lir)
|
||||
{
|
||||
MOZ_ASSERT(lir->cmpMir()->compareType() == MCompare::Compare_Undefined ||
|
||||
lir->cmpMir()->compareType() == MCompare::Compare_Null);
|
||||
MOZ_ASSERT(lir->cmpMir()->operandMightEmulateUndefined(),
|
||||
"Operands which can't emulate undefined should have been folded");
|
||||
DebugOnly<MCompare::CompareType> compareType = lir->cmpMir()->compareType();
|
||||
MOZ_ASSERT(compareType == MCompare::Compare_Undefined ||
|
||||
compareType == MCompare::Compare_Null);
|
||||
|
||||
MIRType lhsType = lir->cmpMir()->lhs()->type();
|
||||
MOZ_ASSERT(lhsType == MIRType_Object || lhsType == MIRType_ObjectOrNull);
|
||||
|
||||
JSOp op = lir->cmpMir()->jsop();
|
||||
MOZ_ASSERT(op == JSOP_EQ || op == JSOP_NE, "Strict equality should have been folded");
|
||||
MOZ_ASSERT(lhsType == MIRType_ObjectOrNull || op == JSOP_EQ || op == JSOP_NE,
|
||||
"Strict equality should have been folded");
|
||||
|
||||
OutOfLineTestObject *ool = new(alloc()) OutOfLineTestObject();
|
||||
addOutOfLineCode(ool, lir->cmpMir());
|
||||
MOZ_ASSERT(lhsType == MIRType_ObjectOrNull || lir->cmpMir()->operandMightEmulateUndefined(),
|
||||
"If the object couldn't emulate undefined, this should have been folded.");
|
||||
|
||||
Label *equal;
|
||||
Label *unequal;
|
||||
MBasicBlock *ifTrue;
|
||||
MBasicBlock *ifFalse;
|
||||
|
||||
{
|
||||
MBasicBlock *ifTrue;
|
||||
MBasicBlock *ifFalse;
|
||||
|
||||
if (op == JSOP_EQ) {
|
||||
ifTrue = lir->ifTrue();
|
||||
ifFalse = lir->ifFalse();
|
||||
} else {
|
||||
// Swap branches.
|
||||
ifTrue = lir->ifFalse();
|
||||
ifFalse = lir->ifTrue();
|
||||
op = JSOP_EQ;
|
||||
}
|
||||
|
||||
equal = getJumpLabelForBranch(ifTrue);
|
||||
unequal = getJumpLabelForBranch(ifFalse);
|
||||
if (op == JSOP_EQ || op == JSOP_STRICTEQ) {
|
||||
ifTrue = lir->ifTrue();
|
||||
ifFalse = lir->ifFalse();
|
||||
} else {
|
||||
// Swap branches.
|
||||
ifTrue = lir->ifFalse();
|
||||
ifFalse = lir->ifTrue();
|
||||
}
|
||||
|
||||
Register objreg = ToRegister(lir->input());
|
||||
Register input = ToRegister(lir->getOperand(0));
|
||||
|
||||
testObjectEmulatesUndefined(objreg, equal, unequal, ToRegister(lir->temp()), ool);
|
||||
if ((op == JSOP_EQ || op == JSOP_NE) && lir->cmpMir()->operandMightEmulateUndefined()) {
|
||||
OutOfLineTestObject *ool = new(alloc()) OutOfLineTestObject();
|
||||
addOutOfLineCode(ool, lir->cmpMir());
|
||||
|
||||
Label *ifTrueLabel = getJumpLabelForBranch(ifTrue);
|
||||
Label *ifFalseLabel = getJumpLabelForBranch(ifFalse);
|
||||
|
||||
if (lhsType == MIRType_ObjectOrNull)
|
||||
masm.branchTestPtr(Assembler::Zero, input, input, ifTrueLabel);
|
||||
|
||||
// Objects that emulate undefined are loosely equal to null/undefined.
|
||||
Register scratch = ToRegister(lir->temp());
|
||||
testObjectEmulatesUndefined(input, ifTrueLabel, ifFalseLabel, scratch, ool);
|
||||
} else {
|
||||
MOZ_ASSERT(lhsType == MIRType_ObjectOrNull);
|
||||
testZeroEmitBranch(Assembler::Equal, input, ifTrue, ifFalse);
|
||||
}
|
||||
}
|
||||
|
||||
typedef JSString *(*ConcatStringsFn)(ExclusiveContext *, HandleString, HandleString);
|
||||
@ -7705,15 +7743,19 @@ CodeGenerator::visitStoreFixedSlotT(LStoreFixedSlotT *ins)
|
||||
const LAllocation *value = ins->value();
|
||||
MIRType valueType = ins->mir()->value()->type();
|
||||
|
||||
ConstantOrRegister nvalue = value->isConstant()
|
||||
? ConstantOrRegister(*value->toConstant())
|
||||
: TypedOrValueRegister(valueType, ToAnyRegister(value));
|
||||
|
||||
Address address(obj, NativeObject::getFixedSlotOffset(slot));
|
||||
if (ins->mir()->needsBarrier())
|
||||
emitPreBarrier(address);
|
||||
|
||||
masm.storeConstantOrRegister(nvalue, address);
|
||||
if (valueType == MIRType_ObjectOrNull) {
|
||||
Register nvalue = ToRegister(value);
|
||||
masm.storeObjectOrNull(nvalue, address);
|
||||
} else {
|
||||
ConstantOrRegister nvalue = value->isConstant()
|
||||
? ConstantOrRegister(*value->toConstant())
|
||||
: TypedOrValueRegister(valueType, ToAnyRegister(value));
|
||||
masm.storeConstantOrRegister(nvalue, address);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -8471,8 +8513,8 @@ CodeGenerator::visitLoadUnboxedPointerT(LLoadUnboxedPointerT *lir)
|
||||
bool bailOnNull;
|
||||
int32_t offsetAdjustment;
|
||||
if (lir->mir()->isLoadUnboxedObjectOrNull()) {
|
||||
bailOnNull = lir->mir()->toLoadUnboxedObjectOrNull()->nullBehavior() !=
|
||||
MLoadUnboxedObjectOrNull::NullNotPossible;
|
||||
bailOnNull = lir->mir()->toLoadUnboxedObjectOrNull()->nullBehavior() ==
|
||||
MLoadUnboxedObjectOrNull::BailOnNull;
|
||||
offsetAdjustment = lir->mir()->toLoadUnboxedObjectOrNull()->offsetAdjustment();
|
||||
} else if (lir->mir()->isLoadUnboxedString()) {
|
||||
bailOnNull = false;
|
||||
@ -8496,6 +8538,18 @@ CodeGenerator::visitLoadUnboxedPointerT(LLoadUnboxedPointerT *lir)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitUnboxObjectOrNull(LUnboxObjectOrNull *lir)
|
||||
{
|
||||
Register obj = ToRegister(lir->input());
|
||||
|
||||
if (lir->mir()->fallible()) {
|
||||
Label bail;
|
||||
masm.branchTestPtr(Assembler::Zero, obj, obj, &bail);
|
||||
bailoutFrom(&bail, lir->snapshot());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitLoadTypedArrayElement(LLoadTypedArrayElement *lir)
|
||||
{
|
||||
|
@ -221,10 +221,10 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void visitCompareS(LCompareS *lir);
|
||||
void visitCompareStrictS(LCompareStrictS *lir);
|
||||
void visitCompareVM(LCompareVM *lir);
|
||||
void visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir);
|
||||
void visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBranch *lir);
|
||||
void visitEmulatesUndefined(LEmulatesUndefined *lir);
|
||||
void visitEmulatesUndefinedAndBranch(LEmulatesUndefinedAndBranch *lir);
|
||||
void visitIsNullOrLikeUndefinedV(LIsNullOrLikeUndefinedV *lir);
|
||||
void visitIsNullOrLikeUndefinedT(LIsNullOrLikeUndefinedT *lir);
|
||||
void visitIsNullOrLikeUndefinedAndBranchV(LIsNullOrLikeUndefinedAndBranchV *lir);
|
||||
void visitIsNullOrLikeUndefinedAndBranchT(LIsNullOrLikeUndefinedAndBranchT *lir);
|
||||
void emitConcat(LInstruction *lir, Register lhs, Register rhs, Register output);
|
||||
void visitConcat(LConcat *lir);
|
||||
void visitCharCodeAt(LCharCodeAt *lir);
|
||||
@ -245,6 +245,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void visitLoadElementHole(LLoadElementHole *lir);
|
||||
void visitLoadUnboxedPointerV(LLoadUnboxedPointerV *lir);
|
||||
void visitLoadUnboxedPointerT(LLoadUnboxedPointerT *lir);
|
||||
void visitUnboxObjectOrNull(LUnboxObjectOrNull *lir);
|
||||
void visitStoreElementT(LStoreElementT *lir);
|
||||
void visitStoreElementV(LStoreElementV *lir);
|
||||
void visitStoreElementHoleT(LStoreElementHoleT *lir);
|
||||
|
@ -2518,6 +2518,51 @@ TryEliminateTypeBarrier(MTypeBarrier *barrier, bool *eliminated)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TryOptimizeLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull *def, MDefinitionVector *peliminateList)
|
||||
{
|
||||
if (def->type() != MIRType_Value)
|
||||
return true;
|
||||
|
||||
MDefinitionVector eliminateList(def->block()->graph().alloc());
|
||||
|
||||
for (MUseDefIterator iter(def); iter; ++iter) {
|
||||
MDefinition *ndef = iter.def();
|
||||
switch (ndef->op()) {
|
||||
case MDefinition::Op_Compare:
|
||||
if (ndef->toCompare()->compareType() != MCompare::Compare_Null)
|
||||
return true;
|
||||
break;
|
||||
case MDefinition::Op_PostWriteBarrier:
|
||||
break;
|
||||
case MDefinition::Op_StoreFixedSlot:
|
||||
break;
|
||||
case MDefinition::Op_StoreSlot:
|
||||
break;
|
||||
case MDefinition::Op_ToObjectOrNull:
|
||||
if (!eliminateList.append(ndef->toToObjectOrNull()))
|
||||
return false;
|
||||
break;
|
||||
case MDefinition::Op_Unbox:
|
||||
MOZ_ASSERT(ndef->type() == MIRType_Object);
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
def->setResultType(MIRType_ObjectOrNull);
|
||||
|
||||
for (size_t i = 0; i < eliminateList.length(); i++) {
|
||||
MDefinition *ndef = eliminateList[i];
|
||||
ndef->replaceAllUsesWith(def);
|
||||
if (!peliminateList->append(ndef))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline MDefinition *
|
||||
PassthroughOperand(MDefinition *def)
|
||||
{
|
||||
@ -2565,6 +2610,8 @@ jit::EliminateRedundantChecks(MIRGraph &graph)
|
||||
}
|
||||
}
|
||||
|
||||
MDefinitionVector eliminateList(graph.alloc());
|
||||
|
||||
// Starting from each self-dominating block, traverse the CFG in pre-order.
|
||||
while (!worklist.empty()) {
|
||||
MBasicBlock *block = worklist.popCopy();
|
||||
@ -2586,6 +2633,9 @@ jit::EliminateRedundantChecks(MIRGraph &graph)
|
||||
} else if (def->isTypeBarrier()) {
|
||||
if (!TryEliminateTypeBarrier(def->toTypeBarrier(), &eliminated))
|
||||
return false;
|
||||
} else if (def->isLoadUnboxedObjectOrNull()) {
|
||||
if (!TryOptimizeLoadUnboxedObjectOrNull(def->toLoadUnboxedObjectOrNull(), &eliminateList))
|
||||
return false;
|
||||
} else {
|
||||
// Now that code motion passes have finished, replace
|
||||
// instructions which pass through one of their operands
|
||||
@ -2601,6 +2651,12 @@ jit::EliminateRedundantChecks(MIRGraph &graph)
|
||||
}
|
||||
|
||||
MOZ_ASSERT(index == graph.numBlocks());
|
||||
|
||||
for (size_t i = 0; i < eliminateList.length(); i++) {
|
||||
MDefinition *def = eliminateList[i];
|
||||
def->block()->discardDef(def);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1728,7 +1728,9 @@ SnapshotIterator::fromStack(int32_t offset) const
|
||||
static Value
|
||||
FromObjectPayload(uintptr_t payload)
|
||||
{
|
||||
return ObjectValue(*reinterpret_cast<JSObject *>(payload));
|
||||
// Note: Both MIRType_Object and MIRType_ObjectOrNull are encoded in
|
||||
// snapshots using JSVAL_TYPE_OBJECT.
|
||||
return ObjectOrNullValue(reinterpret_cast<JSObject *>(payload));
|
||||
}
|
||||
|
||||
static Value
|
||||
|
@ -2498,12 +2498,15 @@ class LBitAndAndBranch : public LControlInstructionHelper<2, 2, 0>
|
||||
}
|
||||
};
|
||||
|
||||
class LIsNullOrLikeUndefined : public LInstructionHelper<1, BOX_PIECES, 2>
|
||||
// Takes a value and tests whether it is null, undefined, or is an object that
|
||||
// emulates |undefined|, as determined by the JSCLASS_EMULATES_UNDEFINED class
|
||||
// flag on unwrapped objects. See also js::EmulatesUndefined.
|
||||
class LIsNullOrLikeUndefinedV : public LInstructionHelper<1, BOX_PIECES, 2>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(IsNullOrLikeUndefined)
|
||||
LIR_HEADER(IsNullOrLikeUndefinedV)
|
||||
|
||||
LIsNullOrLikeUndefined(const LDefinition &temp, const LDefinition &tempToUnbox)
|
||||
LIsNullOrLikeUndefinedV(const LDefinition &temp, const LDefinition &tempToUnbox)
|
||||
{
|
||||
setTemp(0, temp);
|
||||
setTemp(1, tempToUnbox);
|
||||
@ -2524,15 +2527,32 @@ class LIsNullOrLikeUndefined : public LInstructionHelper<1, BOX_PIECES, 2>
|
||||
}
|
||||
};
|
||||
|
||||
class LIsNullOrLikeUndefinedAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 2>
|
||||
// Takes an object or object-or-null pointer and tests whether it is null or is
|
||||
// an object that emulates |undefined|, as above.
|
||||
class LIsNullOrLikeUndefinedT : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(IsNullOrLikeUndefinedT)
|
||||
|
||||
explicit LIsNullOrLikeUndefinedT(const LAllocation &input)
|
||||
{
|
||||
setOperand(0, input);
|
||||
}
|
||||
|
||||
MCompare *mir() {
|
||||
return mir_->toCompare();
|
||||
}
|
||||
};
|
||||
|
||||
class LIsNullOrLikeUndefinedAndBranchV : public LControlInstructionHelper<2, BOX_PIECES, 2>
|
||||
{
|
||||
MCompare *cmpMir_;
|
||||
|
||||
public:
|
||||
LIR_HEADER(IsNullOrLikeUndefinedAndBranch)
|
||||
LIR_HEADER(IsNullOrLikeUndefinedAndBranchV)
|
||||
|
||||
LIsNullOrLikeUndefinedAndBranch(MCompare *cmpMir, MBasicBlock *ifTrue, MBasicBlock *ifFalse,
|
||||
const LDefinition &temp, const LDefinition &tempToUnbox)
|
||||
LIsNullOrLikeUndefinedAndBranchV(MCompare *cmpMir, MBasicBlock *ifTrue, MBasicBlock *ifFalse,
|
||||
const LDefinition &temp, const LDefinition &tempToUnbox)
|
||||
: cmpMir_(cmpMir)
|
||||
{
|
||||
setSuccessor(0, ifTrue);
|
||||
@ -2563,34 +2583,16 @@ class LIsNullOrLikeUndefinedAndBranch : public LControlInstructionHelper<2, BOX_
|
||||
}
|
||||
};
|
||||
|
||||
// Takes an object and tests whether it emulates |undefined|, as determined by
|
||||
// the JSCLASS_EMULATES_UNDEFINED class flag on unwrapped objects. See also
|
||||
// js::EmulatesUndefined.
|
||||
class LEmulatesUndefined : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(EmulatesUndefined)
|
||||
|
||||
explicit LEmulatesUndefined(const LAllocation &input)
|
||||
{
|
||||
setOperand(0, input);
|
||||
}
|
||||
|
||||
MCompare *mir() {
|
||||
return mir_->toCompare();
|
||||
}
|
||||
};
|
||||
|
||||
class LEmulatesUndefinedAndBranch : public LControlInstructionHelper<2, 1, 1>
|
||||
class LIsNullOrLikeUndefinedAndBranchT : public LControlInstructionHelper<2, 1, 1>
|
||||
{
|
||||
MCompare *cmpMir_;
|
||||
|
||||
public:
|
||||
LIR_HEADER(EmulatesUndefinedAndBranch)
|
||||
LIR_HEADER(IsNullOrLikeUndefinedAndBranchT)
|
||||
|
||||
LEmulatesUndefinedAndBranch(MCompare *cmpMir, const LAllocation &input,
|
||||
MBasicBlock *ifTrue, MBasicBlock *ifFalse,
|
||||
const LDefinition &temp)
|
||||
LIsNullOrLikeUndefinedAndBranchT(MCompare *cmpMir, const LAllocation &input,
|
||||
MBasicBlock *ifTrue, MBasicBlock *ifFalse,
|
||||
const LDefinition &temp)
|
||||
: cmpMir_(cmpMir)
|
||||
{
|
||||
setOperand(0, input);
|
||||
@ -4484,6 +4486,24 @@ class LLoadUnboxedPointerT : public LInstructionHelper<1, 2, 0>
|
||||
}
|
||||
};
|
||||
|
||||
class LUnboxObjectOrNull : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(UnboxObjectOrNull);
|
||||
|
||||
explicit LUnboxObjectOrNull(const LAllocation &input)
|
||||
{
|
||||
setOperand(0, input);
|
||||
}
|
||||
|
||||
MUnbox *mir() const {
|
||||
return mir_->toUnbox();
|
||||
}
|
||||
const LAllocation *input() {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Store a boxed value to a dense array's element vector.
|
||||
class LStoreElementV : public LInstructionHelper<0, 2 + BOX_PIECES, 0>
|
||||
{
|
||||
|
@ -118,10 +118,10 @@
|
||||
_(CompareVAndBranch) \
|
||||
_(CompareVM) \
|
||||
_(BitAndAndBranch) \
|
||||
_(IsNullOrLikeUndefined) \
|
||||
_(IsNullOrLikeUndefinedAndBranch)\
|
||||
_(EmulatesUndefined) \
|
||||
_(EmulatesUndefinedAndBranch) \
|
||||
_(IsNullOrLikeUndefinedV) \
|
||||
_(IsNullOrLikeUndefinedT) \
|
||||
_(IsNullOrLikeUndefinedAndBranchV)\
|
||||
_(IsNullOrLikeUndefinedAndBranchT)\
|
||||
_(MinMaxI) \
|
||||
_(MinMaxD) \
|
||||
_(MinMaxF) \
|
||||
@ -219,6 +219,7 @@
|
||||
_(LoadElementHole) \
|
||||
_(LoadUnboxedPointerV) \
|
||||
_(LoadUnboxedPointerT) \
|
||||
_(UnboxObjectOrNull) \
|
||||
_(StoreElementV) \
|
||||
_(StoreElementT) \
|
||||
_(StoreUnboxedPointer) \
|
||||
|
@ -703,13 +703,16 @@ LIRGenerator::visitTest(MTest *test)
|
||||
if (comp->compareType() == MCompare::Compare_Null ||
|
||||
comp->compareType() == MCompare::Compare_Undefined)
|
||||
{
|
||||
if (left->type() == MIRType_Object) {
|
||||
MOZ_ASSERT(comp->operandMightEmulateUndefined(),
|
||||
if (left->type() == MIRType_Object || left->type() == MIRType_ObjectOrNull) {
|
||||
MOZ_ASSERT(left->type() == MIRType_ObjectOrNull ||
|
||||
comp->operandMightEmulateUndefined(),
|
||||
"MCompare::tryFold should handle the never-emulates-undefined case");
|
||||
|
||||
LEmulatesUndefinedAndBranch *lir =
|
||||
new(alloc()) LEmulatesUndefinedAndBranch(comp, useRegister(left),
|
||||
ifTrue, ifFalse, temp());
|
||||
LDefinition tmp =
|
||||
comp->operandMightEmulateUndefined() ? temp() : LDefinition::BogusTemp();
|
||||
LIsNullOrLikeUndefinedAndBranchT *lir =
|
||||
new(alloc()) LIsNullOrLikeUndefinedAndBranchT(comp, useRegister(left),
|
||||
ifTrue, ifFalse, tmp);
|
||||
add(lir, test);
|
||||
return;
|
||||
}
|
||||
@ -723,10 +726,10 @@ LIRGenerator::visitTest(MTest *test)
|
||||
tmpToUnbox = LDefinition::BogusTemp();
|
||||
}
|
||||
|
||||
LIsNullOrLikeUndefinedAndBranch *lir =
|
||||
new(alloc()) LIsNullOrLikeUndefinedAndBranch(comp, ifTrue, ifFalse,
|
||||
tmp, tmpToUnbox);
|
||||
useBox(lir, LIsNullOrLikeUndefinedAndBranch::Value, left);
|
||||
LIsNullOrLikeUndefinedAndBranchV *lir =
|
||||
new(alloc()) LIsNullOrLikeUndefinedAndBranchV(comp, ifTrue, ifFalse,
|
||||
tmp, tmpToUnbox);
|
||||
useBox(lir, LIsNullOrLikeUndefinedAndBranchV::Value, left);
|
||||
add(lir, test);
|
||||
return;
|
||||
}
|
||||
@ -939,11 +942,12 @@ LIRGenerator::visitCompare(MCompare *comp)
|
||||
if (comp->compareType() == MCompare::Compare_Null ||
|
||||
comp->compareType() == MCompare::Compare_Undefined)
|
||||
{
|
||||
if (left->type() == MIRType_Object) {
|
||||
MOZ_ASSERT(comp->operandMightEmulateUndefined(),
|
||||
if (left->type() == MIRType_Object || left->type() == MIRType_ObjectOrNull) {
|
||||
MOZ_ASSERT(left->type() == MIRType_ObjectOrNull ||
|
||||
comp->operandMightEmulateUndefined(),
|
||||
"MCompare::tryFold should have folded this away");
|
||||
|
||||
define(new(alloc()) LEmulatesUndefined(useRegister(left)), comp);
|
||||
define(new(alloc()) LIsNullOrLikeUndefinedT(useRegister(left)), comp);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -956,8 +960,8 @@ LIRGenerator::visitCompare(MCompare *comp)
|
||||
tmpToUnbox = LDefinition::BogusTemp();
|
||||
}
|
||||
|
||||
LIsNullOrLikeUndefined *lir = new(alloc()) LIsNullOrLikeUndefined(tmp, tmpToUnbox);
|
||||
useBox(lir, LIsNullOrLikeUndefined::Value, left);
|
||||
LIsNullOrLikeUndefinedV *lir = new(alloc()) LIsNullOrLikeUndefinedV(tmp, tmpToUnbox);
|
||||
useBox(lir, LIsNullOrLikeUndefinedV::Value, left);
|
||||
define(lir, comp);
|
||||
return;
|
||||
}
|
||||
@ -2627,7 +2631,7 @@ LIRGenerator::visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull *ins)
|
||||
MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
|
||||
MOZ_ASSERT(ins->index()->type() == MIRType_Int32);
|
||||
|
||||
if (ins->type() == MIRType_Object) {
|
||||
if (ins->type() == MIRType_Object || ins->type() == MIRType_ObjectOrNull) {
|
||||
LLoadUnboxedPointerT *lir = new(alloc()) LLoadUnboxedPointerT(useRegister(ins->elements()),
|
||||
useRegisterOrConstant(ins->index()));
|
||||
if (ins->nullBehavior() == MLoadUnboxedObjectOrNull::BailOnNull)
|
||||
|
@ -616,14 +616,18 @@ class MDefinition : public MNode
|
||||
|
||||
bool mightBeType(MIRType type) const {
|
||||
MOZ_ASSERT(type != MIRType_Value);
|
||||
MOZ_ASSERT(type != MIRType_ObjectOrNull);
|
||||
|
||||
if (type == this->type())
|
||||
return true;
|
||||
|
||||
if (MIRType_Value != this->type())
|
||||
return false;
|
||||
if (this->type() == MIRType_ObjectOrNull)
|
||||
return type == MIRType_Object || type == MIRType_Null;
|
||||
|
||||
return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type);
|
||||
if (this->type() == MIRType_Value)
|
||||
return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mightBeMagicType() const;
|
||||
|
@ -424,6 +424,17 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void storeObjectOrNull(Register src, const T &dest) {
|
||||
Label notNull, done;
|
||||
branchTestPtr(Assembler::NonZero, src, src, ¬Null);
|
||||
storeValue(NullValue(), dest);
|
||||
jump(&done);
|
||||
bind(¬Null);
|
||||
storeValue(JSVAL_TYPE_OBJECT, src, dest);
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void storeConstantOrRegister(ConstantOrRegister src, const T &dest) {
|
||||
if (src.constant())
|
||||
|
@ -102,6 +102,13 @@ class CodeGeneratorARM : public CodeGeneratorShared
|
||||
cond = masm.testObject(cond, value);
|
||||
emitBranch(cond, ifTrue, ifFalse);
|
||||
}
|
||||
void testZeroEmitBranch(Assembler::Condition cond, Register reg,
|
||||
MBasicBlock *ifTrue, MBasicBlock *ifFalse)
|
||||
{
|
||||
MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
|
||||
masm.cmpPtr(reg, ImmWord(0));
|
||||
emitBranch(cond, ifTrue, ifFalse);
|
||||
}
|
||||
|
||||
void emitTableSwitchDispatch(MTableSwitch *mir, Register index, Register base);
|
||||
|
||||
|
@ -125,10 +125,19 @@ LIRGeneratorARM::visitBox(MBox *box)
|
||||
void
|
||||
LIRGeneratorARM::visitUnbox(MUnbox *unbox)
|
||||
{
|
||||
// An unbox on arm reads in a type tag (either in memory or a register) and
|
||||
// a payload. Unlike most instructions conusming a box, we ask for the type
|
||||
// second, so that the result can re-use the first input.
|
||||
MDefinition *inner = unbox->getOperand(0);
|
||||
|
||||
if (inner->type() == MIRType_ObjectOrNull) {
|
||||
LUnboxObjectOrNull *lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner));
|
||||
if (unbox->fallible())
|
||||
assignSnapshot(lir, unbox->bailoutKind());
|
||||
defineReuseInput(lir, unbox, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// An unbox on arm reads in a type tag (either in memory or a register) and
|
||||
// a payload. Unlike most instructions consuming a box, we ask for the type
|
||||
// second, so that the result can re-use the first input.
|
||||
MOZ_ASSERT(inner->type() == MIRType_Value);
|
||||
|
||||
ensureDefined(inner);
|
||||
|
@ -160,6 +160,11 @@ class CodeGeneratorMIPS : public CodeGeneratorShared
|
||||
{
|
||||
emitBranch(value.typeReg(), (Imm32)ImmType(JSVAL_TYPE_OBJECT), cond, ifTrue, ifFalse);
|
||||
}
|
||||
void testZeroEmitBranch(Assembler::Condition cond, Register reg,
|
||||
MBasicBlock *ifTrue, MBasicBlock *ifFalse)
|
||||
{
|
||||
emitBranch(reg, Imm32(0), cond, ifTrue, ifFalse);
|
||||
}
|
||||
|
||||
void emitTableSwitchDispatch(MTableSwitch *mir, Register index, Register base);
|
||||
|
||||
|
@ -127,10 +127,19 @@ LIRGeneratorMIPS::visitBox(MBox *box)
|
||||
void
|
||||
LIRGeneratorMIPS::visitUnbox(MUnbox *unbox)
|
||||
{
|
||||
MDefinition *inner = unbox->getOperand(0);
|
||||
|
||||
if (inner->type() == MIRType_ObjectOrNull) {
|
||||
LUnboxObjectOrNull *lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner));
|
||||
if (unbox->fallible())
|
||||
assignSnapshot(lir, unbox->bailoutKind());
|
||||
defineReuseInput(lir, unbox, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// An unbox on mips reads in a type tag (either in memory or a register) and
|
||||
// a payload. Unlike most instructions consuming a box, we ask for the type
|
||||
// second, so that the result can re-use the first input.
|
||||
MDefinition *inner = unbox->getOperand(0);
|
||||
MOZ_ASSERT(inner->type() == MIRType_Value);
|
||||
|
||||
ensureDefined(inner);
|
||||
|
@ -48,6 +48,9 @@ class CodeGeneratorNone : public CodeGeneratorShared
|
||||
void testObjectEmitBranch(Assembler::Condition, ValueOperand, MBasicBlock *, MBasicBlock *) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
void testZeroEmitBranch(Assembler::Condition, Register, MBasicBlock *, MBasicBlock *) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
void emitTableSwitchDispatch(MTableSwitch *, Register, Register) { MOZ_CRASH(); }
|
||||
ValueOperand ToValue(LInstruction *, size_t) { MOZ_CRASH(); }
|
||||
ValueOperand ToOutValue(LInstruction *) { MOZ_CRASH(); }
|
||||
|
@ -378,12 +378,14 @@ CodeGeneratorShared::encodeAllocation(LSnapshot *snapshot, MDefinition *mir,
|
||||
case MIRType_String:
|
||||
case MIRType_Symbol:
|
||||
case MIRType_Object:
|
||||
case MIRType_ObjectOrNull:
|
||||
case MIRType_Boolean:
|
||||
case MIRType_Double:
|
||||
case MIRType_Float32:
|
||||
{
|
||||
LAllocation *payload = snapshot->payloadOfSlot(*allocIndex);
|
||||
JSValueType valueType = ValueTypeFromMIRType(type);
|
||||
JSValueType valueType =
|
||||
(type == MIRType_ObjectOrNull) ? JSVAL_TYPE_OBJECT : ValueTypeFromMIRType(type);
|
||||
if (payload->isMemory()) {
|
||||
if (type == MIRType_Float32)
|
||||
alloc = RValueAllocation::Float32(ToStackIndex(payload));
|
||||
|
@ -147,6 +147,14 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
|
||||
emitBranch(cond, ifTrue, ifFalse);
|
||||
}
|
||||
|
||||
void testZeroEmitBranch(Assembler::Condition cond, Register reg,
|
||||
MBasicBlock *ifTrue, MBasicBlock *ifFalse)
|
||||
{
|
||||
MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
|
||||
masm.cmpPtr(reg, ImmWord(0));
|
||||
emitBranch(cond, ifTrue, ifFalse);
|
||||
}
|
||||
|
||||
void emitTableSwitchDispatch(MTableSwitch *mir, Register index, Register base);
|
||||
|
||||
public:
|
||||
|
@ -80,6 +80,15 @@ void
|
||||
LIRGeneratorX64::visitUnbox(MUnbox *unbox)
|
||||
{
|
||||
MDefinition *box = unbox->getOperand(0);
|
||||
|
||||
if (box->type() == MIRType_ObjectOrNull) {
|
||||
LUnboxObjectOrNull *lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(box));
|
||||
if (unbox->fallible())
|
||||
assignSnapshot(lir, unbox->bailoutKind());
|
||||
defineReuseInput(lir, unbox, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(box->type() == MIRType_Value);
|
||||
|
||||
LUnboxBase *lir;
|
||||
|
@ -98,10 +98,19 @@ LIRGeneratorX86::visitBox(MBox *box)
|
||||
void
|
||||
LIRGeneratorX86::visitUnbox(MUnbox *unbox)
|
||||
{
|
||||
// An unbox on x86 reads in a type tag (either in memory or a register) and
|
||||
// a payload. Unlike most instructions conusming a box, we ask for the type
|
||||
// second, so that the result can re-use the first input.
|
||||
MDefinition *inner = unbox->getOperand(0);
|
||||
|
||||
if (inner->type() == MIRType_ObjectOrNull) {
|
||||
LUnboxObjectOrNull *lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner));
|
||||
if (unbox->fallible())
|
||||
assignSnapshot(lir, unbox->bailoutKind());
|
||||
defineReuseInput(lir, unbox, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// An unbox on x86 reads in a type tag (either in memory or a register) and
|
||||
// a payload. Unlike most instructions consuming a box, we ask for the type
|
||||
// second, so that the result can re-use the first input.
|
||||
MOZ_ASSERT(inner->type() == MIRType_Value);
|
||||
|
||||
ensureDefined(inner);
|
||||
|
Loading…
Reference in New Issue
Block a user