mirror of
https://github.com/classilla/tenfourfox.git
synced 2025-01-16 17:31:17 +00:00
closes #376: M1329901 M1330667 M1342016 (modified) M1304081 M1259476
This commit is contained in:
parent
1fe2d3921c
commit
8a97adc59a
17
js/src/jit-test/tests/ion/pgo-bug1259476.js
Normal file
17
js/src/jit-test/tests/ion/pgo-bug1259476.js
Normal file
@ -0,0 +1,17 @@
|
||||
/* This is supposed to be jit-test --ion-pgo=on */
|
||||
|
||||
try {
|
||||
x = evalcx('');
|
||||
x.__proto__ = 0;
|
||||
} catch (e) {}
|
||||
(function() {
|
||||
for (var i = 0; i < 1; ++i) {
|
||||
if (i % 5 == 0) {
|
||||
for (let z of[0, 0, new Boolean(false), new Boolean(false),
|
||||
new Boolean(false), new Boolean(false)]) {
|
||||
this.x;
|
||||
}
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
@ -391,6 +391,9 @@ BacktrackingAllocator::init()
|
||||
|
||||
LBlock* block = graph.getBlock(i);
|
||||
for (LInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
|
||||
if (mir->shouldCancel("Create data structures (inner loop 1)"))
|
||||
return false;
|
||||
|
||||
for (size_t j = 0; j < ins->numDefs(); j++) {
|
||||
LDefinition* def = ins->getDef(j);
|
||||
if (def->isBogusTemp())
|
||||
@ -828,7 +831,7 @@ BacktrackingAllocator::go()
|
||||
return false;
|
||||
|
||||
QueueItem item = allocationQueue.removeHighest();
|
||||
if (!processBundle(item.bundle))
|
||||
if (!processBundle(mir, item.bundle))
|
||||
return false;
|
||||
}
|
||||
JitSpew(JitSpew_RegAlloc, "Main allocation loop complete");
|
||||
@ -1221,7 +1224,7 @@ BacktrackingAllocator::tryAllocateNonFixed(LiveBundle* bundle,
|
||||
}
|
||||
|
||||
bool
|
||||
BacktrackingAllocator::processBundle(LiveBundle* bundle)
|
||||
BacktrackingAllocator::processBundle(MIRGenerator* mir, LiveBundle* bundle)
|
||||
{
|
||||
if (JitSpewEnabled(JitSpew_RegAlloc)) {
|
||||
JitSpew(JitSpew_RegAlloc, "Allocating %s [priority %lu] [weight %lu]",
|
||||
@ -1256,6 +1259,9 @@ BacktrackingAllocator::processBundle(LiveBundle* bundle)
|
||||
bool fixed;
|
||||
LiveBundleVector conflicting;
|
||||
for (size_t attempt = 0;; attempt++) {
|
||||
if (mir->shouldCancel("Backtracking Allocation (processBundle loop)"))
|
||||
return false;
|
||||
|
||||
if (canAllocate) {
|
||||
bool success = false;
|
||||
fixed = false;
|
||||
@ -1719,7 +1725,7 @@ BacktrackingAllocator::resolveControlFlow()
|
||||
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
|
||||
VirtualRegister& reg = vregs[i];
|
||||
|
||||
if (mir->shouldCancel("Backtracking Resolve Control Flow (vreg loop)"))
|
||||
if (mir->shouldCancel("Backtracking Resolve Control Flow (vreg outer loop)"))
|
||||
return false;
|
||||
|
||||
if (!alloc().ensureBallast())
|
||||
@ -1728,6 +1734,9 @@ BacktrackingAllocator::resolveControlFlow()
|
||||
for (LiveRange::RegisterLinkIterator iter = reg.rangesBegin(); iter; ) {
|
||||
LiveRange* range = LiveRange::get(*iter);
|
||||
|
||||
if (mir->shouldCancel("Backtracking Resolve Control Flow (vreg inner loop)"))
|
||||
return false;
|
||||
|
||||
// Remove ranges which will never be used.
|
||||
if (deadRange(range)) {
|
||||
reg.removeRangeAndIncrement(iter);
|
||||
|
@ -663,7 +663,7 @@ class BacktrackingAllocator : protected RegisterAllocator
|
||||
bool* success, bool* pfixed, LiveBundleVector& conflicting);
|
||||
bool tryAllocateNonFixed(LiveBundle* bundle, Requirement requirement, Requirement hint,
|
||||
bool* success, bool* pfixed, LiveBundleVector& conflicting);
|
||||
bool processBundle(LiveBundle* bundle);
|
||||
bool processBundle(MIRGenerator* mir, LiveBundle* bundle);
|
||||
bool computeRequirement(LiveBundle* bundle, Requirement *prequirement, Requirement *phint);
|
||||
bool tryAllocateRegister(PhysicalRegister& r, LiveBundle* bundle,
|
||||
bool* success, bool* pfixed, LiveBundleVector& conflicting);
|
||||
|
@ -480,6 +480,7 @@ class CompileInfo
|
||||
// the frame is active on the stack. This implies that these definitions
|
||||
// would have to be executed and that they cannot be removed even if they
|
||||
// are unused.
|
||||
#if(0)
|
||||
bool isObservableSlot(uint32_t slot) const {
|
||||
if (isObservableFrameSlot(slot))
|
||||
return true;
|
||||
@ -489,6 +490,17 @@ class CompileInfo
|
||||
|
||||
return false;
|
||||
}
|
||||
#else // bug 1342016 attachment 8849618 for our older code
|
||||
inline bool isObservableSlot(uint32_t slot) const {
|
||||
if (slot >= firstLocalSlot())
|
||||
return false;
|
||||
|
||||
if (slot < firstArgSlot())
|
||||
return isObservableFrameSlot(slot);
|
||||
|
||||
return isObservableArgumentSlot(slot);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool isObservableFrameSlot(uint32_t slot) const {
|
||||
if (!funMaybeLazy())
|
||||
|
@ -24,9 +24,10 @@ EdgeCaseAnalysis::analyzeLate()
|
||||
uint32_t nextId = 0;
|
||||
|
||||
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
|
||||
if (mir->shouldCancel("Analyze Late (first loop)"))
|
||||
return false;
|
||||
for (MDefinitionIterator iter(*block); iter; iter++) {
|
||||
if (mir->shouldCancel("Analyze Late (first loop)"))
|
||||
return false;
|
||||
|
||||
iter->setId(nextId++);
|
||||
iter->analyzeEdgeCasesForward();
|
||||
}
|
||||
@ -34,10 +35,12 @@ EdgeCaseAnalysis::analyzeLate()
|
||||
}
|
||||
|
||||
for (PostorderIterator block(graph.poBegin()); block != graph.poEnd(); block++) {
|
||||
if (mir->shouldCancel("Analyze Late (second loop)"))
|
||||
return false;
|
||||
for (MInstructionReverseIterator riter(block->rbegin()); riter != block->rend(); riter++)
|
||||
for (MInstructionReverseIterator riter(block->rbegin()); riter != block->rend(); riter++) {
|
||||
if (mir->shouldCancel("Analyze Late (second loop)"))
|
||||
return false;
|
||||
|
||||
riter->analyzeEdgeCasesBackward();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1506,17 +1506,20 @@ OptimizeMIR(MIRGenerator* mir)
|
||||
else
|
||||
logger = TraceLoggerForCurrentThread();
|
||||
|
||||
if (mir->shouldCancel("Start"))
|
||||
return false;
|
||||
|
||||
if (!mir->compilingAsmJS()) {
|
||||
if (!MakeMRegExpHoistable(graph))
|
||||
if (!MakeMRegExpHoistable(mir, graph))
|
||||
return false;
|
||||
|
||||
if (mir->shouldCancel("Make MRegExp Hoistable"))
|
||||
return false;
|
||||
}
|
||||
|
||||
gs.spewPass("BuildSSA");
|
||||
AssertBasicGraphCoherency(graph);
|
||||
|
||||
if (mir->shouldCancel("Start"))
|
||||
return false;
|
||||
|
||||
if (!JitOptions.disablePgo && !mir->compilingAsmJS()) {
|
||||
AutoTraceLog log(logger, TraceLogger_PruneUnusedBranches);
|
||||
if (!PruneUnusedBranches(mir, graph))
|
||||
|
@ -30,7 +30,8 @@ using mozilla::DebugOnly;
|
||||
typedef Vector<MPhi*, 16, SystemAllocPolicy> MPhiVector;
|
||||
|
||||
static bool
|
||||
FlagPhiInputsAsHavingRemovedUses(MBasicBlock* block, MBasicBlock* succ, MPhiVector& worklist)
|
||||
FlagPhiInputsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block, MBasicBlock* succ,
|
||||
MPhiVector& worklist)
|
||||
{
|
||||
// When removing an edge between 2 blocks, we might remove the ability of
|
||||
// later phases to figure out that the uses of a Phi should be considered as
|
||||
@ -103,6 +104,9 @@ FlagPhiInputsAsHavingRemovedUses(MBasicBlock* block, MBasicBlock* succ, MPhiVect
|
||||
for (; it != end; it++) {
|
||||
MPhi* phi = *it;
|
||||
|
||||
if (mir->shouldCancel("FlagPhiInputsAsHavingRemovedUses outer loop"))
|
||||
return false;
|
||||
|
||||
// We are looking to mark the Phi inputs which are used across the edge
|
||||
// between the |block| and its successor |succ|.
|
||||
MDefinition* def = phi->getOperand(predIndex);
|
||||
@ -120,9 +124,23 @@ FlagPhiInputsAsHavingRemovedUses(MBasicBlock* block, MBasicBlock* succ, MPhiVect
|
||||
bool isUsed = false;
|
||||
for (size_t idx = 0; !isUsed && idx < worklist.length(); idx++) {
|
||||
phi = worklist[idx];
|
||||
|
||||
if (mir->shouldCancel("FlagPhiInputsAsHavingRemovedUses inner loop 1"))
|
||||
return false;
|
||||
|
||||
if (phi->isUseRemoved() || phi->isImplicitlyUsed()) {
|
||||
// The phi is implicitly used.
|
||||
isUsed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
MUseIterator usesEnd(phi->usesEnd());
|
||||
for (MUseIterator use(phi->usesBegin()); use != usesEnd; use++) {
|
||||
MNode* consumer = (*use)->consumer();
|
||||
|
||||
if (mir->shouldCancel("FlagPhiInputsAsHavingRemovedUses inner loop 2"))
|
||||
return false;
|
||||
|
||||
if (consumer->isResumePoint()) {
|
||||
MResumePoint* rp = consumer->toResumePoint();
|
||||
if (rp->isObservableOperand(*use)) {
|
||||
@ -144,12 +162,6 @@ FlagPhiInputsAsHavingRemovedUses(MBasicBlock* block, MBasicBlock* succ, MPhiVect
|
||||
if (phi->isInWorklist())
|
||||
continue;
|
||||
|
||||
if (phi->isUseRemoved() || phi->isImplicitlyUsed()) {
|
||||
// The phi is implicitly used.
|
||||
isUsed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
phi->setInWorklist();
|
||||
if (!worklist.append(phi))
|
||||
return false;
|
||||
@ -177,11 +189,16 @@ FlagPhiInputsAsHavingRemovedUses(MBasicBlock* block, MBasicBlock* succ, MPhiVect
|
||||
}
|
||||
|
||||
static bool
|
||||
FlagAllOperandsAsHavingRemovedUses(MBasicBlock* block)
|
||||
FlagAllOperandsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block)
|
||||
{
|
||||
const CompileInfo& info = block->info();
|
||||
|
||||
// Flag all instructions operands as having removed uses.
|
||||
MInstructionIterator end = block->end();
|
||||
for (MInstructionIterator it = block->begin(); it != end; it++) {
|
||||
if (mir->shouldCancel("FlagAllOperandsAsHavingRemovedUses loop 1"))
|
||||
return false;
|
||||
|
||||
MInstruction* ins = *it;
|
||||
for (size_t i = 0, e = ins->numOperands(); i < e; i++)
|
||||
ins->getOperand(i)->setUseRemovedUnchecked();
|
||||
@ -191,9 +208,17 @@ FlagAllOperandsAsHavingRemovedUses(MBasicBlock* block)
|
||||
// Note: no need to iterate over the caller's of the resume point as
|
||||
// this is the same as the entry resume point.
|
||||
for (size_t i = 0, e = rp->numOperands(); i < e; i++) {
|
||||
#if(0) // bug 1329901, bug 1342016
|
||||
if (mir->shouldCancel("FlagAllOperandsAsHavingRemovedUses inner loop"))
|
||||
return false;
|
||||
|
||||
if (!rp->isObservableOperand(i))
|
||||
continue;
|
||||
rp->getOperand(i)->setUseRemovedUnchecked();
|
||||
#else
|
||||
if (info.isObservableSlot(i))
|
||||
rp->getOperand(i)->setUseRemovedUnchecked();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,10 +226,18 @@ FlagAllOperandsAsHavingRemovedUses(MBasicBlock* block)
|
||||
// Flag observable operands of the entry resume point as having removed uses.
|
||||
MResumePoint* rp = block->entryResumePoint();
|
||||
while (rp) {
|
||||
if (mir->shouldCancel("FlagAllOperandsAsHavingRemovedUses loop 2"))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0, e = rp->numOperands(); i < e; i++) {
|
||||
#if(0) // bug 1329901, bug 1342016
|
||||
if (!rp->isObservableOperand(i))
|
||||
continue;
|
||||
rp->getOperand(i)->setUseRemovedUnchecked();
|
||||
#else
|
||||
if (info.isObservableSlot(i))
|
||||
rp->getOperand(i)->setUseRemovedUnchecked();
|
||||
#endif
|
||||
}
|
||||
rp = rp->caller();
|
||||
}
|
||||
@ -212,7 +245,10 @@ FlagAllOperandsAsHavingRemovedUses(MBasicBlock* block)
|
||||
// Flag Phi inputs of the successors has having removed uses.
|
||||
MPhiVector worklist;
|
||||
for (size_t i = 0, e = block->numSuccessors(); i < e; i++) {
|
||||
if (!FlagPhiInputsAsHavingRemovedUses(block, block->getSuccessor(i), worklist))
|
||||
if (mir->shouldCancel("FlagAllOperandsAsHavingRemovedUses loop 3"))
|
||||
return false;
|
||||
|
||||
if (!FlagPhiInputsAsHavingRemovedUses(mir, block, block->getSuccessor(i), worklist))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -261,6 +297,9 @@ jit::PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph)
|
||||
// unreachable if all predecessors are flagged as bailing or unreachable.
|
||||
bool someUnreachable = false;
|
||||
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
|
||||
if (mir->shouldCancel("Prune unused branches (main loop)"))
|
||||
return false;
|
||||
|
||||
JitSpew(JitSpew_Prune, "Investigate Block %d:", block->id());
|
||||
|
||||
// Do not touch entry basic blocks.
|
||||
@ -274,6 +313,9 @@ jit::PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph)
|
||||
size_t numPred = block->numPredecessors();
|
||||
size_t i = 0;
|
||||
for (; i < numPred; i++) {
|
||||
if (mir->shouldCancel("Prune unused branches (inner loop 1)"))
|
||||
return false;
|
||||
|
||||
MBasicBlock* pred = block->getPredecessor(i);
|
||||
|
||||
// The backedge is visited after the loop header, but if the loop
|
||||
@ -304,6 +346,9 @@ jit::PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph)
|
||||
size_t predCount = 0;
|
||||
bool isLoopExit = false;
|
||||
while (p--) {
|
||||
if (mir->shouldCancel("Prune unused branches (inner loop 2)"))
|
||||
return false;
|
||||
|
||||
MBasicBlock* pred = block->getPredecessor(p);
|
||||
if (pred->getHitState() == MBasicBlock::HitState::Count)
|
||||
predCount += pred->getHitCount();
|
||||
@ -369,16 +414,22 @@ jit::PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph)
|
||||
// As we are going to remove edges and basic block, we have to mark
|
||||
// instructions which would be needed by baseline if we were to bailout.
|
||||
for (PostorderIterator it(graph.poBegin()); it != graph.poEnd();) {
|
||||
if (mir->shouldCancel("Prune unused branches (marking loop)"))
|
||||
return false;
|
||||
|
||||
MBasicBlock* block = *it++;
|
||||
if (!block->isMarked() && !block->unreachable())
|
||||
continue;
|
||||
|
||||
FlagAllOperandsAsHavingRemovedUses(block);
|
||||
FlagAllOperandsAsHavingRemovedUses(mir, block);
|
||||
}
|
||||
|
||||
// Remove the blocks in post-order such that consumers are visited before
|
||||
// the predecessors, the only exception being the Phi nodes of loop headers.
|
||||
for (PostorderIterator it(graph.poBegin()); it != graph.poEnd();) {
|
||||
if (mir->shouldCancel("Prune unused branches (removal loop)"))
|
||||
return false;
|
||||
|
||||
MBasicBlock* block = *it++;
|
||||
if (!block->isMarked() && !block->unreachable())
|
||||
continue;
|
||||
@ -1071,13 +1122,13 @@ jit::EliminatePhis(MIRGenerator* mir, MIRGraph& graph,
|
||||
// Add all observable phis to a worklist. We use the "in worklist" bit to
|
||||
// mean "this phi is live".
|
||||
for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
|
||||
if (mir->shouldCancel("Eliminate Phis (populate loop)"))
|
||||
return false;
|
||||
|
||||
MPhiIterator iter = block->phisBegin();
|
||||
while (iter != block->phisEnd()) {
|
||||
MPhi* phi = *iter++;
|
||||
|
||||
if (mir->shouldCancel("Eliminate Phis (populate loop)"))
|
||||
return false;
|
||||
|
||||
// Flag all as unused, only observable phis would be marked as used
|
||||
// when processed by the work list.
|
||||
phi->setUnused();
|
||||
@ -1357,6 +1408,9 @@ TypeAnalyzer::specializePhis()
|
||||
return false;
|
||||
|
||||
for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
|
||||
if (mir->shouldCancel("Specialize Phis (inner loop)"))
|
||||
return false;
|
||||
|
||||
bool hasInputsWithEmptyTypes;
|
||||
MIRType type = GuessPhiType(*phi, &hasInputsWithEmptyTypes);
|
||||
phi->specialize(type);
|
||||
@ -1739,10 +1793,10 @@ bool
|
||||
TypeAnalyzer::graphContainsFloat32()
|
||||
{
|
||||
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); ++block) {
|
||||
if (mir->shouldCancel("Ensure Float32 commutativity - Graph contains Float32"))
|
||||
return false;
|
||||
|
||||
for (MDefinitionIterator def(*block); def; def++) {
|
||||
if (mir->shouldCancel("Ensure Float32 commutativity - Graph contains Float32"))
|
||||
return false;
|
||||
|
||||
if (def->type() == MIRType_Float32)
|
||||
return true;
|
||||
}
|
||||
@ -1822,7 +1876,7 @@ jit::ApplyTypeInformation(MIRGenerator* mir, MIRGraph& graph)
|
||||
}
|
||||
|
||||
bool
|
||||
jit::MakeMRegExpHoistable(MIRGraph& graph)
|
||||
jit::MakeMRegExpHoistable(MIRGenerator* mir, MIRGraph& graph)
|
||||
{
|
||||
// If we are compiling try blocks, regular expressions may be observable
|
||||
// from catch blocks (which Ion does not compile). For now just disable the
|
||||
@ -1831,7 +1885,13 @@ jit::MakeMRegExpHoistable(MIRGraph& graph)
|
||||
return true;
|
||||
|
||||
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
|
||||
if (mir->shouldCancel("MakeMRegExpHoistable outer loop"))
|
||||
return false;
|
||||
|
||||
for (MDefinitionIterator iter(*block); iter; iter++) {
|
||||
if (mir->shouldCancel("MakeMRegExpHoistable inner loop"))
|
||||
return false;
|
||||
|
||||
if (!iter->isRegExp())
|
||||
continue;
|
||||
|
||||
@ -1840,6 +1900,9 @@ jit::MakeMRegExpHoistable(MIRGraph& graph)
|
||||
// Test if MRegExp is hoistable by looking at all uses.
|
||||
bool hoistable = true;
|
||||
for (MUseIterator i = regexp->usesBegin(); i != regexp->usesEnd(); i++) {
|
||||
if (mir->shouldCancel("IsRegExpHoistable inner loop"))
|
||||
return false;
|
||||
|
||||
// Ignore resume points. At this point all uses are listed.
|
||||
// No DCE or GVN or something has happened.
|
||||
if (i->consumer()->isResumePoint())
|
||||
@ -1939,7 +2002,7 @@ jit::RemoveUnmarkedBlocks(MIRGenerator* mir, MIRGraph& graph, uint32_t numMarked
|
||||
if (!block->isMarked())
|
||||
continue;
|
||||
|
||||
FlagAllOperandsAsHavingRemovedUses(block);
|
||||
FlagAllOperandsAsHavingRemovedUses(mir, block);
|
||||
}
|
||||
|
||||
// Find unmarked blocks and remove them.
|
||||
|
@ -54,7 +54,7 @@ bool
|
||||
ApplyTypeInformation(MIRGenerator* mir, MIRGraph& graph);
|
||||
|
||||
bool
|
||||
MakeMRegExpHoistable(MIRGraph& graph);
|
||||
MakeMRegExpHoistable(MIRGenerator* mir, MIRGraph& graph);
|
||||
|
||||
bool
|
||||
RenumberBlocks(MIRGraph& graph);
|
||||
|
@ -158,7 +158,9 @@ IonBuilder::IonBuilder(JSContext* analysisContext, CompileCompartment* comp,
|
||||
failedShapeGuard_(info->script()->failedShapeGuard()),
|
||||
failedLexicalCheck_(info->script()->failedLexicalCheck()),
|
||||
nonStringIteration_(false),
|
||||
lazyArguments_(nullptr),
|
||||
#ifdef DEBUG
|
||||
hasLazyArguments_(false),
|
||||
#endif
|
||||
inlineCallInfo_(nullptr),
|
||||
maybeFallbackFunctionGetter_(nullptr)
|
||||
{
|
||||
@ -908,11 +910,11 @@ IonBuilder::build()
|
||||
ins->setResumePoint(entryRpCopy);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// lazyArguments should never be accessed in |argsObjAliasesFormals| scripts.
|
||||
if (info().hasArguments() && !info().argsObjAliasesFormals()) {
|
||||
lazyArguments_ = MConstant::New(alloc(), MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
||||
current->add(lazyArguments_);
|
||||
}
|
||||
if (info().hasArguments() && !info().argsObjAliasesFormals())
|
||||
hasLazyArguments_ = true;
|
||||
#endif
|
||||
|
||||
insertRecompileCheck();
|
||||
|
||||
@ -1080,10 +1082,10 @@ IonBuilder::buildInline(IonBuilder* callerBuilder, MResumePoint* callerResumePoi
|
||||
// +2 for the scope chain and |this|, maybe another +1 for arguments object slot.
|
||||
MOZ_ASSERT(current->entryResumePoint()->stackDepth() == info().totalSlots());
|
||||
|
||||
if (script_->argumentsHasVarBinding()) {
|
||||
lazyArguments_ = MConstant::New(alloc(), MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
||||
current->add(lazyArguments_);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (script_->argumentsHasVarBinding())
|
||||
hasLazyArguments_ = true;
|
||||
#endif
|
||||
|
||||
insertRecompileCheck();
|
||||
|
||||
@ -1349,10 +1351,14 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction** def_,
|
||||
}
|
||||
|
||||
case MIRType_MagicOptimizedArguments:
|
||||
MOZ_ASSERT(lazyArguments_);
|
||||
osrBlock->rewriteSlot(slot, lazyArguments_);
|
||||
def = lazyArguments_;
|
||||
{
|
||||
MOZ_ASSERT(hasLazyArguments_);
|
||||
MConstant* lazyArg = MConstant::New(alloc(), MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
||||
osrBlock->insertBefore(osrBlock->lastIns(), lazyArg);
|
||||
osrBlock->rewriteSlot(slot, lazyArg);
|
||||
def = lazyArg;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -10195,8 +10201,11 @@ IonBuilder::jsop_arguments()
|
||||
current->push(current->argumentsObject());
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(lazyArguments_);
|
||||
current->push(lazyArguments_);
|
||||
|
||||
MOZ_ASSERT(hasLazyArguments_);
|
||||
MConstant* lazyArg = MConstant::New(alloc(), MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
||||
current->add(lazyArg);
|
||||
current->push(lazyArg);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1196,9 +1196,10 @@ class IonBuilder
|
||||
// Has an iterator other than 'for in'.
|
||||
bool nonStringIteration_;
|
||||
|
||||
// If this script can use a lazy arguments object, it will be pre-created
|
||||
// here.
|
||||
MInstruction* lazyArguments_;
|
||||
#ifdef DEBUG
|
||||
// If this script uses the lazy arguments object.
|
||||
bool hasLazyArguments_;
|
||||
#endif
|
||||
|
||||
// If this is an inline builder, the call info for the builder.
|
||||
const CallInfo* inlineCallInfo_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user