// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // // /*============================================================ ** ** Header: RCWWalker.h ** ** ** Purpose: Solve native/manage cyclic reference issue by ** walking RCW objects ** ==============================================================*/ #ifndef _H_RCWWALKER_ #define _H_RCWWALKER_ #ifdef FEATURE_COMINTEROP #include "internalunknownimpl.h" #include "utilcode.h" #include "runtimecallablewrapper.h" // // RCW Walker // Walks jupiter RCW objects and create references from RCW to referenced CCW (in native side) // class RCWWalker { friend struct _DacGlobals; private : static VolatilePtr s_pGCManager; // The one and only GCManager instance static BOOL s_bGCStarted; // Has GC started? SVAL_DECL(BOOL, s_bIsGlobalPeggingOn); // Do we need to peg every CCW? public : #ifndef DACCESS_COMPILE static void OnJupiterRCWCreated(RCW *pRCW, IJupiterObject *pJupiterObject); static void AfterJupiterRCWCreated(RCW *pRCW); static void BeforeJupiterRCWDestroyed(RCW *pRCW); static void OnEEShutdown(); // // Send out a AfterAddRef callback to notify Jupiter we've done a AddRef // We should do this *after* we made a AddRef because we should never // be in a state where reported refs > actual refs // FORCEINLINE static void AfterInterfaceAddRef(RCW *pRCW) { CONTRACTL { NOTHROW; GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; IJupiterObject *pJupiterObject = pRCW->GetJupiterObject(); if (pJupiterObject) { STRESS_LOG2(LF_INTEROP, LL_INFO100, "[RCW Walker] Calling IJupiterObject::AfterAddRef (IJupiterObject = 0x%p, RCW = 0x%p)\n", pJupiterObject, pRCW); pJupiterObject->AfterAddRef(); } } // // Send out BeforeRelease callback for every cached interface pointer // This needs to be made before call Release because we should never be in a // state that reported refs > actual refs // FORCEINLINE static void BeforeInterfaceRelease(RCW *pRCW) { CONTRACTL { NOTHROW; GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; IJupiterObject *pJupiterObject = pRCW->GetJupiterObject(); if (pJupiterObject) { STRESS_LOG2(LF_INTEROP, LL_INFO100, "[RCW Walker] Calling IJupiterObject::BeforeRelease before Release (IJupiterObject = 0x%p, RCW = 0x%p)\n", pJupiterObject, pRCW); pJupiterObject->BeforeRelease(); } } #endif // !DACCESS_COMPILE public : // // Called in ComCallableWrapper::IsWrapperActive // Used to override the individual pegging flag on CCWs and force pegging every jupiter referenced CCW // See IsWrapperActive for more details // static FORCEINLINE BOOL IsGlobalPeggingOn() { // We need this weird cast because s_bIsGlobalPeggingOn is used in DAC and defined as // __GlobalVal in DAC build // C++'s operator magic didn't work if two levels of operator overloading are involved... return VolatileLoad((BOOL *)&s_bIsGlobalPeggingOn); } #ifndef DACCESS_COMPILE // // Tells GC whether walking all the Jupiter RCW is necessary, which only should happen // if we have seen jupiter RCWs // static FORCEINLINE BOOL NeedToWalkRCWs() { LIMITED_METHOD_CONTRACT; return (((IJupiterGCManager *)s_pGCManager) != NULL); } // // Whether a GC has been started and we need to RCW walk // static FORCEINLINE BOOL HasGCStarted() { return s_bGCStarted; } // // Called when GC started // We do most of our work here // static void OnGCStarted(int nCondemnedGeneration); // // Called when GC finished // static void OnGCFinished(int nCondemnedGeneration); private : static void OnGCStartedWorker(); static void OnGCFinishedWorker(); static void WalkRCWs(); static HRESULT WalkOneRCW(RCW *pRCW, RCWRefCache *pRCWRefCache); #endif // DACCESS_COMPILE }; #endif // FEATURE_COMINTEROP #endif // _H_RCWWALKER_