diff options
author | Jan Kotas <jkotas@microsoft.com> | 2018-02-14 20:19:16 -1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-14 20:19:16 -1000 |
commit | 73a175f06746d386084af5d3362994c1077bc6f5 (patch) | |
tree | d4a34a1f60236d577c4450e5b39ac6cbab6a3cf6 | |
parent | 4df1be73ae83ad1e747519d09f67faace6b8aba7 (diff) | |
download | coreclr-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.resx | 8 | ||||
-rw-r--r-- | src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs | 30 | ||||
-rw-r--r-- | src/vm/ecalllist.h | 2 | ||||
-rw-r--r-- | src/vm/reflectioninvocation.cpp | 108 | ||||
-rw-r--r-- | src/vm/reflectioninvocation.h | 2 |
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); |