summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kotas <jkotas@microsoft.com>2018-02-14 20:19:16 -1000
committerGitHub <noreply@github.com>2018-02-14 20:19:16 -1000
commit73a175f06746d386084af5d3362994c1077bc6f5 (patch)
treed4a34a1f60236d577c4450e5b39ac6cbab6a3cf6
parent4df1be73ae83ad1e747519d09f67faace6b8aba7 (diff)
downloadcoreclr-73a175f06746d386084af5d3362994c1077bc6f5.tar.gz
coreclr-73a175f06746d386084af5d3362994c1077bc6f5.tar.bz2
coreclr-73a175f06746d386084af5d3362994c1077bc6f5.zip
Implement RuntimeHelpers.PrepareMethod/PrepareDelegate for CoreCLR (#16382)
* Implement RuntimeHelpers.PrepareMethod/PrepareDelegate for CoreCLR CoreCLR implementation of this method triggers jiting of the given method only. It does not walk a subset of callgraph to provide CER guarantees because of CERs are not supported by CoreCLR. Fixes #15522
-rw-r--r--src/mscorlib/Resources/Strings.resx8
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs30
-rw-r--r--src/vm/ecalllist.h2
-rw-r--r--src/vm/reflectioninvocation.cpp108
-rw-r--r--src/vm/reflectioninvocation.h2
5 files changed, 143 insertions, 7 deletions
diff --git a/src/mscorlib/Resources/Strings.resx b/src/mscorlib/Resources/Strings.resx
index b98553c2a0..6448024c28 100644
--- a/src/mscorlib/Resources/Strings.resx
+++ b/src/mscorlib/Resources/Strings.resx
@@ -3709,4 +3709,10 @@
<data name="Arg_NullArgumentNullRef" xml:space="preserve">
<value>The method was called with a null array argument.</value>
</data>
-</root> \ No newline at end of file
+ <data name="Argument_CannotPrepareAbstract" xml:space="preserve">
+ <value>Abstract methods cannot be prepared.</value>
+ </data>
+ <data name="Argument_InvalidGenericInstantiation" xml:space="preserve">
+ <value>The given generic instantiation was invalid.</value>
+ </data>
+</root>
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs
index b340e4ac71..101f8c45e5 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs
@@ -86,18 +86,36 @@ namespace System.Runtime.CompilerServices
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
internal static extern void _CompileMethod(IRuntimeMethodInfo method);
- public static void PrepareMethod(RuntimeMethodHandle method) { }
- public static void PrepareMethod(RuntimeMethodHandle method, RuntimeTypeHandle[] instantiation) { }
- public static void PrepareContractedDelegate(Delegate d) { }
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static unsafe extern void _PrepareMethod(IRuntimeMethodInfo method, IntPtr* pInstantiation, int cInstantiation);
- public static void PrepareDelegate(Delegate d)
+ public static void PrepareMethod(RuntimeMethodHandle method)
{
- if (d == null)
+ unsafe
{
- throw new ArgumentNullException("d");
+ _PrepareMethod(method.GetMethodInfo(), null, 0);
}
}
+ public static void PrepareMethod(RuntimeMethodHandle method, RuntimeTypeHandle[] instantiation)
+ {
+ unsafe
+ {
+ int length;
+ IntPtr[] instantiationHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(instantiation, out length);
+ fixed (IntPtr* pInstantiation = instantiationHandles)
+ {
+ _PrepareMethod(method.GetMethodInfo(), pInstantiation, length);
+ GC.KeepAlive(instantiation);
+ }
+ }
+ }
+
+ public static void PrepareContractedDelegate(Delegate d) { }
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public static extern void PrepareDelegate(Delegate d);
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern int GetHashCode(Object o);
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 86bc6a202e..1259759ba0 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -1017,6 +1017,8 @@ FCFuncStart(gCompilerFuncs)
FCFuncElement("_RunClassConstructor", ReflectionInvocation::RunClassConstructor)
FCFuncElement("_RunModuleConstructor", ReflectionInvocation::RunModuleConstructor)
QCFuncElement("_CompileMethod", ReflectionInvocation::CompileMethod)
+ FCFuncElement("_PrepareMethod", ReflectionInvocation::PrepareMethod)
+ FCFuncElement("PrepareDelegate", ReflectionInvocation::PrepareDelegate)
FCFuncElement("ExecuteCodeWithGuaranteedCleanup", ReflectionInvocation::ExecuteCodeWithGuaranteedCleanup)
FCFuncElement("GetHashCode", ObjectNative::GetHashCode)
FCFuncElement("Equals", ObjectNative::Equals)
diff --git a/src/vm/reflectioninvocation.cpp b/src/vm/reflectioninvocation.cpp
index 00556d8805..12a386340a 100644
--- a/src/vm/reflectioninvocation.cpp
+++ b/src/vm/reflectioninvocation.cpp
@@ -1996,6 +1996,114 @@ FCIMPL1(void, ReflectionInvocation::RunModuleConstructor, ReflectModuleBaseObjec
}
FCIMPLEND
+static void PrepareMethodHelper(MethodDesc * pMD)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ GCX_PREEMP();
+
+ if (pMD->IsPointingToPrestub())
+ pMD->DoPrestub(NULL);
+
+ if (pMD->IsWrapperStub())
+ {
+ pMD = pMD->GetWrappedMethodDesc();
+ if (pMD->IsPointingToPrestub())
+ pMD->DoPrestub(NULL);
+ }
+}
+
+// This method triggers a given method to be jitted. CoreCLR implementation of this method triggers jiting of the given method only.
+// It does not walk a subset of callgraph to provide CER guarantees.
+FCIMPL3(void, ReflectionInvocation::PrepareMethod, ReflectMethodObject* pMethodUNSAFE, TypeHandle *pInstantiation, UINT32 cInstantiation)
+{
+ CONTRACTL {
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(pMethodUNSAFE, NULL_OK));
+ PRECONDITION(CheckPointer(pInstantiation, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ REFLECTMETHODREF refMethod = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE);
+
+ HELPER_METHOD_FRAME_BEGIN_1(refMethod);
+
+ if (refMethod == NULL)
+ COMPlusThrow(kArgumentException, W("InvalidOperation_HandleIsNotInitialized"));
+
+ MethodDesc *pMD = refMethod->GetMethod();
+
+ if (pMD->IsAbstract())
+ COMPlusThrow(kArgumentException, W("Argument_CannotPrepareAbstract"));
+
+ MethodTable * pExactMT = pMD->GetMethodTable();
+ if (pInstantiation != NULL)
+ {
+ // We were handed an instantiation, check that the method expects it and the right number of types has been provided (the
+ // caller supplies one array containing the class instantiation immediately followed by the method instantiation).
+ if (cInstantiation != (pMD->GetNumGenericMethodArgs() + pMD->GetNumGenericClassArgs()))
+ COMPlusThrow(kArgumentException, W("Argument_InvalidGenericInstantiation"));
+
+ // Check we've got a reasonable looking instantiation.
+ if (!Generics::CheckInstantiation(Instantiation(pInstantiation, cInstantiation)))
+ COMPlusThrow(kArgumentException, W("Argument_InvalidGenericInstantiation"));
+ for (ULONG i = 0; i < cInstantiation; i++)
+ if (pInstantiation[i].ContainsGenericVariables())
+ COMPlusThrow(kArgumentException, W("Argument_InvalidGenericInstantiation"));
+
+ TypeHandle thExactType = ClassLoader::LoadGenericInstantiationThrowing(pMD->GetModule(),
+ pMD->GetMethodTable()->GetCl(),
+ Instantiation(pInstantiation, pMD->GetNumGenericClassArgs()));
+ pExactMT = thExactType.AsMethodTable();
+
+ pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD,
+ pExactMT,
+ FALSE,
+ Instantiation(&pInstantiation[pMD->GetNumGenericClassArgs()], pMD->GetNumGenericMethodArgs()),
+ FALSE);
+ }
+
+ if (pMD->ContainsGenericVariables())
+ COMPlusThrow(kArgumentException, W("Argument_InvalidGenericInstantiation"));
+
+ PrepareMethodHelper(pMD);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+// This method triggers target of a given method to be jitted. CoreCLR implementation of this method triggers jiting
+// of the given method only. It does not walk a subset of callgraph to provide CER guarantees.
+// In the case of a multi-cast delegate, we rely on the fact that each individual component
+// was prepared prior to the Combine.
+FCIMPL1(void, ReflectionInvocation::PrepareDelegate, Object* delegateUNSAFE)
+{
+ CONTRACTL {
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(delegateUNSAFE, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ if (delegateUNSAFE == NULL)
+ return;
+
+ OBJECTREF delegate = ObjectToOBJECTREF(delegateUNSAFE);
+ HELPER_METHOD_FRAME_BEGIN_1(delegate);
+
+ MethodDesc *pMD = COMDelegate::GetMethodDesc(delegate);
+
+ PrepareMethodHelper(pMD);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
// This method checks to see if there is sufficient stack to execute the average Framework method.
// If there is not, then it throws System.InsufficientExecutionStackException. The limit for each
// thread is precomputed when the thread is created.
diff --git a/src/vm/reflectioninvocation.h b/src/vm/reflectioninvocation.h
index 6a183b134c..80b861fe93 100644
--- a/src/vm/reflectioninvocation.h
+++ b/src/vm/reflectioninvocation.h
@@ -51,6 +51,8 @@ public:
static FCDECL1(void, RunClassConstructor, ReflectClassBaseObject *pTypeUNSAFE);
static FCDECL1(void, RunModuleConstructor, ReflectModuleBaseObject *pModuleUNSAFE);
+ static FCDECL3(void, PrepareMethod, ReflectMethodObject* pMethodUNSAFE, TypeHandle *pInstantiation, UINT32 cInstantiation);
+ static FCDECL1(void, PrepareDelegate, Object* delegateUNSAFE);
static FCDECL1(void, PrepareContractedDelegate, Object* delegateUNSAFE);
static FCDECL0(void, ProbeForSufficientStack);
static FCDECL0(void, EnsureSufficientExecutionStack);