1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5
6//
7
8/*============================================================
9**
10** Header: RCWWalker.h
11**
12**
13** Purpose: Solve native/manage cyclic reference issue by
14** walking RCW objects
15**
16==============================================================*/
17
18#ifndef _H_RCWWALKER_
19#define _H_RCWWALKER_
20
21#ifdef FEATURE_COMINTEROP
22
23#include "internalunknownimpl.h"
24#include "utilcode.h"
25#include "runtimecallablewrapper.h"
26
27
28//
29// RCW Walker
30// Walks jupiter RCW objects and create references from RCW to referenced CCW (in native side)
31//
32class RCWWalker
33{
34 friend struct _DacGlobals;
35
36private :
37 static VolatilePtr<IJupiterGCManager> s_pGCManager; // The one and only GCManager instance
38 static BOOL s_bGCStarted; // Has GC started?
39 SVAL_DECL(BOOL, s_bIsGlobalPeggingOn); // Do we need to peg every CCW?
40
41public :
42#ifndef DACCESS_COMPILE
43 static void OnJupiterRCWCreated(RCW *pRCW, IJupiterObject *pJupiterObject);
44 static void AfterJupiterRCWCreated(RCW *pRCW);
45 static void BeforeJupiterRCWDestroyed(RCW *pRCW);
46 static void OnEEShutdown();
47
48 //
49 // Send out a AfterAddRef callback to notify Jupiter we've done a AddRef
50 // We should do this *after* we made a AddRef because we should never
51 // be in a state where reported refs > actual refs
52 //
53 FORCEINLINE static void AfterInterfaceAddRef(RCW *pRCW)
54 {
55
56 CONTRACTL {
57 NOTHROW;
58 GC_NOTRIGGER;
59 MODE_ANY;
60 }
61 CONTRACTL_END;
62
63 IJupiterObject *pJupiterObject = pRCW->GetJupiterObject();
64 if (pJupiterObject)
65 {
66 STRESS_LOG2(LF_INTEROP, LL_INFO100, "[RCW Walker] Calling IJupiterObject::AfterAddRef (IJupiterObject = 0x%p, RCW = 0x%p)\n", pJupiterObject, pRCW);
67 pJupiterObject->AfterAddRef();
68 }
69 }
70
71 //
72 // Send out BeforeRelease callback for every cached interface pointer
73 // This needs to be made before call Release because we should never be in a
74 // state that reported refs > actual refs
75 //
76 FORCEINLINE static void BeforeInterfaceRelease(RCW *pRCW)
77 {
78 CONTRACTL {
79 NOTHROW;
80 GC_NOTRIGGER;
81 MODE_ANY;
82 }
83 CONTRACTL_END;
84
85 IJupiterObject *pJupiterObject = pRCW->GetJupiterObject();
86 if (pJupiterObject)
87 {
88 STRESS_LOG2(LF_INTEROP, LL_INFO100, "[RCW Walker] Calling IJupiterObject::BeforeRelease before Release (IJupiterObject = 0x%p, RCW = 0x%p)\n", pJupiterObject, pRCW);
89 pJupiterObject->BeforeRelease();
90 }
91 }
92
93
94#endif // !DACCESS_COMPILE
95
96
97public :
98 //
99 // Called in ComCallableWrapper::IsWrapperActive
100 // Used to override the individual pegging flag on CCWs and force pegging every jupiter referenced CCW
101 // See IsWrapperActive for more details
102 //
103 static FORCEINLINE BOOL IsGlobalPeggingOn()
104 {
105 // We need this weird cast because s_bIsGlobalPeggingOn is used in DAC and defined as
106 // __GlobalVal in DAC build
107 // C++'s operator magic didn't work if two levels of operator overloading are involved...
108 return VolatileLoad((BOOL *)&s_bIsGlobalPeggingOn);
109 }
110
111#ifndef DACCESS_COMPILE
112 //
113 // Tells GC whether walking all the Jupiter RCW is necessary, which only should happen
114 // if we have seen jupiter RCWs
115 //
116 static FORCEINLINE BOOL NeedToWalkRCWs()
117 {
118 LIMITED_METHOD_CONTRACT;
119
120 return (((IJupiterGCManager *)s_pGCManager) != NULL);
121 }
122
123 //
124 // Whether a GC has been started and we need to RCW walk
125 //
126 static FORCEINLINE BOOL HasGCStarted()
127 {
128 return s_bGCStarted;
129 }
130
131 //
132 // Called when GC started
133 // We do most of our work here
134 //
135 static void OnGCStarted(int nCondemnedGeneration);
136
137 //
138 // Called when GC finished
139 //
140 static void OnGCFinished(int nCondemnedGeneration);
141
142private :
143 static void OnGCStartedWorker();
144 static void OnGCFinishedWorker();
145 static void WalkRCWs();
146 static HRESULT WalkOneRCW(RCW *pRCW, RCWRefCache *pRCWRefCache);
147#endif // DACCESS_COMPILE
148};
149
150#endif // FEATURE_COMINTEROP
151
152#endif // _H_RCWWALKER_
153