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