Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (223085 => 223086)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2017-10-09 23:45:45 UTC (rev 223085)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2017-10-09 23:55:25 UTC (rev 223086)
@@ -68,21 +68,19 @@
namespace JSC { namespace DFG {
-namespace {
-
-#define PARSER_ASSERT(assertion, ...) do { \
- if (UNLIKELY(!(assertion))) { \
- WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
- CRASH_WITH_INFO(__VA_ARGS__); \
- } \
-} while (0)
-
-} // anonymous namespace
-
namespace DFGByteCodeParserInternal {
+#ifdef NDEBUG
static const bool verbose = false;
-}
+#else
+static const bool verbose = true;
+#endif
+} // namespace DFGByteCodeParserInternal
+#define VERBOSE_LOG(...) do { \
+if (DFGByteCodeParserInternal::verbose && Options::verboseDFGBytecodeParsing()) \
+dataLog(__VA_ARGS__); \
+} while (false)
+
class ConstantBufferKey {
public:
ConstantBufferKey()
@@ -181,7 +179,7 @@
}
// Parse a full CodeBlock of bytecode.
- bool parse();
+ void parse();
private:
struct InlineStackEntry;
@@ -191,6 +189,7 @@
void ensureLocals(unsigned newNumLocals)
{
+ VERBOSE_LOG(" ensureLocals: trying to raise m_numLocals from ", m_numLocals, " to ", newNumLocals, "\n");
if (newNumLocals <= m_numLocals)
return;
m_numLocals = newNumLocals;
@@ -203,16 +202,23 @@
bool handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& insertChecks);
void refineStatically(CallLinkStatus&, Node* callTarget);
+ // Blocks can either be targetable (i.e. in the m_blockLinkingTargets of one InlineStackEntry) with a well-defined bytecodeBegin,
+ // or they can be untargetable, with bytecodeBegin==UINT_MAX, to be managed manually and not by the linkBlock machinery.
+ // This is used most notably when doing polyvariant inlining (it requires a fair bit of control-flow with no bytecode analog).
+ // It is also used when doing an early return from an inlined callee: it is easier to fix the bytecode index later on if needed
+ // than to move the right index all the way to the treatment of op_ret.
+ BasicBlock* allocateTargetableBlock(unsigned bytecodeIndex);
+ BasicBlock* allocateUntargetableBlock();
+ // An untargetable block can be given a bytecodeIndex to be later managed by linkBlock, but only once, and it can never go in the other direction
+ void makeBlockTargetable(BasicBlock*, unsigned bytecodeIndex);
+ void addJumpTo(BasicBlock*);
+ void addJumpTo(unsigned bytecodeIndex);
// Handle calls. This resolves issues surrounding inlining and intrinsics.
enum Terminality { Terminal, NonTerminal };
Terminality handleCall(
int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize,
- Node* callTarget, int argCount, int registerOffset, CallLinkStatus,
+ Node* callTarget, int argumentCountIncludingThis, int registerOffset, CallLinkStatus,
SpeculatedType prediction);
- Terminality handleCall(
- int result, NodeType op, CallMode, unsigned instructionSize,
- Node* callTarget, int argCount, int registerOffset, CallLinkStatus);
- Terminality handleCall(int result, NodeType op, CallMode, unsigned instructionSize, int callee, int argCount, int registerOffset);
Terminality handleCall(Instruction* pc, NodeType op, CallMode);
Terminality handleVarargsCall(Instruction* pc, NodeType op, CallMode);
void emitFunctionChecks(CallVariant, Node* callTarget, VirtualRegister thisArgumnt);
@@ -221,11 +227,10 @@
unsigned inliningCost(CallVariant, int argumentCountIncludingThis, InlineCallFrame::Kind); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1.
// Handle inlining. Return true if it succeeded, false if we need to plant a call.
bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, VirtualRegister thisArgument, VirtualRegister argumentsArgument, unsigned argumentsOffset, int argumentCountIncludingThis, unsigned nextOffset, NodeType callOp, InlineCallFrame::Kind, SpeculatedType prediction);
- enum CallerLinkability { CallerDoesNormalLinking, CallerLinksManually };
template<typename ChecksFunctor>
- bool attemptToInlineCall(Node* callTargetNode, int resultOperand, CallVariant, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind, CallerLinkability, SpeculatedType prediction, unsigned& inliningBalance, const ChecksFunctor& insertChecks);
+ bool attemptToInlineCall(Node* callTargetNode, int resultOperand, CallVariant, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind, SpeculatedType prediction, unsigned& inliningBalance, const ChecksFunctor& insertChecks);
template<typename ChecksFunctor>
- void inlineCall(Node* callTargetNode, int resultOperand, CallVariant, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind, CallerLinkability, const ChecksFunctor& insertChecks);
+ void inlineCall(Node* callTargetNode, int resultOperand, CallVariant, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind, const ChecksFunctor& insertChecks);
void cancelLinkingForBlock(InlineStackEntry*, BasicBlock*); // Only works when the given block is the last one to have been added for that inline stack entry.
// Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
template<typename ChecksFunctor>
@@ -301,7 +306,7 @@
bool parseBlock(unsigned limit);
// Link block successors.
void linkBlock(BasicBlock*, Vector<BasicBlock*>& possibleTargets);
- void linkBlocks(Vector<UnlinkedBlock>& unlinkedBlocks, Vector<BasicBlock*>& possibleTargets);
+ void linkBlocks(Vector<BasicBlock*>& unlinkedBlocks, Vector<BasicBlock*>& possibleTargets);
VariableAccessData* newVariableAccessData(VirtualRegister operand)
{
@@ -752,8 +757,7 @@
Node* addToGraph(Node* node)
{
- if (Options::verboseDFGBytecodeParsing())
- dataLog(" appended ", node, " ", Graph::opName(node->op()), "\n");
+ VERBOSE_LOG(" appended ", node, " ", Graph::opName(node->op()), "\n");
m_currentBlock->append(node);
if (clobbersExitState(m_graph, node))
m_exitOK = false;
@@ -1115,33 +1119,24 @@
Vector<unsigned> m_constantBufferRemap;
Vector<unsigned> m_switchRemap;
- // Blocks introduced by this code block, which need successor linking.
- // May include up to one basic block that includes the continuation after
- // the callsite in the caller. These must be appended in the order that they
- // are created, but their bytecodeBegin values need not be in order as they
- // are ignored.
- Vector<UnlinkedBlock> m_unlinkedBlocks;
+ // These are blocks whose terminal is a Jump, Branch or Switch, and whose target has not yet been linked.
+ // Their terminal instead refers to a bytecode index, and the right BB can be found in m_blockLinkingTargets.
+ Vector<BasicBlock*> m_unlinkedBlocks;
// Potential block linking targets. Must be sorted by bytecodeBegin, and
// cannot have two blocks that have the same bytecodeBegin.
Vector<BasicBlock*> m_blockLinkingTargets;
- // If the callsite's basic block was split into two, then this will be
- // the head of the callsite block. It needs its successors linked to the
- // m_unlinkedBlocks, but not the other way around: there's no way for
- // any blocks in m_unlinkedBlocks to jump back into this block.
- BasicBlock* m_callsiteBlockHead;
-
- // Does the callsite block head need linking? This is typically true
- // but will be false for the machine code block's inline stack entry
- // (since that one is not inlined) and for cases where an inline callee
- // did the linking for us.
- bool m_callsiteBlockHeadNeedsLinking;
-
+ // This is set by op_enter in parseBlock(), and indicates the first block of the function.
+ BasicBlock* m_entryBlock;
+
+ // Optional: a continuation block for returns to jump to. It is set by early returns if it does not exist.
+ BasicBlock* m_continuationBlock;
+
VirtualRegister m_returnValue;
// Speculations about variable types collected from the profiled code block,
- // which are based on OSR exit profiles that past DFG compilatins of this
+ // which are based on OSR exit profiles that past DFG compilations of this
// code block had gathered.
LazyOperandValueProfileParser m_lazyOperands;
@@ -1149,13 +1144,6 @@
StubInfoMap m_stubInfos;
ByValInfoMap m_byValInfos;
- // Did we see any returns? We need to handle the (uncommon but necessary)
- // case where a procedure that does not return was inlined.
- bool m_didReturn;
-
- // Did we have any early returns?
- bool m_didEarlyReturn;
-
// Pointers to the argument position trackers for this slice of code.
Vector<ArgumentPosition*> m_argumentPositions;
@@ -1165,7 +1153,6 @@
ByteCodeParser*,
CodeBlock*,
CodeBlock* profiledBlock,
- BasicBlock* callsiteBlockHead,
JSFunction* callee, // Null if this is a closure call.
VirtualRegister returnValueVR,
VirtualRegister inlineCallFrameStart,
@@ -1203,7 +1190,7 @@
, m_value(value)
, m_setMode(setMode)
{
- PARSER_ASSERT(operand.isValid());
+ RELEASE_ASSERT(operand.isValid());
}
Node* execute(ByteCodeParser* parser)
@@ -1224,67 +1211,72 @@
bool m_hasDebuggerEnabled;
};
-// The idiom:
-// if (true) { ...; goto label; } else label: continue
-// Allows using NEXT_OPCODE as a statement, even in unbraced if+else, while containing a `continue`.
-// The more common idiom:
-// do { ...; } while (false)
-// Doesn't allow using `continue`.
-#define NEXT_OPCODE(name) \
- if (true) { \
- m_currentIndex += OPCODE_LENGTH(name); \
- goto WTF_CONCAT(NEXT_OPCODE_, __LINE__); /* Need a unique label: usable more than once per function. */ \
- } else \
- WTF_CONCAT(NEXT_OPCODE_, __LINE__): \
- continue
+BasicBlock* ByteCodeParser::allocateTargetableBlock(unsigned bytecodeIndex)
+{
+ ASSERT(bytecodeIndex != UINT_MAX);
+ Ref<BasicBlock> block = adoptRef(*new BasicBlock(bytecodeIndex, m_numArguments, m_numLocals, 1));
+ BasicBlock* blockPtr = block.ptr();
+ m_inlineStackTop->m_blockLinkingTargets.append(blockPtr);
+ m_graph.appendBlock(WTFMove(block));
+ return blockPtr;
+}
-// Chain expressions with comma-operator so LAST_OPCODE can be used as a statement.
-#define LAST_OPCODE(name) \
- return \
- m_currentIndex += OPCODE_LENGTH(name), \
- m_exitOK = false, \
- shouldContinueParsing
+BasicBlock* ByteCodeParser::allocateUntargetableBlock()
+{
+ Ref<BasicBlock> block = adoptRef(*new BasicBlock(UINT_MAX, m_numArguments, m_numLocals, 1));
+ BasicBlock* blockPtr = block.ptr();
+ m_graph.appendBlock(WTFMove(block));
+ return blockPtr;
+}
-ByteCodeParser::Terminality ByteCodeParser::handleCall(Instruction* pc, NodeType op, CallMode callMode)
+void ByteCodeParser::makeBlockTargetable(BasicBlock* block, unsigned bytecodeIndex)
{
- ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
- ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_tail_call));
- return handleCall(
- pc[1].u.operand, op, callMode, OPCODE_LENGTH(op_call),
- pc[2].u.operand, pc[3].u.operand, -pc[4].u.operand);
+ ASSERT(block->bytecodeBegin == UINT_MAX);
+ block->bytecodeBegin = bytecodeIndex;
+ m_inlineStackTop->m_blockLinkingTargets.append(block);
}
-ByteCodeParser::Terminality ByteCodeParser::handleCall(
- int result, NodeType op, CallMode callMode, unsigned instructionSize,
- int callee, int argumentCountIncludingThis, int registerOffset)
+void ByteCodeParser::addJumpTo(BasicBlock* block)
{
- Node* callTarget = get(VirtualRegister(callee));
+ ASSERT(!m_currentBlock->terminal());
+ Node* jumpNode = addToGraph(Jump);
+ jumpNode->targetBlock() = block;
+ m_currentBlock->didLink();
+}
+
+void ByteCodeParser::addJumpTo(unsigned bytecodeIndex)
+{
+ ASSERT(!m_currentBlock->terminal());
+ addToGraph(Jump, OpInfo(bytecodeIndex));
+ m_inlineStackTop->m_unlinkedBlocks.append(m_currentBlock);
+}
+
+ByteCodeParser::Terminality ByteCodeParser::handleCall(Instruction* pc, NodeType op, CallMode callMode)
+{
+ static_assert(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct),
+ "op_call, op_tail_call and op_construct should always have the same length");
+ static_assert(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_tail_call),
+ "op_call, op_tail_call and op_construct should always have the same length");
+ int result = pc[1].u.operand;
+ Node* callTarget = get(VirtualRegister(pc[2].u.operand));
+ int argumentCountIncludingThis = pc[3].u.operand;
+ int registerOffset = -pc[4].u.operand;
+
CallLinkStatus callLinkStatus = CallLinkStatus::computeFor(
m_inlineStackTop->m_profiledBlock, currentCodeOrigin(),
m_inlineStackTop->m_callLinkInfos, m_callContextMap);
-
- return handleCall(
- result, op, callMode, instructionSize, callTarget,
- argumentCountIncludingThis, registerOffset, callLinkStatus);
+
+ InlineCallFrame::Kind kind = InlineCallFrame::kindFor(callMode);
+
+ return handleCall(result, op, kind, OPCODE_LENGTH(op_call), callTarget,
+ argumentCountIncludingThis, registerOffset, callLinkStatus, getPrediction());
}
-
-ByteCodeParser::Terminality ByteCodeParser::handleCall(
- int result, NodeType op, CallMode callMode, unsigned instructionSize,
- Node* callTarget, int argumentCountIncludingThis, int registerOffset,
- CallLinkStatus callLinkStatus)
-{
- return handleCall(
- result, op, InlineCallFrame::kindFor(callMode), instructionSize, callTarget, argumentCountIncludingThis,
- registerOffset, callLinkStatus, getPrediction());
-}
void ByteCodeParser::refineStatically(CallLinkStatus& callLinkStatus, Node* callTarget)
{
- if (callTarget->isCellConstant()) {
+ if (callTarget->isCellConstant())
callLinkStatus.setProvenConstantCallee(CallVariant(callTarget->asCell()));
- return;
- }
}
ByteCodeParser::Terminality ByteCodeParser::handleCall(
@@ -1296,39 +1288,37 @@
refineStatically(callLinkStatus, callTarget);
- if (Options::verboseDFGBytecodeParsing())
- dataLog(" Handling call at ", currentCodeOrigin(), ": ", callLinkStatus, "\n");
+ VERBOSE_LOG(" Handling call at ", currentCodeOrigin(), ": ", callLinkStatus, "\n");
- if (!callLinkStatus.canOptimize()) {
- // Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically
- // that we cannot optimize them.
+ // We first check that we have profiling information about this call, and that it did not behave too polymorphically.
+ if (callLinkStatus.canOptimize()) {
+ VirtualRegister thisArgument = virtualRegisterForArgument(0, registerOffset);
- Node* callNode = addCall(result, op, nullptr, callTarget, argumentCountIncludingThis, registerOffset, prediction);
- if (callNode->op() == TailCall)
- return Terminal;
- ASSERT(callNode->op() != TailCallVarargs && callNode->op() != TailCallForwardVarargs);
- return NonTerminal;
+ // Inlining is quite complex, and managed by a pipeline of functions:
+ // handle(Varargs)Call -> handleInlining -> attemptToInlineCall -> inlineCall
+ // - handleCall and handleVarargsCall deal with the case where no inlining happens, and do some sanity checks on their arguments
+ // - handleInlining checks whether the call is polymorphic, and if so is responsible for inserting a switch on the callee
+ // - attemptToInlineCall deals with special cases such as intrinsics, it also checks the inlining heuristic (through inliningCost)
+ // - inlineCall finally does the actual inlining, after a complicated procedure to setup the stack correctly
+ unsigned nextOffset = m_currentIndex + instructionSize;
+ if (handleInlining(callTarget, result, callLinkStatus, registerOffset, thisArgument, VirtualRegister(), 0, argumentCountIncludingThis, nextOffset, op, kind, prediction)) {
+ if (UNLIKELY(m_graph.compilation()))
+ m_graph.compilation()->noticeInlinedCall();
+ return NonTerminal;
+ }
}
- unsigned nextOffset = m_currentIndex + instructionSize;
-
- if (handleInlining(callTarget, result, callLinkStatus, registerOffset, virtualRegisterForArgument(0, registerOffset), VirtualRegister(), 0, argumentCountIncludingThis, nextOffset, op, kind, prediction)) {
- if (UNLIKELY(m_graph.compilation()))
- m_graph.compilation()->noticeInlinedCall();
- return NonTerminal;
- }
-
Node* callNode = addCall(result, op, nullptr, callTarget, argumentCountIncludingThis, registerOffset, prediction);
- if (callNode->op() == TailCall)
- return Terminal;
ASSERT(callNode->op() != TailCallVarargs && callNode->op() != TailCallForwardVarargs);
- return NonTerminal;
+ return callNode->op() == TailCall ? Terminal : NonTerminal;
}
ByteCodeParser::Terminality ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CallMode callMode)
{
- ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_construct_varargs));
- ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_tail_call_varargs));
+ static_assert(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_construct_varargs),
+ "op_call_varargs, op_tail_call_varargs and op_construct_varargs should always have the same length");
+ static_assert(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_tail_call_varargs),
+ "op_call_varargs, op_tail_call_varargs and op_construct_varargs should always have the same length");
int result = pc[1].u.operand;
int callee = pc[2].u.operand;
@@ -1346,8 +1336,7 @@
m_inlineStackTop->m_callLinkInfos, m_callContextMap);
refineStatically(callLinkStatus, callTarget);
- if (Options::verboseDFGBytecodeParsing())
- dataLog(" Varargs call link status at ", currentCodeOrigin(), ": ", callLinkStatus, "\n");
+ VERBOSE_LOG(" Varargs call link status at ", currentCodeOrigin(), ": ", callLinkStatus, "\n");
if (callLinkStatus.canOptimize()
&& handleInlining(callTarget, result, callLinkStatus, firstFreeReg, VirtualRegister(thisReg), VirtualRegister(arguments), firstVarArgOffset, 0, m_currentIndex + OPCODE_LENGTH(op_call_varargs), op, InlineCallFrame::varargsKindFor(callMode), prediction)) {
@@ -1426,19 +1415,16 @@
{
CallMode callMode = InlineCallFrame::callModeFor(kind);
CodeSpecializationKind specializationKind = specializationKindFor(callMode);
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Considering inlining ", callee, " into ", currentCodeOrigin(), "\n");
+ VERBOSE_LOG("Considering inlining ", callee, " into ", currentCodeOrigin(), "\n");
if (m_hasDebuggerEnabled) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Failing because the debugger is in use.\n");
+ VERBOSE_LOG(" Failing because the debugger is in use.\n");
return UINT_MAX;
}
FunctionExecutable* executable = callee.functionExecutable();
if (!executable) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Failing because there is no function executable.\n");
+ VERBOSE_LOG(" Failing because there is no function executable.\n");
return UINT_MAX;
}
@@ -1451,15 +1437,13 @@
// it's a rare case because we expect that any hot callees would have already been compiled.
CodeBlock* codeBlock = executable->baselineCodeBlockFor(specializationKind);
if (!codeBlock) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Failing because no code block available.\n");
+ VERBOSE_LOG(" Failing because no code block available.\n");
return UINT_MAX;
}
if (!Options::useArityFixupInlining()) {
if (codeBlock->numParameters() > argumentCountIncludingThis) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Failing because of arity mismatch.\n");
+ VERBOSE_LOG(" Failing because of arity mismatch.\n");
return UINT_MAX;
}
}
@@ -1466,18 +1450,15 @@
CapabilityLevel capabilityLevel = inlineFunctionForCapabilityLevel(
codeBlock, specializationKind, callee.isClosureCall());
- if (DFGByteCodeParserInternal::verbose) {
- dataLog(" Call mode: ", callMode, "\n");
- dataLog(" Is closure call: ", callee.isClosureCall(), "\n");
- dataLog(" Capability level: ", capabilityLevel, "\n");
- dataLog(" Might inline function: ", mightInlineFunctionFor(codeBlock, specializationKind), "\n");
- dataLog(" Might compile function: ", mightCompileFunctionFor(codeBlock, specializationKind), "\n");
- dataLog(" Is supported for inlining: ", isSupportedForInlining(codeBlock), "\n");
- dataLog(" Is inlining candidate: ", codeBlock->ownerScriptExecutable()->isInliningCandidate(), "\n");
- }
+ VERBOSE_LOG(" Call mode: ", callMode, "\n");
+ VERBOSE_LOG(" Is closure call: ", callee.isClosureCall(), "\n");
+ VERBOSE_LOG(" Capability level: ", capabilityLevel, "\n");
+ VERBOSE_LOG(" Might inline function: ", mightInlineFunctionFor(codeBlock, specializationKind), "\n");
+ VERBOSE_LOG(" Might compile function: ", mightCompileFunctionFor(codeBlock, specializationKind), "\n");
+ VERBOSE_LOG(" Is supported for inlining: ", isSupportedForInlining(codeBlock), "\n");
+ VERBOSE_LOG(" Is inlining candidate: ", codeBlock->ownerScriptExecutable()->isInliningCandidate(), "\n");
if (!canInline(capabilityLevel)) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Failing because the function is not inlineable.\n");
+ VERBOSE_LOG(" Failing because the function is not inlineable.\n");
return UINT_MAX;
}
@@ -1486,8 +1467,7 @@
// purpose of unsetting SABI.
if (!isSmallEnoughToInlineCodeInto(m_codeBlock)) {
codeBlock->m_shouldAlwaysBeInlined = false;
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Failing because the caller is too large.\n");
+ VERBOSE_LOG(" Failing because the caller is too large.\n");
return UINT_MAX;
}
@@ -1510,8 +1490,7 @@
for (InlineStackEntry* entry = m_inlineStackTop; entry; entry = entry->m_caller) {
++depth;
if (depth >= Options::maximumInliningDepth()) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Failing because depth exceeded.\n");
+ VERBOSE_LOG(" Failing because depth exceeded.\n");
return UINT_MAX;
}
@@ -1518,15 +1497,13 @@
if (entry->executable() == executable) {
++recursion;
if (recursion >= Options::maximumInliningRecursion()) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Failing because recursion detected.\n");
+ VERBOSE_LOG(" Failing because recursion detected.\n");
return UINT_MAX;
}
}
}
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Inlining should be possible.\n");
+ VERBOSE_LOG(" Inlining should be possible.\n");
// It might be possible to inline.
return codeBlock->instructionCount();
@@ -1533,7 +1510,7 @@
}
template<typename ChecksFunctor>
-void ByteCodeParser::inlineCall(Node* callTargetNode, int resultOperand, CallVariant callee, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind kind, CallerLinkability callerLinkability, const ChecksFunctor& insertChecks)
+void ByteCodeParser::inlineCall(Node* callTargetNode, int resultOperand, CallVariant callee, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind kind, const ChecksFunctor& insertChecks)
{
CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
@@ -1578,8 +1555,6 @@
calleeVariable->mergeShouldNeverUnbox(true);
}
- Vector<std::pair<Node*, VirtualRegister>> delayedAritySets;
-
if (arityFixupCount) {
// Note: we do arity fixup in two phases:
// 1. We get all the values we need and MovHint them to the expected locals.
@@ -1630,10 +1605,9 @@
// our callee's frame. We emit an ExitOK below from the callee's CodeOrigin.
}
- InlineStackEntry inlineStackEntry(
- this, codeBlock, codeBlock, m_graph.lastBlock(), callee.function(), resultReg,
+ InlineStackEntry inlineStackEntry(this, codeBlock, codeBlock, callee.function(), resultReg,
(VirtualRegister)inlineCallFrameStart, argumentCountIncludingThis, kind);
-
+
// This is where the actual inlining really happens.
unsigned oldIndex = m_currentIndex;
m_currentIndex = 0;
@@ -1649,11 +1623,11 @@
inlineVariableData.argumentPositionStart = argumentPositionStart;
inlineVariableData.calleeVariable = 0;
- PARSER_ASSERT(
+ RELEASE_ASSERT(
m_inlineStackTop->m_inlineCallFrame->isClosureCall
== callee.isClosureCall());
if (callee.isClosureCall()) {
- PARSER_ASSERT(calleeVariable);
+ RELEASE_ASSERT(calleeVariable);
inlineVariableData.calleeVariable = calleeVariable;
}
@@ -1664,109 +1638,27 @@
m_currentIndex = oldIndex;
m_exitOK = false;
+
+ linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets);
- // If the inlined code created some new basic blocks, then we have linking to do.
- if (inlineStackEntry.m_callsiteBlockHead != m_graph.lastBlock()) {
-
- ASSERT(!inlineStackEntry.m_unlinkedBlocks.isEmpty());
- if (inlineStackEntry.m_callsiteBlockHeadNeedsLinking)
- linkBlock(inlineStackEntry.m_callsiteBlockHead, inlineStackEntry.m_blockLinkingTargets);
- else
- ASSERT(inlineStackEntry.m_callsiteBlockHead->isLinked);
-
- if (callerLinkability == CallerDoesNormalLinking)
- cancelLinkingForBlock(inlineStackEntry.m_caller, inlineStackEntry.m_callsiteBlockHead);
-
- linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets);
- } else
- ASSERT(inlineStackEntry.m_unlinkedBlocks.isEmpty());
-
- BasicBlock* lastBlock = m_graph.lastBlock();
- // 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) {
- 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 (DFGByteCodeParserInternal::verbose)
- dataLog("Adding unlinked block ", RawPointer(m_graph.lastBlock()), " (one return)\n");
- m_inlineStackTop->m_caller->m_unlinkedBlocks.append(UnlinkedBlock(m_graph.lastBlock()));
- }
- }
-
- m_currentBlock = m_graph.lastBlock();
- return;
+ // If the callee returned at least once, it prepared a continuation block for us.
+ if (inlineStackEntry.m_continuationBlock)
+ m_currentBlock = inlineStackEntry.m_continuationBlock;
+ else {
+ // We are in the case where the callee never returns (for example it loops forever).
+ // In that case, all blocks should end in a terminal.
+ ASSERT(m_graph.lastBlock()->terminal());
+ // We then allocate a new block to continue in.
+ m_currentBlock = allocateTargetableBlock(nextOffset);
}
+ ASSERT(m_currentBlock);
+ ASSERT(!m_currentBlock->terminal());
- 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->terminal());
-
- // Need to create a new basic block for the continuation at the caller.
- Ref<BasicBlock> block = adoptRef(*new BasicBlock(nextOffset, m_numArguments, m_numLocals, 1));
-
- // Link the early returns to the basic block we're about to create.
- for (size_t i = 0; i < inlineStackEntry.m_unlinkedBlocks.size(); ++i) {
- if (!inlineStackEntry.m_unlinkedBlocks[i].m_needsEarlyReturnLinking)
- continue;
- BasicBlock* blockToLink = inlineStackEntry.m_unlinkedBlocks[i].m_block;
- ASSERT(!blockToLink->isLinked);
- Node* node = blockToLink->terminal();
- ASSERT(node->op() == Jump);
- ASSERT(!node->targetBlock());
- node->targetBlock() = block.ptr();
- inlineStackEntry.m_unlinkedBlocks[i].m_needsEarlyReturnLinking = false;
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Marking ", RawPointer(blockToLink), " as linked (jumps to return)\n");
- blockToLink->didLink();
- }
-
- m_currentBlock = block.ptr();
- ASSERT(m_inlineStackTop->m_caller->m_blockLinkingTargets.isEmpty() || m_inlineStackTop->m_caller->m_blockLinkingTargets.last()->bytecodeBegin < nextOffset);
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Adding unlinked block ", RawPointer(block.ptr()), " (many returns)\n");
- if (callerLinkability == CallerDoesNormalLinking) {
- m_inlineStackTop->m_caller->m_unlinkedBlocks.append(UnlinkedBlock(block.ptr()));
- m_inlineStackTop->m_caller->m_blockLinkingTargets.append(block.ptr());
- }
- m_graph.appendBlock(WTFMove(block));
prepareToParseBlock();
}
-void ByteCodeParser::cancelLinkingForBlock(InlineStackEntry* inlineStackEntry, BasicBlock* block)
-{
- // It's possible that the callsite block head is not owned by the caller.
- if (!inlineStackEntry->m_unlinkedBlocks.isEmpty()) {
- // It's definitely owned by the caller, because the caller created new blocks.
- // Assert that this all adds up.
- ASSERT_UNUSED(block, inlineStackEntry->m_unlinkedBlocks.last().m_block == block);
- ASSERT(inlineStackEntry->m_unlinkedBlocks.last().m_needsNormalLinking);
- inlineStackEntry->m_unlinkedBlocks.last().m_needsNormalLinking = false;
- } else {
- // It's definitely not owned by the caller. Tell the caller that he does not
- // need to link his callsite block head, because we did it for him.
- ASSERT(inlineStackEntry->m_callsiteBlockHeadNeedsLinking);
- ASSERT_UNUSED(block, inlineStackEntry->m_callsiteBlockHead == block);
- inlineStackEntry->m_callsiteBlockHeadNeedsLinking = false;
- }
-}
-
template<typename ChecksFunctor>
-bool ByteCodeParser::attemptToInlineCall(Node* callTargetNode, int resultOperand, CallVariant callee, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind kind, CallerLinkability callerLinkability, SpeculatedType prediction, unsigned& inliningBalance, const ChecksFunctor& insertChecks)
+bool ByteCodeParser::attemptToInlineCall(Node* callTargetNode, int resultOperand, CallVariant callee, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind kind, SpeculatedType prediction, unsigned& inliningBalance, const ChecksFunctor& insertChecks)
{
CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
@@ -1773,8 +1665,7 @@
if (!inliningBalance)
return false;
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Considering callee ", callee, "\n");
+ VERBOSE_LOG(" Considering callee ", callee, "\n");
// Intrinsics and internal functions can only be inlined if we're not doing varargs. This is because
// we currently don't have any way of getting profiling information for arguments to non-JS varargs
@@ -1793,13 +1684,13 @@
if (InternalFunction* function = callee.internalFunction()) {
if (handleConstantInternalFunction(callTargetNode, resultOperand, function, registerOffset, argumentCountIncludingThis, specializationKind, prediction, insertChecksWithAccounting)) {
- PARSER_ASSERT(didInsertChecks);
+ RELEASE_ASSERT(didInsertChecks);
addToGraph(Phantom, callTargetNode);
emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
inliningBalance--;
return true;
}
- PARSER_ASSERT(!didInsertChecks);
+ RELEASE_ASSERT(!didInsertChecks);
return false;
}
@@ -1806,7 +1697,7 @@
Intrinsic intrinsic = callee.intrinsicFor(specializationKind);
if (intrinsic != NoIntrinsic) {
if (handleIntrinsicCall(callTargetNode, resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
- PARSER_ASSERT(didInsertChecks);
+ RELEASE_ASSERT(didInsertChecks);
addToGraph(Phantom, callTargetNode);
emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
inliningBalance--;
@@ -1813,7 +1704,7 @@
return true;
}
- PARSER_ASSERT(!didInsertChecks);
+ RELEASE_ASSERT(!didInsertChecks);
// We might still try to inline the Intrinsic because it might be a builtin JS function.
}
@@ -1820,13 +1711,13 @@
if (Options::useDOMJIT()) {
if (const DOMJIT::Signature* signature = callee.signatureFor(specializationKind)) {
if (handleDOMJITCall(callTargetNode, resultOperand, signature, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
- PARSER_ASSERT(didInsertChecks);
+ RELEASE_ASSERT(didInsertChecks);
addToGraph(Phantom, callTargetNode);
emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
inliningBalance--;
return true;
}
- PARSER_ASSERT(!didInsertChecks);
+ RELEASE_ASSERT(!didInsertChecks);
}
}
}
@@ -1836,7 +1727,7 @@
return false;
Instruction* savedCurrentInstruction = m_currentInstruction;
- inlineCall(callTargetNode, resultOperand, callee, registerOffset, argumentCountIncludingThis, nextOffset, kind, callerLinkability, insertChecks);
+ inlineCall(callTargetNode, resultOperand, callee, registerOffset, argumentCountIncludingThis, nextOffset, kind, insertChecks);
inliningBalance -= myInliningCost;
m_currentInstruction = savedCurrentInstruction;
return true;
@@ -1848,22 +1739,17 @@
VirtualRegister argumentsArgument, unsigned argumentsOffset, int argumentCountIncludingThis,
unsigned nextOffset, NodeType callOp, InlineCallFrame::Kind kind, SpeculatedType prediction)
{
- if (DFGByteCodeParserInternal::verbose) {
- dataLog("Handling inlining...\n");
- dataLog("Stack: ", currentCodeOrigin(), "\n");
- }
+ VERBOSE_LOG("Handling inlining...\nStack: ", currentCodeOrigin(), "\n");
CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
if (!callLinkStatus.size()) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Bailing inlining.\n");
+ VERBOSE_LOG("Bailing inlining.\n");
return false;
}
if (InlineCallFrame::isVarargs(kind)
&& callLinkStatus.maxNumArguments() > Options::maximumVarargsForInlining()) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Bailing inlining because of varargs.\n");
+ VERBOSE_LOG("Bailing inlining because of varargs.\n");
return false;
}
@@ -1908,7 +1794,7 @@
bool result = attemptToInlineCall(
callTargetNode, resultOperand, callLinkStatus[0], registerOffset,
- argumentCountIncludingThis, nextOffset, kind, CallerDoesNormalLinking, prediction,
+ argumentCountIncludingThis, nextOffset, kind, prediction,
inliningBalance, [&] (CodeBlock* codeBlock) {
emitFunctionChecks(callLinkStatus[0], callTargetNode, thisArgument);
@@ -1981,11 +1867,7 @@
}
}
});
- if (DFGByteCodeParserInternal::verbose) {
- dataLog("Done inlining (simple).\n");
- dataLog("Stack: ", currentCodeOrigin(), "\n");
- dataLog("Result: ", result, "\n");
- }
+ VERBOSE_LOG("Done inlining (simple).\nStack: ", currentCodeOrigin(), "\nResult: ", result, "\n");
return result;
}
@@ -1997,10 +1879,7 @@
// also.
if (!isFTL(m_graph.m_plan.mode) || !Options::usePolymorphicCallInlining()
|| InlineCallFrame::isVarargs(kind)) {
- if (DFGByteCodeParserInternal::verbose) {
- dataLog("Bailing inlining (hard).\n");
- dataLog("Stack: ", currentCodeOrigin(), "\n");
- }
+ VERBOSE_LOG("Bailing inlining (hard).\nStack: ", currentCodeOrigin(), "\n");
return false;
}
@@ -2009,15 +1888,10 @@
// it has no idea.
if (!Options::usePolymorphicCallInliningForNonStubStatus()
&& !callLinkStatus.isBasedOnStub()) {
- if (DFGByteCodeParserInternal::verbose) {
- dataLog("Bailing inlining (non-stub polymorphism).\n");
- dataLog("Stack: ", currentCodeOrigin(), "\n");
- }
+ VERBOSE_LOG("Bailing inlining (non-stub polymorphism).\nStack: ", currentCodeOrigin(), "\n");
return false;
}
-
- unsigned oldOffset = m_currentIndex;
-
+
bool allAreClosureCalls = true;
bool allAreDirectCalls = true;
for (unsigned i = callLinkStatus.size(); i--;) {
@@ -2026,7 +1900,7 @@
else
allAreClosureCalls = false;
}
-
+
Node* thingToSwitchOn;
if (allAreDirectCalls)
thingToSwitchOn = callTargetNode;
@@ -2037,30 +1911,22 @@
// where it would be beneficial. It might be best to handle these cases as if all calls were
// closure calls.
// https://bugs.webkit.org/show_bug.cgi?id=136020
- if (DFGByteCodeParserInternal::verbose) {
- dataLog("Bailing inlining (mix).\n");
- dataLog("Stack: ", currentCodeOrigin(), "\n");
- }
+ VERBOSE_LOG("Bailing inlining (mix).\nStack: ", currentCodeOrigin(), "\n");
return false;
}
-
- if (DFGByteCodeParserInternal::verbose) {
- dataLog("Doing hard inlining...\n");
- dataLog("Stack: ", currentCodeOrigin(), "\n");
- }
-
+
+ VERBOSE_LOG("Doing hard inlining...\nStack: ", currentCodeOrigin(), "\n");
+
int registerOffset = registerOffsetOrFirstFreeReg;
-
+
// This makes me wish that we were in SSA all the time. We need to pick a variable into which to
// store the callee so that it will be accessible to all of the blocks we're about to create. We
// get away with doing an immediate-set here because we wouldn't have performed any side effects
// yet.
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Register offset: ", registerOffset);
+ VERBOSE_LOG("Register offset: ", registerOffset);
VirtualRegister calleeReg(registerOffset + CallFrameSlot::callee);
calleeReg = m_inlineStackTop->remapOperand(calleeReg);
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Callee is going to be ", calleeReg, "\n");
+ VERBOSE_LOG("Callee is going to be ", calleeReg, "\n");
setDirect(calleeReg, callTargetNode, ImmediateSetWithFlush);
// It's OK to exit right now, even though we set some locals. That's because those locals are not
@@ -2071,13 +1937,8 @@
SwitchData& data = ""
data.kind = SwitchCell;
addToGraph(Switch, OpInfo(&data), thingToSwitchOn);
+ m_currentBlock->didLink();
- BasicBlock* originBlock = m_currentBlock;
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Marking ", RawPointer(originBlock), " as linked (origin of poly inline)\n");
- originBlock->didLink();
- cancelLinkingForBlock(m_inlineStackTop, originBlock);
-
// Each inlined callee will have a landing block that it returns at. They should all have jumps
// to the continuation block, which we create last.
Vector<BasicBlock*> landingBlocks;
@@ -2085,14 +1946,13 @@
// We may force this true if we give up on inlining any of the edges.
bool couldTakeSlowPath = callLinkStatus.couldTakeSlowPath();
- if (DFGByteCodeParserInternal::verbose)
- dataLog("About to loop over functions at ", currentCodeOrigin(), ".\n");
-
+ VERBOSE_LOG("About to loop over functions at ", currentCodeOrigin(), ".\n");
+
+ unsigned oldOffset = m_currentIndex;
for (unsigned i = 0; i < callLinkStatus.size(); ++i) {
m_currentIndex = oldOffset;
- Ref<BasicBlock> block = adoptRef(*new BasicBlock(UINT_MAX, m_numArguments, m_numLocals, 1));
- m_currentBlock = block.ptr();
- m_graph.appendBlock(block.copyRef());
+ BasicBlock* calleeEntryBlock = allocateUntargetableBlock();
+ m_currentBlock = calleeEntryBlock;
prepareToParseBlock();
Node* myCallTargetNode = getDirect(calleeReg);
@@ -2099,17 +1959,17 @@
bool inliningResult = attemptToInlineCall(
myCallTargetNode, resultOperand, callLinkStatus[i], registerOffset,
- argumentCountIncludingThis, nextOffset, kind, CallerLinksManually, prediction,
+ argumentCountIncludingThis, nextOffset, kind, prediction,
inliningBalance, [&] (CodeBlock*) { });
if (!inliningResult) {
// That failed so we let the block die. Nothing interesting should have been added to
// the block. We also give up on inlining any of the (less frequent) callees.
- ASSERT(m_currentBlock == block.ptr());
- ASSERT(m_graph.m_blocks.last() == block.ptr());
- m_graph.killBlockAndItsContents(block.ptr());
+ ASSERT(m_graph.m_blocks.last() == m_currentBlock);
+ m_graph.killBlockAndItsContents(m_currentBlock);
m_graph.m_blocks.removeLast();
-
+ VERBOSE_LOG("Inlining of a poly call failed, we will have to go through a slow path\n");
+
// The fact that inlining failed means we need a slow path.
couldTakeSlowPath = true;
break;
@@ -2122,7 +1982,7 @@
ASSERT(allAreClosureCalls);
thingToCaseOn = callLinkStatus[i].executable();
}
- data.cases.append(SwitchCase(m_graph.freeze(thingToCaseOn), block.ptr()));
+ data.cases.append(SwitchCase(m_graph.freeze(thingToCaseOn), calleeEntryBlock));
m_currentIndex = nextOffset;
m_exitOK = true;
processSetLocalQueue(); // This only comes into play for intrinsics, since normal inlined code will leave an empty queue.
@@ -2129,33 +1989,32 @@
if (Node* terminal = m_currentBlock->terminal())
ASSERT_UNUSED(terminal, terminal->op() == TailCall || terminal->op() == TailCallVarargs || terminal->op() == TailCallForwardVarargs);
else {
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=177926 we can avoid this indirection in the case of normal inlined call
+ // by passing the continuation block all the way into inlineStackEntry->m_continuationBlock in inlineCall.
+ // It is not trivial because of the SetLocalQueue managed by intrinsics.
addToGraph(Jump);
landingBlocks.append(m_currentBlock);
}
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Marking ", RawPointer(m_currentBlock), " as linked (tail of poly inlinee)\n");
+ VERBOSE_LOG("Marking ", RawPointer(m_currentBlock), " as linked (tail of poly inlinee)\n");
m_currentBlock->didLink();
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Finished inlining ", callLinkStatus[i], " at ", currentCodeOrigin(), ".\n");
+ VERBOSE_LOG("Finished inlining ", callLinkStatus[i], " at ", currentCodeOrigin(), ".\n");
}
- Ref<BasicBlock> slowPathBlock = adoptRef(
- *new BasicBlock(UINT_MAX, m_numArguments, m_numLocals, 1));
+ BasicBlock* slowPathBlock = allocateUntargetableBlock();
m_currentIndex = oldOffset;
m_exitOK = true;
- data.fallThrough = BranchTarget(slowPathBlock.ptr());
- m_graph.appendBlock(slowPathBlock.copyRef());
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Marking ", RawPointer(slowPathBlock.ptr()), " as linked (slow path block)\n");
+ data.fallThrough = BranchTarget(slowPathBlock);
+ VERBOSE_LOG("Marking ", RawPointer(slowPathBlock), " as linked (slow path block)\n");
slowPathBlock->didLink();
prepareToParseBlock();
- m_currentBlock = slowPathBlock.ptr();
+ m_currentBlock = slowPathBlock;
Node* myCallTargetNode = getDirect(calleeReg);
if (couldTakeSlowPath) {
addCall(
resultOperand, callOp, nullptr, myCallTargetNode, argumentCountIncludingThis,
registerOffset, prediction);
+ VERBOSE_LOG("We added a call in the slow path\n");
} else {
addToGraph(CheckBadCell);
addToGraph(Phantom, myCallTargetNode);
@@ -2162,6 +2021,7 @@
emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
set(VirtualRegister(resultOperand), addToGraph(BottomValue));
+ VERBOSE_LOG("coultTakeSlowPath was wrong\n");
}
m_currentIndex = nextOffset;
@@ -2173,26 +2033,22 @@
addToGraph(Jump);
landingBlocks.append(m_currentBlock);
}
-
- Ref<BasicBlock> continuationBlock = adoptRef(
- *new BasicBlock(UINT_MAX, m_numArguments, m_numLocals, 1));
- m_graph.appendBlock(continuationBlock.copyRef());
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Adding unlinked block ", RawPointer(continuationBlock.ptr()), " (continuation)\n");
- m_inlineStackTop->m_unlinkedBlocks.append(UnlinkedBlock(continuationBlock.ptr()));
+
+ // Continuation block
+ m_currentBlock = allocateUntargetableBlock();
+ VERBOSE_LOG("Adding untargetable block ", RawPointer(m_currentBlock), " (continuation)\n");
prepareToParseBlock();
- m_currentBlock = continuationBlock.ptr();
+
+ for (auto &landingBlock : landingBlocks) {
+ landingBlock->terminal()->targetBlock() = m_currentBlock;
+ landingBlock->didLink();
+ VERBOSE_LOG("We linked ", RawPointer(m_currentBlock), " (landing block) to the continuation block \n");
+ }
- for (unsigned i = landingBlocks.size(); i--;)
- landingBlocks[i]->terminal()->targetBlock() = continuationBlock.ptr();
-
m_currentIndex = oldOffset;
m_exitOK = true;
- if (DFGByteCodeParserInternal::verbose) {
- dataLog("Done inlining (hard).\n");
- dataLog("Stack: ", currentCodeOrigin(), "\n");
- }
+ VERBOSE_LOG("Done inlining (hard).\nStack: ", currentCodeOrigin(), "\n");
return true;
}
@@ -2229,8 +2085,7 @@
template<typename ChecksFunctor>
bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks)
{
- if (Options::verboseDFGBytecodeParsing())
- dataLog(" The intrinsic is ", intrinsic, "\n");
+ VERBOSE_LOG(" The intrinsic is ", intrinsic, "\n");
// It so happens that the code below doesn't handle the invalid result case. We could fix that, but
// it would only benefit intrinsics called as setters, like if you do:
@@ -3323,8 +3178,7 @@
Node* callTargetNode, int resultOperand, InternalFunction* function, int registerOffset,
int argumentCountIncludingThis, CodeSpecializationKind kind, SpeculatedType prediction, const ChecksFunctor& insertChecks)
{
- if (Options::verboseDFGBytecodeParsing())
- dataLog(" Handling constant internal function ", JSValue(function), "\n");
+ VERBOSE_LOG(" Handling constant internal function ", JSValue(function), "\n");
// It so happens that the code below assumes that the result operand is valid. It's extremely
// unlikely that the result operand would be invalid - you'd have to call this via a setter call.
@@ -3541,14 +3395,13 @@
GetByOffsetMethod ByteCodeParser::planLoad(const ObjectPropertyCondition& condition)
{
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Planning a load: ", condition, "\n");
+ VERBOSE_LOG("Planning a load: ", condition, "\n");
// We might promote this to Equivalence, and a later DFG pass might also do such promotion
// even if we fail, but for simplicity this cannot be asked to load an equivalence condition.
// None of the clients of this method will request a load of an Equivalence condition anyway,
// and supporting it would complicate the heuristics below.
- PARSER_ASSERT(condition.kind() == PropertyCondition::Presence);
+ RELEASE_ASSERT(condition.kind() == PropertyCondition::Presence);
// Here's the ranking of how to handle this, from most preferred to least preferred:
//
@@ -3651,14 +3504,13 @@
GetByOffsetMethod ByteCodeParser::planLoad(const ObjectPropertyConditionSet& conditionSet)
{
- if (DFGByteCodeParserInternal::verbose)
- dataLog("conditionSet = ", conditionSet, "\n");
+ VERBOSE_LOG("conditionSet = ", conditionSet, "\n");
GetByOffsetMethod result;
for (const ObjectPropertyCondition& condition : conditionSet) {
switch (condition.kind()) {
case PropertyCondition::Presence:
- PARSER_ASSERT(!result); // Should only see exactly one of these.
+ RELEASE_ASSERT(!result); // Should only see exactly one of these.
result = planLoad(condition);
if (!result)
return GetByOffsetMethod();
@@ -3833,7 +3685,7 @@
Node* ByteCodeParser::store(Node* base, unsigned identifier, const PutByIdVariant& variant, Node* value)
{
- PARSER_ASSERT(variant.kind() == PutByIdVariant::Replace);
+ RELEASE_ASSERT(variant.kind() == PutByIdVariant::Replace);
checkPresenceLike(base, m_graph.identifiers()[identifier], variant.offset(), variant.structure());
return handlePutByOffset(base, identifier, variant.offset(), variant.requiredType(), value);
@@ -4220,6 +4072,42 @@
return static_cast<uint64_t>(identifierNumber) | (static_cast<uint64_t>(getPutInfo) << 32);
}
+// The idiom:
+// if (true) { ...; goto label; } else label: continue
+// Allows using NEXT_OPCODE as a statement, even in unbraced if+else, while containing a `continue`.
+// The more common idiom:
+// do { ...; } while (false)
+// Doesn't allow using `continue`.
+#define NEXT_OPCODE(name) \
+ if (true) { \
+ m_currentIndex += OPCODE_LENGTH(name); \
+ goto WTF_CONCAT(NEXT_OPCODE_, __LINE__); /* Need a unique label: usable more than once per function. */ \
+ } else \
+ WTF_CONCAT(NEXT_OPCODE_, __LINE__): \
+ continue
+
+#define LAST_OPCODE_LINKED(name) \
+ return \
+ m_currentIndex += OPCODE_LENGTH(name), \
+ m_exitOK = false, \
+ shouldContinueParsing
+
+#define LAST_OPCODE(name) \
+ do { \
+ if (m_currentBlock->terminal()) { \
+ switch (m_currentBlock->terminal()->op()) { \
+ case Jump: \
+ case Branch: \
+ case Switch: \
+ ASSERT(!m_currentBlock->isLinked); \
+ m_inlineStackTop->m_unlinkedBlocks.append(m_currentBlock); \
+ break;\
+ default: break; \
+ } \
+ } \
+ LAST_OPCODE_LINKED(name); \
+ } while (false)
+
bool ByteCodeParser::parseBlock(unsigned limit)
{
bool shouldContinueParsing = true;
@@ -4232,7 +4120,7 @@
// opposed to using a value we set explicitly.
if (m_currentBlock == m_graph.block(0) && !inlineCallFrame()) {
auto addResult = m_graph.m_rootToArguments.add(m_currentBlock, ArgumentsVector());
- PARSER_ASSERT(addResult.isNewEntry);
+ RELEASE_ASSERT(addResult.isNewEntry);
ArgumentsVector& entrypointArguments = addResult.iterator->value;
entrypointArguments.resize(m_numArguments);
@@ -4254,7 +4142,7 @@
}
while (true) {
- // We're staring a new bytecode instruction. Hence, we once again have a place that we can exit
+ // We're staring at a new bytecode instruction. So we once again have a place that we can exit
// to.
m_exitOK = true;
@@ -4269,11 +4157,9 @@
// logic relies on every bytecode resulting in one or more nodes, which would
// be true anyway except for op_loop_hint, which emits a Phantom to force this
// to be true.
- // We also don't insert a jump if the block already has a terminal,
- // which could happen after a tail call.
- ASSERT(m_currentBlock->isEmpty() || !m_currentBlock->terminal());
+
if (!m_currentBlock->isEmpty())
- addToGraph(Jump, OpInfo(m_currentIndex));
+ addJumpTo(m_currentIndex);
return shouldContinueParsing;
}
@@ -4282,8 +4168,7 @@
m_currentInstruction = currentInstruction; // Some methods want to use this, and we'd rather not thread it through calls.
OpcodeID opcodeID = Interpreter::getOpcodeID(currentInstruction->u.opcode);
- if (Options::verboseDFGBytecodeParsing())
- dataLog(" parsing ", currentCodeOrigin(), ": ", opcodeID, "\n");
+ VERBOSE_LOG(" parsing ", currentCodeOrigin(), ": ", opcodeID, "\n");
if (UNLIKELY(m_graph.compilation())) {
addToGraph(CountExecution, OpInfo(m_graph.compilation()->executionCounterFor(
@@ -4299,6 +4184,9 @@
// Initialize all locals to undefined.
for (int i = 0; i < m_inlineStackTop->m_codeBlock->m_numVars; ++i)
set(virtualRegisterForLocal(i), undefined, ImmediateNakedSet);
+
+ m_inlineStackTop->m_entryBlock = m_currentBlock;
+
NEXT_OPCODE(op_enter);
}
@@ -5276,33 +5164,38 @@
case op_ret:
ASSERT(!m_currentBlock->terminal());
- if (inlineCallFrame()) {
+ if (!inlineCallFrame()) {
+ // Simple case: we are just producing a return
+ addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand)));
flushForReturn();
- if (m_inlineStackTop->m_returnValue.isValid())
- setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush);
- m_inlineStackTop->m_didReturn = true;
- if (m_inlineStackTop->m_unlinkedBlocks.isEmpty()) {
- // If we're returning from the first block, then we're done parsing.
- ASSERT(m_inlineStackTop->m_callsiteBlockHead == m_graph.lastBlock());
+ LAST_OPCODE(op_ret);
+ }
+
+ flushForReturn();
+ if (m_inlineStackTop->m_returnValue.isValid())
+ setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush);
+
+ if (!m_inlineStackTop->m_continuationBlock && m_currentIndex + OPCODE_LENGTH(op_ret) != m_inlineStackTop->m_codeBlock->instructions().size()) {
+ if (m_inlineStackTop->m_entryBlock == m_currentBlock) {
+ // This is a rather weird case: we are returning from the first block in the function, so all the rest of the function is dead code.
+ // So we treat this as a normal return instead of an early return, and signal to skip the rest of the function.
+ // FIXME https://bugs.webkit.org/show_bug.cgi?id=177925: evaluate whether that optimization is useful, it seems like a really weird corner case.
shouldContinueParsing = false;
- LAST_OPCODE(op_ret);
} else {
- // If inlining created blocks, and we're doing a return, then we need some
- // special linking.
- ASSERT(m_inlineStackTop->m_unlinkedBlocks.last().m_block == m_graph.lastBlock());
- m_inlineStackTop->m_unlinkedBlocks.last().m_needsNormalLinking = false;
+ // This is an early return from an inlined function and we do not have a continuation block, so we must allocate one.
+ // It is untargetable, because we do not know the appropriate index.
+ // If this block turns out to be a jump target, parseCodeBlock will fix its bytecodeIndex before putting it in m_blockLinkingTargets
+ m_inlineStackTop->m_continuationBlock = allocateUntargetableBlock();
}
- if (m_currentIndex + OPCODE_LENGTH(op_ret) != m_inlineStackTop->m_codeBlock->instructions().size() || m_inlineStackTop->m_didEarlyReturn) {
- ASSERT(m_currentIndex + OPCODE_LENGTH(op_ret) <= m_inlineStackTop->m_codeBlock->instructions().size());
- addToGraph(Jump, OpInfo(0));
- m_inlineStackTop->m_unlinkedBlocks.last().m_needsEarlyReturnLinking = true;
- m_inlineStackTop->m_didEarlyReturn = true;
- }
- LAST_OPCODE(op_ret);
}
- addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand)));
- flushForReturn();
- LAST_OPCODE(op_ret);
+
+ if (m_inlineStackTop->m_continuationBlock)
+ addJumpTo(m_inlineStackTop->m_continuationBlock);
+ else {
+ // We are returning from an inlined function, and do not need to jump anywhere, so we just keep the current block
+ m_inlineStackTop->m_continuationBlock = m_currentBlock;
+ }
+ LAST_OPCODE_LINKED(op_ret);
case op_end:
ASSERT(!inlineCallFrame());
@@ -5334,7 +5227,7 @@
NEXT_OPCODE(op_catch);
}
- PARSER_ASSERT(!m_currentBlock->size());
+ RELEASE_ASSERT(!m_currentBlock->size());
ValueProfileAndOperandBuffer* buffer = static_cast<ValueProfileAndOperandBuffer*>(currentInstruction[3].u.pointer);
@@ -5359,8 +5252,8 @@
if (operand.isLocal())
localPredictions.append(prediction);
else {
- PARSER_ASSERT(operand.isArgument());
- PARSER_ASSERT(static_cast<uint32_t>(operand.toArgument()) < argumentPredictions.size());
+ RELEASE_ASSERT(operand.isArgument());
+ RELEASE_ASSERT(static_cast<uint32_t>(operand.toArgument()) < argumentPredictions.size());
if (validationEnabled())
seenArguments.add(operand.toArgument());
argumentPredictions[operand.toArgument()] = prediction;
@@ -5369,7 +5262,7 @@
if (validationEnabled()) {
for (unsigned argument = 0; argument < m_numArguments; ++argument)
- PARSER_ASSERT(seenArguments.contains(argument));
+ RELEASE_ASSERT(seenArguments.contains(argument));
}
}
@@ -5410,7 +5303,7 @@
{
auto addResult = m_graph.m_rootToArguments.add(m_currentBlock, ArgumentsVector());
- PARSER_ASSERT(addResult.isNewEntry);
+ RELEASE_ASSERT(addResult.isNewEntry);
ArgumentsVector& entrypointArguments = addResult.iterator->value;
entrypointArguments.resize(m_numArguments);
@@ -5450,7 +5343,7 @@
Terminality terminality = handleCall(currentInstruction, TailCall, CallMode::Tail);
ASSERT_WITH_MESSAGE(m_currentInstruction == currentInstruction, "handleCall, which may have inlined the callee, trashed m_currentInstruction");
// If the call is terminal then we should not parse any further bytecodes as the TailCall will exit the function.
- // If the call is not terminal, however, then we want the subsequent op_ret/op_jump to update metadata and clean
+ // If the call is not terminal, however, then we want the subsequent op_ret/op_jmp to update metadata and clean
// things up.
if (terminality == NonTerminal)
NEXT_OPCODE(op_tail_call);
@@ -5474,7 +5367,7 @@
Terminality terminality = handleVarargsCall(currentInstruction, TailCallVarargs, CallMode::Tail);
ASSERT_WITH_MESSAGE(m_currentInstruction == currentInstruction, "handleVarargsCall, which may have inlined the callee, trashed m_currentInstruction");
// If the call is terminal then we should not parse any further bytecodes as the TailCall will exit the function.
- // If the call is not terminal, however, then we want the subsequent op_ret/op_jump to update metadata and clean
+ // If the call is not terminal, however, then we want the subsequent op_ret/op_jmp to update metadata and clean
// things up.
if (terminality == NonTerminal)
NEXT_OPCODE(op_tail_call_varargs);
@@ -5490,12 +5383,12 @@
Terminality terminality = handleVarargsCall(currentInstruction, TailCallForwardVarargs, CallMode::Tail);
ASSERT_WITH_MESSAGE(m_currentInstruction == currentInstruction, "handleVarargsCall, which may have inlined the callee, trashed m_currentInstruction");
// If the call is terminal then we should not parse any further bytecodes as the TailCall will exit the function.
- // If the call is not terminal, however, then we want the subsequent op_ret/op_jump to update metadata and clean
+ // If the call is not terminal, however, then we want the subsequent op_ret/op_jmp to update metadata and clean
// things up.
if (terminality == NonTerminal)
- NEXT_OPCODE(op_tail_call);
+ NEXT_OPCODE(op_tail_call_forward_arguments);
else
- LAST_OPCODE(op_tail_call);
+ LAST_OPCODE(op_tail_call_forward_arguments);
}
case op_construct_varargs: {
@@ -5555,8 +5448,8 @@
case GlobalLexicalVar:
case GlobalLexicalVarWithVarInjectionChecks: {
JSScope* constantScope = JSScope::constantScopeForCodeBlock(resolveType, m_inlineStackTop->m_codeBlock);
- PARSER_ASSERT(constantScope);
- PARSER_ASSERT(static_cast<JSScope*>(currentInstruction[6].u.pointer) == constantScope);
+ RELEASE_ASSERT(constantScope);
+ RELEASE_ASSERT(static_cast<JSScope*>(currentInstruction[6].u.pointer) == constantScope);
set(VirtualRegister(dst), weakJSConstant(constantScope));
addToGraph(Phantom, get(VirtualRegister(scope)));
break;
@@ -5897,7 +5790,7 @@
// Baseline->DFG OSR jumps between loop hints. The DFG assumes that Baseline->DFG
// OSR can only happen at basic block boundaries. Assert that these two statements
// are compatible.
- PARSER_ASSERT(m_currentIndex == blockBegin);
+ RELEASE_ASSERT(m_currentIndex == blockBegin);
// We never do OSR into an inlined code block. That could not happen, since OSR
// looks up the code block that is the replacement for the baseline JIT code
@@ -6244,25 +6137,18 @@
}
default:
- break;
+ RELEASE_ASSERT_NOT_REACHED();
}
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Marking ", RawPointer(block), " as linked (actually did linking)\n");
+ VERBOSE_LOG("Marking ", RawPointer(block), " as linked (actually did linking)\n");
block->didLink();
}
-void ByteCodeParser::linkBlocks(Vector<UnlinkedBlock>& unlinkedBlocks, Vector<BasicBlock*>& possibleTargets)
+void ByteCodeParser::linkBlocks(Vector<BasicBlock*>& unlinkedBlocks, Vector<BasicBlock*>& possibleTargets)
{
for (size_t i = 0; i < unlinkedBlocks.size(); ++i) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog("Attempting to link ", RawPointer(unlinkedBlocks[i].m_block), "\n");
- if (unlinkedBlocks[i].m_needsNormalLinking) {
- if (DFGByteCodeParserInternal::verbose)
- dataLog(" Does need normal linking.\n");
- linkBlock(unlinkedBlocks[i].m_block, possibleTargets);
- unlinkedBlocks[i].m_needsNormalLinking = false;
- }
+ VERBOSE_LOG("Attempting to link ", RawPointer(unlinkedBlocks[i]), "\n");
+ linkBlock(unlinkedBlocks[i], possibleTargets);
}
}
@@ -6270,7 +6156,6 @@
ByteCodeParser* byteCodeParser,
CodeBlock* codeBlock,
CodeBlock* profiledBlock,
- BasicBlock* callsiteBlockHead,
JSFunction* callee, // Null if this is a closure call.
VirtualRegister returnValueVR,
VirtualRegister inlineCallFrameStart,
@@ -6279,10 +6164,8 @@
: m_byteCodeParser(byteCodeParser)
, m_codeBlock(codeBlock)
, m_profiledBlock(profiledBlock)
- , m_callsiteBlockHead(callsiteBlockHead)
+ , m_continuationBlock(nullptr)
, m_returnValue(returnValueVR)
- , m_didReturn(false)
- , m_didEarlyReturn(false)
, m_caller(byteCodeParser->m_inlineStackTop)
{
{
@@ -6312,7 +6195,6 @@
// Inline case.
ASSERT(codeBlock != byteCodeParser->m_codeBlock);
ASSERT(inlineCallFrameStart.isValid());
- ASSERT(callsiteBlockHead);
m_inlineCallFrame = byteCodeParser->m_graph.m_plan.inlineCallFrames->add();
@@ -6357,7 +6239,6 @@
m_switchRemap[i] = byteCodeParser->m_codeBlock->numberOfSwitchJumpTables();
byteCodeParser->m_codeBlock->addSwitchJumpTable() = codeBlock->switchJumpTable(i);
}
- m_callsiteBlockHeadNeedsLinking = true;
} else {
// Machine code block case.
ASSERT(codeBlock == byteCodeParser->m_codeBlock);
@@ -6364,7 +6245,6 @@
ASSERT(!callee);
ASSERT(!returnValueVR.isValid());
ASSERT(!inlineCallFrameStart.isValid());
- ASSERT(!callsiteBlockHead);
m_inlineCallFrame = 0;
@@ -6377,7 +6257,6 @@
m_constantBufferRemap[i] = i;
for (size_t i = 0; i < codeBlock->numberOfSwitchJumpTables(); ++i)
m_switchRemap[i] = i;
- m_callsiteBlockHeadNeedsLinking = false;
}
byteCodeParser->m_inlineStackTop = this;
@@ -6432,47 +6311,20 @@
// Loop until we reach the current limit (i.e. next jump target).
do {
+ // There may already be a currentBlock in two cases:
+ // - we may have just entered the loop for the first time
+ // - we may have just returned from an inlined callee that had some early returns and
+ // so allocated a continuation block, and the instruction after the call is a jump target.
+ // In both cases, we want to keep using it.
if (!m_currentBlock) {
- // Check if we can use the last block.
- if (m_graph.numBlocks() && m_graph.lastBlock()->isEmpty()) {
- // This must be a block belonging to us.
- ASSERT(m_inlineStackTop->m_unlinkedBlocks.last().m_block == m_graph.lastBlock());
- // Either the block is linkable or it isn't. If it's linkable then it's the last
- // block in the blockLinkingTargets list. If it's not then the last block will
- // have a lower bytecode index that the one we're about to give to this block.
- if (m_inlineStackTop->m_blockLinkingTargets.isEmpty() || m_inlineStackTop->m_blockLinkingTargets.last()->bytecodeBegin != m_currentIndex) {
- // Make the block linkable.
- ASSERT(m_inlineStackTop->m_blockLinkingTargets.isEmpty() || m_inlineStackTop->m_blockLinkingTargets.last()->bytecodeBegin < m_currentIndex);
- m_inlineStackTop->m_blockLinkingTargets.append(m_graph.lastBlock());
- }
- // Change its bytecode begin and continue.
- m_currentBlock = m_graph.lastBlock();
- m_currentBlock->bytecodeBegin = m_currentIndex;
- } else {
- Ref<BasicBlock> block = adoptRef(*new BasicBlock(m_currentIndex, m_numArguments, m_numLocals, 1));
- m_currentBlock = block.ptr();
- // This assertion checks two things:
- // 1) If the bytecodeBegin is greater than currentIndex, then something has gone
- // horribly wrong. So, we're probably generating incorrect code.
- // 2) If the bytecodeBegin is equal to the currentIndex, then we failed to do
- // a peephole coalescing of this block in the if statement above. So, we're
- // generating suboptimal code and leaving more work for the CFG simplifier.
- if (!m_inlineStackTop->m_unlinkedBlocks.isEmpty()) {
- unsigned lastBegin =
- m_inlineStackTop->m_unlinkedBlocks.last().m_block->bytecodeBegin;
- ASSERT_UNUSED(
- lastBegin, lastBegin == UINT_MAX || lastBegin < m_currentIndex);
- }
- m_inlineStackTop->m_unlinkedBlocks.append(UnlinkedBlock(block.ptr()));
- m_inlineStackTop->m_blockLinkingTargets.append(block.ptr());
- // The first block is definitely an OSR target.
- if (!m_graph.numBlocks()) {
- block->isOSRTarget = true;
- m_graph.m_roots.append(block.ptr());
- }
- m_graph.appendBlock(WTFMove(block));
- prepareToParseBlock();
+ m_currentBlock = allocateTargetableBlock(m_currentIndex);
+
+ // The first block is definitely an OSR target.
+ if (m_graph.numBlocks() == 1) {
+ m_currentBlock->isOSRTarget = true;
+ m_graph.m_roots.append(m_currentBlock);
}
+ prepareToParseBlock();
}
bool shouldContinueParsing = parseBlock(limit);
@@ -6479,21 +6331,22 @@
// We should not have gone beyond the limit.
ASSERT(m_currentIndex <= limit);
-
- // We should have planted a terminal, or we just gave up because
- // we realized that the jump target information is imprecise, or we
- // 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->terminal() || (m_currentIndex == codeBlock->instructions().size() && inlineCallFrame()) || !shouldContinueParsing);
if (!shouldContinueParsing) {
- if (Options::verboseDFGBytecodeParsing())
- dataLog("Done parsing ", *codeBlock, "\n");
+ VERBOSE_LOG("Done parsing ", *codeBlock, "\n");
return;
}
-
- m_currentBlock = nullptr;
+
+ if (m_currentBlock->isEmpty()) {
+ // This case only happens if the last instruction was an inlined call with early returns
+ // or polymorphic (creating an empty continuation block),
+ // and then we hit the limit before putting anything in the continuation block.
+ ASSERT(m_currentIndex == limit);
+ makeBlockTargetable(m_currentBlock, m_currentIndex);
+ } else {
+ ASSERT(m_currentBlock->terminal() || (m_currentIndex == codeBlock->instructions().size() && inlineCallFrame()));
+ m_currentBlock = nullptr;
+ }
} while (m_currentIndex < limit);
}
@@ -6500,17 +6353,15 @@
// 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");
+ VERBOSE_LOG("Done parsing ", *codeBlock, " (fell off end)\n");
}
-bool ByteCodeParser::parse()
+void ByteCodeParser::parse()
{
// Set during construction.
ASSERT(!m_currentIndex);
- if (Options::verboseDFGBytecodeParsing())
- dataLog("Parsing ", *m_codeBlock, "\n");
+ VERBOSE_LOG("Parsing ", *m_codeBlock, "\n");
m_dfgCodeBlock = m_graph.m_plan.profiledDFGCodeBlock;
if (isFTL(m_graph.m_plan.mode) && m_dfgCodeBlock
@@ -6522,7 +6373,7 @@
}
InlineStackEntry inlineStackEntry(
- this, m_codeBlock, m_profiledBlock, 0, 0, VirtualRegister(), VirtualRegister(),
+ this, m_codeBlock, m_profiledBlock, 0, VirtualRegister(), VirtualRegister(),
m_codeBlock->numParameters(), InlineCallFrame::Call);
parseCodeBlock();
@@ -6529,6 +6380,8 @@
linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets);
m_graph.determineReachability();
+ if (Options::verboseDFGBytecodeParsing())
+ m_graph.dump();
m_graph.killUnreachableBlocks();
for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
@@ -6543,13 +6396,11 @@
m_graph.m_localVars = m_numLocals;
m_graph.m_parameterSlots = m_parameterSlots;
-
- return true;
}
-bool parse(Graph& graph)
+void parse(Graph& graph)
{
- return ByteCodeParser(graph).parse();
+ ByteCodeParser(graph).parse();
}
} } // namespace JSC::DFG