Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-10-01 00:47:24 +0300
committerScott Mosier <smosier@microsoft.com>2015-10-01 00:47:24 +0300
commitad0323ab91a7b1469b42ca5457ddd631b94294fe (patch)
tree88fae57e1ec3aae90288463dc07e58f7aebc1de8 /src/Native/Runtime/profheapwalkhelper.cpp
parent6763d16387778f126ec510c0421783952602f8f7 (diff)
Initial population of CoreRT Runtime files.
Diffstat (limited to 'src/Native/Runtime/profheapwalkhelper.cpp')
-rw-r--r--src/Native/Runtime/profheapwalkhelper.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/Native/Runtime/profheapwalkhelper.cpp b/src/Native/Runtime/profheapwalkhelper.cpp
new file mode 100644
index 000000000..cc6986028
--- /dev/null
+++ b/src/Native/Runtime/profheapwalkhelper.cpp
@@ -0,0 +1,216 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+//
+// On desktop CLR, GC ETW event firing borrows heavily from code in the profiling API,
+// as the GC already called hooks in the profapi to notify it of roots & references.
+// This file shims up that profapi code the GC expects, though only for the purpose of
+// firing ETW events (not for getting a full profapi up on redhawk).
+//
+
+#if defined(FEATURE_EVENT_TRACE)
+
+#include "commontypes.h"
+#include "daccess.h"
+#include "debugmacrosext.h"
+#include "palredhawkcommon.h"
+#include "gcrhenv.h"
+
+
+//---------------------------------------------------------------------------------------
+//
+// Callback of type promote_func called by GC while scanning roots (in GCProfileWalkHeap,
+// called after the collection). Wrapper around EEToProfInterfaceImpl::RootReference2,
+// which does the real work.
+//
+// Arguments:
+// ppObject - Object reference encountered
+/// ppObjectRef - Address that references ppObject
+// pSC - ProfilingScanContext * containing the root kind and GCReferencesData used
+// by RootReference2
+// dwFlags - Properties of the root as GC_CALL* constants (this function converts
+// to COR_PRF_GC_ROOT_FLAGS.
+//
+
+void ScanRootsHelper(Object** ppObject, Object** ppObjectRef, ScanContext *pSC, DWORD dwFlags)
+{
+ ProfilingScanContext *pPSC = (ProfilingScanContext *)pSC;
+
+ DWORD dwEtwRootFlags = 0;
+ if (dwFlags & GC_CALL_INTERIOR)
+ dwEtwRootFlags |= kEtwGCRootFlagsInterior;
+ if (dwFlags & GC_CALL_PINNED)
+ dwEtwRootFlags |= kEtwGCRootFlagsPinning;
+
+ void *rootID = ppObjectRef;
+
+ if (pPSC->dwEtwRootKind == kEtwGCRootKindFinalizer)
+ ppObject = ppObjectRef;
+
+ // Notify ETW of the root
+
+ if (ETW::GCLog::ShouldWalkHeapRootsForEtw())
+ {
+ ETW::GCLog::RootReference(
+ rootID, // root address
+ *ppObject, // object being rooted
+ NULL, // pSecondaryNodeForDependentHandle is NULL, cuz this isn't a dependent handle
+ FALSE, // is dependent handle
+ pPSC,
+ dwFlags, // dwGCFlags
+ dwEtwRootFlags);
+ }
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Callback of type walk_fn used by GCHeap::WalkObject. Keeps a count of each
+// object reference found.
+//
+// Arguments:
+// pBO - Object reference encountered in walk
+// context - running count of object references encountered
+//
+// Return Value:
+// Always returns TRUE to object walker so it walks the entire object
+//
+
+BOOL CountContainedObjectRef(Object * pBO, void * context)
+{
+ LIMITED_METHOD_CONTRACT;
+ // Increase the count
+ (*((size_t *)context))++;
+
+ return TRUE;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Callback of type walk_fn used by GCHeap::WalkObject. Stores each object reference
+// encountered into an array.
+//
+// Arguments:
+// pBO - Object reference encountered in walk
+// context - Array of locations within the walked object that point to other
+// objects. On entry, (*context) points to the next unfilled array
+// entry. On exit, that location is filled, and (*context) is incremented
+// to point to the next entry.
+//
+// Return Value:
+// Always returns TRUE to object walker so it walks the entire object
+//
+
+BOOL SaveContainedObjectRef(Object * pBO, void * context)
+{
+ LIMITED_METHOD_CONTRACT;
+ // Assign the value
+ **((Object ***)context) = pBO;
+
+ // Now increment the array pointer
+ //
+ // Note that HeapWalkHelper has already walked the references once to count them up,
+ // and then allocated an array big enough to hold those references. First time this
+ // callback is called for a given object, (*context) points to the first entry in the
+ // array. So "blindly" incrementing (*context) here and using it next time around
+ // for the next reference, over and over again, should be safe.
+ (*((Object ***)context))++;
+
+ return TRUE;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Callback of type walk_fn used by the GC when walking the heap, to help profapi
+// track objects. This guy orchestrates the use of the above callbacks which dig
+// into object references contained each object encountered by this callback.
+//
+// Arguments:
+// pBO - Object reference encountered on the heap
+//
+// Return Value:
+// BOOL indicating whether the heap walk should continue.
+// TRUE=continue
+// FALSE=stop
+//
+
+BOOL HeapWalkHelper(Object * pBO, void * pvContext)
+{
+ OBJECTREF * arrObjRef = NULL;
+ size_t cNumRefs = 0;
+ bool bOnStack = false;
+ //MethodTable * pMT = pBO->GetMethodTable();
+
+ ProfilerWalkHeapContext * pProfilerWalkHeapContext = (ProfilerWalkHeapContext *) pvContext;
+
+ //if (pMT->ContainsPointersOrCollectible())
+ {
+ // First round through calculates the number of object refs for this class
+ GCHeap::GetGCHeap()->WalkObject(pBO, &CountContainedObjectRef, (void *)&cNumRefs);
+
+ if (cNumRefs > 0)
+ {
+ // Create an array to contain all of the refs for this object
+ bOnStack = cNumRefs <= 32 ? true : false;
+
+ if (bOnStack)
+ {
+ // It's small enough, so just allocate on the stack
+ arrObjRef = (OBJECTREF *)_alloca(cNumRefs * sizeof(OBJECTREF));
+ }
+ else
+ {
+ // Otherwise, allocate from the heap
+ arrObjRef = new (nothrow) OBJECTREF[cNumRefs];
+
+ if (!arrObjRef)
+ {
+ return FALSE;
+ }
+ }
+
+ // Second round saves off all of the ref values
+ OBJECTREF * pCurObjRef = arrObjRef;
+ GCHeap::GetGCHeap()->WalkObject(pBO, &SaveContainedObjectRef, (void *)&pCurObjRef);
+ }
+ }
+
+ HRESULT hr = E_FAIL;
+
+#ifdef FEATURE_ETW
+ if (ETW::GCLog::ShouldWalkHeapObjectsForEtw())
+ {
+ ETW::GCLog::ObjectReference(
+ pProfilerWalkHeapContext,
+ pBO,
+ ULONGLONG(pBO->get_SafeEEType()),
+ cNumRefs,
+ (Object **) arrObjRef);
+ }
+#endif // FEATURE_ETW
+
+ // If the data was not allocated on the stack, need to clean it up.
+ if ((arrObjRef != NULL) && !bOnStack)
+ {
+ delete [] arrObjRef;
+ }
+
+ // Return TRUE iff we want to the heap walk to continue. The only way we'd abort the
+ // heap walk is if we're issuing profapi callbacks, and the profapi profiler
+ // intentionally returned a failed HR (as its request that we stop the walk). There's
+ // a potential conflict here. If a profapi profiler and an ETW profiler are both
+ // monitoring the heap dump, and the profapi profiler requests to abort the walk (but
+ // the ETW profiler may not want to abort the walk), then what do we do? The profapi
+ // profiler gets precedence. We don't want to accidentally send more callbacks to a
+ // profapi profiler that explicitly requested an abort. The ETW profiler will just
+ // have to deal. In theory, I could make the code more complex by remembering that a
+ // profapi profiler requested to abort the dump but an ETW profiler is still
+ // attached, and then intentionally inhibit the remainder of the profapi callbacks
+ // for this GC. But that's unnecessary complexity. In practice, it should be
+ // extremely rare that a profapi profiler is monitoring heap dumps AND an ETW
+ // profiler is also monitoring heap dumps.
+ return TRUE;
+}
+
+#endif // defined(FEATURE_EVENT_TRACE)