Properly handle byrefs in tailcall helper stubs (#41815)
authorJakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
Fri, 4 Sep 2020 05:47:26 +0000 (07:47 +0200)
committerGitHub <noreply@github.com>
Fri, 4 Sep 2020 05:47:26 +0000 (22:47 -0700)
* Properly handle byrefs in tailcall helper stubs

Switch to using ByReference instead of using stind.i/ldind.i and relying
on the JIT to report the locations being moved between.

Fixes #41555

* Move NextCallReturnAddress call back

src/coreclr/src/vm/corelib.h
src/coreclr/src/vm/tailcallhelp.cpp

index 044147c..bd5a8a6 100644 (file)
@@ -589,6 +589,8 @@ DEFINE_FIELD(NULL,                  VALUE,          Value)
 DEFINE_CLASS(NULLABLE,              System,                 Nullable`1)
 
 DEFINE_CLASS(BYREFERENCE,           System,                 ByReference`1)
+DEFINE_METHOD(BYREFERENCE,          CTOR,                   .ctor, NoSig)
+DEFINE_METHOD(BYREFERENCE,          GET_VALUE,              get_Value, NoSig)
 DEFINE_CLASS(SPAN,                  System,                 Span`1)
 DEFINE_METHOD(SPAN,                 GET_ITEM,               get_Item, IM_Int_RetRefT)
 DEFINE_CLASS(READONLY_SPAN,         System,                 ReadOnlySpan`1)
index 10a9c50..7dcb8dd 100644 (file)
@@ -372,7 +372,6 @@ MethodDesc* TailCallHelp::CreateStoreArgsStub(TailCallInfo& info)
     for (COUNT_T i = 0; i < info.ArgBufLayout.Values.GetCount(); i++)
     {
         const ArgBufferValue& arg = info.ArgBufLayout.Values[i];
-        CorElementType ty = arg.TyHnd.GetSignatureCorElementType();
 
         emitOffs(arg.Offset);
         pCode->EmitLDARG(i);
@@ -629,35 +628,63 @@ void TailCallHelp::CreateCallTargetStubSig(const TailCallInfo& info, SigBuilder*
 #endif // _DEBUG
 }
 
+// Get TypeHandle for ByReference<System.Byte>
+static TypeHandle GetByReferenceOfByteType()
+{
+    TypeHandle byteTH(CoreLibBinder::GetElementType(ELEMENT_TYPE_U1));
+    Instantiation byteInst(&byteTH, 1);
+    TypeHandle th = TypeHandle(CoreLibBinder::GetClass(CLASS__BYREFERENCE)).Instantiate(byteInst);
+    return th;
+}
+
+// Get MethodDesc* for ByReference<System.Byte>::get_Value
+static MethodDesc* GetByReferenceOfByteValueGetter()
+{
+    MethodDesc* getter = CoreLibBinder::GetMethod(METHOD__BYREFERENCE__GET_VALUE);
+    getter =
+        MethodDesc::FindOrCreateAssociatedMethodDesc(
+                getter,
+                GetByReferenceOfByteType().GetMethodTable(),
+                false,
+                Instantiation(),
+                TRUE);
+
+    return getter;
+}
+
+// Get MethodDesc* for ByReference<System.Byte>::.ctor
+static MethodDesc* GetByReferenceOfByteCtor()
+{
+    MethodDesc* ctor = CoreLibBinder::GetMethod(METHOD__BYREFERENCE__CTOR);
+    ctor =
+        MethodDesc::FindOrCreateAssociatedMethodDesc(
+                ctor,
+                GetByReferenceOfByteType().GetMethodTable(),
+                false,
+                Instantiation(),
+                TRUE);
+
+    return ctor;
+}
+
 void TailCallHelp::EmitLoadTyHnd(ILCodeStream* stream, TypeHandle tyHnd)
 {
-    CorElementType ty = tyHnd.GetSignatureCorElementType();
     if (tyHnd.IsByRef())
-    {
-        // Note: we can use an "untracked" ldind.i here even with byrefs because
-        // we are loading between two tracked positions.
-        stream->EmitLDIND_I();
-    }
+        stream->EmitCALL(stream->GetToken(GetByReferenceOfByteValueGetter()), 1, 1);
     else
-    {
-        int token = stream->GetToken(tyHnd);
-        stream->EmitLDOBJ(token);
-    }
+        stream->EmitLDOBJ(stream->GetToken(tyHnd));
 }
 
 void TailCallHelp::EmitStoreTyHnd(ILCodeStream* stream, TypeHandle tyHnd)
 {
-    CorElementType ty = tyHnd.GetSignatureCorElementType();
     if (tyHnd.IsByRef())
     {
-        // Note: we can use an "untracked" stind.i here even with byrefs because
-        // we are storing between two tracked positions.
-        stream->EmitSTIND_I();
+        stream->EmitNEWOBJ(stream->GetToken(GetByReferenceOfByteCtor()), 1);
+        stream->EmitSTOBJ(stream->GetToken(GetByReferenceOfByteType()));
     }
     else
     {
-        int token = stream->GetToken(tyHnd);
-        stream->EmitSTOBJ(token);
+        stream->EmitSTOBJ(stream->GetToken(tyHnd));
     }
 }