Skip to content

Commit

Permalink
Fix a few profiler related issues associated with frozen objects (#79563
Browse files Browse the repository at this point in the history
)
  • Loading branch information
cshung authored Jan 11, 2023
1 parent 6da8e2a commit 6aaaaaa
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 41 deletions.
6 changes: 3 additions & 3 deletions src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33326,6 +33326,9 @@ void gc_heap::walk_relocation (void* profiling_context, record_surv_fn fn)
int condemned_gen_number = settings.condemned_generation;
int stop_gen_idx = get_stop_generation_index (condemned_gen_number);

reset_pinned_queue_bos();
update_oldest_pinned_plug();

for (int i = condemned_gen_number; i >= stop_gen_idx; i--)
{
generation* condemned_gen = generation_of (i);
Expand All @@ -33339,9 +33342,6 @@ void gc_heap::walk_relocation (void* profiling_context, record_surv_fn fn)
size_t current_brick = brick_of (start_address);

PREFIX_ASSUME(current_heap_segment != NULL);

reset_pinned_queue_bos();
update_oldest_pinned_plug();
size_t end_brick = brick_of (heap_segment_allocated (current_heap_segment)-1);
walk_relocate_args args;
args.is_shortened = FALSE;
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/gc/gcee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,9 @@ segment_handle GCHeap::RegisterFrozenSegment(segment_info *pseginfo)
heap_segment_next(seg) = 0;
heap_segment_used(seg) = heap_segment_allocated(seg);
heap_segment_plan_allocated(seg) = 0;
#ifdef USE_REGIONS
heap_segment_gen_num(seg) = max_generation;
#endif //USE_REGIONS
seg->flags = heap_segment_flags_readonly;

#ifdef MULTIPLE_HEAPS
Expand Down
80 changes: 44 additions & 36 deletions src/coreclr/vm/frozenobjectheap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ FrozenObjectHeapManager::FrozenObjectHeapManager():
// Allocates an object of the give size (including header) on a frozen segment.
// May return nullptr if object is too large (larger than FOH_COMMIT_SIZE)
// in such cases caller is responsible to find a more appropriate heap to allocate it
Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t objectSize)
Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t objectSize, bool publish)
{
CONTRACTL
{
Expand All @@ -32,51 +32,59 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t
return nullptr;
#else // FEATURE_BASICFREEZE

CrstHolder ch(&m_Crst);
Object* obj = nullptr;
{
CrstHolder ch(&m_Crst);

_ASSERT(type != nullptr);
_ASSERT(FOH_COMMIT_SIZE >= MIN_OBJECT_SIZE);
_ASSERT(type != nullptr);
_ASSERT(FOH_COMMIT_SIZE >= MIN_OBJECT_SIZE);

#ifdef FEATURE_64BIT_ALIGNMENT
_ASSERT(!type->RequiresAlign8());
#endif
#ifdef FEATURE_64BIT_ALIGNMENT
_ASSERT(!type->RequiresAlign8());
#endif

// NOTE: objectSize is expected be the full size including header
_ASSERT(objectSize >= MIN_OBJECT_SIZE);
// NOTE: objectSize is expected be the full size including header
_ASSERT(objectSize >= MIN_OBJECT_SIZE);

if (objectSize > FOH_COMMIT_SIZE)
{
// The current design doesn't allow objects larger than FOH_COMMIT_SIZE and
// since FrozenObjectHeap is just an optimization, let's not fill it with huge objects.
return nullptr;
}
if (objectSize > FOH_COMMIT_SIZE)
{
// The current design doesn't allow objects larger than FOH_COMMIT_SIZE and
// since FrozenObjectHeap is just an optimization, let's not fill it with huge objects.
return nullptr;
}

if (m_CurrentSegment == nullptr)
{
// Create the first segment on first allocation
m_CurrentSegment = new FrozenObjectSegment(FOH_SEGMENT_DEFAULT_SIZE);
m_FrozenSegments.Append(m_CurrentSegment);
_ASSERT(m_CurrentSegment != nullptr);
}
if (m_CurrentSegment == nullptr)
{
// Create the first segment on first allocation
m_CurrentSegment = new FrozenObjectSegment(FOH_SEGMENT_DEFAULT_SIZE);
m_FrozenSegments.Append(m_CurrentSegment);
_ASSERT(m_CurrentSegment != nullptr);
}

Object* obj = m_CurrentSegment->TryAllocateObject(type, objectSize);
obj = m_CurrentSegment->TryAllocateObject(type, objectSize);

// The only case where it can be null is when the current segment is full and we need
// to create a new one
if (obj == nullptr)
{
// Double the reserved size to reduce the number of frozen segments in apps with lots of frozen objects
// Use the same size in case if prevSegmentSize*2 operation overflows.
size_t prevSegmentSize = m_CurrentSegment->GetSize();
m_CurrentSegment = new FrozenObjectSegment(max(prevSegmentSize, prevSegmentSize * 2));
m_FrozenSegments.Append(m_CurrentSegment);
// The only case where it can be null is when the current segment is full and we need
// to create a new one
if (obj == nullptr)
{
// Double the reserved size to reduce the number of frozen segments in apps with lots of frozen objects
// Use the same size in case if prevSegmentSize*2 operation overflows.
size_t prevSegmentSize = m_CurrentSegment->GetSize();
m_CurrentSegment = new FrozenObjectSegment(max(prevSegmentSize, prevSegmentSize * 2));
m_FrozenSegments.Append(m_CurrentSegment);

// Try again
obj = m_CurrentSegment->TryAllocateObject(type, objectSize);
// Try again
obj = m_CurrentSegment->TryAllocateObject(type, objectSize);

// This time it's not expected to be null
_ASSERT(obj != nullptr);
// This time it's not expected to be null
_ASSERT(obj != nullptr);
}
}
if (publish)
{
PublishFrozenObject(obj);
}

return obj;
#endif // !FEATURE_BASICFREEZE
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/frozenobjectheap.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class FrozenObjectHeapManager
{
public:
FrozenObjectHeapManager();
Object* TryAllocateObject(PTR_MethodTable type, size_t objectSize);
Object* TryAllocateObject(PTR_MethodTable type, size_t objectSize, bool publish = true);

private:
Crst m_Crst;
Expand Down
9 changes: 8 additions & 1 deletion src/coreclr/vm/gchelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,11 @@ void PublishObjectAndNotify(TObj* &orObject, GC_ALLOC_FLAGS flags)
#endif // FEATURE_EVENT_TRACE
}

void PublishFrozenObject(Object*& orObject)
{
PublishObjectAndNotify(orObject, GC_ALLOC_NO_FLAGS);
}

inline SIZE_T MaxArrayLength()
{
// Impose limits on maximum array length to prevent corner case integer overflow bugs
Expand Down Expand Up @@ -886,10 +891,12 @@ STRINGREF AllocateString(DWORD cchStringLength, bool preferFrozenHeap, bool* pIs
if (preferFrozenHeap)
{
FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager();
orString = static_cast<StringObject*>(foh->TryAllocateObject(g_pStringClass, totalSize));
orString = static_cast<StringObject*>(foh->TryAllocateObject(g_pStringClass, totalSize, /* publish = */false));
if (orString != nullptr)
{
orString->SetStringLength(cchStringLength);
// Publish needs to be postponed in this case because we need to specify string length
PublishObjectAndNotify(orString, GC_ALLOC_NO_FLAGS);
_ASSERTE(orString->GetBuffer()[cchStringLength] == W('\0'));
orStringRef = ObjectToSTRINGREF(orString);
*pIsFrozen = true;
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/vm/gchelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,7 @@ extern void ThrowOutOfMemoryDimensionsExceeded();

void ErectWriteBarrier(OBJECTREF* dst, OBJECTREF ref);
void SetCardsAfterBulkCopy(Object **start, size_t len);

void PublishFrozenObject(Object*& orObject);

#endif // _GCHELPERS_H_

0 comments on commit 6aaaaaa

Please sign in to comment.