Fix for a special CoreRT helper CORINFO_HELP_JIT_PINVOKE_BEGIN (#14147)
authorSergey Andreenko <seandree@microsoft.com>
Tue, 26 Sep 2017 22:35:01 +0000 (15:35 -0700)
committerJan Kotas <jkotas@microsoft.com>
Tue, 26 Sep 2017 22:35:01 +0000 (15:35 -0700)
Documentation/botr/clr-abi.md
src/jit/liveness.cpp
src/jit/lsra.cpp
src/jit/lsra.h

index 621bd26..cfa0130 100644 (file)
@@ -119,7 +119,7 @@ For IL stubs only, the per-frame initialization includes setting `Thread->m_pFra
 2. For JIT64/AMD64 only: Next for non-IL stubs, the InlinedCallFrame is 'pushed' by setting `Thread->m_pFrame` to point to the InlinedCallFrame (recall that the per-frame initialization already set `InlinedCallFrame->m_pNext` to point to the previous top). For IL stubs this step is accomplished in the per-frame initialization.
 3. The Frame is made active by setting `InlinedCallFrame->m_pCallerReturnAddress`.
 4. The code then toggles the GC mode by setting `Thread->m_fPreemptiveGCDisabled = 0`.
-5. Starting now, no GC pointers may be live in registers.
+5. Starting now, no GC pointers may be live in registers. RyuJit LSRA meets this requirement by adding special refPositon `RefTypeKillGCRefs` before unmanaged calls and special helpers.
 6. Then comes the actual call/PInvoke.
 7. The GC mode is set back by setting `Thread->m_fPreemptiveGCDisabled = 1`.
 8. Then we check to see if `g_TrapReturningThreads` is set (non-zero). If it is, we call `CORINFO_HELP_STOP_FOR_GC`.
index fdec25b..5555ffb 100644 (file)
@@ -1603,8 +1603,6 @@ void Compiler::fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call)
         }
     }
 
-    /* GC refs cannot be enregistered accross an unmanaged call */
-
     // TODO: we should generate the code for saving to/restoring
     //       from the inlined N/Direct frame instead.
 
index 6d6567d..8f86ca1 100644 (file)
@@ -3073,7 +3073,7 @@ bool LinearScan::buildKillPositionsForNode(GenTree* tree, LsraLocation currentLo
             }
         }
 
-        if (tree->IsCall() && (tree->gtFlags & GTF_CALL_UNMANAGED) != 0)
+        if (killGCRefs(tree))
         {
             RefPosition* pos = newRefPosition((Interval*)nullptr, currentLoc, RefTypeKillGCRefs, tree,
                                               (allRegs(TYP_REF) & ~RBM_ARG_REGS));
@@ -3084,6 +3084,35 @@ bool LinearScan::buildKillPositionsForNode(GenTree* tree, LsraLocation currentLo
     return false;
 }
 
+//------------------------------------------------------------------------
+// killGCRefs:
+// Given some tree node return does it need all GC refs to be spilled from
+// callee save registers.
+//
+// Arguments:
+//    tree       - the tree for which we ask about gc refs.
+//
+// Return Value:
+//    true       - tree kills GC refs on callee save registers
+//    false      - tree doesn't affect GC refs on callee save registers
+bool LinearScan::killGCRefs(GenTree* tree)
+{
+    if (tree->IsCall())
+    {
+        if ((tree->gtFlags & GTF_CALL_UNMANAGED) != 0)
+        {
+            return true;
+        }
+
+        if (tree->AsCall()->gtCallMethHnd == compiler->eeFindHelper(CORINFO_HELP_JIT_PINVOKE_BEGIN))
+        {
+            assert(compiler->opts.ShouldUsePInvokeHelpers());
+            return true;
+        }
+    }
+    return false;
+}
+
 //----------------------------------------------------------------------------
 // defineNewInternalTemp: Defines a ref position for an internal temp.
 //
index 3f0349f..d149b32 100644 (file)
@@ -777,6 +777,8 @@ private:
     // Given some tree node add refpositions for all the registers this node kills
     bool buildKillPositionsForNode(GenTree* tree, LsraLocation currentLoc);
 
+    bool killGCRefs(GenTree* tree);
+
     regMaskTP allRegs(RegisterType rt);
     regMaskTP allRegs(GenTree* tree);
     regMaskTP allMultiRegCallNodeRegs(GenTreeCall* tree);