author | Jan de Mooij <jdemooij@mozilla.com> |
Thu, 05 Mar 2015 15:47:13 +0100 | |
changeset 232054 | 57ddae8223f9dc29dd6f2611c477f7221d3930dd |
parent 232053 | 6e51757fe12e33791a58a2330e22bc16869a013d |
child 232055 | 3e386e0dbdadad0fb0e14453e4b3f6db55fcc621 |
push id | 28368 |
push user | kwierso@gmail.com |
push date | Thu, 05 Mar 2015 23:18:02 +0000 |
treeherder | mozilla-central@1fe0dd36816b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bhackett |
bugs | 1059364 |
milestone | 39.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -749,22 +749,20 @@ CodeGenerator::visitFunctionDispatch(LFu void CodeGenerator::visitObjectGroupDispatch(LObjectGroupDispatch *lir) { MObjectGroupDispatch *mir = lir->mir(); Register input = ToRegister(lir->input()); Register temp = ToRegister(lir->temp()); - // Hold the incoming ObjectGroup. - + // Load the incoming ObjectGroup in temp. masm.loadPtr(Address(input, JSObject::offsetOfGroup()), temp); // Compare ObjectGroups. - MacroAssembler::BranchGCPtr lastBranch; LBlock *lastBlock = nullptr; InlinePropertyTable *propTable = mir->propTable(); for (size_t i = 0; i < mir->numCases(); i++) { JSFunction *func = mir->getCase(i); LBlock *target = skipTrivialBlocks(mir->getCaseBlock(i))->lir(); DebugOnly<bool> found = false; @@ -779,17 +777,32 @@ CodeGenerator::visitObjectGroupDispatch( lastBranch = MacroAssembler::BranchGCPtr(Assembler::Equal, temp, ImmGCPtr(group), target->label()); lastBlock = target; found = true; } MOZ_ASSERT(found); } - // Unknown function: jump to fallback block. + // Jump to fallback block if we have an unknown ObjectGroup. If there's no + // fallback block, we should have handled all cases. + + if (!mir->hasFallback()) { + MOZ_ASSERT(lastBranch.isInitialized()); +#ifdef DEBUG + Label ok; + lastBranch.relink(&ok); + lastBranch.emit(masm); + masm.assumeUnreachable("Unexpected ObjectGroup"); + masm.bind(&ok); +#endif + if (!isNextBlock(lastBlock)) + masm.jump(lastBlock->label()); + return; + } LBlock *fallback = skipTrivialBlocks(mir->getFallback())->lir(); if (!lastBranch.isInitialized()) { if (!isNextBlock(fallback)) masm.jump(fallback->label()); return; } @@ -2671,19 +2684,17 @@ void CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO *lir) { OutOfLineCallPostWriteBarrier *ool = new(alloc()) OutOfLineCallPostWriteBarrier(lir, lir->object()); addOutOfLineCode(ool, lir->mir()); Register temp = ToTempRegisterOrInvalid(lir->temp()); if (lir->object()->isConstant()) { -#ifdef DEBUG MOZ_ASSERT(!IsInsideNursery(&lir->object()->toConstant()->toObject())); -#endif } else { masm.branchPtrInNurseryRange(Assembler::Equal, ToRegister(lir->object()), temp, ool->rejoin()); } masm.branchPtrInNurseryRange(Assembler::Equal, ToRegister(lir->value()), temp, ool->entry()); masm.bind(ool->rejoin());
--- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -5349,22 +5349,16 @@ IonBuilder::inlineCalls(CallInfo &callIn // Note: this is an upperbound. Unreachable targets and uninlineable natives are also counted. uint32_t count = 1; // Possible fallback block. for (uint32_t i = 0; i < targets.length(); i++) { if (choiceSet[i]) count++; } retPhi->reserveLength(count); - // During inlining the 'this' value is assigned a type set which is - // specialized to the groups which can generate that inlining target. - // After inlining the original type set is restored. - TemporaryTypeSet *cacheObjectTypeSet = - maybeCache ? maybeCache->object()->resultTypeSet() : nullptr; - // Inline each of the inlineable targets. for (uint32_t i = 0; i < targets.length(); i++) { // Target must be inlineable. if (!choiceSet[i]) continue; // Even though we made one round of inline decisions already, we may // be amending them below. @@ -5402,22 +5396,26 @@ IonBuilder::inlineCalls(CallInfo &callIn // Create a new CallInfo to track modified state within the inline block. CallInfo inlineInfo(alloc(), callInfo.constructing()); if (!inlineInfo.init(callInfo)) return false; inlineInfo.popFormals(inlineBlock); inlineInfo.setFun(funcDef); if (maybeCache) { + // Assign the 'this' value a TypeSet specialized to the groups that + // can generate this inlining target. MOZ_ASSERT(callInfo.thisArg() == maybeCache->object()); - TemporaryTypeSet *targetThisTypes = - maybeCache->propTable()->buildTypeSetForFunction(target); - if (!targetThisTypes) + TemporaryTypeSet *thisTypes = maybeCache->propTable()->buildTypeSetForFunction(target); + if (!thisTypes) return false; - maybeCache->object()->setResultTypeSet(targetThisTypes); + + MFilterTypeSet *filter = MFilterTypeSet::New(alloc(), inlineInfo.thisArg(), thisTypes); + inlineBlock->add(filter); + inlineInfo.setThis(filter); } // Inline the call into the inlineBlock. if (!setCurrentAndSpecializePhis(inlineBlock)) return false; InliningStatus status = inlineSingleCall(inlineInfo, target); if (status == InliningStatus_Error) return false; @@ -5442,37 +5440,78 @@ IonBuilder::inlineCalls(CallInfo &callIn MDefinition *retVal = inlineReturnBlock->peek(-1); retPhi->addInput(retVal); inlineReturnBlock->end(MGoto::New(alloc(), returnBlock)); if (!returnBlock->addPredecessorWithoutPhis(inlineReturnBlock)) return false; } // Patch the InlinePropertyTable to not dispatch to vetoed paths. + bool useFallback; if (maybeCache) { - maybeCache->object()->setResultTypeSet(cacheObjectTypeSet); - InlinePropertyTable *propTable = maybeCache->propTable(); propTable->trimTo(targets, choiceSet); - // If all paths were vetoed, output only a generic fallback path. if (propTable->numEntries() == 0) { + // If all paths were vetoed, output only a generic fallback path. MOZ_ASSERT(dispatch->numCases() == 0); maybeCache = nullptr; - } + useFallback = true; + } else { + // We need a fallback path if the ObjectGroup dispatch does not + // handle all incoming objects. + useFallback = false; + TemporaryTypeSet *objectTypes = maybeCache->object()->resultTypeSet(); + for (uint32_t i = 0; i < objectTypes->getObjectCount(); i++) { + TypeSet::ObjectKey *obj = objectTypes->getObject(i); + if (!obj) + continue; + + if (!obj->isGroup()) { + useFallback = true; + break; + } + + if (!propTable->hasObjectGroup(obj->group())) { + useFallback = true; + break; + } + } + + if (!useFallback) { + // The object group dispatch handles all possible incoming + // objects, so the cache and barrier will not be reached and + // can be eliminated. + if (callInfo.fun()->isGetPropertyCache()) { + MOZ_ASSERT(callInfo.fun() == maybeCache); + } else { + MTypeBarrier *barrier = callInfo.fun()->toTypeBarrier(); + MOZ_ASSERT(!barrier->hasUses()); + MOZ_ASSERT(barrier->type() == MIRType_Object); + MOZ_ASSERT(barrier->input()->isGetPropertyCache()); + MOZ_ASSERT(barrier->input()->toGetPropertyCache() == maybeCache); + barrier->block()->discard(barrier); + } + + MOZ_ASSERT(!maybeCache->hasUses()); + maybeCache->block()->discard(maybeCache); + } + } + } else { + useFallback = dispatch->numCases() < targets.length(); } // If necessary, generate a fallback path. - // MObjectGroupDispatch always uses a fallback path. - if (maybeCache || dispatch->numCases() < targets.length()) { + if (useFallback) { // Generate fallback blocks, and set |current| to the fallback return block. if (maybeCache) { MBasicBlock *fallbackTarget; - if (!inlineObjectGroupFallback(callInfo, dispatchBlock, (MObjectGroupDispatch *)dispatch, - maybeCache, &fallbackTarget)) + if (!inlineObjectGroupFallback(callInfo, dispatchBlock, + dispatch->toObjectGroupDispatch(), + maybeCache, &fallbackTarget)) { return false; } dispatch->addFallback(fallbackTarget); } else { JSFunction *remaining = nullptr; // If there is only 1 remaining case, we can annotate the fallback call
--- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -2149,39 +2149,43 @@ class LFunctionDispatch : public LInstru public: LIR_HEADER(FunctionDispatch); explicit LFunctionDispatch(const LAllocation &in) { setOperand(0, in); } - MFunctionDispatch *mir() { + MFunctionDispatch *mir() const { return mir_->toFunctionDispatch(); } }; class LObjectGroupDispatch : public LInstructionHelper<0, 1, 1> { // Dispatch is performed based on an ObjectGroup -> block // map inferred by the MIR. public: LIR_HEADER(ObjectGroupDispatch); + const char *extraName() const { + return mir()->hasFallback() ? "HasFallback" : "NoFallback"; + } + LObjectGroupDispatch(const LAllocation &in, const LDefinition &temp) { setOperand(0, in); setTemp(0, temp); } const LDefinition *temp() { return getTemp(0); } - MObjectGroupDispatch *mir() { + MObjectGroupDispatch *mir() const { return mir_->toObjectGroupDispatch(); } }; // Compares two integral values of the same JS type, either integer or object. // For objects, both operands are in registers. class LCompare : public LInstructionHelper<1, 2, 0> {
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -4184,16 +4184,26 @@ InlinePropertyTable::hasFunction(JSFunct { for (size_t i = 0; i < numEntries(); i++) { if (entries_[i]->func == func) return true; } return false; } +bool +InlinePropertyTable::hasObjectGroup(ObjectGroup *group) const +{ + for (size_t i = 0; i < numEntries(); i++) { + if (entries_[i]->group == group) + return true; + } + return false; +} + TemporaryTypeSet * InlinePropertyTable::buildTypeSetForFunction(JSFunction *func) const { LifoAlloc *alloc = GetJitContext()->temp->lifoAlloc(); TemporaryTypeSet *types = alloc->new_<TemporaryTypeSet>(); if (!types) return nullptr; for (size_t i = 0; i < numEntries(); i++) {
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9521,16 +9521,18 @@ class InlinePropertyTable : public TempO } JSFunction *getFunction(size_t i) const { MOZ_ASSERT(i < numEntries()); return entries_[i]->func; } bool hasFunction(JSFunction *func) const; + bool hasObjectGroup(ObjectGroup *group) const; + TemporaryTypeSet *buildTypeSetForFunction(JSFunction *func) const; // Remove targets that vetoed inlining from the InlinePropertyTable. void trimTo(const ObjectVector &targets, const BoolVector &choiceSet); // Ensure that the InlinePropertyTable's domain is a subset of |targets|. void trimToTargets(const ObjectVector &targets); };