Source/JavaScriptCore: DFG inlining breaks function.arguments[something] if the argument being
retrieved was subjected to DFG's unboxing optimizations
https://bugs.webkit.org/show_bug.cgi?id=71436

Reviewed by Oliver Hunt.
        
This makes inlined arguments retrieval use some of the same machinery as
OSR to determine where from, and how, to retrieve a value that the DFG
might have somehow squirreled away while the old JIT would put it in its
obvious location, using an obvious format.
        
To that end, previously DFG-internal notions such as DataFormat,
VirtualRegister, and ValueRecovery are now in bytecode/ since they are
stored as part of InlineCallFrames.

* bytecode/CodeOrigin.h:
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::exitSpeculativeWithOSR):
* dfg/DFGJITCompiler32_64.cpp:
(JSC::DFG::JITCompiler::exitSpeculativeWithOSR):
* dfg/DFGNode.h:
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::propagateNodePredictions):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* interpreter/CallFrame.cpp:
(JSC::CallFrame::trueCallerFrame):
* interpreter/CallFrame.h:
(JSC::ExecState::inlineCallFrame):
* interpreter/Register.h:
(JSC::Register::asInlineCallFrame):
(JSC::Register::unboxedInt32):
(JSC::Register::unboxedBoolean):
(JSC::Register::unboxedCell):
* runtime/Arguments.h:
(JSC::Arguments::finishCreationAndCopyRegisters):

LayoutTests: DFG inlining breaks function.arguments[something] if the argument being
retrieved was subjected to DFG's unboxing optimizations
https://bugs.webkit.org/show_bug.cgi?id=71436        

Reviewed by Oliver Hunt.

* fast/js/dfg-inline-arguments-int32-expected.txt: Added.
* fast/js/dfg-inline-arguments-int32.html: Added.
* fast/js/script-tests/dfg-inline-arguments-int32.js: Added.
(foo):
(bar):
(baz):
(argsToStr):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@99148 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 329db61..00ad7ce 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -659,6 +659,7 @@
         break;
             
     case Phantom:
+    case InlineStart:
         break;
     }
     
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 0c99438..2c8368f 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1003,7 +1003,11 @@
     // This is where the actual inlining really happens.
     unsigned oldIndex = m_currentIndex;
     m_currentIndex = 0;
+
+    addToGraph(InlineStart);
+    
     parseCodeBlock();
+    
     m_currentIndex = oldIndex;
     
     // If the inlined code created some new basic blocks, then we have linking to do.
@@ -2326,7 +2330,7 @@
         inlineCallFrame.stackOffset = inlineCallFrameStart + RegisterFile::CallFrameHeaderSize;
         inlineCallFrame.callee.set(*byteCodeParser->m_globalData, byteCodeParser->m_codeBlock->ownerExecutable(), callee);
         inlineCallFrame.caller = byteCodeParser->currentCodeOrigin();
-        inlineCallFrame.numArgumentsIncludingThis = codeBlock->m_numParameters;
+        inlineCallFrame.arguments.resize(codeBlock->m_numParameters); // Set the number of arguments including this, but don't configure the value recoveries, yet.
         inlineCallFrame.isCall = isCall(kind);
         byteCodeParser->m_codeBlock->inlineCallFrames().append(inlineCallFrame);
         m_inlineCallFrame = &byteCodeParser->m_codeBlock->inlineCallFrames().last();
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index 87537f5..466b5aa 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -783,7 +783,7 @@
         storePtr(TrustedImmPtr(inlineCallFrame->callee->scope()), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ScopeChain)));
         storePtr(callerFrameGPR, addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::CallerFrame)));
         storePtr(TrustedImmPtr(jumpTarget), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ReturnPC)));
-        storePtr(TrustedImmPtr(JSValue::encode(jsNumber(inlineCallFrame->numArgumentsIncludingThis))), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ArgumentCount)));
+        storePtr(TrustedImmPtr(JSValue::encode(jsNumber(inlineCallFrame->arguments.size()))), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ArgumentCount)));
         storePtr(TrustedImmPtr(inlineCallFrame->callee.get()), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee)));
     }
     
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler32_64.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler32_64.cpp
index fce5ddb3..a6868f4 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler32_64.cpp
@@ -528,7 +528,7 @@
         storePtr(callerFrameGPR, payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::CallerFrame)));
         storePtr(TrustedImmPtr(jumpTarget), payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ReturnPC)));
         store32(Imm32(JSValue::Int32Tag), tagFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ArgumentCount)));
-        store32(Imm32(inlineCallFrame->numArgumentsIncludingThis), payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ArgumentCount)));
+        store32(Imm32(inlineCallFrame->arguments.size()), payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ArgumentCount)));
         store32(Imm32(JSValue::CellTag), tagFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee)));
         storePtr(TrustedImmPtr(inlineCallFrame->callee.get()), payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee)));
     }
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index d4726d0..f261a63 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -220,6 +220,11 @@
     /* Marker for arguments being set. */\
     macro(SetArgument, 0) \
     \
+    /* Hint that inlining begins here. No code is generated for this node. It's only */\
+    /* used for copying OSR data into inline frame data, to support reification of */\
+    /* call frames of inlined functions. */\
+    macro(InlineStart, 0) \
+    \
     /* Nodes for bitwise operations. */\
     macro(BitAnd, NodeResultInt32) \
     macro(BitOr, NodeResultInt32) \
diff --git a/Source/JavaScriptCore/dfg/DFGPropagator.cpp b/Source/JavaScriptCore/dfg/DFGPropagator.cpp
index 17737e2..c3901b8 100644
--- a/Source/JavaScriptCore/dfg/DFGPropagator.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPropagator.cpp
@@ -607,8 +607,9 @@
         case PutByOffset:
             break;
             
-        // This gets ignored because it doesn't do anything.
+        // These gets ignored because it doesn't do anything.
         case Phantom:
+        case InlineStart:
             break;
 #else
         default:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index d58aa45..19f28fc 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -263,8 +263,28 @@
 #if DFG_ENABLE(DEBUG_VERBOSE)
             fprintf(stderr, "SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x     ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
 #endif
-            if (node.op == SetLocal)
+            switch (node.op) {
+            case SetLocal:
                 compileMovHint(node);
+                break;
+
+            case InlineStart: {
+                InlineCallFrame* inlineCallFrame = node.codeOrigin.inlineCallFrame;
+                unsigned argumentsStart = inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize - inlineCallFrame->arguments.size();
+                for (unsigned i = 0; i < inlineCallFrame->arguments.size(); ++i) {
+                    ValueRecovery recovery = computeValueRecoveryFor(m_variables[argumentsStart + i]);
+                    // The recovery cannot point to registers, since the call frame reification isn't
+                    // as smart as OSR, so it can't handle that. The exception is the this argument,
+                    // which we don't really need to be able to recover.
+                    ASSERT(!i || !recovery.isInRegisters());
+                    inlineCallFrame->arguments[i] = recovery;
+                }
+                break;
+            }
+                
+            default:
+                break;
+            }
         } else {
             
 #if DFG_ENABLE(DEBUG_VERBOSE)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index d343d46..c384ab0 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2491,6 +2491,10 @@
         // This is a no-op.
         noResult(m_compileIndex);
         break;
+        
+    case InlineStart:
+        ASSERT_NOT_REACHED();
+        break;
     }
 
     if (node.hasResult() && node.mustGenerate())