Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (183093 => 183094)
--- trunk/Source/_javascript_Core/ChangeLog 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,3 +1,118 @@
+2015-04-21 Filip Pizlo <[email protected]>
+
+ DFG should allow Phantoms after terminals
+ https://bugs.webkit.org/show_bug.cgi?id=126778
+
+ Reviewed by Mark Lam.
+
+ It's important for us to be able to place liveness-marking nodes after nodes that do
+ things. These liveness-marking nodes are nops. Previously, we disallowed such nodes after
+ terminals. That made things awkward, especially for Switch and Branch, which may do
+ things that necessitate liveness markers (for example they might want to use a converted
+ version of a value rather than the value that was MovHinted). We previously made this
+ work by disallowing certain optimizations on Switch and Branch, which was probably a bad
+ thing.
+
+ This changes our IR to allow for the terminal to not be the last node in a block. Asking
+ for the terminal involves a search. DFG::validate() checks that the nodes after the
+ terminal are liveness markers that have no effects or checks.
+
+ This is perf-neutral but will allow more optimizations in the future. It will also make
+ it cleaner to fix https://bugs.webkit.org/show_bug.cgi?id=143735.
+
+ * dfg/DFGBasicBlock.cpp:
+ (JSC::DFG::BasicBlock::replaceTerminal):
+ * dfg/DFGBasicBlock.h:
+ (JSC::DFG::BasicBlock::findTerminal):
+ (JSC::DFG::BasicBlock::terminal):
+ (JSC::DFG::BasicBlock::insertBeforeTerminal):
+ (JSC::DFG::BasicBlock::numSuccessors):
+ (JSC::DFG::BasicBlock::successor):
+ (JSC::DFG::BasicBlock::successorForCondition):
+ (JSC::DFG::BasicBlock::successors):
+ (JSC::DFG::BasicBlock::last): Deleted.
+ (JSC::DFG::BasicBlock::takeLast): Deleted.
+ (JSC::DFG::BasicBlock::insertBeforeLast): Deleted.
+ (JSC::DFG::BasicBlock::SuccessorsIterable::SuccessorsIterable): Deleted.
+ (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::iterator): Deleted.
+ (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator*): Deleted.
+ (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator++): Deleted.
+ (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator==): Deleted.
+ (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator!=): Deleted.
+ (JSC::DFG::BasicBlock::SuccessorsIterable::begin): Deleted.
+ (JSC::DFG::BasicBlock::SuccessorsIterable::end): Deleted.
+ * dfg/DFGBasicBlockInlines.h:
+ (JSC::DFG::BasicBlock::appendNonTerminal):
+ (JSC::DFG::BasicBlock::replaceTerminal):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::addToGraph):
+ (JSC::DFG::ByteCodeParser::inlineCall):
+ (JSC::DFG::ByteCodeParser::handleInlining):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ (JSC::DFG::ByteCodeParser::linkBlock):
+ (JSC::DFG::ByteCodeParser::parseCodeBlock):
+ * dfg/DFGCFGSimplificationPhase.cpp:
+ (JSC::DFG::CFGSimplificationPhase::run):
+ (JSC::DFG::CFGSimplificationPhase::convertToJump):
+ (JSC::DFG::CFGSimplificationPhase::mergeBlocks):
+ * dfg/DFGCPSRethreadingPhase.cpp:
+ (JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock):
+ * dfg/DFGCommon.h:
+ (JSC::DFG::NodeAndIndex::NodeAndIndex):
+ (JSC::DFG::NodeAndIndex::operator!):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupBlock):
+ (JSC::DFG::FixupPhase::fixupNode):
+ (JSC::DFG::FixupPhase::injectTypeConversionsInBlock):
+ (JSC::DFG::FixupPhase::clearPhantomsAtEnd): Deleted.
+ * dfg/DFGForAllKills.h:
+ (JSC::DFG::forAllLiveNodesAtTail):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::terminalsAreValid):
+ (JSC::DFG::Graph::dumpBlockHeader):
+ * dfg/DFGGraph.h:
+ * dfg/DFGInPlaceAbstractState.cpp:
+ (JSC::DFG::InPlaceAbstractState::mergeToSuccessors):
+ * dfg/DFGLICMPhase.cpp:
+ (JSC::DFG::LICMPhase::run):
+ (JSC::DFG::LICMPhase::attemptHoist):
+ * dfg/DFGMovHintRemovalPhase.cpp:
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::SuccessorsIterable::SuccessorsIterable):
+ (JSC::DFG::Node::SuccessorsIterable::iterator::iterator):
+ (JSC::DFG::Node::SuccessorsIterable::iterator::operator*):
+ (JSC::DFG::Node::SuccessorsIterable::iterator::operator++):
+ (JSC::DFG::Node::SuccessorsIterable::iterator::operator==):
+ (JSC::DFG::Node::SuccessorsIterable::iterator::operator!=):
+ (JSC::DFG::Node::SuccessorsIterable::begin):
+ (JSC::DFG::Node::SuccessorsIterable::end):
+ (JSC::DFG::Node::successors):
+ * dfg/DFGObjectAllocationSinkingPhase.cpp:
+ (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints):
+ (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints):
+ (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields):
+ * dfg/DFGPhantomRemovalPhase.cpp:
+ (JSC::DFG::PhantomRemovalPhase::run):
+ * dfg/DFGPutStackSinkingPhase.cpp:
+ * dfg/DFGSSAConversionPhase.cpp:
+ (JSC::DFG::SSAConversionPhase::run):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::detectPeepHoleBranch):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGStaticExecutionCountEstimationPhase.cpp:
+ (JSC::DFG::StaticExecutionCountEstimationPhase::run):
+ * dfg/DFGTierUpCheckInjectionPhase.cpp:
+ (JSC::DFG::TierUpCheckInjectionPhase::run):
+ * dfg/DFGValidate.cpp:
+ (JSC::DFG::Validate::validate):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileNode):
+ * tests/stress/closure-call-exit.js: Added.
+ (foo):
+
2015-04-21 Basile Clement <[email protected]>
PhantomNewObject should be marked NodeMustGenerate
Modified: trunk/Source/_javascript_Core/dfg/DFGBasicBlock.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGBasicBlock.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGBasicBlock.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -71,6 +71,19 @@
intersectionOfPastValuesAtHead.ensureLocals(newNumLocals, AbstractValue::fullTop());
}
+void BasicBlock::replaceTerminal(Node* node)
+{
+ NodeAndIndex result = findTerminal();
+ if (!result)
+ append(node);
+ else {
+ m_nodes.insert(result.index + 1, node);
+ result.node->convertToPhantom();
+ }
+
+ ASSERT(terminal());
+}
+
bool BasicBlock::isInPhis(Node* node) const
{
for (size_t i = 0; i < phis.size(); ++i) {
Modified: trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -63,18 +63,63 @@
Node* at(size_t i) const { return m_nodes[i]; }
Node*& operator[](size_t i) { return at(i); }
Node* operator[](size_t i) const { return at(i); }
- Node* last() const { return at(size() - 1); }
- Node* takeLast() { return m_nodes.takeLast(); }
+
+ // Use this to find both the index of the terminal and the terminal itself in one go. May
+ // return a clear NodeAndIndex if the basic block currently lacks a terminal. That may happen
+ // in the middle of IR transformations within a phase but should never be the case in between
+ // phases.
+ //
+ // The reason why this is more than just "at(size() - 1)" is that we may place non-terminal
+ // liveness marking instructions after the terminal. This is supposed to happen infrequently
+ // but some basic blocks - most notably return blocks - will have liveness markers for all of
+ // the flushed variables right after the return.
+ //
+ // It turns out that doing this linear search is basically perf-neutral, so long as we force
+ // the method to be inlined. Hence the ALWAYS_INLINE.
+ ALWAYS_INLINE NodeAndIndex findTerminal() const
+ {
+ size_t i = size();
+ while (i--) {
+ Node* node = at(i);
+ switch (node->op()) {
+ case Jump:
+ case Branch:
+ case Switch:
+ case Return:
+ case Unreachable:
+ return NodeAndIndex(node, i);
+ // The bitter end can contain Phantoms and the like. There will probably only be one or two nodes after the terminal.
+ case Phantom:
+ case PhantomLocal:
+ case Flush:
+ break;
+ default:
+ return NodeAndIndex();
+ }
+ }
+ return NodeAndIndex();
+ }
+
+ ALWAYS_INLINE Node* terminal() const
+ {
+ return findTerminal().node;
+ }
+
void resize(size_t size) { m_nodes.resize(size); }
void grow(size_t size) { m_nodes.grow(size); }
void append(Node* node) { m_nodes.append(node); }
- void insertBeforeLast(Node* node)
+ void insertBeforeTerminal(Node* node)
{
- append(last());
- at(size() - 2) = node;
+ NodeAndIndex result = findTerminal();
+ if (!result)
+ append(node);
+ else
+ m_nodes.insert(result.index, node);
}
+ void replaceTerminal(Node*);
+
size_t numNodes() const { return phis.size() + size(); }
Node* node(size_t i) const
{
@@ -93,85 +138,20 @@
Node* firstOriginNode();
NodeOrigin firstOrigin();
- unsigned numSuccessors() { return last()->numSuccessors(); }
+ unsigned numSuccessors() { return terminal()->numSuccessors(); }
BasicBlock*& successor(unsigned index)
{
- return last()->successor(index);
+ return terminal()->successor(index);
}
BasicBlock*& successorForCondition(bool condition)
{
- return last()->successorForCondition(condition);
+ return terminal()->successorForCondition(condition);
}
-
- class SuccessorsIterable {
- public:
- SuccessorsIterable()
- : m_block(nullptr)
- {
- }
-
- SuccessorsIterable(BasicBlock* block)
- : m_block(block)
- {
- }
-
- class iterator {
- public:
- iterator()
- : m_block(nullptr)
- , m_index(UINT_MAX)
- {
- }
-
- iterator(BasicBlock* block, unsigned index)
- : m_block(block)
- , m_index(index)
- {
- }
-
- BasicBlock* operator*()
- {
- return m_block->successor(m_index);
- }
-
- iterator& operator++()
- {
- m_index++;
- return *this;
- }
-
- bool operator==(const iterator& other) const
- {
- return m_index == other.m_index;
- }
-
- bool operator!=(const iterator& other) const
- {
- return !(*this == other);
- }
- private:
- BasicBlock* m_block;
- unsigned m_index;
- };
-
- iterator begin()
- {
- return iterator(m_block, 0);
- }
-
- iterator end()
- {
- return iterator(m_block, m_block->numSuccessors());
- }
-
- private:
- BasicBlock* m_block;
- };
-
- SuccessorsIterable successors()
+
+ Node::SuccessorsIterable successors()
{
- return SuccessorsIterable(this);
+ return terminal()->successors();
}
void removePredecessor(BasicBlock* block);
@@ -183,6 +163,9 @@
template<typename... Params>
Node* appendNonTerminal(Graph&, SpeculatedType, Params...);
+ template<typename... Params>
+ Node* replaceTerminal(Graph&, SpeculatedType, Params...);
+
void dump(PrintStream& out) const;
void didLink()
Modified: trunk/Source/_javascript_Core/dfg/DFGBasicBlockInlines.h (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGBasicBlockInlines.h 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGBasicBlockInlines.h 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -45,10 +45,18 @@
Node* BasicBlock::appendNonTerminal(Graph& graph, SpeculatedType type, Params... params)
{
Node* result = graph.addNode(type, params...);
- insertBeforeLast(result);
+ insertBeforeTerminal(result);
return result;
}
+template<typename... Params>
+Node* BasicBlock::replaceTerminal(Graph& graph, SpeculatedType type, Params... params)
+{
+ Node* result = graph.addNode(type, params...);
+ replaceTerminal(result);
+ return result;
+}
+
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,4 +1,4 @@
- /*
+/*
* Copyright (C) 2011-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -622,40 +622,40 @@
return data;
}
+ Node* addToGraph(Node* node)
+ {
+ if (Options::verboseDFGByteCodeParsing())
+ dataLog(" appended ", node, " ", Graph::opName(node->op()), "\n");
+ m_currentBlock->append(node);
+ return node;
+ }
+
Node* addToGraph(NodeType op, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
{
Node* result = m_graph.addNode(
SpecNone, op, currentNodeOrigin(), Edge(child1), Edge(child2),
Edge(child3));
- ASSERT(op != Phi);
- m_currentBlock->append(result);
- return result;
+ return addToGraph(result);
}
Node* addToGraph(NodeType op, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
{
Node* result = m_graph.addNode(
SpecNone, op, currentNodeOrigin(), child1, child2, child3);
- ASSERT(op != Phi);
- m_currentBlock->append(result);
- return result;
+ return addToGraph(result);
}
Node* addToGraph(NodeType op, OpInfo info, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
{
Node* result = m_graph.addNode(
SpecNone, op, currentNodeOrigin(), info, Edge(child1), Edge(child2),
Edge(child3));
- ASSERT(op != Phi);
- m_currentBlock->append(result);
- return result;
+ return addToGraph(result);
}
Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
{
Node* result = m_graph.addNode(
SpecNone, op, currentNodeOrigin(), info1, info2,
Edge(child1), Edge(child2), Edge(child3));
- ASSERT(op != Phi);
- m_currentBlock->append(result);
- return result;
+ return addToGraph(result);
}
Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2)
@@ -663,8 +663,7 @@
Node* result = m_graph.addNode(
SpecNone, Node::VarArg, op, currentNodeOrigin(), info1, info2,
m_graph.m_varArgChildren.size() - m_numPassedVarArgs, m_numPassedVarArgs);
- ASSERT(op != Phi);
- m_currentBlock->append(result);
+ addToGraph(result);
m_numPassedVarArgs = 0;
@@ -1360,14 +1359,19 @@
// If there was a return, but no early returns, then we're done. We allow parsing of
// the caller to continue in whatever basic block we're in right now.
if (!inlineStackEntry.m_didEarlyReturn && inlineStackEntry.m_didReturn) {
- ASSERT(lastBlock->isEmpty() || !lastBlock->last()->isTerminal());
+ if (Options::verboseDFGByteCodeParsing())
+ dataLog(" Allowing parsing to continue in last inlined block.\n");
+ ASSERT(lastBlock->isEmpty() || !lastBlock->terminal());
+
// If we created new blocks then the last block needs linking, but in the
// caller. It doesn't need to be linked to, but it needs outgoing links.
if (!inlineStackEntry.m_unlinkedBlocks.isEmpty()) {
// For debugging purposes, set the bytecodeBegin. Note that this doesn't matter
// for release builds because this block will never serve as a potential target
// in the linker's binary search.
+ if (Options::verboseDFGByteCodeParsing())
+ dataLog(" Repurposing last block from ", lastBlock->bytecodeBegin, " to ", m_currentIndex, "\n");
lastBlock->bytecodeBegin = m_currentIndex;
if (callerLinkability == CallerDoesNormalLinking) {
if (verbose)
@@ -1380,8 +1384,11 @@
return;
}
+ if (Options::verboseDFGByteCodeParsing())
+ dataLog(" Creating new block after inlining.\n");
+
// If we get to this point then all blocks must end in some sort of terminals.
- ASSERT(lastBlock->last()->isTerminal());
+ ASSERT(lastBlock->terminal());
// Need to create a new basic block for the continuation at the caller.
RefPtr<BasicBlock> block = adoptRef(new BasicBlock(nextOffset, m_numArguments, m_numLocals, PNaN));
@@ -1392,7 +1399,7 @@
continue;
BasicBlock* blockToLink = inlineStackEntry.m_unlinkedBlocks[i].m_block;
ASSERT(!blockToLink->isLinked);
- Node* node = blockToLink->last();
+ Node* node = blockToLink->terminal();
ASSERT(node->op() == Jump);
ASSERT(!node->targetBlock());
node->targetBlock() = block.get();
@@ -1803,7 +1810,7 @@
m_currentBlock = continuationBlock.get();
for (unsigned i = landingBlocks.size(); i--;)
- landingBlocks[i]->last()->targetBlock() = continuationBlock.get();
+ landingBlocks[i]->terminal()->targetBlock() = continuationBlock.get();
m_currentIndex = oldOffset;
@@ -3129,9 +3136,9 @@
case op_jmp: {
int relativeOffset = currentInstruction[1].u.operand;
+ addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
if (relativeOffset <= 0)
flushForTerminal();
- addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
LAST_OPCODE(op_jmp);
}
@@ -3251,8 +3258,8 @@
continue;
data.cases.append(SwitchCase::withBytecodeIndex(m_graph.freeze(jsNumber(static_cast<int32_t>(table.min + i))), target));
}
+ addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
flushIfTerminal(data);
- addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
LAST_OPCODE(op_switch_imm);
}
@@ -3271,8 +3278,8 @@
data.cases.append(
SwitchCase::withBytecodeIndex(LazyJSValue::singleCharacterString(table.min + i), target));
}
+ addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
flushIfTerminal(data);
- addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
LAST_OPCODE(op_switch_char);
}
@@ -3291,14 +3298,14 @@
data.cases.append(
SwitchCase::withBytecodeIndex(LazyJSValue::knownStringImpl(iter->key.get()), target));
}
+ addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
flushIfTerminal(data);
- addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
LAST_OPCODE(op_switch_string);
}
case op_ret:
- flushForReturn();
if (inlineCallFrame()) {
+ flushForReturn();
if (m_inlineStackTop->m_returnValue.isValid())
setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush);
m_inlineStackTop->m_didReturn = true;
@@ -3322,12 +3329,13 @@
LAST_OPCODE(op_ret);
}
addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand)));
+ flushForReturn();
LAST_OPCODE(op_ret);
case op_end:
- flushForReturn();
ASSERT(!inlineCallFrame());
addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand)));
+ flushForReturn();
LAST_OPCODE(op_end);
case op_throw:
@@ -3854,7 +3862,7 @@
{
ASSERT(!block->isLinked);
ASSERT(!block->isEmpty());
- Node* node = block->last();
+ Node* node = block->terminal();
ASSERT(node->isTerminal());
switch (node->op()) {
@@ -4134,10 +4142,13 @@
// are at the end of an inline function, or we realized that we
// should stop parsing because there was a return in the first
// basic block.
- ASSERT(m_currentBlock->isEmpty() || m_currentBlock->last()->isTerminal() || (m_currentIndex == codeBlock->instructions().size() && inlineCallFrame()) || !shouldContinueParsing);
+ ASSERT(m_currentBlock->isEmpty() || m_currentBlock->terminal() || (m_currentIndex == codeBlock->instructions().size() && inlineCallFrame()) || !shouldContinueParsing);
- if (!shouldContinueParsing)
+ if (!shouldContinueParsing) {
+ if (Options::verboseDFGByteCodeParsing())
+ dataLog("Done parsing ", *codeBlock, "\n");
return;
+ }
m_currentBlock = 0;
} while (m_currentIndex < limit);
@@ -4145,6 +4156,9 @@
// Should have reached the end of the instructions.
ASSERT(m_currentIndex == codeBlock->instructions().size());
+
+ if (Options::verboseDFGByteCodeParsing())
+ dataLog("Done parsing ", *codeBlock, " (fell off end)\n");
}
bool ByteCodeParser::parse()
Modified: trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -59,7 +59,7 @@
continue;
ASSERT(block->isReachable);
- switch (block->last()->op()) {
+ switch (block->terminal()->op()) {
case Jump: {
// Successor with one predecessor -> merge.
if (block->successor(0)->predecessors.size() == 1) {
@@ -99,17 +99,19 @@
if (extremeLogging)
m_graph.dump();
m_graph.dethread();
-
- ASSERT(block->last()->isTerminal());
- NodeOrigin boundaryNodeOrigin = block->last()->origin;
- block->last()->convertToPhantom();
- ASSERT(block->last()->refCount() == 1);
-
+
+ Node* terminal = block->terminal();
+ ASSERT(terminal->isTerminal());
+ NodeOrigin boundaryNodeOrigin = terminal->origin;
+
jettisonBlock(block, jettisonedBlock, boundaryNodeOrigin);
-
- block->appendNode(
+
+ block->replaceTerminal(
m_graph, SpecNone, Jump, boundaryNodeOrigin,
OpInfo(targetBlock));
+
+ ASSERT(block->terminal());
+
}
innerChanged = outerChanged = true;
break;
@@ -129,7 +131,7 @@
}
case Switch: {
- SwitchData* data = ""
+ SwitchData* data = ""
// Prune out cases that end up jumping to default.
for (unsigned i = 0; i < data->cases.size(); ++i) {
@@ -149,8 +151,9 @@
}
// Switch on constant -> jettison all other targets and merge.
- if (block->last()->child1()->hasConstant()) {
- FrozenValue* value = block->last()->child1()->constant();
+ Node* terminal = block->terminal();
+ if (terminal->child1()->hasConstant()) {
+ FrozenValue* value = terminal->child1()->constant();
TriState found = FalseTriState;
BasicBlock* targetBlock = 0;
for (unsigned i = data->cases.size(); found == FalseTriState && i--;) {
@@ -166,10 +169,9 @@
ASSERT(targetBlock);
Vector<BasicBlock*, 1> jettisonedBlocks;
- for (unsigned i = block->numSuccessors(); i--;) {
- BasicBlock* jettisonedBlock = block->successor(i);
- if (jettisonedBlock != targetBlock)
- jettisonedBlocks.append(jettisonedBlock);
+ for (BasicBlock* successor : terminal->successors()) {
+ if (successor != targetBlock)
+ jettisonedBlocks.append(successor);
}
if (targetBlock->predecessors.size() == 1) {
@@ -183,11 +185,12 @@
m_graph.dump();
m_graph.dethread();
- NodeOrigin boundaryNodeOrigin = block->last()->origin;
- block->last()->convertToPhantom();
+ NodeOrigin boundaryNodeOrigin = terminal->origin;
+
for (unsigned i = jettisonedBlocks.size(); i--;)
jettisonBlock(block, jettisonedBlocks[i], boundaryNodeOrigin);
- block->appendNode(
+
+ block->replaceTerminal(
m_graph, SpecNone, Jump, boundaryNodeOrigin, OpInfo(targetBlock));
}
innerChanged = outerChanged = true;
@@ -253,13 +256,10 @@
m_graph.dethread();
mergeBlocks(block, targetBlock, noBlocks());
} else {
- Node* branch = block->last();
- ASSERT(branch->isTerminal());
+ Node* branch = block->terminal();
ASSERT(branch->op() == Branch || branch->op() == Switch);
- branch->convertToPhantom();
- ASSERT(branch->refCount() == 1);
-
- block->appendNode(
+
+ block->replaceTerminal(
m_graph, SpecNone, Jump, branch->origin, OpInfo(targetBlock));
}
}
@@ -318,10 +318,11 @@
// Remove the terminal of firstBlock since we don't need it anymore. Well, we don't
// really remove it; we actually turn it into a Phantom.
- ASSERT(firstBlock->last()->isTerminal());
- NodeOrigin boundaryNodeOrigin = firstBlock->last()->origin;
- firstBlock->last()->convertToPhantom();
- ASSERT(firstBlock->last()->refCount() == 1);
+ Node* terminal = firstBlock->terminal();
+ ASSERT(terminal->isTerminal());
+ NodeOrigin boundaryNodeOrigin = terminal->origin;
+ terminal->convertToPhantom();
+ ASSERT(terminal->refCount() == 1);
for (unsigned i = jettisonedBlocks.size(); i--;) {
BasicBlock* jettisonedBlock = jettisonedBlocks[i];
@@ -342,7 +343,7 @@
for (size_t i = 0; i < secondBlock->size(); ++i)
firstBlock->append(secondBlock->at(i));
- ASSERT(firstBlock->last()->isTerminal());
+ ASSERT(firstBlock->terminal()->isTerminal());
// Fix the predecessors of my new successors. This is tricky, since we are going to reset
// all predecessors anyway due to reachability analysis. But we need to fix the
Modified: trunk/Source/_javascript_Core/dfg/DFGCPSRethreadingPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGCPSRethreadingPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGCPSRethreadingPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -363,6 +363,10 @@
m_availableForOSR.operand(node->unlinkedLocal()) = node->child1();
break;
+ case ZombieHint:
+ m_availableForOSR.operand(node->unlinkedLocal()) = Edge();
+ break;
+
default:
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGCommon.h (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGCommon.h 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGCommon.h 2015-04-22 03:38:17 UTC (rev 183094)
@@ -274,6 +274,29 @@
JS_EXPORT_PRIVATE bool isCrashing();
+struct NodeAndIndex {
+ NodeAndIndex()
+ : node(nullptr)
+ , index(UINT_MAX)
+ {
+ }
+
+ NodeAndIndex(Node* node, unsigned index)
+ : node(node)
+ , index(index)
+ {
+ ASSERT(!node == (index == UINT_MAX));
+ }
+
+ bool operator!() const
+ {
+ return !node;
+ }
+
+ Node* node;
+ unsigned index;
+};
+
} } // namespace JSC::DFG
namespace WTF {
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -85,7 +85,7 @@
addPhantomsIfNecessary();
fixupNode(m_currentNode);
}
- clearPhantomsAtEnd();
+ addPhantomsIfNecessary();
m_insertionSet.execute(block);
}
@@ -725,9 +725,8 @@
else if (node->child1()->shouldSpeculateObjectOrOther())
fixEdge<ObjectOrOtherUse>(node->child1());
// FIXME: We should just be able to do shouldSpeculateInt32OrBoolean() and
- // shouldSpeculateNumberOrBoolean() here, but we can't because then the Branch
- // could speculate on the result of a non-speculative conversion node.
- // https://bugs.webkit.org/show_bug.cgi?id=126778
+ // shouldSpeculateNumberOrBoolean() here now that
+ // https://bugs.webkit.org/show_bug.cgi?id=126778 is fixed.
else if (node->child1()->shouldSpeculateInt32())
fixEdge<Int32Use>(node->child1());
else if (node->child1()->shouldSpeculateNumber())
@@ -1996,7 +1995,7 @@
tryToRelaxRepresentation(m_currentNode);
DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, injectTypeConversionsForEdge);
}
- clearPhantomsAtEnd();
+ addPhantomsIfNecessary();
m_insertionSet.execute(block);
}
@@ -2161,21 +2160,6 @@
m_requiredPhantoms.resize(0);
}
- void clearPhantomsAtEnd()
- {
- // Terminal nodes don't need post-phantoms, and inserting them would violate
- // the current requirement that a terminal is the last thing in a block. We
- // should eventually change that requirement. Currently we get around this by
- // ensuring that all terminals accept just one input, and if that input is a
- // conversion node then no further speculations will be performed. See
- // references to the bug, below, for places where we have to have hacks to
- // work around this.
- // FIXME: Get rid of this by allowing Phantoms after terminals.
- // https://bugs.webkit.org/show_bug.cgi?id=126778
-
- m_requiredPhantoms.resize(0);
- }
-
BasicBlock* m_block;
unsigned m_indexInBlock;
Node* m_currentNode;
Modified: trunk/Source/_javascript_Core/dfg/DFGForAllKills.h (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGForAllKills.h 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGForAllKills.h 2015-04-22 03:38:17 UTC (rev 183094)
@@ -48,13 +48,13 @@
functor(node);
}
- DFG_ASSERT(graph, block->last(), block->last()->origin.forExit.isSet());
+ DFG_ASSERT(graph, block->terminal(), block->terminal()->origin.forExit.isSet());
AvailabilityMap& availabilityMap = block->ssa->availabilityAtTail;
for (unsigned i = availabilityMap.m_locals.size(); i--;) {
VirtualRegister reg = availabilityMap.m_locals.virtualRegisterForIndex(i);
- if (!graph.isLiveInBytecode(reg, block->last()->origin.forExit))
+ if (!graph.isLiveInBytecode(reg, block->terminal()->origin.forExit))
continue;
availabilityMap.closeStartingWithLocal(
Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -365,6 +365,15 @@
out.print("\n");
}
+bool Graph::terminalsAreValid()
+{
+ for (BasicBlock* block : blocksInNaturalOrder()) {
+ if (!block->terminal())
+ return false;
+ }
+ return true;
+}
+
void Graph::dumpBlockHeader(PrintStream& out, const char* prefix, BasicBlock* block, PhiNodeDumpMode phiNodeDumpMode, DumpContext* context)
{
out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->origin.semantic, context), "):", block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n");
@@ -375,13 +384,16 @@
out.print(" ", *block->predecessors[i]);
out.print("\n");
out.print(prefix, " Successors:");
- for (BasicBlock* successor : block->successors()) {
- out.print(" ", *successor);
- if (m_prePostNumbering.isValid())
- out.print(" (", m_prePostNumbering.edgeKind(block, successor), ")");
- }
+ if (block->terminal()) {
+ for (BasicBlock* successor : block->successors()) {
+ out.print(" ", *successor);
+ if (m_prePostNumbering.isValid())
+ out.print(" (", m_prePostNumbering.edgeKind(block, successor), ")");
+ }
+ } else
+ out.print(" <invalid>");
out.print("\n");
- if (m_dominators.isValid()) {
+ if (m_dominators.isValid() && terminalsAreValid()) {
out.print(prefix, " Dominated by: ", m_dominators.dominatorsOf(block), "\n");
out.print(prefix, " Dominates: ", m_dominators.blocksDominatedBy(block), "\n");
out.print(prefix, " Dominance Frontier: ", m_dominators.dominanceFrontierOf(block), "\n");
Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGGraph.h 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h 2015-04-22 03:38:17 UTC (rev 183094)
@@ -196,6 +196,9 @@
// CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
void dump(PrintStream& = WTF::dataFile(), DumpContext* = 0);
+
+ bool terminalsAreValid();
+
enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis };
void dumpBlockHeader(PrintStream&, const char* prefix, BasicBlock*, PhiNodeDumpMode, DumpContext*);
void dump(PrintStream&, Edge);
Modified: trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -361,7 +361,7 @@
inline bool InPlaceAbstractState::mergeToSuccessors(BasicBlock* basicBlock)
{
- Node* terminal = basicBlock->last();
+ Node* terminal = basicBlock->terminal();
ASSERT(terminal->isTerminal());
Modified: trunk/Source/_javascript_Core/dfg/DFGLICMPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGLICMPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGLICMPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -128,7 +128,7 @@
preHeader = predecessor;
}
- DFG_ASSERT(m_graph, preHeader->last(), preHeader->last()->op() == Jump);
+ DFG_ASSERT(m_graph, preHeader->terminal(), preHeader->terminal()->op() == Jump);
data.preHeader = preHeader;
}
@@ -237,10 +237,10 @@
"\n");
}
- data.preHeader->insertBeforeLast(node);
+ data.preHeader->insertBeforeTerminal(node);
node->owner = data.preHeader;
NodeOrigin originalOrigin = node->origin;
- node->origin.forExit = data.preHeader->last()->origin.forExit;
+ node->origin.forExit = data.preHeader->terminal()->origin.forExit;
// Modify the states at the end of the preHeader of the loop we hoisted to,
// and all pre-headers inside the loop.
Modified: trunk/Source/_javascript_Core/dfg/DFGMovHintRemovalPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGMovHintRemovalPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGMovHintRemovalPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -82,7 +82,7 @@
for (unsigned i = m_state.size(); i--;) {
VirtualRegister reg = m_state.virtualRegisterForIndex(i);
- if (m_graph.isLiveInBytecode(reg, block->last()->origin.forExit))
+ if (m_graph.isLiveInBytecode(reg, block->terminal()->origin.forExit))
m_state[i] = currentEpoch;
else
m_state[i] = Epoch();
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1142,6 +1142,76 @@
}
}
+ class SuccessorsIterable {
+ public:
+ SuccessorsIterable()
+ : m_terminal(nullptr)
+ {
+ }
+
+ SuccessorsIterable(Node* terminal)
+ : m_terminal(terminal)
+ {
+ }
+
+ class iterator {
+ public:
+ iterator()
+ : m_terminal(nullptr)
+ , m_index(UINT_MAX)
+ {
+ }
+
+ iterator(Node* terminal, unsigned index)
+ : m_terminal(terminal)
+ , m_index(index)
+ {
+ }
+
+ BasicBlock* operator*()
+ {
+ return m_terminal->successor(m_index);
+ }
+
+ iterator& operator++()
+ {
+ m_index++;
+ return *this;
+ }
+
+ bool operator==(const iterator& other) const
+ {
+ return m_index == other.m_index;
+ }
+
+ bool operator!=(const iterator& other) const
+ {
+ return !(*this == other);
+ }
+ private:
+ Node* m_terminal;
+ unsigned m_index;
+ };
+
+ iterator begin()
+ {
+ return iterator(m_terminal, 0);
+ }
+
+ iterator end()
+ {
+ return iterator(m_terminal, m_terminal->numSuccessors());
+ }
+
+ private:
+ Node* m_terminal;
+ };
+
+ SuccessorsIterable successors()
+ {
+ return SuccessorsIterable(this);
+ }
+
BasicBlock*& successorForCondition(bool condition)
{
return branchData()->forCondition(condition);
Modified: trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -352,7 +352,7 @@
// already handled the case where the predecessor has multiple successors.
DFG_ASSERT(m_graph, block, block->numSuccessors() == 1);
- createMaterialize(allocation, block->last());
+ createMaterialize(allocation, block->terminal());
}
}
}
@@ -461,8 +461,9 @@
}
}
- size_t upsilonInsertionPoint = block->size() - 1;
- Node* upsilonWhere = block->last();
+ NodeAndIndex terminal = block->findTerminal();
+ size_t upsilonInsertionPoint = terminal.index;
+ Node* upsilonWhere = terminal.node;
NodeOrigin upsilonOrigin = upsilonWhere->origin;
for (BasicBlock* successorBlock : block->successors()) {
for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(successorBlock)) {
@@ -708,8 +709,9 @@
}
// Gotta drop some Upsilons.
- size_t upsilonInsertionPoint = block->size() - 1;
- NodeOrigin upsilonOrigin = block->last()->origin;
+ NodeAndIndex terminal = block->findTerminal();
+ size_t upsilonInsertionPoint = terminal.index;
+ NodeOrigin upsilonOrigin = terminal.node->origin;
for (BasicBlock* successorBlock : block->successors()) {
for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(successorBlock)) {
Node* phiNode = phiDef->value();
Modified: trunk/Source/_javascript_Core/dfg/DFGPhantomRemovalPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGPhantomRemovalPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGPhantomRemovalPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -90,6 +90,9 @@
Node* lastNode = nullptr;
if (sourceIndex > 1) {
lastNode = block->at(sourceIndex - 2);
+
+ // This doesn't need to specialize for Phantom. lastNode could be any node
+ // that isn't subject to DCE. But we keep it simple for now.
if (lastNode->op() != Phantom
|| lastNode->origin.forExit != node->origin.forExit)
lastNode = nullptr;
Modified: trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -441,8 +441,9 @@
} }
}
- size_t upsilonInsertionPoint = block->size() - 1;
- NodeOrigin upsilonOrigin = block->last()->origin;
+ NodeAndIndex terminal = block->findTerminal();
+ size_t upsilonInsertionPoint = terminal.index;
+ NodeOrigin upsilonOrigin = terminal.node->origin;
for (BasicBlock* successorBlock : block->successors()) {
for (SSACalculator::Def* phiDef : ssaCalculator.phisForBlock(successorBlock)) {
Node* phiNode = phiDef->value();
Modified: trunk/Source/_javascript_Core/dfg/DFGSSAConversionPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGSSAConversionPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGSSAConversionPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -335,8 +335,9 @@
// seems dangerous because the Upsilon will have a checking UseKind. But, we will not
// actually be performing the check at the point of the Upsilon; the check will
// already have been performed at the point where the original SetLocal was.
- size_t upsilonInsertionPoint = block->size() - 1;
- NodeOrigin upsilonOrigin = block->last()->origin;
+ NodeAndIndex terminal = block->findTerminal();
+ size_t upsilonInsertionPoint = terminal.index;
+ NodeOrigin upsilonOrigin = terminal.node->origin;
for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) {
BasicBlock* successorBlock = block->successor(successorIndex);
for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(successorBlock)) {
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2015-04-22 03:38:17 UTC (rev 183094)
@@ -681,7 +681,7 @@
}
// Check if the lastNode is a branch on this node.
- Node* lastNode = m_block->last();
+ Node* lastNode = m_block->terminal();
return lastNode->op() == Branch && lastNode->child1() == m_currentNode ? m_block->size() - 1 : UINT_MAX;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1832,11 +1832,14 @@
break;
}
- case MovHint:
- case ZombieHint: {
+ case MovHint: {
RELEASE_ASSERT_NOT_REACHED();
break;
}
+
+ case ZombieHint:
+ recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead);
+ break;
case SetLocal: {
switch (node->variableAccessData()->flushFormat()) {
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1932,7 +1932,7 @@
noResult(node);
break;
}
-
+
case SetLocal: {
switch (node->variableAccessData()->flushFormat()) {
case FlushedDouble: {
Modified: trunk/Source/_javascript_Core/dfg/DFGStaticExecutionCountEstimationPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGStaticExecutionCountEstimationPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGStaticExecutionCountEstimationPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -63,16 +63,17 @@
if (!block)
continue;
- switch (block->last()->op()) {
+ Node* terminal = block->terminal();
+ switch (terminal->op()) {
case Branch: {
- BranchData* data = ""
+ BranchData* data = ""
applyCounts(data->taken);
applyCounts(data->notTaken);
break;
}
case Switch: {
- SwitchData* data = ""
+ SwitchData* data = ""
for (unsigned i = data->cases.size(); i--;)
applyCounts(data->cases[i].target);
applyCounts(data->fallThrough);
Modified: trunk/Source/_javascript_Core/dfg/DFGTierUpCheckInjectionPhase.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGTierUpCheckInjectionPhase.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGTierUpCheckInjectionPhase.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -103,9 +103,10 @@
break;
}
- if (block->last()->op() == Return) {
+ NodeAndIndex terminal = block->findTerminal();
+ if (terminal.node->op() == Return) {
insertionSet.insertNode(
- block->size() - 1, SpecNone, CheckTierUpAtReturn, block->last()->origin);
+ terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node->origin);
}
insertionSet.execute(block);
Modified: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -189,10 +189,24 @@
V_EQUAL((node), m_myRefCounts.get(node), node->adjustedRefCount());
}
- for (size_t i = 0 ; i < block->size() - 1; ++i) {
+ bool foundTerminal = false;
+ for (size_t i = 0 ; i < block->size(); ++i) {
Node* node = block->at(i);
- VALIDATE((node), !node->isTerminal());
+ if (node->isTerminal()) {
+ foundTerminal = true;
+ for (size_t j = i + 1; j < block->size(); ++j) {
+ node = block->at(j);
+ VALIDATE((node), node->op() == Phantom || node->op() == PhantomLocal || node->op() == Flush);
+ m_graph.doToChildren(
+ node,
+ [&] (Edge edge) {
+ VALIDATE((node, edge), shouldNotHaveTypeCheck(edge.useKind()));
+ });
+ }
+ break;
+ }
}
+ VALIDATE((block), foundTerminal);
for (size_t i = 0; i < block->size(); ++i) {
Node* node = block->at(i);
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (183093 => 183094)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2015-04-22 03:38:17 UTC (rev 183094)
@@ -859,8 +859,11 @@
DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend");
break;
}
-
- if (!m_state.isValid() && !m_node->isTerminal()) {
+
+ if (m_node->isTerminal())
+ return false;
+
+ if (!m_state.isValid()) {
safelyInvalidateAfterTermination();
return false;
}
Added: trunk/Source/_javascript_Core/tests/stress/closure-call-exit.js (0 => 183094)
--- trunk/Source/_javascript_Core/tests/stress/closure-call-exit.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/closure-call-exit.js 2015-04-22 03:38:17 UTC (rev 183094)
@@ -0,0 +1,15 @@
+function foo(o, i) {
+ return o[i]();
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+ var result = foo([function() { return 42; }], 0);
+ if (result != 42)
+ throw "Error: bad result: " + result;
+}
+
+var result = foo([function() { return 43; }], 0);
+if (result != 43)
+ throw "Error: bad result at end: " + result;