зеркало из https://github.com/mozilla/gecko-dev.git
Bug 900849 - Make polymorphic inlining work with non-singletons. r=djvj
This commit is contained in:
Родитель
9bcffcb8a6
Коммит
6e185bd06d
|
@ -722,9 +722,14 @@ CodeGenerator::visitFunctionDispatch(LFunctionDispatch *lir)
|
|||
// Compare function pointers, except for the last case.
|
||||
for (size_t i = 0; i < casesWithFallback - 1; i++) {
|
||||
MOZ_ASSERT(i < mir->numCases());
|
||||
JSFunction *func = mir->getCase(i);
|
||||
LBlock *target = skipTrivialBlocks(mir->getCaseBlock(i))->lir();
|
||||
masm.branchPtr(Assembler::Equal, input, ImmGCPtr(func), target->label());
|
||||
if (types::TypeObject *funcType = mir->getCaseTypeObject(i)) {
|
||||
masm.branchPtr(Assembler::Equal, Address(input, JSObject::offsetOfType()),
|
||||
ImmGCPtr(funcType), target->label());
|
||||
} else {
|
||||
JSFunction *func = mir->getCase(i);
|
||||
masm.branchPtr(Assembler::Equal, input, ImmGCPtr(func), target->label());
|
||||
}
|
||||
}
|
||||
|
||||
// Jump to the last case.
|
||||
|
|
|
@ -271,11 +271,9 @@ IonBuilder::getSingleCallTarget(types::TemporaryTypeSet *calleeTypes)
|
|||
|
||||
bool
|
||||
IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
|
||||
ObjectVector &targets, uint32_t maxTargets, bool *gotLambda)
|
||||
ObjectVector &targets, uint32_t maxTargets)
|
||||
{
|
||||
MOZ_ASSERT(targets.empty());
|
||||
MOZ_ASSERT(gotLambda);
|
||||
*gotLambda = false;
|
||||
|
||||
if (!calleeTypes)
|
||||
return true;
|
||||
|
@ -290,9 +288,11 @@ IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constr
|
|||
|
||||
if (!targets.reserve(objCount))
|
||||
return false;
|
||||
for(unsigned i = 0; i < objCount; i++) {
|
||||
for (unsigned i = 0; i < objCount; i++) {
|
||||
JSObject *obj = calleeTypes->getSingleObject(i);
|
||||
if (!obj) {
|
||||
if (obj) {
|
||||
MOZ_ASSERT(obj->hasSingletonType());
|
||||
} else {
|
||||
types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
|
||||
if (!typeObj)
|
||||
continue;
|
||||
|
@ -303,7 +303,7 @@ IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constr
|
|||
return true;
|
||||
}
|
||||
|
||||
*gotLambda = true;
|
||||
MOZ_ASSERT(!obj->hasSingletonType());
|
||||
}
|
||||
|
||||
// Don't optimize if the callee is not callable or constructable per
|
||||
|
@ -317,10 +317,6 @@ IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constr
|
|||
targets.infallibleAppend(obj);
|
||||
}
|
||||
|
||||
// For now, only inline "singleton" lambda calls
|
||||
if (*gotLambda && targets.length() > 1)
|
||||
targets.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4833,7 +4829,7 @@ IonBuilder::inlineSingleCall(CallInfo &callInfo, JSObject *targetArg)
|
|||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineCallsite(const ObjectVector &targets, ObjectVector &originals,
|
||||
bool lambda, CallInfo &callInfo)
|
||||
CallInfo &callInfo)
|
||||
{
|
||||
if (targets.empty())
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -4868,7 +4864,7 @@ IonBuilder::inlineCallsite(const ObjectVector &targets, ObjectVector &originals,
|
|||
// If the callee is not going to be a lambda (which may vary across
|
||||
// different invocations), then the callee definition can be replaced by a
|
||||
// constant.
|
||||
if (!lambda) {
|
||||
if (target->hasSingletonType()) {
|
||||
// Replace the function with an MConstant.
|
||||
MConstant *constFun = constant(ObjectValue(*target));
|
||||
callInfo.setFun(constFun);
|
||||
|
@ -5110,12 +5106,19 @@ IonBuilder::inlineCalls(CallInfo &callInfo, const ObjectVector &targets,
|
|||
if (!inlineBlock)
|
||||
return false;
|
||||
|
||||
// Create a function MConstant to use in the entry ResumePoint.
|
||||
MConstant *funcDef = MConstant::New(alloc(), ObjectValue(*target), constraints());
|
||||
// Create a function MConstant to use in the entry ResumePoint. If we
|
||||
// can't use a constant, add a no-op MPolyInlineGuard, to prevent
|
||||
// hoisting scope chain gets above the dispatch instruction.
|
||||
MInstruction *funcDef;
|
||||
if (target->hasSingletonType())
|
||||
funcDef = MConstant::New(alloc(), ObjectValue(*target), constraints());
|
||||
else
|
||||
funcDef = MPolyInlineGuard::New(alloc(), callInfo.fun());
|
||||
|
||||
funcDef->setImplicitlyUsedUnchecked();
|
||||
dispatchBlock->add(funcDef);
|
||||
|
||||
// Use the MConstant in the inline resume point and on stack.
|
||||
// Use the inlined callee in the inline resume point and on stack.
|
||||
int funIndex = inlineBlock->entryResumePoint()->stackDepth() - callInfo.numFormals();
|
||||
inlineBlock->entryResumePoint()->replaceOperand(funIndex, funcDef);
|
||||
inlineBlock->rewriteSlot(funIndex, funcDef);
|
||||
|
@ -5160,7 +5163,8 @@ IonBuilder::inlineCalls(CallInfo &callInfo, const ObjectVector &targets,
|
|||
//
|
||||
// Note that guarding is on the original function pointer even
|
||||
// if there is a clone, since cloning occurs at the callsite.
|
||||
dispatch->addCase(original, inlineBlock);
|
||||
types::TypeObject *funType = original->hasSingletonType() ? nullptr : original->type();
|
||||
dispatch->addCase(original, funType, inlineBlock);
|
||||
|
||||
MDefinition *retVal = inlineReturnBlock->peek(-1);
|
||||
retPhi->addInput(retVal);
|
||||
|
@ -5211,8 +5215,11 @@ IonBuilder::inlineCalls(CallInfo &callInfo, const ObjectVector &targets,
|
|||
MOZ_ASSERT(!remaining);
|
||||
|
||||
if (targets[i]->is<JSFunction>()) {
|
||||
remaining = &targets[i]->as<JSFunction>();
|
||||
clonedAtCallsite = targets[i] != originals[i];
|
||||
JSFunction *target = &targets[i]->as<JSFunction>();
|
||||
if (target->hasSingletonType()) {
|
||||
remaining = target;
|
||||
clonedAtCallsite = target != originals[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -5641,13 +5648,9 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
|
|||
|
||||
// Acquire known call target if existent.
|
||||
ObjectVector originals(alloc());
|
||||
bool gotLambda = false;
|
||||
types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||
if (calleeTypes) {
|
||||
if (!getPolyCallTargets(calleeTypes, constructing, originals, 4, &gotLambda))
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT_IF(gotLambda, originals.length() <= 1);
|
||||
if (calleeTypes && !getPolyCallTargets(calleeTypes, constructing, originals, 4))
|
||||
return false;
|
||||
|
||||
// If any call targets need to be cloned, look for existing clones to use.
|
||||
// Keep track of the originals as we need to case on them for poly inline.
|
||||
|
@ -5676,7 +5679,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
|
|||
return false;
|
||||
|
||||
// Try inlining
|
||||
InliningStatus status = inlineCallsite(targets, originals, gotLambda, callInfo);
|
||||
InliningStatus status = inlineCallsite(targets, originals, callInfo);
|
||||
if (status == InliningStatus_Inlined)
|
||||
return true;
|
||||
if (status == InliningStatus_Error)
|
||||
|
|
|
@ -238,7 +238,7 @@ class IonBuilder
|
|||
|
||||
JSFunction *getSingleCallTarget(types::TemporaryTypeSet *calleeTypes);
|
||||
bool getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
|
||||
ObjectVector &targets, uint32_t maxTargets, bool *gotLambda);
|
||||
ObjectVector &targets, uint32_t maxTargets);
|
||||
|
||||
void popCfgStack();
|
||||
DeferredEdge *filterDeadDeferredEdges(DeferredEdge *edge);
|
||||
|
@ -817,7 +817,7 @@ class IonBuilder
|
|||
|
||||
// Call functions
|
||||
InliningStatus inlineCallsite(const ObjectVector &targets, ObjectVector &originals,
|
||||
bool lambda, CallInfo &callInfo);
|
||||
CallInfo &callInfo);
|
||||
bool inlineCalls(CallInfo &callInfo, const ObjectVector &targets, ObjectVector &originals,
|
||||
BoolVector &choiceSet, MGetPropertyCache *maybeCache);
|
||||
|
||||
|
|
|
@ -3159,6 +3159,13 @@ LIRGenerator::visitGuardString(MGuardString *ins)
|
|||
redefine(ins, ins->input());
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitPolyInlineGuard(MPolyInlineGuard *ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->input()->type() == MIRType_Object);
|
||||
redefine(ins, ins->input());
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitGuardShapePolymorphic(MGuardShapePolymorphic *ins)
|
||||
{
|
||||
|
|
|
@ -220,6 +220,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitGuardObject(MGuardObject *ins);
|
||||
void visitGuardString(MGuardString *ins);
|
||||
void visitGuardShapePolymorphic(MGuardShapePolymorphic *ins);
|
||||
void visitPolyInlineGuard(MPolyInlineGuard *ins);
|
||||
void visitAssertRange(MAssertRange *ins);
|
||||
void visitCallGetProperty(MCallGetProperty *ins);
|
||||
void visitDeleteProperty(MDeleteProperty *ins);
|
||||
|
|
|
@ -4120,6 +4120,28 @@ class MGuardString
|
|||
}
|
||||
};
|
||||
|
||||
class MPolyInlineGuard
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
explicit MPolyInlineGuard(MDefinition *ins)
|
||||
: MUnaryInstruction(ins)
|
||||
{
|
||||
setGuard();
|
||||
setResultType(MIRType_Object);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(PolyInlineGuard)
|
||||
|
||||
static MPolyInlineGuard *New(TempAllocator &alloc, MDefinition *ins) {
|
||||
return new(alloc) MPolyInlineGuard(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const MOZ_OVERRIDE {
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
class MAssertRange
|
||||
: public MUnaryInstruction,
|
||||
public NoTypePolicy::Data
|
||||
|
@ -9384,10 +9406,14 @@ class MDispatchInstruction
|
|||
// Map from JSFunction* -> MBasicBlock.
|
||||
struct Entry {
|
||||
JSFunction *func;
|
||||
// If |func| has a singleton type, |funcType| is null. Otherwise,
|
||||
// |funcType| holds the TypeObject for |func|, and dispatch guards
|
||||
// on the type instead of directly on the function.
|
||||
types::TypeObject *funcType;
|
||||
MBasicBlock *block;
|
||||
|
||||
Entry(JSFunction *func, MBasicBlock *block)
|
||||
: func(func), block(block)
|
||||
Entry(JSFunction *func, types::TypeObject *funcType, MBasicBlock *block)
|
||||
: func(func), funcType(funcType), block(block)
|
||||
{ }
|
||||
};
|
||||
Vector<Entry, 4, JitAllocPolicy> map_;
|
||||
|
@ -9455,8 +9481,8 @@ class MDispatchInstruction
|
|||
}
|
||||
|
||||
public:
|
||||
void addCase(JSFunction *func, MBasicBlock *block) {
|
||||
map_.append(Entry(func, block));
|
||||
void addCase(JSFunction *func, types::TypeObject *funcType, MBasicBlock *block) {
|
||||
map_.append(Entry(func, funcType, block));
|
||||
}
|
||||
uint32_t numCases() const {
|
||||
return map_.length();
|
||||
|
@ -9464,6 +9490,9 @@ class MDispatchInstruction
|
|||
JSFunction *getCase(uint32_t i) const {
|
||||
return map_[i].func;
|
||||
}
|
||||
types::TypeObject *getCaseTypeObject(uint32_t i) const {
|
||||
return map_[i].funcType;
|
||||
}
|
||||
MBasicBlock *getCaseBlock(uint32_t i) const {
|
||||
return map_[i].block;
|
||||
}
|
||||
|
|
|
@ -102,6 +102,7 @@ namespace jit {
|
|||
_(Unbox) \
|
||||
_(GuardObject) \
|
||||
_(GuardString) \
|
||||
_(PolyInlineGuard) \
|
||||
_(AssertRange) \
|
||||
_(ToDouble) \
|
||||
_(ToFloat32) \
|
||||
|
|
Загрузка…
Ссылка в новой задаче