From: Jan Kotas Date: Thu, 15 Feb 2018 06:19:16 +0000 (-1000) Subject: Implement RuntimeHelpers.PrepareMethod/PrepareDelegate for CoreCLR (#16382) X-Git-Tag: accepted/tizen/unified/20190422.045933~2959 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=73a175f06746d386084af5d3362994c1077bc6f5;p=platform%2Fupstream%2Fcoreclr.git 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 --- diff --git a/src/mscorlib/Resources/Strings.resx b/src/mscorlib/Resources/Strings.resx index b98553c..6448024 100644 --- a/src/mscorlib/Resources/Strings.resx +++ b/src/mscorlib/Resources/Strings.resx @@ -3709,4 +3709,10 @@ The method was called with a null array argument. - \ No newline at end of file + + Abstract methods cannot be prepared. + + + The given generic instantiation was invalid. + + diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index b340e4a..101f8c4 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 86bc6a2..1259759 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 00556d8..12a3863 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 6a183b1..80b861f 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);