Procházet zdrojové kódy

OSG:20015601 Do not clear inlinee callinfo prior to a bailout, as we need the callinfo to help us box stack args and set up the interpreter instance

Paul Leathers před 6 roky
rodič
revize
660bcf93e6

+ 9 - 1
lib/Backend/BailOut.cpp

@@ -1258,6 +1258,8 @@ BailOutRecord::BailOutInlinedHelper(Js::JavascriptCallStackLayout * layout, Bail
     }
 
     // Let's restore the inline stack - so that in case of a stack walk we have it available
+    InlinedFrameLayout *inlinedFrameToRestore = nullptr;
+    Js::ArgSlot clearedCallInfoCount = 0;
     if (entryPointInfo->HasInlinees())
     {
         InlineeFrameRecord* inlineeFrameRecord = entryPointInfo->FindInlineeFrame(returnAddress);
@@ -1267,7 +1269,7 @@ BailOutRecord::BailOutInlinedHelper(Js::JavascriptCallStackLayout * layout, Bail
             // object, the cached version (that was previously boxed) will be reused to maintain pointer identity and correctness
             // after the transition to the interpreter.
             InlinedFrameLayout* outerMostFrame = (InlinedFrameLayout *)(((uint8 *)Js::JavascriptCallStackLayout::ToFramePointer(layout)) - entryPointInfo->GetFrameHeight());
-            inlineeFrameRecord->RestoreFrames(functionBody, outerMostFrame, layout, true /* boxArgs */);
+            inlineeFrameRecord->RestoreFrames(functionBody, outerMostFrame, layout, true /*boxArgs*/, &inlinedFrameToRestore, &clearedCallInfoCount);
         }
     }
 
@@ -1275,6 +1277,12 @@ BailOutRecord::BailOutInlinedHelper(Js::JavascriptCallStackLayout * layout, Bail
     {
         InlinedFrameLayout *inlinedFrame = (InlinedFrameLayout *)(((char *)layout) + currentBailOutRecord->globalBailOutRecordTable->firstActualStackOffset);
         Js::InlineeCallInfo inlineeCallInfo = inlinedFrame->callInfo;
+        if (inlinedFrameToRestore == inlinedFrame)
+        {
+            // Restore the frame's callinfo count prior to using it to create an interpreter instance
+            Assert(inlineeCallInfo.Count == 0);
+            inlineeCallInfo.Count = clearedCallInfoCount;
+        }
         Assert((Js::ArgSlot)inlineeCallInfo.Count == currentBailOutRecord->actualCount);
 
         Js::CallFlags callFlags = Js::CallFlags_Value;

+ 7 - 1
lib/Backend/InlineeFrameInfo.cpp

@@ -243,7 +243,7 @@ void InlineeFrameRecord::Restore(Js::FunctionBody* functionBody, InlinedFrameLay
 // Note: the boxValues parameter should be true when this is called from a Bailout codepath to ensure that multiple vars to
 // the same object reuse the cached value during the transition to the interpreter.
 // Otherwise, this parameter should be false as the values are not required to be moved to the heap to restore the frame.
-void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostFrame, Js::JavascriptCallStackLayout* callstack, bool boxValues)
+void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostFrame, Js::JavascriptCallStackLayout* callstack, bool boxValues, InlinedFrameLayout **ppInlinedFrameToRestore, Js::ArgSlot *pClearedCallInfoCount)
 {
     InlineeFrameRecord* innerMostRecord = this;
     class AutoReverse
@@ -287,6 +287,12 @@ void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFr
     }
 
     // Terminate the inlined stack
+    if (ppInlinedFrameToRestore)
+    {
+        // Tell the caller that we need to restore this frame's callinfo count before using it to create an interpreter instance
+        *ppInlinedFrameToRestore = currentFrame;
+        *pClearedCallInfoCount = currentFrame->callInfo.Count;
+    }
     currentFrame->callInfo.Count = 0;
 }
 

+ 1 - 1
lib/Backend/InlineeFrameInfo.h

@@ -110,7 +110,7 @@ struct InlineeFrameRecord
     }
 
     void PopulateParent(Func* func);
-    void RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostInlinee, Js::JavascriptCallStackLayout* callstack, bool boxValues);
+    void RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostInlinee, Js::JavascriptCallStackLayout* callstack, bool boxValues, InlinedFrameLayout ** ppInlinedFrameToRestore = nullptr, Js::ArgSlot *pClearedCallInfoCount = nullptr);
     void Finalize(Func* inlinee, uint currentOffset);
 #if DBG_DUMP
     void Dump() const;

+ 5 - 0
test/Function/rlexe.xml

@@ -453,6 +453,11 @@
       <baseline>stackArgsLenConstOpt.baseline</baseline>
     </default>
   </test>
+  <test>
+    <default>
+      <files>stackArgsWithInlineeBailOut.js</files>
+    </default>
+  </test>
   <test>
     <default>
       <files>childCallsEvalJitLoopBody.js</files>

+ 15 - 0
test/Function/stackArgsWithInlineeBailOut.js

@@ -0,0 +1,15 @@
+var gi = 3;
+var bigArray = new Array(50);
+bigArray.fill(42);
+function foo() {
+return arguments[gi];
+}
+function bar() {
+bigArray.every(function (x) {
+foo();
+});
+}
+for (var i = 0; i < 3; ++i) {
+bar();
+}
+WScript.Echo('pass');