summaryrefslogtreecommitdiff
path: root/src/gc/gcenv.ee.standalone.inl
diff options
context:
space:
mode:
Diffstat (limited to 'src/gc/gcenv.ee.standalone.inl')
-rw-r--r--src/gc/gcenv.ee.standalone.inl88
1 files changed, 62 insertions, 26 deletions
diff --git a/src/gc/gcenv.ee.standalone.inl b/src/gc/gcenv.ee.standalone.inl
index 3b64586d70..31f3d1d8da 100644
--- a/src/gc/gcenv.ee.standalone.inl
+++ b/src/gc/gcenv.ee.standalone.inl
@@ -11,166 +11,202 @@
// will be fowarded to this interface instance.
extern IGCToCLR* g_theGCToCLR;
+// A note about this:
+// In general, we don't want to pretend to be smarter than the compiler
+// and force it to inline things. However, inlining is here is required
+// for correctness as it stands today (though it will not always be required).
+//
+// The reason for this is because:
+// 1) This file (and the GCToEEInterface class) define symbols that are inline
+// and static, so the symbol GCToEEInterface::XYZ defines a symbol with weak
+// linkage when the function is not inlined,
+// 2) src/vm/gcenv.ee.cpp all define symbols that are not inline and instance methods
+// of GCToEEInterface, with external linkage.
+// 3) When it comes time to link the GC and the VM, the linker observes the duplicate
+// symbols and discards the one with weak linkage.
+// 4) All of the calls within the GC to the functions in this file are replaced by
+// the linker to calls to the implementation of a pure virtual IGCToCLR. The
+// functions implementing IGCToCLR have an extra argument (this).
+// 5) Now, all calls to these functions from within the GC are doomed because of the
+// functions that actually get called expect this to be in rdi, where the compiler
+// has placed the first argument instead.
+//
+// For now, by forcing the compiler to inline these functions, the compiler won't actually
+// emit symbols for them and we'll avoid the linker havoc.
+#ifdef _MSC_VER
+ #define ALWAYS_INLINE __forceinline
+#else
+ #define ALWAYS_INLINE __attribute__((always_inline)) inline
+#endif
+
// When we are building the GC in a standalone environment, we
// will be dispatching virtually against g_theGCToCLR to call
// into the EE. This class provides an identical API to the existing
// GCToEEInterface, but only forwards the call onto the global
// g_theGCToCLR instance.
-inline void GCToEEInterface::SuspendEE(SUSPEND_REASON reason)
+ALWAYS_INLINE void GCToEEInterface::SuspendEE(SUSPEND_REASON reason)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->SuspendEE(reason);
}
-inline void GCToEEInterface::RestartEE(bool bFinishedGC)
+ALWAYS_INLINE void GCToEEInterface::RestartEE(bool bFinishedGC)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->RestartEE(bFinishedGC);
}
-inline void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc)
+ALWAYS_INLINE void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->GcScanRoots(fn, condemned, max_gen, sc);
}
-inline void GCToEEInterface::GcStartWork(int condemned, int max_gen)
+ALWAYS_INLINE void GCToEEInterface::GcStartWork(int condemned, int max_gen)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->GcStartWork(condemned, max_gen);
}
-inline void GCToEEInterface::AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc)
+ALWAYS_INLINE void GCToEEInterface::AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->AfterGcScanRoots(condemned, max_gen, sc);
}
-inline void GCToEEInterface::GcBeforeBGCSweepWork()
+ALWAYS_INLINE void GCToEEInterface::GcBeforeBGCSweepWork()
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->GcBeforeBGCSweepWork();
}
-inline void GCToEEInterface::GcDone(int condemned)
+ALWAYS_INLINE void GCToEEInterface::GcDone(int condemned)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->GcDone(condemned);
}
-inline bool GCToEEInterface::RefCountedHandleCallbacks(Object * pObject)
+ALWAYS_INLINE bool GCToEEInterface::RefCountedHandleCallbacks(Object * pObject)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->RefCountedHandleCallbacks(pObject);
}
-inline void GCToEEInterface::SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2)
+ALWAYS_INLINE void GCToEEInterface::SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->SyncBlockCacheWeakPtrScan(scanProc, lp1, lp2);
}
-inline void GCToEEInterface::SyncBlockCacheDemote(int max_gen)
+ALWAYS_INLINE void GCToEEInterface::SyncBlockCacheDemote(int max_gen)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->SyncBlockCacheDemote(max_gen);
}
-inline void GCToEEInterface::SyncBlockCachePromotionsGranted(int max_gen)
+ALWAYS_INLINE void GCToEEInterface::SyncBlockCachePromotionsGranted(int max_gen)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->SyncBlockCachePromotionsGranted(max_gen);
}
-inline bool GCToEEInterface::IsPreemptiveGCDisabled(Thread * pThread)
+ALWAYS_INLINE bool GCToEEInterface::IsPreemptiveGCDisabled(Thread * pThread)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->IsPreemptiveGCDisabled(pThread);
}
-inline void GCToEEInterface::EnablePreemptiveGC(Thread * pThread)
+ALWAYS_INLINE void GCToEEInterface::EnablePreemptiveGC(Thread * pThread)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->EnablePreemptiveGC(pThread);
}
-inline void GCToEEInterface::DisablePreemptiveGC(Thread * pThread)
+ALWAYS_INLINE void GCToEEInterface::DisablePreemptiveGC(Thread * pThread)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->DisablePreemptiveGC(pThread);
}
-inline gc_alloc_context * GCToEEInterface::GetAllocContext(Thread * pThread)
+ALWAYS_INLINE gc_alloc_context * GCToEEInterface::GetAllocContext(Thread * pThread)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->GetAllocContext(pThread);
}
-inline bool GCToEEInterface::CatchAtSafePoint(Thread * pThread)
+ALWAYS_INLINE bool GCToEEInterface::CatchAtSafePoint(Thread * pThread)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->CatchAtSafePoint(pThread);
}
-inline void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* param)
+ALWAYS_INLINE void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* param)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->GcEnumAllocContexts(fn, param);
}
-inline Thread* GCToEEInterface::CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg)
+ALWAYS_INLINE Thread* GCToEEInterface::CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->CreateBackgroundThread(threadStart, arg);
}
-inline void GCToEEInterface::DiagGCStart(int gen, bool isInduced)
+ALWAYS_INLINE void GCToEEInterface::DiagGCStart(int gen, bool isInduced)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->DiagGCStart(gen, isInduced);
}
-inline void GCToEEInterface::DiagUpdateGenerationBounds()
+ALWAYS_INLINE void GCToEEInterface::DiagUpdateGenerationBounds()
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->DiagUpdateGenerationBounds();
}
-inline void GCToEEInterface::DiagGCEnd(size_t index, int gen, int reason, bool fConcurrent)
+ALWAYS_INLINE void GCToEEInterface::DiagGCEnd(size_t index, int gen, int reason, bool fConcurrent)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->DiagGCEnd(index, gen, reason, fConcurrent);
}
-inline void GCToEEInterface::DiagWalkFReachableObjects(void* gcContext)
+ALWAYS_INLINE void GCToEEInterface::DiagWalkFReachableObjects(void* gcContext)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->DiagWalkFReachableObjects(gcContext);
}
-inline void GCToEEInterface::DiagWalkSurvivors(void* gcContext)
+ALWAYS_INLINE void GCToEEInterface::DiagWalkSurvivors(void* gcContext)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->DiagWalkSurvivors(gcContext);
}
-inline void GCToEEInterface::DiagWalkLOHSurvivors(void* gcContext)
+ALWAYS_INLINE void GCToEEInterface::DiagWalkLOHSurvivors(void* gcContext)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->DiagWalkLOHSurvivors(gcContext);
}
-inline void GCToEEInterface::DiagWalkBGCSurvivors(void* gcContext)
+ALWAYS_INLINE void GCToEEInterface::DiagWalkBGCSurvivors(void* gcContext)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->DiagWalkBGCSurvivors(gcContext);
}
-inline void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args)
+ALWAYS_INLINE void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args)
{
assert(g_theGCToCLR != nullptr);
g_theGCToCLR->StompWriteBarrier(args);
}
+ALWAYS_INLINE void GCToEEInterface::EnableFinalization(bool foundFinalizers)
+{
+ assert(g_theGCToCLR != nullptr);
+ g_theGCToCLR->EnableFinalization(foundFinalizers);
+}
+
+#undef ALWAYS_INLINE
+
#endif // __GCTOENV_EE_STANDALONE_INL__