Inlining of a function that ends in op_unreachable crashes
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGByteCodeParser.cpp
index ea3afa5da697d5b4d4fed71660f6aaa0d952ee03..0f7f77aa1d2c770487ea9fd78439283cb61f3a9b 100644 (file)
@@ -139,6 +139,7 @@ private:
     // 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);
     // 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* allocateTargetableBlock(InlineStackEntry*, 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);
     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);
@@ -1143,14 +1144,19 @@ private:
 };
 
 BasicBlock* ByteCodeParser::allocateTargetableBlock(unsigned bytecodeIndex)
 };
 
 BasicBlock* ByteCodeParser::allocateTargetableBlock(unsigned bytecodeIndex)
+{
+    return allocateTargetableBlock(m_inlineStackTop, bytecodeIndex);
+}
+
+BasicBlock* ByteCodeParser::allocateTargetableBlock(InlineStackEntry* stackEntry, unsigned bytecodeIndex)
 {
     ASSERT(bytecodeIndex != UINT_MAX);
     Ref<BasicBlock> block = adoptRef(*new BasicBlock(bytecodeIndex, m_numArguments, m_numLocals, 1));
     BasicBlock* blockPtr = block.ptr();
     // m_blockLinkingTargets must always be sorted in increasing order of bytecodeBegin
 {
     ASSERT(bytecodeIndex != UINT_MAX);
     Ref<BasicBlock> block = adoptRef(*new BasicBlock(bytecodeIndex, m_numArguments, m_numLocals, 1));
     BasicBlock* blockPtr = block.ptr();
     // m_blockLinkingTargets must always be sorted in increasing order of bytecodeBegin
-    if (m_inlineStackTop->m_blockLinkingTargets.size())
-        ASSERT(m_inlineStackTop->m_blockLinkingTargets.last()->bytecodeBegin < bytecodeIndex);
-    m_inlineStackTop->m_blockLinkingTargets.append(blockPtr);
+    if (stackEntry->m_blockLinkingTargets.size())
+        ASSERT(stackEntry->m_blockLinkingTargets.last()->bytecodeBegin < bytecodeIndex);
+    stackEntry->m_blockLinkingTargets.append(blockPtr);
     m_graph.appendBlock(WTFMove(block));
     return blockPtr;
 }
     m_graph.appendBlock(WTFMove(block));
     return blockPtr;
 }
@@ -1652,11 +1658,13 @@ void ByteCodeParser::inlineCall(Node* callTargetNode, int resultOperand, CallVar
 
     linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets);
     
 
     linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets);
     
-    // There is an invariant that we use here: every function has at least one op_ret somewhere.
-    // And when parseBlock encounters an op_ret, it setups a continuation block if there was none.
-    // If this invariant was to be changed, we would need to allocate a new block here in the case where there was no continuation block ready.
-    RELEASE_ASSERT(inlineStackEntry.m_continuationBlock);
-    m_currentBlock = inlineStackEntry.m_continuationBlock;
+    // Most functions have at least one op_ret and thus set up the continuation block.
+    // In some rare cases, a function ends in op_unreachable, forcing us to allocate a new continuationBlock here.
+    // We must be careful to allocate it in the caller and not the top of the inline stack, since the callee is still on the stack at this point.
+    if (inlineStackEntry.m_continuationBlock)
+        m_currentBlock = inlineStackEntry.m_continuationBlock;
+    else
+        m_currentBlock = allocateTargetableBlock(inlineStackEntry.m_caller, m_currentIndex);
     ASSERT(!m_currentBlock->terminal());
 
     prepareToParseBlock();
     ASSERT(!m_currentBlock->terminal());
 
     prepareToParseBlock();