} COR_PRF_GC_GENERATION_RANGE;
+/*
+ * COR_PRF_NONGC_GENERATION_RANGE describes a range of memory in the GetNonGCHeapBounds function.
+ */
+typedef struct COR_PRF_NONGC_HEAP_RANGE
+{
+ ObjectID rangeStart; // the start of the range
+ UINT_PTR rangeLength; // the used length of the range
+ UINT_PTR rangeLengthReserved; // the amount of memory reserved for the range (including rangeLength)
+
+} COR_PRF_NONGC_HEAP_RANGE;
+
/*
* COR_PRF_CLAUSE_TYPE defines the various clause codes for the EX clauses
interface ICorProfilerInfo14 : ICorProfilerInfo13
{
HRESULT EnumerateNonGCObjects([out] ICorProfilerObjectEnum** ppEnum);
+
+ HRESULT GetNonGCHeapBounds(
+ [in] ULONG cObjectRanges,
+ [out] ULONG *pcObjectRanges,
+ [out, size_is(cObjectRanges), length_is(*pcObjectRanges)] COR_PRF_NONGC_HEAP_RANGE ranges[]);
}
/*
UINT_PTR rangeLengthReserved;
} COR_PRF_GC_GENERATION_RANGE;
+typedef struct COR_PRF_NONGC_HEAP_RANGE
+ {
+ ObjectID rangeStart;
+ UINT_PTR rangeLength;
+ UINT_PTR rangeLengthReserved;
+ } COR_PRF_NONGC_HEAP_RANGE;
+
typedef /* [public][public][public] */
enum __MIDL___MIDL_itf_corprof_0000_0001_0005
{
virtual HRESULT STDMETHODCALLTYPE EnumerateNonGCObjects(
/* [out] */ ICorProfilerObjectEnum **ppEnum) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetNonGCHeapBounds(
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_NONGC_HEAP_RANGE ranges[ ]) = 0;
+
};
ICorProfilerInfo14 * This,
/* [out] */ ICorProfilerObjectEnum **ppEnum);
+ DECLSPEC_XFGVIRT(ICorProfilerInfo14, GetNonGCHeapBounds)
+ HRESULT ( STDMETHODCALLTYPE *GetNonGCHeapBounds )(
+ ICorProfilerInfo14 * This,
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_NONGC_HEAP_RANGE ranges[ ]);
+
END_INTERFACE
} ICorProfilerInfo14Vtbl;
#define ICorProfilerInfo14_EnumerateNonGCObjects(This,ppEnum) \
( (This)->lpVtbl -> EnumerateNonGCObjects(This,ppEnum) )
+#define ICorProfilerInfo14_GetNonGCHeapBounds(This,cObjectRanges,pcObjectRanges,ranges) \
+ ( (This)->lpVtbl -> GetNonGCHeapBounds(This,cObjectRanges,pcObjectRanges,ranges) )
+
#endif /* COBJMACROS */
uint8_t* nextObj = (reinterpret_cast<uint8_t*>(obj) + ALIGN_UP(obj->GetSize(), DATA_ALIGNMENT));
if (nextObj < m_pCurrent)
{
- Object* result = reinterpret_cast<Object*>(nextObj);
- INDEBUG(result->Validate());
- return result;
+ return reinterpret_cast<Object*>(nextObj);
}
// Current object is the last one in the segment
FrozenObjectSegment* m_CurrentSegment;
friend class ProfilerObjectEnum;
+ friend class ProfToEEInterfaceImpl;
};
class FrozenObjectSegment
INDEBUG(size_t m_ObjectsCount);
friend class ProfilerObjectEnum;
+ friend class ProfToEEInterfaceImpl;
};
#endif // _FROZENOBJECTHEAP_H
#include "safemath.h"
#include "threadsuspend.h"
#include "inlinetracking.h"
+#include "frozenobjectheap.h"
#ifdef PROFILING_SUPPORTED
#include "profilinghelper.h"
GC_NOTRIGGER;
MODE_ANY;
EE_THREAD_NOT_REQUIRED;
+
+ // FrozenObjectHeapManager takes a lock
+ CAN_TAKE_LOCK;
}
CONTRACTL_END;
return hr;
}
+HRESULT ProfToEEInterfaceImpl::GetNonGCHeapBounds(ULONG cObjectRanges,
+ ULONG *pcObjectRanges,
+ COR_PRF_NONGC_HEAP_RANGE ranges[])
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ EE_THREAD_NOT_REQUIRED;
+
+ // FrozenObjectHeapManager takes a lock
+ CAN_TAKE_LOCK;
+ }
+ CONTRACTL_END;
+
+ if ((cObjectRanges > 0) && (ranges == nullptr))
+ {
+ // Copy GetGenerationBounds's behavior for consistency
+ return E_INVALIDARG;
+ }
+
+ FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager();
+ CrstHolder ch(&foh->m_Crst);
+
+ const unsigned segmentsCount = foh->m_FrozenSegments.GetCount();
+ FrozenObjectSegment** segments = foh->m_FrozenSegments.GetElements();
+ if (segments != nullptr && segmentsCount > 0)
+ {
+ const ULONG segmentsToInspect = min(cObjectRanges, (ULONG)segmentsCount);
+
+ for (unsigned segIdx = 0; segIdx < segmentsToInspect; segIdx++)
+ {
+ uint8_t* firstObj = segments[segIdx]->m_pStart + sizeof(ObjHeader);
+
+ // Start of the segment (first object)
+ ranges[segIdx].rangeStart = (ObjectID)firstObj;
+
+ // Total size reserved for a segment
+ ranges[segIdx].rangeLengthReserved = (UINT_PTR)segments[segIdx]->m_Size;
+
+ // Size of the segment that is currently in use
+ ranges[segIdx].rangeLength = (UINT_PTR)(segments[segIdx]->m_pCurrent - firstObj);
+ }
+
+ if (pcObjectRanges != nullptr)
+ {
+ *pcObjectRanges = segmentsToInspect;
+ }
+ }
+ else
+ {
+ if (pcObjectRanges != nullptr)
+ {
+ *pcObjectRanges = 0;
+ }
+ }
+ return S_OK;
+}
+
/*
* GetStringLayout
*
COM_METHOD EnumerateNonGCObjects(
ICorProfilerObjectEnum** ppEnum);
+ COM_METHOD GetNonGCHeapBounds(ULONG cObjectRanges,
+ ULONG * pcObjectRanges,
+ COR_PRF_NONGC_HEAP_RANGE ranges[]);
+
// end ICorProfilerInfo14
protected:
_garbageCollections++;
+ const int MAX_NON_GC_HEAP_SEGMENTS = 16;
+ COR_PRF_NONGC_HEAP_RANGE segments[MAX_NON_GC_HEAP_SEGMENTS];
+ ULONG segCount;
+ ObjectID firstObj = 0;
+ HRESULT hr = pCorProfilerInfo->GetNonGCHeapBounds(MAX_NON_GC_HEAP_SEGMENTS, &segCount, segments);
+ if (FAILED(hr))
+ {
+ printf("GetNonGCHeapBounds returned an error\n!");
+ _failures++;
+ }
+ else if (segCount == 0 || segCount > MAX_NON_GC_HEAP_SEGMENTS)
+ {
+ printf("GetNonGCHeapBounds: invalid segCount (%u)\n!", segCount);
+ _failures++;
+ }
+ else
+ {
+ // Save very first object ID to compare with EnumerateNonGCObjects
+ firstObj = segments[0].rangeStart;
+
+ printf("\nGetNonGCHeapBounds (segCount = %u):\n", segCount);
+ for (ULONG i = 0; i < segCount; i++)
+ {
+ printf("\tseg#%u, rangeStart=%p, rangeLength=%u, rangeLengthReserved=%u\n",
+ i, (void*)segments[i].rangeStart, (ULONG)segments[i].rangeLength, (ULONG)segments[i].rangeLengthReserved);
+
+ if ((ULONG)segments[i].rangeLength > (ULONG)segments[i].rangeLengthReserved)
+ {
+ printf("GetNonGCHeapBounds: rangeLength > rangeLengthReserved");
+ _failures++;
+ }
+
+ if (!segments[i].rangeStart)
+ {
+ printf("GetNonGCHeapBounds: rangeStart is null");
+ _failures++;
+ }
+ }
+ printf("\n");
+ }
+
// Let's make sure we got the same number of objects as we got from the callback
// by testing the EnumerateNonGCObjects API.
ICorProfilerObjectEnum* pEnum = NULL;
- HRESULT hr = pCorProfilerInfo->EnumerateNonGCObjects(&pEnum);
+ hr = pCorProfilerInfo->EnumerateNonGCObjects(&pEnum);
if (FAILED(hr))
{
printf("EnumerateNonGCObjects returned an error\n!");
{
int nonGcObjectsEnumerated = 0;
ObjectID obj;
+ bool isFirstObj = true;
while (pEnum->Next(1, &obj, NULL) == S_OK)
{
+ if (isFirstObj)
+ {
+ if (firstObj != obj)
+ {
+ printf("EnumerateNonGCObjects: firstObj != obj\n!");
+ _failures++;
+ }
+ }
+
+ // Add test coverage for IsFrozenObject API, currently, it is expected to return true
+ // for objects from non-GC heap (it might also return true for frozen segments we don't track)
+ BOOL isFrozen;
+ hr = pCorProfilerInfo->IsFrozenObject(obj, &isFrozen);
+ if (FAILED(hr) || !isFrozen)
+ {
+ printf("EnumerateNonGCObjects: IsFrozenObject failed\n!");
+ _failures++;
+ }
+
+ isFirstObj = false;
nonGcObjectsEnumerated++;
}