diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index 94ed1f03b71ae7..ae2d8852744d8c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -410,27 +410,70 @@ internal static Delegate CreateDelegateNoSecurityCheck(Type type, object? target Justification = "The parameter 'methodType' is passed by ref to QCallTypeHandle")] private bool BindToMethodName(object? target, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllMethods)] RuntimeType methodType, string method, DelegateBindingFlags flags) { - Delegate d = this; - return BindToMethodName(ObjectHandleOnStack.Create(ref d), ObjectHandleOnStack.Create(ref target), - new QCallTypeHandle(ref methodType), method, flags); + bool ret = BindToMethodName(RuntimeHelpers.GetMethodTable(this), (target != null) ? RuntimeHelpers.GetMethodTable(target) : null, + new QCallTypeHandle(ref methodType), method, flags, ObjectHandleOnStack.Create(ref target), out BindToMethodDetails bindToMethodDetails); + + if (ret) + { + // Apply the results of the QCall to the delegate instance. + _methodPtr = bindToMethodDetails.methodPtr; + _methodPtrAux = bindToMethodDetails.methodPtrAux; + Unsafe.As(this)._invocationCount = bindToMethodDetails.invocationCount; + if (bindToMethodDetails.loaderAllocatorGCHandle.IsAllocated) + { + _methodBase = bindToMethodDetails.loaderAllocatorGCHandle.Target; + GC.KeepAlive(method); + } + + if (bindToMethodDetails.selfReferentialTarget != 0) + _target = this; + else + _target = target; + } + return ret; + } + + private struct BindToMethodDetails + { + public int selfReferentialTarget; // Whether the delegate's target object is the same as the first argument of the method to bind to. Only meaningful for open instance delegates. + public IntPtr methodPtr; + public IntPtr methodPtrAux; + public IntPtr invocationCount; + public GCHandle loaderAllocatorGCHandle; // The loader allocator needed if the delegate needs to keep it alive } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_BindToMethodName", StringMarshalling = StringMarshalling.Utf8)] [return: MarshalAs(UnmanagedType.Bool)] - private static partial bool BindToMethodName(ObjectHandleOnStack d, ObjectHandleOnStack target, QCallTypeHandle methodType, string method, DelegateBindingFlags flags); + private static partial bool BindToMethodName(MethodTable* pDelegateMT, MethodTable *pTargetMT, QCallTypeHandle methodType, string method, DelegateBindingFlags flags, ObjectHandleOnStack targetParameter, out BindToMethodDetails bindToMethodDetails); private bool BindToMethodInfo(object? target, IRuntimeMethodInfo method, RuntimeType methodType, DelegateBindingFlags flags) { - Delegate d = this; - bool ret = BindToMethodInfo(ObjectHandleOnStack.Create(ref d), ObjectHandleOnStack.Create(ref target), - method.Value, new QCallTypeHandle(ref methodType), flags); - GC.KeepAlive(method); + bool ret = BindToMethodInfo(RuntimeHelpers.GetMethodTable(this), (target != null) ? RuntimeHelpers.GetMethodTable(target) : null, + method.Value, new QCallTypeHandle(ref methodType), flags, ObjectHandleOnStack.Create(ref target), out BindToMethodDetails bindToMethodDetails); + + if (ret) + { + // Apply the results of the QCall to the delegate instance. + _methodPtr = bindToMethodDetails.methodPtr; + _methodPtrAux = bindToMethodDetails.methodPtrAux; + Unsafe.As(this)._invocationCount = bindToMethodDetails.invocationCount; + if (bindToMethodDetails.loaderAllocatorGCHandle.IsAllocated) + { + _methodBase = bindToMethodDetails.loaderAllocatorGCHandle.Target; + GC.KeepAlive(method); + } + + if (bindToMethodDetails.selfReferentialTarget != 0) + _target = this; + else + _target = target; + } return ret; } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_BindToMethodInfo")] [return: MarshalAs(UnmanagedType.Bool)] - private static partial bool BindToMethodInfo(ObjectHandleOnStack d, ObjectHandleOnStack target, RuntimeMethodHandleInternal method, QCallTypeHandle methodType, DelegateBindingFlags flags); + private static partial bool BindToMethodInfo(MethodTable* pDelegateMT, MethodTable *pTargetMT, RuntimeMethodHandleInternal method, QCallTypeHandle methodType, DelegateBindingFlags flags, ObjectHandleOnStack targetParameter, out BindToMethodDetails bindToMethodDetails); private static MulticastDelegate InternalAlloc(RuntimeType type) { @@ -475,12 +518,26 @@ private void DelegateConstruct(object target, IntPtr method) throw new ArgumentNullException(nameof(method)); } - Delegate _this = this; - Construct(ObjectHandleOnStack.Create(ref _this), ObjectHandleOnStack.Create(ref target), method); + Construct(RuntimeHelpers.GetMethodTable(this), (target != null) ? RuntimeHelpers.GetMethodTable(target) : null, + method, out BindToMethodDetails bindToMethodDetails); + + // Apply the results of the QCall to the delegate instance. + _methodPtr = bindToMethodDetails.methodPtr; + _methodPtrAux = bindToMethodDetails.methodPtrAux; + Unsafe.As(this)._invocationCount = bindToMethodDetails.invocationCount; + if (bindToMethodDetails.loaderAllocatorGCHandle.IsAllocated) + { + _methodBase = bindToMethodDetails.loaderAllocatorGCHandle.Target; + } + + if (bindToMethodDetails.selfReferentialTarget != 0) + _target = this; + else + _target = target; } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_Construct")] - private static partial void Construct(ObjectHandleOnStack _this, ObjectHandleOnStack target, IntPtr method); + private static partial void Construct(MethodTable* pDelegateMT, MethodTable* pTargetMT, IntPtr method, out BindToMethodDetails bindToMethodDetails); [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe void* GetMulticastInvoke(MethodTable* pMT); @@ -535,11 +592,13 @@ private static bool InternalEqualMethodHandles(Delegate left, Delegate right) internal static IntPtr AdjustTarget(object target, IntPtr methodPtr) { - return AdjustTarget(ObjectHandleOnStack.Create(ref target), methodPtr); + IntPtr result = AdjustTarget(RuntimeHelpers.GetMethodTable(target), methodPtr); + GC.KeepAlive(target); + return result; } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_AdjustTarget")] - private static partial IntPtr AdjustTarget(ObjectHandleOnStack target, IntPtr methodPtr); + private static partial IntPtr AdjustTarget(MethodTable* targetMT, IntPtr methodPtr); internal void InitializeVirtualCallStub(IntPtr methodPtr) { diff --git a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs index 38fd1f5189f6ec..2348719e9e1282 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs @@ -22,7 +22,7 @@ public abstract partial class MulticastDelegate : Delegate // 2. Unmanaged function pointer // 3. Open virtual delegate private object? _invocationList; // Initialized by VM as needed - private nint _invocationCount; + internal nint _invocationCount; internal bool IsUnmanagedFunctionPtr() { diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index 54bde6c60c6845..074a56f366755e 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -12471,15 +12471,6 @@ HRESULT Debugger::ApplyChangesAndSendResult(DebuggerModule * pDebuggerModule, } else { - // Violation with the following call stack: - // CONTRACT in MethodTableBuilder::InitMethodDesc - // CONTRACT in EEClass::AddMethod - // CONTRACT in EditAndContinueModule::AddMethod - // CONTRACT in EditAndContinueModule::ApplyEditAndContinue - // CONTRACT in EEDbgInterfaceImpl::EnCApplyChanges - // VIOLATED--> CONTRACT in Debugger::ApplyChangesAndSendResult - CONTRACT_VIOLATION(GCViolation); - // Tell the VM to apply the edit hr = g_pEEInterface->EnCApplyChanges( (EditAndContinueModule*)pModule, cbMetadata, pMetadata, cbIL, pIL); diff --git a/src/coreclr/debug/ee/funceval.cpp b/src/coreclr/debug/ee/funceval.cpp index 263beaa911bbfc..e6009e0bc88263 100644 --- a/src/coreclr/debug/ee/funceval.cpp +++ b/src/coreclr/debug/ee/funceval.cpp @@ -2099,6 +2099,7 @@ void GatherFuncEvalMethodInfo(DebuggerEval *pDE, // if ((pDE->m_evalType != DB_IPCE_FET_NEW_OBJECT) && !pDE->m_md->IsStatic() && pDE->m_md->IsUnboxingStub()) { + GCX_PREEMP(); *ppUnboxedMD = pDE->m_md->GetMethodTable()->GetUnboxedEntryPointMD(pDE->m_md); } @@ -2213,13 +2214,19 @@ void GatherFuncEvalMethodInfo(DebuggerEval *pDE, // Now, find the proper MethodDesc for this interface method based on the object we're invoking the // method on. // - pDE->m_targetCodeAddr = pDE->m_md->GetCallTarget(&objRef, pDE->m_ownerTypeHandle); + { + GCX_PREEMP(); + pDE->m_targetCodeAddr = pDE->m_md->GetCallTarget(&objRef, pDE->m_ownerTypeHandle); + } GCPROTECT_END(); } else { - pDE->m_targetCodeAddr = pDE->m_md->GetCallTarget(NULL, pDE->m_ownerTypeHandle); + { + GCX_PREEMP(); + pDE->m_targetCodeAddr = pDE->m_md->GetCallTarget(NULL, pDE->m_ownerTypeHandle); + } } // @@ -3195,7 +3202,10 @@ static void DoNormalFuncEval( DebuggerEval *pDE, // Now that all the args are protected, we can go back and deal with generic args and resolving // all their information. // - ResolveFuncEvalGenericArgInfo(pDE); + { + GCX_PREEMP(); + ResolveFuncEvalGenericArgInfo(pDE); + } // // Grab the signature of the method we're working on and do some error checking. diff --git a/src/coreclr/vm/amd64/cgenamd64.cpp b/src/coreclr/vm/amd64/cgenamd64.cpp index e8380e10983f34..cd56d890b7a8c1 100644 --- a/src/coreclr/vm/amd64/cgenamd64.cpp +++ b/src/coreclr/vm/amd64/cgenamd64.cpp @@ -24,9 +24,7 @@ #include "clrtocomcall.h" #endif // FEATURE_COMINTEROP -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegisters * pRegs) { @@ -607,13 +605,9 @@ DWORD GetOffsetAtEndOfFunction(ULONGLONG uImageBase, size_t rxOffset = pStartRX - pStart; \ BYTE * p = pStart; -#ifdef FEATURE_PERFMAP #define BEGIN_DYNAMIC_HELPER_EMIT(size) \ BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) \ PerfMap::LogStubs(__FUNCTION__, "DynamicHelper", (PCODE)p, size, PerfMapStubType::Individual); -#else -#define BEGIN_DYNAMIC_HELPER_EMIT(size) BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) -#endif #define END_DYNAMIC_HELPER_EMIT() \ _ASSERTE(pStart + cb == p); \ diff --git a/src/coreclr/vm/arm/stubs.cpp b/src/coreclr/vm/arm/stubs.cpp index 2f0215b21006c0..24eb174ec59904 100644 --- a/src/coreclr/vm/arm/stubs.cpp +++ b/src/coreclr/vm/arm/stubs.cpp @@ -25,9 +25,7 @@ #include "ecall.h" #include "threadsuspend.h" -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif // target write barriers EXTERN_C void JIT_WriteBarrier(Object **dst, Object *ref); @@ -1494,13 +1492,9 @@ void MovRegImm(BYTE* p, int reg, TADDR imm) size_t rxOffset = pStartRX - pStart; \ BYTE * p = pStart; -#ifdef FEATURE_PERFMAP #define BEGIN_DYNAMIC_HELPER_EMIT(size) \ BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) \ PerfMap::LogStubs(__FUNCTION__, "DynamicHelper", (PCODE)p, size, PerfMapStubType::Individual); -#else -#define BEGIN_DYNAMIC_HELPER_EMIT(size) BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) -#endif #define END_DYNAMIC_HELPER_EMIT() \ diff --git a/src/coreclr/vm/arm64/stubs.cpp b/src/coreclr/vm/arm64/stubs.cpp index 9ee0c4b42377d4..f7274eb0d1ab7d 100644 --- a/src/coreclr/vm/arm64/stubs.cpp +++ b/src/coreclr/vm/arm64/stubs.cpp @@ -13,9 +13,7 @@ #include "ecall.h" #include "writebarriermanager.h" -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #ifndef DACCESS_COMPILE //----------------------------------------------------------------------- @@ -951,13 +949,9 @@ void StubLinkerCPU::EmitCallManagedMethod(MethodDesc *pMD, BOOL fTailCall) size_t rxOffset = pStartRX - pStart; \ BYTE * p = pStart; -#ifdef FEATURE_PERFMAP #define BEGIN_DYNAMIC_HELPER_EMIT(size) \ BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) \ PerfMap::LogStubs(__FUNCTION__, "DynamicHelper", (PCODE)p, size, PerfMapStubType::Individual); -#else -#define BEGIN_DYNAMIC_HELPER_EMIT(size) BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) -#endif #define END_DYNAMIC_HELPER_EMIT() \ diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index 5f2526172d941d..b408cb8ed17154 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -1156,7 +1156,11 @@ static void RunMainInternal(Param* pParam) StrArgArray = *pParam->stringArgs; pParam->pFD->EnsureActive(); - PCODE entryPoint = pParam->pFD->GetSingleCallableAddrOfCode(); + PCODE entryPoint; + { + GCX_PREEMP(); + entryPoint = pParam->pFD->GetSingleCallableAddrOfCode(); + } BOOL hasReturnValue = !pParam->pFD->IsVoid(); PTRARRAYREF* pArgument = (pParam->EntryType == EntryManagedMain) ? &StrArgArray : NULL; @@ -1701,7 +1705,8 @@ void Assembly::AddType( CONTRACTL { THROWS; - GC_TRIGGERS; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END @@ -1727,7 +1732,8 @@ void Assembly::AddExportedType(mdExportedType cl) CONTRACTL { THROWS; - GC_TRIGGERS; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END @@ -1991,6 +1997,7 @@ void Assembly::SetError(Exception *ex) SetProfilerNotified(); #ifdef PROFILING_SUPPORTED + GCX_PREEMP(); // Only send errors for non-shared assemblies; other assemblies might be successfully completed // in another app domain later. m_pModule->NotifyProfilerLoadFinished(ex->GetHR()); diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp index 97ee4dfc6dfbab..f0fe61dcac9a38 100644 --- a/src/coreclr/vm/assemblynative.cpp +++ b/src/coreclr/vm/assemblynative.cpp @@ -1408,7 +1408,6 @@ extern "C" void QCALLTYPE AssemblyNative_ApplyUpdate( _ASSERTE(ilDeltaLength > 0); #ifdef FEATURE_METADATA_UPDATER - GCX_COOP(); { if (CORDebuggerAttached()) { diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp index 2568a1483d5714..b2160b1ac6bfd3 100644 --- a/src/coreclr/vm/callhelpers.cpp +++ b/src/coreclr/vm/callhelpers.cpp @@ -559,11 +559,17 @@ void CallDefaultConstructor(OBJECTREF ref) GCPROTECT_BEGIN (ref); - MethodDesc *pMD = pMT->GetDefaultConstructor(); + + PCODE methodEntry; + { + GCX_PREEMP(); + MethodDesc *pMD = pMT->GetDefaultConstructor(); + methodEntry = pMD->GetSingleCallableAddrOfCode(); + } UnmanagedCallersOnlyCaller defaultCtorInvoker{METHOD__RUNTIME_HELPERS__CALL_DEFAULT_CONSTRUCTOR}; - defaultCtorInvoker.InvokeThrowing(&ref, pMD->GetSingleCallableAddrOfCode()); + defaultCtorInvoker.InvokeThrowing(&ref, methodEntry); GCPROTECT_END (); } diff --git a/src/coreclr/vm/callhelpers.h b/src/coreclr/vm/callhelpers.h index a91f65078c271c..b5b19b89d61a33 100644 --- a/src/coreclr/vm/callhelpers.h +++ b/src/coreclr/vm/callhelpers.h @@ -104,103 +104,17 @@ class MethodDescCallSite } #endif // _DEBUG - void DefaultInit(OBJECTREF* porProtectedThis) - { - CONTRACTL - { - MODE_ANY; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END; - -#ifdef _DEBUG - // - // Make sure we are passing in a 'this' if and only if it is required - // - if (m_pMD->IsVtableMethod()) - { - CONSISTENCY_CHECK_MSG(NULL != porProtectedThis, "You did not pass in the 'this' object for a vtable method"); - } - else - { - if (NULL != porProtectedThis) - { - if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AssertOnUnneededThis)) - { - CONSISTENCY_CHECK_MSG(NULL == porProtectedThis, "You passed in a 'this' object to a non-vtable method."); - } - else - { - LogWeakAssert(); - } - - } - } -#endif // _DEBUG - - m_pCallTarget = m_pMD->GetCallTarget(porProtectedThis); - - m_argIt.ForceSigWalk(); - } - - void DefaultInit(TypeHandle th) - { - CONTRACTL - { - MODE_ANY; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END; - - m_pCallTarget = m_pMD->GetCallTarget(NULL, th); - - m_argIt.ForceSigWalk(); -} - void CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *pReturnValue, int cbReturnValue); public: - // Used to avoid touching metadata for CoreLib methods. - // instance methods must pass in the 'this' object - // static methods must pass null - MethodDescCallSite(BinderMethodID id, OBJECTREF* porProtectedThis = NULL) : - m_pMD( - CoreLibBinder::GetMethod(id) - ), - m_methodSig(id), - m_argIt(&m_methodSig) - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - DefaultInit(porProtectedThis); - } - - // Used to avoid touching metadata for CoreLib methods. - // instance methods must pass in the 'this' object - // static methods must pass null - MethodDescCallSite(BinderMethodID id, OBJECTHANDLE hThis) : - m_pMD( - CoreLibBinder::GetMethod(id) - ), - m_methodSig(id), - m_argIt(&m_methodSig) - { - WRAPPER_NO_CONTRACT; - - DefaultInit((OBJECTREF*)hThis); - } - - // instance methods must pass in the 'this' object - // static methods must pass null - MethodDescCallSite(MethodDesc* pMD, OBJECTREF* porProtectedThis = NULL) : + // + // Only use this constructor if you're certain you know where + // you're going and it cannot be affected by generics/virtual + // dispatch/etc.. + // + MethodDescCallSite(MethodDesc* pMD, PCODE pCallTarget) : m_pMD(pMD), + m_pCallTarget(pCallTarget), m_methodSig(pMD), m_argIt(&m_methodSig) { @@ -208,72 +122,13 @@ class MethodDescCallSite { THROWS; GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - if (porProtectedThis == NULL) - { - // We don't have a "this" pointer - ensure that we have activated the containing module - m_pMD->EnsureActive(); - } - - DefaultInit(porProtectedThis); - } - - // instance methods must pass in the 'this' object - // static methods must pass null - MethodDescCallSite(MethodDesc* pMD, OBJECTHANDLE hThis) : - m_pMD(pMD), - m_methodSig(pMD), - m_argIt(&m_methodSig) - { - WRAPPER_NO_CONTRACT; - - if (hThis == NULL) - { - // We don't have a "this" pointer - ensure that we have activated the containing module - m_pMD->EnsureActive(); - } - - DefaultInit((OBJECTREF*)hThis); - } - - // instance methods must pass in the 'this' object - // static methods must pass null - MethodDescCallSite(MethodDesc* pMD, LPHARDCODEDMETASIG pwzSignature, OBJECTREF* porProtectedThis = NULL) : - m_pMD(pMD), - m_methodSig(pwzSignature), - m_argIt(&m_methodSig) - { - WRAPPER_NO_CONTRACT; - - if (porProtectedThis == NULL) - { - // We don't have a "this" pointer - ensure that we have activated the containing module - m_pMD->EnsureActive(); - } - - DefaultInit(porProtectedThis); - } - - MethodDescCallSite(MethodDesc* pMD, TypeHandle th) : - m_pMD(pMD), - m_methodSig(pMD, th), - m_argIt(&m_methodSig) - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; + MODE_ANY; } CONTRACTL_END; - // We don't have a "this" pointer - ensure that we have activated the containing module m_pMD->EnsureActive(); - DefaultInit(th); + m_argIt.ForceSigWalk(); } // @@ -281,10 +136,10 @@ class MethodDescCallSite // you're going and it cannot be affected by generics/virtual // dispatch/etc.. // - MethodDescCallSite(MethodDesc* pMD, PCODE pCallTarget) : + MethodDescCallSite(MethodDesc* pMD, PCODE pCallTarget, TypeHandle th) : m_pMD(pMD), m_pCallTarget(pCallTarget), - m_methodSig(pMD), + m_methodSig(pMD, th), m_argIt(&m_methodSig) { CONTRACTL diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index ab5a28c591051e..d4c08fe7bc32e9 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -214,8 +214,9 @@ void Module::UpdateNewlyAddedTypes() { CONTRACTL { + MODE_PREEMPTIVE; THROWS; - GC_TRIGGERS; + GC_NOTRIGGER; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END @@ -278,7 +279,7 @@ void Module::NotifyProfilerLoadFinished(HRESULT hr) THROWS; GC_TRIGGERS; INJECT_FAULT(COMPlusThrowOM()); - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -296,7 +297,6 @@ void Module::NotifyProfilerLoadFinished(HRESULT hr) { BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads()); { - GCX_PREEMP(); (&g_profControlBlock)->ModuleLoadFinished((ModuleID) this, hr); if (SUCCEEDED(hr)) @@ -640,8 +640,8 @@ void Module::ApplyMetaData() CONTRACTL { THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -957,7 +957,7 @@ void Module::SetDynamicRvaField(mdToken token, TADDR blobAddress) { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; } CONTRACTL_END; diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index d9ab0c0c0d5326..96e850b9943279 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -194,9 +194,7 @@ #include "profilinghelper.h" #endif // PROFILING_SUPPORTED -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #include "diagnosticserveradapter.h" #include "eventpipeadapter.h" diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 551c456691954b..66956a029feb41 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -322,7 +322,7 @@ HRESULT EEClass::AddField(MethodTable* pMT, mdFieldDef fieldDef, FieldDesc** ppN { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; PRECONDITION(pMT != NULL); PRECONDITION(ppNewFD != NULL); } @@ -442,7 +442,7 @@ HRESULT EEClass::AddFieldDesc( { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; PRECONDITION(pMT != NULL); PRECONDITION(ppNewFD != NULL); } @@ -508,7 +508,7 @@ HRESULT EEClass::AddMethod(MethodTable* pMT, mdMethodDef methodDef, MethodDesc** { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; PRECONDITION(pMT != NULL); PRECONDITION(methodDef != mdTokenNil); } @@ -776,7 +776,7 @@ HRESULT EEClass::AddMethodDesc( { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; PRECONDITION(pMT != NULL); PRECONDITION(methodDef != mdTokenNil); PRECONDITION(ppNewMD != NULL); @@ -1709,6 +1709,7 @@ void TypeHandle::NotifyDebuggerUnload() const MethodDesc* MethodTable::GetBoxedEntryPointMD(MethodDesc *pMD) { CONTRACT (MethodDesc *) { + MODE_PREEMPTIVE; THROWS; GC_TRIGGERS; INJECT_FAULT(COMPlusThrowOM();); @@ -1732,6 +1733,7 @@ MethodDesc* MethodTable::GetBoxedEntryPointMD(MethodDesc *pMD) MethodDesc* MethodTable::GetUnboxedEntryPointMD(MethodDesc *pMD) { CONTRACT (MethodDesc *) { + MODE_PREEMPTIVE; THROWS; GC_TRIGGERS; INJECT_FAULT(COMPlusThrowOM();); diff --git a/src/coreclr/vm/classhash.cpp b/src/coreclr/vm/classhash.cpp index 10c73eeff8570a..7c361f8d39c6b7 100644 --- a/src/coreclr/vm/classhash.cpp +++ b/src/coreclr/vm/classhash.cpp @@ -73,8 +73,8 @@ EEClassHashTable *EEClassHashTable::Create(Module *pModule, DWORD dwNumBuckets, CONTRACTL { THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM();); PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED()); @@ -676,7 +676,7 @@ BOOL EEClassHashTable::IsNested(ModuleBase *pModule, mdToken token, mdToken *mdE CONTRACTL { if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; - if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; + GC_NOTRIGGER; if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); } MODE_ANY; SUPPORTS_DAC; @@ -714,7 +714,7 @@ BOOL EEClassHashTable::IsNested(const NameHandle* pName, mdToken *mdEncloser) CONTRACTL { if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; - if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; + GC_NOTRIGGER; if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); } MODE_ANY; SUPPORTS_DAC; diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index ba86d440ecb2fc..fa7c2442a9cb95 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -584,8 +584,8 @@ VOID ClassLoader::PopulateAvailableClassHashTable(Module* pModule, { INSTANCE_CHECK; THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END; @@ -638,8 +638,8 @@ void ClassLoader::LazyPopulateCaseSensitiveHashTablesDontHaveLock() { INSTANCE_CHECK; THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM()); } CONTRACTL_END; @@ -655,8 +655,8 @@ void ClassLoader::LazyPopulateCaseSensitiveHashTables() { INSTANCE_CHECK; THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM()); } CONTRACTL_END; @@ -3455,8 +3455,8 @@ VOID ClassLoader::AddAvailableClassDontHaveLock(Module *pModule, { INSTANCE_CHECK; THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END @@ -3490,8 +3490,8 @@ VOID ClassLoader::AddAvailableClassHaveLock( { INSTANCE_CHECK; THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END @@ -3564,8 +3564,8 @@ VOID ClassLoader::AddExportedTypeDontHaveLock(Module *pManifestModule, { INSTANCE_CHECK; THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END @@ -3589,8 +3589,8 @@ VOID ClassLoader::AddExportedTypeHaveLock(Module *pManifestModule, { INSTANCE_CHECK; THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index d7af1a7af7041f..f4f1fae937523a 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -41,9 +41,7 @@ #include "../debug/daccess/fntableaccess.h" #endif // HOST_64BIT -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif // Default number of jump stubs in a jump stub block #define DEFAULT_JUMPSTUBS_PER_BLOCK 32 @@ -6469,9 +6467,7 @@ PCODE ExecutionManager::getNextJumpStub(MethodDesc* pMD, PCODE target, emitBackToBackJump(jumpStub, jumpStubRW, (void*) target); -#ifdef FEATURE_PERFMAP PerfMap::LogStubs(__FUNCTION__, "emitBackToBackJump", (PCODE)jumpStub, BACK_TO_BACK_JUMP_ALLOCATE_SIZE, PerfMapStubType::IndividualWithinBlock); -#endif // We always add the new jumpstub to the jumpStubCache // diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 371174c434a9a8..03c82e7280323f 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -152,6 +152,12 @@ void ReportStubBlock(void* start, size_t size, StubCodeBlockKind kind); #ifndef FEATURE_PERFMAP inline void ReportStubBlock(void* start, size_t size, StubCodeBlockKind kind) { + CONTRACTL + { + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } + CONTRACTL_END; } #endif diff --git a/src/coreclr/vm/comcallablewrapper.cpp b/src/coreclr/vm/comcallablewrapper.cpp index a04559c8ea9030..e2ac8f04267da3 100644 --- a/src/coreclr/vm/comcallablewrapper.cpp +++ b/src/coreclr/vm/comcallablewrapper.cpp @@ -2836,7 +2836,7 @@ namespace { THROWS; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM()); } CONTRACTL_END; diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index f4c60e20ea451e..09e2cef87c7196 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -556,14 +556,24 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs { UnmanagedCallersOnlyCaller invokeConnectionPointProviderMethod(METHOD__STUBHELPERS__INVOKE_CONNECTION_POINT_PROVIDER_METHOD); + PCODE pProvCode; + PCODE pDlgCtorCode; + PCODE pEventMethodCode; + { + GCX_PREEMP(); + pProvCode = pProvMethodDesc->GetSingleCallableAddrOfCode(); + pDlgCtorCode = pDlgCtorMD->GetSingleCallableAddrOfCode(); + pEventMethodCode = pEventMethodDesc->GetMultiCallableAddrOfCode(); + } + // Using GetMultiCallableAddrOfCode() for the event target since it is stored for future invokes. invokeConnectionPointProviderMethod.InvokeThrowing( &pProvider, - pProvMethodDesc->GetSingleCallableAddrOfCode(), + pProvCode, &pDelegate, - pDlgCtorMD->GetSingleCallableAddrOfCode(), + pDlgCtorCode, &pSubscriber, - pEventMethodDesc->GetMultiCallableAddrOfCode()); + pEventMethodCode); } GCPROTECT_END(); } diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 8f0d4a2438aace..564a986318813a 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -967,7 +967,7 @@ static PCODE GetVirtualCallStub(MethodDesc *method, TypeHandle scopeType) { THROWS; GC_TRIGGERS; - MODE_ANY; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM()); // from MetaSig::SizeOfArgStack } CONTRACTL_END; @@ -990,8 +990,8 @@ static PCODE GetVirtualCallStub(MethodDesc *method, TypeHandle scopeType) ); } -extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(QCall::ObjectHandleOnStack d, QCall::ObjectHandleOnStack target, - QCall::TypeHandle pMethodType, LPCUTF8 pszMethodName, DelegateBindingFlags flags) +extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(MethodTable* pDelegateMT, MethodTable *pTargetMT, + QCall::TypeHandle pMethodType, LPCUTF8 pszMethodName, DelegateBindingFlags flags, QCall::ObjectHandleOnStack targetParameter, BindToMethodDetails *pBindToMethodDetails) { QCALL_CONTRACT; @@ -999,25 +999,11 @@ extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(QCall::ObjectHandleOnStack d BEGIN_QCALL; - GCX_COOP(); - - struct - { - DELEGATEREF refThis; - OBJECTREF target; - } gc; - - gc.refThis = (DELEGATEREF) d.Get(); - gc.target = target.Get(); - - GCPROTECT_BEGIN(gc); TypeHandle methodType = pMethodType.AsTypeHandle(); - TypeHandle targetType((gc.target != NULL) ? gc.target->GetMethodTable() : NULL); // get the invoke of the delegate - MethodTable * pDelegateType = gc.refThis->GetMethodTable(); - MethodDesc* pInvokeMeth = COMDelegate::FindDelegateInvokeMethod(pDelegateType); + MethodDesc* pInvokeMeth = COMDelegate::FindDelegateInvokeMethod(pDelegateMT); _ASSERTE(pInvokeMeth); // @@ -1073,10 +1059,10 @@ extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(QCall::ObjectHandleOnStack d false /* do not allow code with a shared-code calling convention to be returned */, true /* Ensure that methods on generic interfaces are returned as instantiated method descs */); bool fIsOpenDelegate; - if (!COMDelegate::IsMethodDescCompatible((gc.target == NULL) ? TypeHandle() : gc.target->GetTypeHandle(), + if (!COMDelegate::IsMethodDescCompatible(TypeHandle(pTargetMT), methodType, pCurMethod, - gc.refThis->GetTypeHandle(), + TypeHandle(pDelegateMT), pInvokeMeth, flags, &fIsOpenDelegate)) @@ -1087,11 +1073,13 @@ extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(QCall::ObjectHandleOnStack d // Found the target that matches the signature and satisfies security transparency rules // Initialize the delegate to point to the target method. - COMDelegate::BindToMethod(&gc.refThis, - &gc.target, - pCurMethod, - methodType.GetMethodTable(), - fIsOpenDelegate); + COMDelegate::BindToMethod(pDelegateMT, + pTargetMT, + pCurMethod, + methodType.GetMethodTable(), + fIsOpenDelegate, + targetParameter, + pBindToMethodDetails); pMatchingMethod = pCurMethod; goto done; @@ -1101,15 +1089,14 @@ extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(QCall::ObjectHandleOnStack d done: ; - GCPROTECT_END(); END_QCALL; return (pMatchingMethod != NULL); } -extern "C" BOOL QCALLTYPE Delegate_BindToMethodInfo(QCall::ObjectHandleOnStack d, QCall::ObjectHandleOnStack target, - MethodDesc * method, QCall::TypeHandle pMethodType, DelegateBindingFlags flags) +extern "C" BOOL QCALLTYPE Delegate_BindToMethodInfo(MethodTable* pDelegateMT, MethodTable *pTargetMT, + MethodDesc * method, QCall::TypeHandle pMethodType, DelegateBindingFlags flags, QCall::ObjectHandleOnStack targetParameter, BindToMethodDetails *pBindToMethodDetails) { QCALL_CONTRACT; @@ -1117,62 +1104,49 @@ extern "C" BOOL QCALLTYPE Delegate_BindToMethodInfo(QCall::ObjectHandleOnStack d BEGIN_QCALL; - GCX_COOP(); - - struct - { - DELEGATEREF refThis; - OBJECTREF refFirstArg; - } gc; - - gc.refThis = (DELEGATEREF) d.Get(); - gc.refFirstArg = target.Get(); - - GCPROTECT_BEGIN(gc); - MethodTable *pMethMT = pMethodType.AsTypeHandle().GetMethodTable(); - // Assert to track down VS#458689. - _ASSERTE(gc.refThis != gc.refFirstArg); - // A generic method had better be instantiated (we can't dispatch to an uninstantiated one). if (method->IsGenericMethodDefinition()) COMPlusThrow(kArgumentException, W("Arg_DlgtTargMeth")); // get the invoke of the delegate - MethodTable * pDelegateType = gc.refThis->GetMethodTable(); - MethodDesc* pInvokeMeth = COMDelegate::FindDelegateInvokeMethod(pDelegateType); + MethodDesc* pInvokeMeth = COMDelegate::FindDelegateInvokeMethod(pDelegateMT); _ASSERTE(pInvokeMeth); // See the comment in BindToMethodName - method = - MethodDesc::FindOrCreateAssociatedMethodDesc(method, - pMethMT, - (!method->IsStatic() && pMethMT->IsValueType()), - method->GetMethodInstantiation(), - false /* do not allow code with a shared-code calling convention to be returned */, - true /* Ensure that methods on generic interfaces are returned as instantiated method descs */); - bool fIsOpenDelegate; - if (COMDelegate::IsMethodDescCompatible((gc.refFirstArg == NULL) ? TypeHandle() : gc.refFirstArg->GetTypeHandle(), + + method = MethodDesc::FindOrCreateAssociatedMethodDesc(method, + pMethMT, + (!method->IsStatic() && pMethMT->IsValueType()), + method->GetMethodInstantiation(), + false /* do not allow code with a shared-code calling convention to be returned */, + true /* Ensure that methods on generic interfaces are returned as instantiated method descs */); + + if (COMDelegate::IsMethodDescCompatible(TypeHandle(pTargetMT), TypeHandle(pMethMT), method, - gc.refThis->GetTypeHandle(), + TypeHandle(pDelegateMT), pInvokeMeth, flags, &fIsOpenDelegate)) { // Initialize the delegate to point to the target method. - COMDelegate::BindToMethod(&gc.refThis, - &gc.refFirstArg, + COMDelegate::BindToMethod(pDelegateMT, + pTargetMT, method, pMethMT, - fIsOpenDelegate); + fIsOpenDelegate, + targetParameter, + pBindToMethodDetails); + + result = TRUE; } else + { result = FALSE; - - GCPROTECT_END(); + } END_QCALL; @@ -1182,19 +1156,20 @@ extern "C" BOOL QCALLTYPE Delegate_BindToMethodInfo(QCall::ObjectHandleOnStack d // This method is called (in the late bound case only) once a target method has been decided on. All the consistency checks // (signature matching etc.) have been done at this point, this method will simply initialize the delegate, with any required // wrapping. The delegate returned will be ready for invocation immediately. -void COMDelegate::BindToMethod(DELEGATEREF *pRefThis, - OBJECTREF *pRefFirstArg, +void COMDelegate::BindToMethod(MethodTable* pDelegateMT, + MethodTable *pTargetMT, MethodDesc *pTargetMethod, MethodTable *pExactMethodType, - BOOL fIsOpenDelegate) + BOOL fIsOpenDelegate, + QCall::ObjectHandleOnStack targetParameter, + BindToMethodDetails *pBindToMethodDetails) { CONTRACTL { THROWS; GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pRefThis)); - PRECONDITION(CheckPointer(pRefFirstArg, NULL_OK)); + MODE_PREEMPTIVE; + PRECONDITION(CheckPointer(pDelegateMT)); PRECONDITION(CheckPointer(pTargetMethod)); PRECONDITION(CheckPointer(pExactMethodType)); } @@ -1204,19 +1179,16 @@ void COMDelegate::BindToMethod(DELEGATEREF *pRefThis, if (fIsOpenDelegate) { - _ASSERTE(pRefFirstArg == NULL || *pRefFirstArg == NULL); - // Open delegates use themselves as the target (which handily allows their shuffle thunks to locate additional data at // invocation time). - (*pRefThis)->SetTarget(*pRefThis); + pBindToMethodDetails->selfReferentialTarget = TRUE; // We need to shuffle arguments for open delegates since the first argument on the calling side is not meaningful to the // callee. - MethodTable * pDelegateMT = (*pRefThis)->GetMethodTable(); PCODE pEntryPoint = SetupShuffleThunk(pDelegateMT, pTargetMethod); // Indicate that the delegate will jump to the shuffle thunk rather than directly to the target method. - (*pRefThis)->SetMethodPtr(pEntryPoint); + pBindToMethodDetails->methodPtr = pEntryPoint; // Use stub dispatch for all virtuals. // Investigate not using this for non-interface virtuals. @@ -1229,9 +1201,8 @@ void COMDelegate::BindToMethod(DELEGATEREF *pRefThis, // Since this is an open delegate over a virtual method we cannot virtualize the call target now. So the shuffle thunk // needs to jump to another stub (this time provided by the VirtualStubManager) that will virtualize the call at // runtime. - PCODE pTargetCall = GetVirtualCallStub(pTargetMethod, TypeHandle(pExactMethodType)); - (*pRefThis)->SetMethodPtrAux(pTargetCall); - (*pRefThis)->SetInvocationCount((INT_PTR)(void *)pTargetMethod); + pBindToMethodDetails->methodPtrAux = GetVirtualCallStub(pTargetMethod, TypeHandle(pExactMethodType)); + pBindToMethodDetails->invocationCount = (INT_PTR)(void *)pTargetMethod; } else { @@ -1255,12 +1226,12 @@ void COMDelegate::BindToMethod(DELEGATEREF *pRefThis, // Note that it is important to cache pTargetCode in local variable to avoid GC hole. // GetMultiCallableAddrOfCode() can trigger GC. - PCODE pTargetCode = pTargetMethod->GetMultiCallableAddrOfCode(); - (*pRefThis)->SetMethodPtrAux(pTargetCode); + pBindToMethodDetails->methodPtrAux = pTargetMethod->GetMultiCallableAddrOfCode(); } } else { + pBindToMethodDetails->selfReferentialTarget = FALSE; PCODE pTargetCode = (PCODE)NULL; // For virtual methods we can (and should) virtualize the call now (so we don't have to insert a thunk to do so at runtime). @@ -1270,10 +1241,11 @@ void COMDelegate::BindToMethod(DELEGATEREF *pRefThis, // virtualize since we're just going to throw NullRefException at invocation time). // if (pTargetMethod->IsVirtual() - && *pRefFirstArg != NULL - && pTargetMethod->GetMethodTable() != (*pRefFirstArg)->GetMethodTable()) + && pTargetMT != NULL + && pTargetMethod->GetMethodTable() != pTargetMT) { - pTargetCode = pTargetMethod->GetMultiCallableAddrOfVirtualizedCode(pRefFirstArg, pTargetMethod->GetMethodTable()); + // Casting Object** to OBJECTREF* is safe as long as no code attempts to mutate the OBJECTREF through the OBJECTREF* (and we don't, we only use it to read the this pointer/target object) + pTargetCode = pTargetMethod->GetMultiCallableAddrOfVirtualizedCode((OBJECTREF*)targetParameter.GetObjectPointer(), pTargetMethod->GetMethodTable()); } #ifdef HAS_THISPTR_RETBUF_PRECODE else if (pTargetMethod->IsStatic() && pTargetMethod->HasRetBuffArg() && IsRetBuffPassedAsFirstArg()) @@ -1286,15 +1258,13 @@ void COMDelegate::BindToMethod(DELEGATEREF *pRefThis, pTargetCode = pTargetMethod->GetMultiCallableAddrOfCode(); } _ASSERTE(pTargetCode); - - (*pRefThis)->SetTarget(*pRefFirstArg); - (*pRefThis)->SetMethodPtr(pTargetCode); + pBindToMethodDetails->methodPtr = pTargetCode; } LoaderAllocator *pLoaderAllocator = pTargetMethod->GetLoaderAllocator(); - if (pLoaderAllocator->IsCollectible()) - (*pRefThis)->SetMethodBase(pLoaderAllocator->GetExposedObject()); + // If the loader allocator is not collectible, this will be NULL + pBindToMethodDetails->loaderAllocatorGCHandle = pLoaderAllocator->GetLoaderAllocatorObjectHandle(); } // Marshals a delegate to a unmanaged callback. @@ -1341,6 +1311,7 @@ LPVOID COMDelegate::ConvertToCallback(OBJECTREF pDelegateObj) InteropSyncBlockInfo* pInteropInfo = pSyncBlock->GetInteropInfo(); + GCX_PREEMP(); pUMEntryThunk = pInteropInfo->GetUMEntryThunk(); if (!pUMEntryThunk) @@ -1350,8 +1321,6 @@ LPVOID COMDelegate::ConvertToCallback(OBJECTREF pDelegateObj) if (!pUMThunkMarshInfo) { - GCX_PREEMP(); - pUMThunkMarshInfo = (UMThunkMarshInfo*)(void*)pMT->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(DelegateUMThunkMarshInfo))); new (pUMThunkMarshInfo) DelegateUMThunkMarshInfo(pInvokeMeth); @@ -1368,15 +1337,22 @@ LPVOID COMDelegate::ConvertToCallback(OBJECTREF pDelegateObj) _ASSERTE(pUMThunkMarshInfo == pClass->m_pUMThunkMarshInfo); pUMEntryThunk = UMEntryThunkData::CreateUMEntryThunk(); + Holder umHolder; umHolder.Assign(pUMEntryThunk); - // multicast. go thru Invoke - OBJECTHANDLE objhnd = GetAppDomain()->CreateLongWeakHandle(pDelegate); - _ASSERTE(objhnd != NULL); + OBJECTHANDLE objhnd; + PCODE pManagedTargetForDiagnostics; + { + GCX_COOP(); + + // multicast. go thru Invoke + objhnd = GetAppDomain()->CreateLongWeakHandle(pDelegate); + _ASSERTE(objhnd != NULL); - // This target should not ever be used. We are storing it in the thunk for better diagnostics of "call on collected delegate" crashes. - PCODE pManagedTargetForDiagnostics = (pDelegate->GetMethodPtrAux() != (PCODE)NULL) ? pDelegate->GetMethodPtrAux() : pDelegate->GetMethodPtr(); + // This target should not ever be used. We are storing it in the thunk for better diagnostics of "call on collected delegate" crashes. + pManagedTargetForDiagnostics = (pDelegate->GetMethodPtrAux() != (PCODE)NULL) ? pDelegate->GetMethodPtrAux() : pDelegate->GetMethodPtr(); + } // MethodDesc is passed in for profiling to know the method desc of target pUMEntryThunk->LoadTimeInit( @@ -1576,13 +1552,13 @@ extern "C" void QCALLTYPE Delegate_InitializeVirtualCallStub(QCall::ObjectHandle BEGIN_QCALL; - GCX_COOP(); - MethodDesc *pMeth = NonVirtualEntry2MethodDesc((PCODE)method); _ASSERTE(pMeth); _ASSERTE(!pMeth->IsStatic() && pMeth->IsVirtual()); PCODE target = GetVirtualCallStub(pMeth, TypeHandle(pMeth->GetMethodTable())); + GCX_COOP(); + DELEGATEREF refThis = (DELEGATEREF)d.Get(); refThis->SetMethodPtrAux(target); refThis->SetInvocationCount((INT_PTR)(void*)pMeth); @@ -1590,18 +1566,12 @@ extern "C" void QCALLTYPE Delegate_InitializeVirtualCallStub(QCall::ObjectHandle END_QCALL; } -extern "C" PCODE QCALLTYPE Delegate_AdjustTarget(QCall::ObjectHandleOnStack target, PCODE method) +extern "C" PCODE QCALLTYPE Delegate_AdjustTarget(MethodTable* pMTTarg, PCODE method) { QCALL_CONTRACT; BEGIN_QCALL; - GCX_COOP(); - - _ASSERTE(method); - - MethodTable* pMTTarg = target.Get()->GetMethodTable(); - MethodDesc *pMeth = NonVirtualEntry2MethodDesc(method); _ASSERTE(pMeth); _ASSERTE(!pMeth->IsStatic()); @@ -1654,7 +1624,7 @@ uint32_t MethodDescToNumFixedArgs(MethodDesc *pMD) // This is the single constructor for all Delegates. The compiler // doesn't provide an implementation of the Delegate constructor. We // provide that implementation through a QCall call to this method. -extern "C" void QCALLTYPE Delegate_Construct(QCall::ObjectHandleOnStack _this, QCall::ObjectHandleOnStack target, PCODE method) +extern "C" void QCALLTYPE Delegate_Construct(MethodTable* pDelegateMT, MethodTable* pTargetMT, PCODE method, BindToMethodDetails *pBindToMethodDetails) { QCALL_CONTRACT; @@ -1663,23 +1633,15 @@ extern "C" void QCALLTYPE Delegate_Construct(QCall::ObjectHandleOnStack _this, Q _ASSERTE(method != (PCODE)NULL); BEGIN_QCALL; - GCX_COOP(); - - DELEGATEREF refThis = (DELEGATEREF) ObjectToOBJECTREF(_this.Get()); - _ASSERTE(refThis != NULL); - - GCPROTECT_BEGIN(refThis); + _ASSERTE(pDelegateMT != NULL); // Programmers could feed garbage data to DelegateConstruct(). // It's difficult to validate a method code pointer, but at least we'll // try to catch the easy garbage. _ASSERTE(isMemoryReadable(method, 1)); - MethodTable* pMTTarg = NULL; - if (target.Get() != NULL) - pMTTarg = target.Get()->GetMethodTable(); - - MethodTable* pDelMT = refThis->GetMethodTable(); + MethodTable* pMTTarg = pTargetMT; + MethodTable* pDelMT = pDelegateMT; MethodDesc* pMethOrig = NonVirtualEntry2MethodDesc(method); MethodDesc* pMeth = pMethOrig; _ASSERTE(pMeth != NULL); @@ -1708,38 +1670,41 @@ extern "C" void QCALLTYPE Delegate_Construct(QCall::ObjectHandleOnStack _this, Q if (!isStatic) methodArgCount++; // count 'this' - if (pMeth->GetLoaderAllocator()->IsCollectible()) - refThis->SetMethodBase(pMeth->GetLoaderAllocator()->GetExposedObject()); + // If the loader allocator is not collectible, this will be NULL + pBindToMethodDetails->loaderAllocatorGCHandle = pMeth->GetLoaderAllocator()->GetLoaderAllocatorObjectHandle(); // Open delegates. if (invokeArgCount == methodArgCount) { - // set the target - refThis->SetTarget(refThis); + pBindToMethodDetails->selfReferentialTarget = TRUE; // set the shuffle thunk PCODE pEntryPoint = SetupShuffleThunk(pDelMT, pMeth); - refThis->SetMethodPtr(pEntryPoint); + pBindToMethodDetails->methodPtr = pEntryPoint; // set the ptr aux according to what is needed, if virtual need to call make virtual stub dispatch if (!pMeth->IsStatic() && pMeth->IsVirtual() && !pMeth->GetMethodTable()->IsValueType()) { - PCODE pTargetCall = GetVirtualCallStub(pMeth, TypeHandle(pMeth->GetMethodTable())); - refThis->SetMethodPtrAux(pTargetCall); - refThis->SetInvocationCount((INT_PTR)(void *)pMeth); + PCODE pTargetCall; + { + pTargetCall = GetVirtualCallStub(pMeth, TypeHandle(pMeth->GetMethodTable())); + } + pBindToMethodDetails->methodPtrAux = pTargetCall; + pBindToMethodDetails->invocationCount = (INT_PTR)(void *)pMeth; } else { - refThis->SetMethodPtrAux(method); + pBindToMethodDetails->methodPtrAux = method; } } else { + pBindToMethodDetails->selfReferentialTarget = FALSE; MethodTable* pMTMeth = pMeth->GetMethodTable(); if (!pMeth->IsStatic()) { - if (target.Get() == NULL) + if (pTargetMT == NULL) COMPlusThrow(kArgumentException, W("Arg_DlgtNullInst")); if (pMTTarg != NULL) @@ -1779,11 +1744,9 @@ extern "C" void QCALLTYPE Delegate_Construct(QCall::ObjectHandleOnStack _this, Q } #endif // HAS_THISPTR_RETBUF_PRECODE - refThis->SetTarget(target.Get()); - refThis->SetMethodPtr((PCODE)(void *)method); + pBindToMethodDetails->methodPtr = (PCODE)(void *)method; } - GCPROTECT_END(); END_QCALL; } @@ -2044,7 +2007,10 @@ extern "C" void QCALLTYPE Delegate_FindMethodHandle(QCall::ObjectHandleOnStack d GCX_COOP(); MethodDesc* pMD = COMDelegate::GetMethodDesc(d.Get()); - pMD = MethodDesc::FindOrCreateAssociatedMethodDescForReflection(pMD, TypeHandle(pMD->GetMethodTable()), pMD->GetMethodInstantiation()); + { + GCX_PREEMP(); + pMD = MethodDesc::FindOrCreateAssociatedMethodDescForReflection(pMD, TypeHandle(pMD->GetMethodTable()), pMD->GetMethodInstantiation()); + } retMethodInfo.Set(pMD->AllocateStubMethodInfo()); END_QCALL; diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index 4982f93c418744..63d3c473703572 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -26,6 +26,15 @@ enum class ShuffleComputationType }; BOOL GenerateShuffleArrayPortable(MethodDesc* pMethodSrc, MethodDesc *pMethodDst, SArray * pShuffleEntryArray, ShuffleComputationType shuffleType); +struct BindToMethodDetails +{ + BOOL selfReferentialTarget; // Whether the delegate's target object is the same as the first argument of the method to bind to. Only meaningful for open instance delegates. + PCODE methodPtr; + PCODE methodPtrAux; + INT_PTR invocationCount; + OBJECTHANDLE loaderAllocatorGCHandle; // The loader allocator needed if the delegate needs to keep it alive +}; + // This class represents the native methods for the Delegate class class COMDelegate { @@ -80,18 +89,20 @@ class COMDelegate bool *pfIsOpenDelegate); static MethodDesc* GetDelegateCtor(TypeHandle delegateType, MethodDesc *pTargetMethod, DelegateCtorArgs *pCtorData); - static void BindToMethod(DELEGATEREF *pRefThis, - OBJECTREF *pRefFirstArg, + static void BindToMethod(MethodTable* pDelegateMT, + MethodTable *pTargetMT, MethodDesc *pTargetMethod, MethodTable *pExactMethodType, - BOOL fIsOpenDelegate); + BOOL fIsOpenDelegate, + QCall::ObjectHandleOnStack targetParameter, + BindToMethodDetails *pBindToMethodDetails); }; -extern "C" void QCALLTYPE Delegate_Construct(QCall::ObjectHandleOnStack _this, QCall::ObjectHandleOnStack target, PCODE method); +extern "C" void QCALLTYPE Delegate_Construct(MethodTable* pDelegateMT, MethodTable* pTargetMT, PCODE method, BindToMethodDetails *pBindToMethodDetails); extern "C" PCODE QCALLTYPE Delegate_GetMulticastInvokeSlow(MethodTable* pDelegateMT); -extern "C" PCODE QCALLTYPE Delegate_AdjustTarget(QCall::ObjectHandleOnStack target, PCODE method); +extern "C" PCODE QCALLTYPE Delegate_AdjustTarget(MethodTable* pMTTarg, PCODE method); extern "C" void QCALLTYPE Delegate_InitializeVirtualCallStub(QCall::ObjectHandleOnStack d, PCODE method); @@ -108,11 +119,11 @@ enum DelegateBindingFlags DBF_RelaxedSignature = 0x00000040, // Allow relaxed signature matching (co/contra variance) }; -extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(QCall::ObjectHandleOnStack d, QCall::ObjectHandleOnStack target, - QCall::TypeHandle pMethodType, LPCUTF8 pszMethodName, DelegateBindingFlags flags); +extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(MethodTable* pDelegateMT, MethodTable *pTargetMT, + QCall::TypeHandle pMethodType, LPCUTF8 pszMethodName, DelegateBindingFlags flags, QCall::ObjectHandleOnStack targetParameter, BindToMethodDetails *pBindToMethodDetails); -extern "C" BOOL QCALLTYPE Delegate_BindToMethodInfo(QCall::ObjectHandleOnStack d, QCall::ObjectHandleOnStack target, - MethodDesc * method, QCall::TypeHandle pMethodType, DelegateBindingFlags flags); +extern "C" BOOL QCALLTYPE Delegate_BindToMethodInfo(MethodTable* pDelegateMT, MethodTable *pTargetMT, + MethodDesc * method, QCall::TypeHandle pMethodType, DelegateBindingFlags flags, QCall::ObjectHandleOnStack targetParameter, BindToMethodDetails *pBindToMethodDetails); extern "C" void QCALLTYPE Delegate_FindMethodHandle(QCall::ObjectHandleOnStack d, QCall::ObjectHandleOnStack retMethodInfo); diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp index 8db3217f1cb855..64723383a2ad6e 100644 --- a/src/coreclr/vm/comutilnative.cpp +++ b/src/coreclr/vm/comutilnative.cpp @@ -775,19 +775,23 @@ extern "C" void* QCALLTYPE GCInterface_GetNextFinalizableObject(QCall::ObjectHan BEGIN_QCALL; - GCX_COOP(); - - OBJECTREF target = FinalizerThread::GetNextFinalizableObject(); - - if (target != NULL) + MethodTable *pTargetMT = NULL; { - pObj.Set(target); + GCX_COOP(); - MethodTable* pMT = target->GetMethodTable(); + OBJECTREF target = FinalizerThread::GetNextFinalizableObject(); - funcPtr = pMT->GetRestoredSlot(g_pObjectFinalizerMD->GetSlot()); + if (target != NULL) + { + pObj.Set(target); + + pTargetMT = target->GetMethodTable(); + } } + if (pTargetMT != NULL) + funcPtr = pTargetMT->GetRestoredSlot(g_pObjectFinalizerMD->GetSlot()); + END_QCALL; return (void*)funcPtr; diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp index 64e0e308e9aba4..e7c525050bd8e0 100644 --- a/src/coreclr/vm/corhost.cpp +++ b/src/coreclr/vm/corhost.cpp @@ -430,7 +430,11 @@ HRESULT CorHost2::ExecuteInDefaultAppDomain(LPCWSTR pwzAssemblyPath, UnmanagedCallersOnlyCaller executeInDefaultAppDomain(METHOD__ENVIRONMENT__EXECUTE_IN_DEFAULT_APP_DOMAIN); pMethodMD->EnsureActive(); - PCODE entryPoint = pMethodMD->GetSingleCallableAddrOfCode(); + PCODE entryPoint; + { + GCX_PREEMP(); + entryPoint = pMethodMD->GetSingleCallableAddrOfCode(); + } INT32 retval = executeInDefaultAppDomain.InvokeThrowing_Ret( static_cast(entryPoint), diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index 59c3d87f73b3d2..7f82b876f718d1 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -915,7 +915,14 @@ extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( MethodDesc* pCtorMD = ((REFLECTMETHODREF)pMethod.Get())->GetMethod(); TypeHandle th = ((REFLECTCLASSBASEREF)pCaType.Get())->GetType(); - MethodDescCallSite ctorCallSite(pCtorMD, th); + PCODE pCallTarget; + + { + GCX_PREEMP(); + pCallTarget = pCtorMD->GetCallTarget(NULL, th); + } + + MethodDescCallSite ctorCallSite(pCtorMD, pCallTarget, th); MetaSig* pSig = ctorCallSite.GetMetaSig(); BYTE* pBlob = *ppBlob; diff --git a/src/coreclr/vm/dispatchinfo.cpp b/src/coreclr/vm/dispatchinfo.cpp index 388c4366d2e74d..fe840a99ea99c5 100644 --- a/src/coreclr/vm/dispatchinfo.cpp +++ b/src/coreclr/vm/dispatchinfo.cpp @@ -2514,13 +2514,12 @@ BOOL DispatchInfo::SynchWithManagedView() // Determine if this is the first time we synch. BOOL bFirstSynch = (m_pFirstMemberInfo == NULL); + GCX_PREEMP(); + // This method needs to be synchronized to make sure two threads don't try and // add members at the same time. CrstHolder ch(&m_lock); { - // Make sure we switch to cooperative mode before we start. - GCX_COOP(); - // Go through the list of member info's and find the end. DispatchMemberInfo **ppNextMember = &m_pFirstMemberInfo; while (*ppNextMember) @@ -2529,6 +2528,9 @@ BOOL DispatchInfo::SynchWithManagedView() // Retrieve the member info map. pMemberMap = GetMemberInfoMap(); + // Make sure we switch to cooperative mode before we start. + GCX_COOP(); + for (int cPhase = 0; cPhase < 3; cPhase++) { PTRARRAYREF MemberArrayObj = NULL; @@ -2837,13 +2839,12 @@ ComMTMemberInfoMap *DispatchInfo::GetMemberInfoMap() { THROWS; GC_TRIGGERS; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM()); POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; - // Create the member info map. NewHolder pMemberInfoMap (new ComMTMemberInfoMap(m_pMT)); diff --git a/src/coreclr/vm/dllimportcallback.cpp b/src/coreclr/vm/dllimportcallback.cpp index e4cb9206c9160f..5c08f190499e49 100644 --- a/src/coreclr/vm/dllimportcallback.cpp +++ b/src/coreclr/vm/dllimportcallback.cpp @@ -19,9 +19,7 @@ #include "stubgen.h" #include "appdomain.inl" -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif class UMEntryThunkFreeList { @@ -122,7 +120,7 @@ UMEntryThunkData *UMEntryThunkCache::GetUMEntryThunk(MethodDesc *pMD) { THROWS; GC_TRIGGERS; - MODE_ANY; + MODE_PREEMPTIVE; PRECONDITION(CheckPointer(pMD)); POSTCONDITION(CheckPointer(RETVAL)); } @@ -270,7 +268,7 @@ UMEntryThunkData* UMEntryThunkData::CreateUMEntryThunk() { THROWS; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM()); POSTCONDITION(CheckPointer(RETVAL)); } @@ -293,9 +291,7 @@ UMEntryThunkData* UMEntryThunkData::CreateUMEntryThunk() #else // !FEATURE_PORTABLE_ENTRYPOINTS pThunk = (UMEntryThunk*)pamTracker->Track(pLoaderAllocator->GetNewStubPrecodeHeap()->AllocStub()); #endif // FEATURE_PORTABLE_ENTRYPOINTS -#ifdef FEATURE_PERFMAP PerfMap::LogStubs(__FUNCTION__, "UMEntryThunk", (PCODE)pThunk, sizeof(UMEntryThunk), PerfMapStubType::IndividualWithinBlock); -#endif pData->m_pUMEntryThunk = pThunk; pThunk->Init(pThunk, dac_cast(pData), NULL, dac_cast(PRECODE_UMENTRY_THUNK)); pamTracker->SuppressRelease(); diff --git a/src/coreclr/vm/encee.cpp b/src/coreclr/vm/encee.cpp index 025df8ac2aa77f..9a8bd30c3e13d3 100644 --- a/src/coreclr/vm/encee.cpp +++ b/src/coreclr/vm/encee.cpp @@ -109,7 +109,7 @@ HRESULT EditAndContinueModule::ApplyEditAndContinue( { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -340,7 +340,7 @@ HRESULT EditAndContinueModule::UpdateMethod(MethodDesc *pMethod) { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -417,7 +417,7 @@ HRESULT EditAndContinueModule::AddMethod(mdMethodDef token) { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -493,7 +493,7 @@ HRESULT EditAndContinueModule::AddField(mdFieldDef token) { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -1147,7 +1147,7 @@ void EnCFieldDesc::Init(mdFieldDef token, BOOL fIsStatic) { THROWS; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -1627,17 +1627,18 @@ void EnCEEClassData::AddField(EnCAddedFieldElement *pAddedField) // If the list is empty, just add this field as the only entry if (*pList == NULL) { - *pList = pAddedField; + VolatileStore(pList, pAddedField); return; } // Otherwise, add this field to the end of the field list - EnCAddedFieldElement *pCur = *pList; - while (pCur->m_next != NULL) + EnCAddedFieldElement *pCur = VolatileLoad(pList); + EnCAddedFieldElement *pNext; + while (pNext = VolatileLoad(&pCur->m_next), pNext != NULL) { - pCur = pCur->m_next; + pCur = pNext; } - pCur->m_next = pAddedField; + VolatileStore(&pCur->m_next, pAddedField); } #endif // #ifndef DACCESS_COMPILE @@ -1831,7 +1832,7 @@ PTR_EnCFieldDesc EncApproxFieldDescIterator::NextEnC() // We're at the start of the instance list. if ( doInst ) { - m_pCurrListElem = m_encClassData->m_pAddedInstanceFields; + m_pCurrListElem = VolatileLoad(&m_encClassData->m_pAddedInstanceFields); } } @@ -1844,7 +1845,7 @@ PTR_EnCFieldDesc EncApproxFieldDescIterator::NextEnC() // We're at the start of the statics list. if ( doStatic ) { - m_pCurrListElem = m_encClassData->m_pAddedStaticFields; + m_pCurrListElem = VolatileLoad(&m_encClassData->m_pAddedStaticFields); } } @@ -1859,7 +1860,7 @@ PTR_EnCFieldDesc EncApproxFieldDescIterator::NextEnC() // Advance the list pointer and return the element m_encFieldsReturned++; PTR_EnCFieldDesc fd = PTR_EnCFieldDesc(PTR_HOST_MEMBER_TADDR(EnCAddedFieldElement, m_pCurrListElem, m_fieldDesc)); - m_pCurrListElem = m_pCurrListElem->m_next; + m_pCurrListElem = VolatileLoad(&m_pCurrListElem->m_next); return fd; } diff --git a/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h index 67d8e3c54dd6eb..b8ad4bc9585b26 100644 --- a/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h @@ -15,9 +15,7 @@ #include #include #include -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #undef DS_LOG_ALWAYS_0 #define DS_LOG_ALWAYS_0(msg) STRESS_LOG0(LF_DIAGNOSTICS_PORT, LL_ALWAYS, msg "\n") diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 0bc243d9650e18..6791a194729b26 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -9556,7 +9556,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowWin32() CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9572,7 +9572,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowWin32(HRESULT hr) CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9593,7 +9593,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowOM() CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; CANNOT_TAKE_LOCK; MODE_ANY; SUPPORTS_DAC; @@ -9611,7 +9611,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrow(RuntimeExceptionKind reKind) CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9631,7 +9631,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowNonLocalized(RuntimeExceptionKind reKind, CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9712,33 +9712,13 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr) EX_THROW(EEMessageException, (hr)); } - -VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr, tagGetErrorInfo) -{ - CONTRACTL - { - THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this - MODE_ANY; - } - CONTRACTL_END; - - // Get an IErrorInfo if one is available. - IErrorInfo *pErrInfo = NULL; - - if (SafeGetErrorInfo(&pErrInfo) != S_OK) - pErrInfo = NULL; - - // Throw the exception. - RealCOMPlusThrowHR(hr, pErrInfo); -} #else // FEATURE_COMINTEROP VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr) { CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9786,7 +9766,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrow(RuntimeExceptionKind reKind, LPCWSTR wsz CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; PRECONDITION(CheckPointer(wszResourceName)); } @@ -9826,7 +9806,7 @@ VOID DECLSPEC_NORETURN ThrowTypeLoadException(LPCWSTR pFullTypeName, CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9846,7 +9826,7 @@ VOID DECLSPEC_NORETURN ThrowFieldLayoutError(mdTypeDef cl, // cl CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9877,7 +9857,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowArithmetic() CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9893,7 +9873,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowArgumentNull(LPCWSTR argName, LPCWSTR wsz CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; PRECONDITION(CheckPointer(wszResourceName)); } @@ -9908,7 +9888,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowArgumentNull(LPCWSTR argName) CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9925,7 +9905,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowArgumentOutOfRange(LPCWSTR argName, LPCWS CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9941,7 +9921,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowArgumentException(LPCWSTR argName, LPCWST CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9966,7 +9946,7 @@ VOID DECLSPEC_NORETURN ThrowTypeLoadException(LPCUTF8 pszNameSpace, CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -9984,7 +9964,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrow(RuntimeExceptionKind reKind, UINT resID CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -10024,7 +10004,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(EXCEPINFO *pExcepInfo) CONTRACTL { THROWS; - DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; diff --git a/src/coreclr/vm/excep.h b/src/coreclr/vm/excep.h index 472782de483d33..04c737390dbe5a 100644 --- a/src/coreclr/vm/excep.h +++ b/src/coreclr/vm/excep.h @@ -239,13 +239,6 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr, UINT resID, LPCWSTR wszArg #ifdef FEATURE_COMINTEROP -enum tagGetErrorInfo -{ - kGetErrorInfo -}; - -VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr, tagGetErrorInfo); - //========================================================================== // Throw a runtime exception based on an HResult, check for error info //========================================================================== diff --git a/src/coreclr/vm/fptrstubs.cpp b/src/coreclr/vm/fptrstubs.cpp index cf3f4db379f92b..f0e3a466df6bf0 100644 --- a/src/coreclr/vm/fptrstubs.cpp +++ b/src/coreclr/vm/fptrstubs.cpp @@ -78,6 +78,7 @@ PCODE FuncPtrStubs::GetFuncPtrStub(MethodDesc * pMD, PrecodeType type) { return pPrecode->GetEntryPoint(); } + GCX_PREEMP(); PCODE target = (PCODE)NULL; bool setTargetAfterAddingToHashTable = false; @@ -151,8 +152,6 @@ PCODE FuncPtrStubs::GetFuncPtrStub(MethodDesc * pMD, PrecodeType type) if (setTargetAfterAddingToHashTable) { - GCX_PREEMP(); - _ASSERTE(pMD->IsVersionableWithVtableSlotBackpatch()); PCODE temporaryEntryPoint = pMD->GetTemporaryEntryPoint(); diff --git a/src/coreclr/vm/genericdict.cpp b/src/coreclr/vm/genericdict.cpp index e9d15c0fa6bb63..ce2cfd806363f8 100644 --- a/src/coreclr/vm/genericdict.cpp +++ b/src/coreclr/vm/genericdict.cpp @@ -674,6 +674,7 @@ Dictionary::PopulateEntry( Module * pModule /* = NULL */) { CONTRACTL { + MODE_PREEMPTIVE; THROWS; GC_TRIGGERS; } CONTRACTL_END; diff --git a/src/coreclr/vm/genmeth.cpp b/src/coreclr/vm/genmeth.cpp index d85bc52fd210fe..3dad76b6d29983 100644 --- a/src/coreclr/vm/genmeth.cpp +++ b/src/coreclr/vm/genmeth.cpp @@ -170,6 +170,7 @@ static MethodDesc * FindTightlyBoundWrappedMethodDesc(MethodDesc * pMD) { CONTRACTL { + MODE_ANY; NOTHROW; GC_NOTRIGGER; PRECONDITION(CheckPointer(pMD)); @@ -401,6 +402,7 @@ InstantiatedMethodDesc::NewInstantiatedMethodDesc(MethodTable *pExactMT, { CONTRACT(InstantiatedMethodDesc*) { + MODE_PREEMPTIVE; THROWS; GC_TRIGGERS; INJECT_FAULT(COMPlusThrowOM();); @@ -596,45 +598,6 @@ InstantiatedMethodDesc::NewInstantiatedMethodDesc(MethodTable *pExactMT, RETURN pNewMD; } - -// Calling this method is equivalent to -// FindOrCreateAssociatedMethodDesc(pCanonicalMD, pExactMT, FALSE, Instantiation(), FALSE, TRUE) -// except that it also creates InstantiatedMethodDescs based on shared class methods. This is -// convenient for interop where, unlike ordinary managed methods, marshaling stubs for say Foo -// and Foo look very different and need separate representation. -InstantiatedMethodDesc* -InstantiatedMethodDesc::FindOrCreateExactClassMethod(MethodTable *pExactMT, - MethodDesc *pCanonicalMD) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(!pExactMT->IsSharedByGenericInstantiations()); - PRECONDITION(pCanonicalMD->IsSharedByGenericInstantiations()); - } - CONTRACTL_END; - - InstantiatedMethodDesc *pInstMD = FindLoadedInstantiatedMethodDesc(pExactMT, - pCanonicalMD->GetMemberDef(), - Instantiation(), - FALSE, - pCanonicalMD->IsAsyncVariantMethod()); - - if (pInstMD == NULL) - { - // create a new MD if not found - pInstMD = NewInstantiatedMethodDesc(pExactMT, - pCanonicalMD, - pCanonicalMD, - Instantiation(), - FALSE); - } - - return pInstMD; -} - #endif // !DACCESS_COMPILE // N.B. it is not guarantee that the returned InstantiatedMethodDesc is restored. @@ -807,6 +770,7 @@ MethodDesc::FindOrCreateAssociatedMethodDesc(MethodDesc* pDefMD, CONTRACT(MethodDesc*) { THROWS; + if (allowCreate) { MODE_PREEMPTIVE; } else { MODE_ANY; } if (allowCreate) { GC_TRIGGERS; } else { GC_NOTRIGGER; } if (!allowCreate) { SUPPORTS_DAC; } INJECT_FAULT(COMPlusThrowOM();); @@ -1322,6 +1286,7 @@ MethodDesc::FindOrCreateAssociatedMethodDesc(MethodDesc* pDefMD, Instantiation methodInst) { CONTRACTL { + MODE_PREEMPTIVE; THROWS; GC_TRIGGERS; // Because allowCreate is TRUE PRECONDITION(CheckPointer(pMethod)); diff --git a/src/coreclr/vm/i386/cgenx86.cpp b/src/coreclr/vm/i386/cgenx86.cpp index 8068a7ed4f1a70..fa234e073cc976 100644 --- a/src/coreclr/vm/i386/cgenx86.cpp +++ b/src/coreclr/vm/i386/cgenx86.cpp @@ -37,9 +37,7 @@ #include "stublink.inl" -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegisters * regs) { @@ -565,13 +563,9 @@ void ResumeAtJit(PCONTEXT pContext, LPVOID oldESP) size_t rxOffset = pStartRX - pStart; \ BYTE * p = pStart; -#ifdef FEATURE_PERFMAP #define BEGIN_DYNAMIC_HELPER_EMIT(size) \ BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) \ PerfMap::LogStubs(__FUNCTION__, "DynamicHelper", (PCODE)p, size, PerfMapStubType::Individual); -#else -#define BEGIN_DYNAMIC_HELPER_EMIT(size) BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) -#endif #define END_DYNAMIC_HELPER_EMIT() \ _ASSERTE(pStart + cb == p); \ diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 714f41bfa7a742..0cee688250ef1d 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -3161,6 +3161,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr // miss, resolve the virtual method and cache it targetMethod = CallWithSEHWrapper( [&pMD, &pThisArg]() { + GCX_PREEMP(); return pMD->GetMethodDescOfVirtualizedCode(pThisArg, pMD->GetMethodTable()); }); g_InterpDispatchCache.Insert(dispatchToken, pObjMT, targetMethod, (uint16_t)dispatchTokenHash); @@ -3328,6 +3329,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr NULL_CHECK(*pThisArg); targetMethod = CallWithSEHWrapper( [&targetMethod, &pThisArg]() { + GCX_PREEMP(); return targetMethod->GetMethodDescOfVirtualizedCode(pThisArg, targetMethod->GetMethodTable()); }); } diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index a389d56231ba0c..1861f91bc15f88 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -721,6 +721,7 @@ extern "C" PCODE QCALLTYPE ResolveVirtualFunctionPointer(QCall::ObjectHandleOnSt } else { + GCX_PREEMP(); // This is the new way of resolving a virtual call, including generic virtual methods. // The code is now also used by reflection, remoting etc. addr = pStaticMD->GetMultiCallableAddrOfVirtualizedCode(&objRef, staticTH); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index cbe730ecd363e7..7aaa7238d70364 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -52,9 +52,7 @@ #endif // HAVE_GCCOVER #include "debugdebugger.h" -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #ifdef FEATURE_PGO #include "pgo.h" diff --git a/src/coreclr/vm/loongarch64/stubs.cpp b/src/coreclr/vm/loongarch64/stubs.cpp index fc5a820e0aca07..096d160695d435 100644 --- a/src/coreclr/vm/loongarch64/stubs.cpp +++ b/src/coreclr/vm/loongarch64/stubs.cpp @@ -14,9 +14,7 @@ #include "jitinterface.h" #include "ecall.h" -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #ifndef DACCESS_COMPILE //----------------------------------------------------------------------- @@ -961,13 +959,9 @@ void StubLinkerCPU::EmitCallManagedMethod(MethodDesc *pMD, BOOL fTailCall) size_t rxOffset = pStartRX - pStart; \ BYTE * p = pStart; -#ifdef FEATURE_PERFMAP #define BEGIN_DYNAMIC_HELPER_EMIT(size) \ BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) \ PerfMap::LogStubs(__FUNCTION__, "DynamicHelper", (PCODE)p, size, PerfMapStubType::Individual); -#else -#define BEGIN_DYNAMIC_HELPER_EMIT(size) BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) -#endif #define END_DYNAMIC_HELPER_EMIT() \ _ASSERTE(pStart + cb == p); \ diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index a71ea6efd1a0c2..ac0d91b15957e8 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -619,7 +619,7 @@ PCODE MethodDesc::GetMethodEntryPoint() { THROWS; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; SUPPORTS_DAC; } CONTRACTL_END; @@ -1602,7 +1602,6 @@ MethodDesc *MethodDesc::GetExistingWrappedMethodDesc() { THROWS; GC_NOTRIGGER; - MODE_ANY; } CONTRACTL_END; @@ -1937,6 +1936,7 @@ MethodDesc* MethodDesc::ResolveGenericVirtualMethod(OBJECTREF *orThis) { CONTRACT(MethodDesc *) { + MODE_PREEMPTIVE; THROWS; GC_TRIGGERS; @@ -1949,7 +1949,12 @@ MethodDesc* MethodDesc::ResolveGenericVirtualMethod(OBJECTREF *orThis) CONTRACT_END; // Method table of target (might be instantiated) - MethodTable *pObjMT = (*orThis)->GetMethodTable(); + MethodTable *pObjMT; + + { + GCX_COOP(); + pObjMT = (*orThis)->GetMethodTable(); + } // This is the static method descriptor describing the call. // It is not the destination of the call, which we must compute. @@ -2007,7 +2012,7 @@ PCODE MethodDesc::GetSingleCallableAddrOfCodeForUnmanagedCallersOnly() { THROWS; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; PRECONDITION(HasUnmanagedCallersOnlyAttribute()); } CONTRACTL_END; @@ -2028,16 +2033,22 @@ PCODE MethodDesc::GetSingleCallableAddrOfCodeForUnmanagedCallersOnly() //******************************************************************************* PCODE MethodDesc::GetSingleCallableAddrOfVirtualizedCode(OBJECTREF *orThis, TypeHandle staticTH) { - WRAPPER_NO_CONTRACT; - PRECONDITION(IsVtableMethod()); + CONTRACTL + { + THROWS; // Resolving a generic virtual method can throw + GC_TRIGGERS; + MODE_PREEMPTIVE; + } + CONTRACTL_END; - MethodTable *pObjMT = (*orThis)->GetMethodTable(); + PRECONDITION(IsVtableMethod()); + if (HasMethodInstantiation()) { CheckRestore(); MethodDesc *pResultMD = ResolveGenericVirtualMethod(orThis); - + // If we're remoting this call we can't call directly on the returned // method desc, we need to go through a stub that guarantees we end up // in the remoting handler. The stub we use below is normally just for @@ -2045,16 +2056,21 @@ PCODE MethodDesc::GetSingleCallableAddrOfVirtualizedCode(OBJECTREF *orThis, Type // where we could end up bypassing the remoting system), but it serves // our purpose here (basically pushes our correctly instantiated, // resolved method desc on the stack and calls the remoting code). - + return pResultMD->GetSingleCallableAddrOfCode(); } - + if (IsInterface()) { MethodDesc * pTargetMD = MethodTable::GetMethodDescForInterfaceMethodAndServer(staticTH,this,orThis); return pTargetMD->GetSingleCallableAddrOfCode(); } - + + MethodTable *pObjMT; + { + GCX_COOP(); + pObjMT = (*orThis)->GetMethodTable(); + } return pObjMT->GetRestoredSlot(GetSlot()); } @@ -2062,6 +2078,7 @@ MethodDesc* MethodDesc::GetMethodDescOfVirtualizedCode(OBJECTREF *orThis, TypeHa { CONTRACT(MethodDesc*) { + MODE_PREEMPTIVE; THROWS; GC_TRIGGERS; @@ -2070,8 +2087,6 @@ MethodDesc* MethodDesc::GetMethodDescOfVirtualizedCode(OBJECTREF *orThis, TypeHa POSTCONDITION(RETVAL != NULL); } CONTRACT_END; - // Method table of target (might be instantiated) - MethodTable *pObjMT = (*orThis)->GetMethodTable(); // This is the static method descriptor describing the call. // It is not the destination of the call, which we must compute. @@ -2088,6 +2103,12 @@ MethodDesc* MethodDesc::GetMethodDescOfVirtualizedCode(OBJECTREF *orThis, TypeHa RETURN(MethodTable::GetMethodDescForInterfaceMethodAndServer(staticTH, pStaticMD, orThis)); } + // Method table of target (might be instantiated) + MethodTable *pObjMT; + { + GCX_COOP(); + pObjMT = (*orThis)->GetMethodTable(); + } RETURN(pObjMT->GetMethodDescForSlot(pStaticMD->GetSlot())); } @@ -2099,6 +2120,7 @@ PCODE MethodDesc::GetMultiCallableAddrOfVirtualizedCode(OBJECTREF *orThis, TypeH { CONTRACT(PCODE) { + MODE_PREEMPTIVE; THROWS; GC_TRIGGERS; POSTCONDITION(RETVAL != NULL); @@ -2294,7 +2316,7 @@ PCODE MethodDesc::GetCallTarget(OBJECTREF* pThisObj, TypeHandle ownerType) { THROWS; // Resolving a generic virtual method can throw GC_TRIGGERS; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; } CONTRACTL_END @@ -2789,7 +2811,7 @@ PCODE MethodDesc::GetTemporaryEntryPoint() { THROWS; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -2864,7 +2886,7 @@ void MethodDesc::EnsureTemporaryEntryPointCore(AllocMemTracker *pamTracker) { THROWS; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index b99da340071645..628c3f4de7bb47 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -3884,9 +3884,6 @@ class InstantiatedMethodDesc final : public MethodDesc WORD m_wNumGenericArgs; public: - static InstantiatedMethodDesc *FindOrCreateExactClassMethod(MethodTable *pExactMT, - MethodDesc *pCanonicalMD); - static InstantiatedMethodDesc* FindLoadedInstantiatedMethodDesc(MethodTable *pMT, mdMethodDef methodDef, Instantiation methodInst, diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index d29124382c46ef..772b84adf44f73 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -475,7 +475,7 @@ PTR_MethodTable InterfaceInfo_t::GetApproxMethodTable(Module * pContainingModule { THROWS; GC_TRIGGERS; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; PRECONDITION(CheckPointer(pItfMD)); PRECONDITION(pItfMD->IsInterface()); PRECONDITION(!ownerType.IsNull()); @@ -483,14 +483,23 @@ PTR_MethodTable InterfaceInfo_t::GetApproxMethodTable(Module * pContainingModule POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; - VALIDATEOBJECTREF(*pServer); +#ifdef DEBUG + { + GCX_COOP(); + VALIDATEOBJECTREF(*pServer); + } +#endif #ifdef _DEBUG MethodTable * pItfMT = ownerType.GetMethodTable(); _ASSERTE(pItfMT != NULL); #endif // _DEBUG - MethodTable *pServerMT = (*pServer)->GetMethodTable(); + MethodTable *pServerMT; + { + GCX_COOP(); + pServerMT = (*pServer)->GetMethodTable(); + } _ASSERTE(pServerMT != NULL); #ifdef FEATURE_COMINTEROP @@ -516,15 +525,19 @@ PTR_MethodTable InterfaceInfo_t::GetApproxMethodTable(Module * pContainingModule && !TypeHandle(pServerMT).CanCastTo(ownerType)) // we need to make sure object doesn't implement this interface in a natural way { TypeHandle implTypeHandle; - OBJECTREF obj = *pServer; + { + GCX_COOP(); - GCPROTECT_BEGIN(obj); - OBJECTREF implTypeRef = DynamicInterfaceCastable::GetInterfaceImplementation(&obj, ownerType); - _ASSERTE(implTypeRef != NULL); + OBJECTREF obj = *pServer; - ReflectClassBaseObject *implTypeObj = ((ReflectClassBaseObject *)OBJECTREFToObject(implTypeRef)); - implTypeHandle = implTypeObj->GetType(); - GCPROTECT_END(); + GCPROTECT_BEGIN(obj); + OBJECTREF implTypeRef = DynamicInterfaceCastable::GetInterfaceImplementation(&obj, ownerType); + _ASSERTE(implTypeRef != NULL); + + ReflectClassBaseObject *implTypeObj = ((ReflectClassBaseObject *)OBJECTREFToObject(implTypeRef)); + implTypeHandle = implTypeObj->GetType(); + GCPROTECT_END(); + } RETURN(implTypeHandle.GetMethodTable()->GetMethodDescForInterfaceMethod(ownerType, pItfMD, TRUE /* throwOnConflict */)); } @@ -542,7 +555,7 @@ MethodDesc *MethodTable::GetMethodDescForComInterfaceMethod(MethodDesc *pItfMD) { THROWS; GC_TRIGGERS; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; PRECONDITION(CheckPointer(pItfMD)); PRECONDITION(pItfMD->IsInterface()); PRECONDITION(IsComObjectType()); @@ -3537,7 +3550,11 @@ BOOL MethodTable::RunClassInitEx(OBJECTREF *pThrowable) MethodTable * pCanonMT = GetCanonicalMethodTable(); // Call the code method without touching MethodDesc if possible - PCODE pCctorCode = pCanonMT->GetRestoredSlot(pCanonMT->GetClassConstructorSlot()); + PCODE pCctorCode; + { + GCX_PREEMP(); + pCctorCode = pCanonMT->GetRestoredSlot(pCanonMT->GetClassConstructorSlot()); + } MethodTable* instantiatingArg = pCanonMT->IsSharedByGenericInstantiations() ? this : nullptr; UnmanagedCallersOnlyCaller caller(METHOD__INITHELPERS__CALLCLASSCONSTRUCTOR); caller.InvokeThrowing(pCctorCode, instantiatingArg); @@ -7750,7 +7767,7 @@ PCODE MethodTable::GetRestoredSlot(DWORD slotNumber) CONTRACTL { THROWS; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; SUPPORTS_DAC; } CONTRACTL_END; diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 5bd6ddf711b680..e6b343e86a2e63 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -407,7 +407,7 @@ inline MethodDesc* MethodTable::GetMethodDescForSlot(DWORD slot) { THROWS; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index fb16290b29e561..586558485195ed 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -675,7 +675,7 @@ MethodTableBuilder::BuildMethodTableThrowException( CONTRACTL { THROWS; - GC_TRIGGERS; + GC_NOTRIGGER; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END @@ -6255,7 +6255,7 @@ MethodTableBuilder::InitMethodDesc( { THROWS; if (fEnC) { GC_NOTRIGGER; } else { GC_TRIGGERS; } - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; diff --git a/src/coreclr/vm/methodtablebuilder.h b/src/coreclr/vm/methodtablebuilder.h index fece0cc7c6f83f..d7096697f61d4f 100644 --- a/src/coreclr/vm/methodtablebuilder.h +++ b/src/coreclr/vm/methodtablebuilder.h @@ -2394,8 +2394,8 @@ class MethodTableBuilder CONTRACTL { THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; } CONTRACTL_END; bmtError->resIDWhy = idResWhy; @@ -2416,8 +2416,8 @@ class MethodTableBuilder CONTRACTL { THROWS; - GC_TRIGGERS; - MODE_ANY; + GC_NOTRIGGER; + MODE_PREEMPTIVE; } CONTRACTL_END; bmtError->resIDWhy = idResWhy; diff --git a/src/coreclr/vm/perfmap.cpp b/src/coreclr/vm/perfmap.cpp index 248488d1383dc2..4efb8e36b935b5 100644 --- a/src/coreclr/vm/perfmap.cpp +++ b/src/coreclr/vm/perfmap.cpp @@ -422,7 +422,7 @@ void PerfMap::LogStubs(const char* stubType, const char* stubOwner, PCODE pCode, CONTRACTL { GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; diff --git a/src/coreclr/vm/perfmap.h b/src/coreclr/vm/perfmap.h index c748c95bd67f40..972d992ad6e747 100644 --- a/src/coreclr/vm/perfmap.h +++ b/src/coreclr/vm/perfmap.h @@ -57,7 +57,7 @@ class PerfMap CONTRACTL { GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; } diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp index 6b72dee83957bc..e62556c72e9bda 100644 --- a/src/coreclr/vm/precode.cpp +++ b/src/coreclr/vm/precode.cpp @@ -15,9 +15,7 @@ #include #endif // FEATURE_INTERPRETER -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif InterleavedLoaderHeapConfig s_stubPrecodeHeapConfig; #ifdef HAS_FIXUP_PRECODE @@ -253,9 +251,7 @@ InterpreterPrecode* Precode::AllocateInterpreterPrecode(PCODE byteCode, FlushCacheForDynamicMappedStub(pPrecode, sizeof(InterpreterPrecode)); -#ifdef FEATURE_PERFMAP PerfMap::LogStubs(__FUNCTION__, "UMEntryThunk", (PCODE)pPrecode, sizeof(InterpreterPrecode), PerfMapStubType::IndividualWithinBlock); -#endif return pPrecode; } #endif // FEATURE_INTERPRETER @@ -288,9 +284,7 @@ Precode* Precode::Allocate(PrecodeType t, MethodDesc* pMD, // to see the actual final Target (which doesn't require any further synchronization), or we'll hit the memory // barrier in the second portion of the FixupPrecodeThunk and find that the MethodDesc/PrecodeFixupThunk are // properly set. See FixupPrecode::GenerateDataPage for the code to fill in the target. -#ifdef FEATURE_PERFMAP PerfMap::LogStubs(__FUNCTION__, "FixupPrecode", (PCODE)pPrecode, sizeof(FixupPrecode), PerfMapStubType::IndividualWithinBlock); -#endif } #ifdef HAS_THISPTR_RETBUF_PRECODE else if (t == PRECODE_THISPTR_RETBUF) @@ -302,9 +296,7 @@ Precode* Precode::Allocate(PrecodeType t, MethodDesc* pMD, FlushCacheForDynamicMappedStub(pPrecode, sizeof(ThisPtrRetBufPrecode)); -#ifdef FEATURE_PERFMAP PerfMap::LogStubs(__FUNCTION__, "ThisPtrRetBuf", (PCODE)pPrecode, sizeof(ThisPtrRetBufPrecodeData), PerfMapStubType::IndividualWithinBlock); -#endif } #endif // HAS_THISPTR_RETBUF_PRECODE else @@ -315,9 +307,7 @@ Precode* Precode::Allocate(PrecodeType t, MethodDesc* pMD, FlushCacheForDynamicMappedStub(pPrecode, sizeof(StubPrecode)); -#ifdef FEATURE_PERFMAP PerfMap::LogStubs(__FUNCTION__, t == PRECODE_STUB ? "StubPrecode" : "PInvokeImportPrecode", (PCODE)pPrecode, sizeof(StubPrecode), PerfMapStubType::IndividualWithinBlock); -#endif } return pPrecode; diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 17cff51ae1a062..d18e05102dc78b 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -33,9 +33,7 @@ #include "clrtocomcall.h" #endif -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #include "methoddescbackpatchinfo.h" @@ -371,10 +369,8 @@ PCODE MethodDesc::PrepareCode(PrepareCodeConfig* pConfig) pCode = GetPrecompiledCode(pConfig, shouldTier); } -#ifdef FEATURE_PERFMAP if (pCode != (PCODE)NULL) PerfMap::LogPreCompiledMethod(this, pCode); -#endif } if (pConfig->IsForMulticoreJit() && pCode == (PCODE)NULL && pConfig->ReadyToRunRejectedPrecompiledCode()) @@ -876,10 +872,8 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J } #endif // PROFILING_SUPPORTED -#ifdef FEATURE_PERFMAP // Save the JIT'd method information so that perf can resolve JIT'd call frames. PerfMap::LogJITCompiledMethod(this, pCode, sizeOfCode, pConfig); -#endif // The notification will only occur if someone has registered for this method. DACNotifyCompilationFinished(this, pCode); @@ -2879,14 +2873,16 @@ EXTERN_C PCODE STDCALL ExternalMethodFixupWorker(TransitionBlock * pTransitionBl if (fVirtual) { - GCX_COOP_THREAD_EXISTS(CURRENT_THREAD); - // Get the stub manager for this module VirtualCallStubManager *pMgr = pModule->GetLoaderAllocator()->GetVirtualCallStubManager(); OBJECTREF *protectedObj = pEMFrame->GetThisPtr(); _ASSERTE(protectedObj != NULL); - if (*protectedObj == NULL) { + if (!*protectedObj) { + // NOTE: This is in a preemptive block, but the ! operator + // is safe to use on OBJECTREF even in preemptive mode + // (as long as the OBJECTREF is not on a managed object which + // in this case it is not) COMPlusThrow(kNullReferenceException); } @@ -2925,6 +2921,8 @@ EXTERN_C PCODE STDCALL ExternalMethodFixupWorker(TransitionBlock * pTransitionBl #endif } + GCX_COOP_THREAD_EXISTS(CURRENT_THREAD); + // We lost the race or the R2R image was generated without cached interface dispatch support, simply do the resolution in pure C++ DispatchToken token; if (pMT->IsInterface()) @@ -2950,6 +2948,7 @@ EXTERN_C PCODE STDCALL ExternalMethodFixupWorker(TransitionBlock * pTransitionBl token = pMT->GetLoaderAllocator()->GetDispatchToken(pMT->GetTypeID(), slot); StubCallSite callSite(pIndirection, pEMFrame->GetReturnAddress()); + GCX_COOP_THREAD_EXISTS(CURRENT_THREAD); pCode = pMgr->ResolveWorker(&callSite, protectedObj, token, STUB_CODE_BLOCK_VSD_LOOKUP_STUB); } else @@ -3774,6 +3773,8 @@ extern "C" SIZE_T STDCALL DynamicHelperWorker(TransitionBlock * pTransitionBlock if (objRef == NULL) COMPlusThrow(kNullReferenceException); + GCX_PREEMP(); + // Duplicated logic from JIT_VirtualFunctionPointer_Framed if (!pMD->IsVtableMethod()) { diff --git a/src/coreclr/vm/qcall.h b/src/coreclr/vm/qcall.h index a64bf4a2d7836c..96d59421ae50dc 100644 --- a/src/coreclr/vm/qcall.h +++ b/src/coreclr/vm/qcall.h @@ -196,12 +196,24 @@ class QCall { Object** m_ppObject; + bool IsNull() const + { + LIMITED_METHOD_CONTRACT; + return *m_ppObject == NULL; + } + OBJECTREF Get() { LIMITED_METHOD_CONTRACT; return ObjectToOBJECTREF(*m_ppObject); } + Object** GetObjectPointer() const + { + LIMITED_METHOD_CONTRACT; + return m_ppObject; + } + #ifndef DACCESS_COMPILE // // Helpers for returning common managed types from QCall diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp index ee9ca4fd3dec65..444e6afea845d2 100644 --- a/src/coreclr/vm/readytoruninfo.cpp +++ b/src/coreclr/vm/readytoruninfo.cpp @@ -20,9 +20,7 @@ #include "ilstubcache.h" #include "sigbuilder.h" -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #ifndef DACCESS_COMPILE extern "C" PCODE g_pMethodWithSlotAndModule; @@ -2533,9 +2531,7 @@ PCODE CreateDynamicHelperPrecode(LoaderAllocator *pAllocator, AllocMemTracker *p FlushCacheForDynamicMappedStub(pPrecode, sizeof(StubPrecode)); -#ifdef FEATURE_PERFMAP PerfMap::LogStubs(__FUNCTION__, "DynamicHelper", (PCODE)pPrecode, size, PerfMapStubType::IndividualWithinBlock); -#endif return ((Precode*)pPrecode)->GetEntryPoint(); } diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index 3b0b32dd32ec20..2b623fb397ae22 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -443,13 +443,16 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_InvokeMethod( // This is duplicated logic from MethodDesc::GetCallTarget PCODE pTarget; - if (pMeth->IsVtableMethod()) { - pTarget = pMeth->GetSingleCallableAddrOfVirtualizedCode(&gc.target, ownerType); - } - else - { - pTarget = pMeth->GetSingleCallableAddrOfCode(); + GCX_PREEMP(); + if (pMeth->IsVtableMethod()) + { + pTarget = pMeth->GetSingleCallableAddrOfVirtualizedCode(&gc.target, ownerType); + } + else + { + pTarget = pMeth->GetSingleCallableAddrOfCode(); + } } callDescrData.pTarget = pTarget; diff --git a/src/coreclr/vm/riscv64/stubs.cpp b/src/coreclr/vm/riscv64/stubs.cpp index 9064d3f844f5fd..10571d08e5ca19 100644 --- a/src/coreclr/vm/riscv64/stubs.cpp +++ b/src/coreclr/vm/riscv64/stubs.cpp @@ -14,9 +14,7 @@ #include "jitinterface.h" #include "ecall.h" -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #ifndef DACCESS_COMPILE //----------------------------------------------------------------------- @@ -1027,13 +1025,9 @@ void StubLinkerCPU::EmitCallManagedMethod(MethodDesc *pMD, BOOL fTailCall) size_t rxOffset = pStartRX - pStart; \ BYTE * p = pStart; -#ifdef FEATURE_PERFMAP #define BEGIN_DYNAMIC_HELPER_EMIT(size) \ BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) \ PerfMap::LogStubs(__FUNCTION__, "DynamicHelper", (PCODE)p, size, PerfMapStubType::Individual); -#else -#define BEGIN_DYNAMIC_HELPER_EMIT(size) BEGIN_DYNAMIC_HELPER_EMIT_WORKER(size) -#endif #define END_DYNAMIC_HELPER_EMIT() \ _ASSERTE(pStart + cb == p); \ diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 1e1fb0c0222cae..0857ebee305668 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1947,22 +1947,23 @@ extern "C" MethodDesc* QCALLTYPE RuntimeMethodHandle_GetStubIfNeededSlow(MethodD BEGIN_QCALL; - GCX_COOP(); + TypeHandle* inst = NULL; + DWORD ntypars = 0; + if (pMethod->IsAsyncVariantMethod()) { // do not report async variants to reflection. pMethod = pMethod->GetOrdinaryVariant(/*allowInstParam*/ false); } - + TypeHandle instType = declaringTypeHandle.AsTypeHandle(); - - TypeHandle* inst = NULL; - DWORD ntypars = 0; - + // Construct TypeHandle array for instantiation. - if (methodInstantiation.Get() != NULL) + if (!methodInstantiation.IsNull()) { + GCX_COOP(); + ntypars = ((PTRARRAYREF)methodInstantiation.Get())->GetNumComponents(); size_t size = ntypars * sizeof(TypeHandle); @@ -2037,7 +2038,10 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_GetMethodBody(MethodDesc* pMethod, { MethodDesc* pMethodIL = pMethod; if (pMethod->IsWrapperStub()) + { + GCX_PREEMP(); pMethodIL = pMethod->GetWrappedMethodDesc(); + } pILHeader = pMethodIL->GetILHeader(); } diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index 695b3542dd6f0b..36450b365f7bea 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -16,9 +16,7 @@ #include "rtlfunctions.h" -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #define S_BYTEPTR(x) S_SIZE_T((SIZE_T)(x)) @@ -563,9 +561,7 @@ Stub *StubLinker::Link(LoaderHeap *pHeap, DWORD flags, const char *stubType) EmitStub(pStub, globalsize, size, pHeap); -#ifdef FEATURE_PERFMAP PerfMap::LogStubs(__FUNCTION__, stubType, pStub->GetEntryPoint(), pStub->GetNumCodeBytes(), PerfMapStubType::Individual); -#endif return pStub.Detach(); } diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index b290e205367523..1616335ee6f080 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -51,9 +51,7 @@ #include #endif -#ifdef FEATURE_PERFMAP #include "perfmap.h" -#endif #include "exinfo.h" @@ -1028,13 +1026,13 @@ void InitThreadManagerPerfMapData() GC_TRIGGERS; } CONTRACTL_END; -#ifdef FEATURE_PERFMAP +#ifndef FEATURE_PORTABLE_HELPERS if (IsWriteBarrierCopyEnabled()) { size_t writeBarrierSize = (BYTE*)JIT_PatchedCodeLast - (BYTE*)JIT_PatchedCodeStart; PerfMap::LogStubs(__FUNCTION__, "JIT_CopiedWriteBarriers", (PCODE)s_barrierCopy, writeBarrierSize, PerfMapStubType::Individual); } -#endif +#endif // !FEATURE_PORTABLE_HELPERS } //--------------------------------------------------------------------------- @@ -6096,7 +6094,7 @@ Frame * Thread::NotifyFrameChainOfExceptionUnwind(Frame* pStartFrame, LPVOID pvL CONTRACTL { NOTHROW; - DISABLED(GC_TRIGGERS); // due to UnwindFrameChain from NOTRIGGER areas + GC_NOTRIGGER; MODE_COOPERATIVE; PRECONDITION(CheckPointer(pStartFrame)); PRECONDITION(CheckPointer(pvLimitSP)); diff --git a/src/coreclr/vm/virtualcallstub.cpp b/src/coreclr/vm/virtualcallstub.cpp index 0b1567592843c8..d5b16a8abfdd31 100644 --- a/src/coreclr/vm/virtualcallstub.cpp +++ b/src/coreclr/vm/virtualcallstub.cpp @@ -98,11 +98,23 @@ struct CachedIndirectionCellBlockListNode BYTE* GenerateDispatchStubCellEntryMethodDesc(LoaderAllocator *pLoaderAllocator, TypeHandle ownerType, MethodDesc *pMD, LCGMethodResolver *pResolver) { + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + return GenerateDispatchStubCellEntrySlot(pLoaderAllocator, ownerType, pMD->GetSlot(), pResolver); } BYTE* GenerateDispatchStubCellEntrySlot(LoaderAllocator *pLoaderAllocator, TypeHandle ownerType, int methodSlot, LCGMethodResolver *pResolver) { + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + VirtualCallStubManager * pMgr = pLoaderAllocator->GetVirtualCallStubManager(); DispatchToken token = VirtualCallStubManager::GetTokenFromOwnerAndSlot(ownerType, methodSlot); @@ -992,7 +1004,7 @@ DispatchToken VirtualCallStubManager::GetTokenFromOwnerAndSlot(TypeHandle ownerT { THROWS; GC_TRIGGERS; - MODE_ANY; + MODE_PREEMPTIVE; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END @@ -1015,7 +1027,7 @@ PCODE VirtualCallStubManager::GetCallStub(TypeHandle ownerType, MethodDesc *pMD) CONTRACTL { THROWS; GC_TRIGGERS; - MODE_ANY; + MODE_PREEMPTIVE; PRECONDITION(CheckPointer(pMD)); PRECONDITION(!pMD->IsInterface() || ownerType.GetMethodTable()->HasSameTypeDefAs(pMD->GetMethodTable())); INJECT_FAULT(COMPlusThrowOM();); @@ -1485,7 +1497,12 @@ extern "C" PCODE CID_VirtualOpenDelegateDispatchWorker(TransitionBlock * pTransi GCStress::MaybeTriggerAndProtect(pObj); - DispatchToken token = VirtualCallStubManager::GetTokenFromOwnerAndSlot(TypeHandle(pTargetMD->GetMethodTable()), pTargetMD->GetSlot()); + DispatchToken token; + + { + GCX_PREEMP(); + token = VirtualCallStubManager::GetTokenFromOwnerAndSlot(TypeHandle(pTargetMD->GetMethodTable()), pTargetMD->GetSlot()); + } target = CachedInterfaceDispatchResolveWorker(NULL, protectedObj, token); #if _DEBUG