Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Replace CQuickSort with qsort in GC info encoders. #4163

Merged
merged 1 commit into from
Apr 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 37 additions & 50 deletions src/gcinfo/dbggcinfoencoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,56 +420,48 @@ void GcInfoEncoder::SetSizeOfStackOutgoingAndScratchArea( UINT32 size )
#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA


class LifetimeTransitionsQuickSort : public CQuickSort<GcInfoEncoder::LifetimeTransition>
int __cdecl CompareLifetimeTransitionsForQsort(const void* p1, const void* p2)
{
public:
LifetimeTransitionsQuickSort(
GcInfoEncoder::LifetimeTransition* pBase,
size_t count
)
: CQuickSort<GcInfoEncoder::LifetimeTransition>( pBase, count )
{}
const GcInfoEncoder::LifetimeTransition* pFirst = (const GcInfoEncoder::LifetimeTransition*) p1;
const GcInfoEncoder::LifetimeTransition* pSecond = (const GcInfoEncoder::LifetimeTransition*) p2;

int Compare( GcInfoEncoder::LifetimeTransition* pFirst, GcInfoEncoder::LifetimeTransition* pSecond )
// All registers come before all stack slots
if( pFirst->SlotDesc.IsRegister && !pSecond->SlotDesc.IsRegister ) return -1;
if( !pFirst->SlotDesc.IsRegister && pSecond->SlotDesc.IsRegister ) return 1;

// Then sort them by slot
if( pFirst->SlotDesc.IsRegister )
{
_ASSERTE( pSecond->SlotDesc.IsRegister );
if( pFirst->SlotDesc.Slot.RegisterNumber < pSecond->SlotDesc.Slot.RegisterNumber ) return -1;
if( pFirst->SlotDesc.Slot.RegisterNumber > pSecond->SlotDesc.Slot.RegisterNumber ) return 1;
}
else
{
// All registers come before all stack slots
if( pFirst->SlotDesc.IsRegister && !pSecond->SlotDesc.IsRegister ) return -1;
if( !pFirst->SlotDesc.IsRegister && pSecond->SlotDesc.IsRegister ) return 1;
_ASSERTE( !pSecond->SlotDesc.IsRegister );
if( pFirst->SlotDesc.Slot.Stack.SpOffset < pSecond->SlotDesc.Slot.Stack.SpOffset ) return -1;
if( pFirst->SlotDesc.Slot.Stack.SpOffset > pSecond->SlotDesc.Slot.Stack.SpOffset ) return 1;

// Then sort them by slot
if( pFirst->SlotDesc.IsRegister )
{
_ASSERTE( pSecond->SlotDesc.IsRegister );
if( pFirst->SlotDesc.Slot.RegisterNumber < pSecond->SlotDesc.Slot.RegisterNumber ) return -1;
if( pFirst->SlotDesc.Slot.RegisterNumber > pSecond->SlotDesc.Slot.RegisterNumber ) return 1;
}
else
{
_ASSERTE( !pSecond->SlotDesc.IsRegister );
if( pFirst->SlotDesc.Slot.Stack.SpOffset < pSecond->SlotDesc.Slot.Stack.SpOffset ) return -1;
if( pFirst->SlotDesc.Slot.Stack.SpOffset > pSecond->SlotDesc.Slot.Stack.SpOffset ) return 1;
// This is arbitrary, but we want to make sure they are considered separate slots
if( pFirst->SlotDesc.Slot.Stack.Base < pSecond->SlotDesc.Slot.Stack.Base ) return -1;
if( pFirst->SlotDesc.Slot.Stack.Base > pSecond->SlotDesc.Slot.Stack.Base ) return 1;
}

// This is arbitrary, but we want to make sure they are considered separate slots
if( pFirst->SlotDesc.Slot.Stack.Base < pSecond->SlotDesc.Slot.Stack.Base ) return -1;
if( pFirst->SlotDesc.Slot.Stack.Base > pSecond->SlotDesc.Slot.Stack.Base ) return 1;
}
// Then sort them by code offset
size_t firstOffset = pFirst->CodeOffset;
size_t secondOffset = pSecond->CodeOffset;
if( firstOffset < secondOffset ) return -1;
if( firstOffset > secondOffset ) return 1;

// Then sort them by code offset
size_t firstOffset = pFirst->CodeOffset;
size_t secondOffset = pSecond->CodeOffset;
if( firstOffset < secondOffset ) return -1;
if( firstOffset > secondOffset ) return 1;

//
// Same slot and offset. We put all the going-live transition first
// so that the encoder will skip the remaining transitions and
// the going-live transitions take precedence
//
_ASSERTE( ( pFirst->BecomesLive == 0 ) || ( pFirst->BecomesLive == 1 ) );
_ASSERTE( ( pSecond->BecomesLive == 0 ) || ( pSecond->BecomesLive == 1 ) );
return ( pSecond->BecomesLive - pFirst->BecomesLive );
}
};
//
// Same slot and offset. We put all the going-live transition first
// so that the encoder will skip the remaining transitions and
// the going-live transitions take precedence
//
_ASSERTE( ( pFirst->BecomesLive == 0 ) || ( pFirst->BecomesLive == 1 ) );
_ASSERTE( ( pSecond->BecomesLive == 0 ) || ( pSecond->BecomesLive == 1 ) );
return ( pSecond->BecomesLive - pFirst->BecomesLive );
}


void GcInfoEncoder::Build()
Expand Down Expand Up @@ -585,13 +577,8 @@ void GcInfoEncoder::Build()
m_LifetimeTransitions.CopyTo(m_rgSortedTransitions);

// Sort them first
LifetimeTransitionsQuickSort lifetimeTransitionsQSort(
m_rgSortedTransitions,
m_LifetimeTransitions.Count()
);
lifetimeTransitionsQSort.Sort();

size_t numTransitions = m_LifetimeTransitions.Count();
qsort(m_rgSortedTransitions, numTransitions, sizeof(LifetimeTransition), CompareLifetimeTransitionsForQsort);

//------------------------------------------------------------------
// Count registers and stack slots
Expand Down
114 changes: 50 additions & 64 deletions src/gcinfo/gcinfoencoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,58 +809,52 @@ void GcInfoEncoder::SetSizeOfStackOutgoingAndScratchArea( UINT32 size )
}
#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA

class SlotTableIndexesQuickSort : public CQuickSort<UINT32>

struct GcSlotDescAndId
{
GcSlotDesc* m_SlotTable;

public:
SlotTableIndexesQuickSort(
GcSlotDesc* slotTable,
UINT32* pBase,
size_t count
)
: CQuickSort<UINT32>( pBase, count ), m_SlotTable(slotTable)
{}

int Compare( UINT32* a, UINT32* b )
{
GcSlotDesc* pFirst = &(m_SlotTable[*a]);
GcSlotDesc* pSecond = &(m_SlotTable[*b]);

int firstFlags = pFirst->Flags ^ GC_SLOT_UNTRACKED;
int secondFlags = pSecond->Flags ^ GC_SLOT_UNTRACKED;

// All registers come before all stack slots
// All untracked come last
// Then sort them by flags, ensuring that the least-frequent interior/pinned flag combinations are first
// This is accomplished in the comparison of flags, since we encode IsRegister in the highest flag bit
// And we XOR the UNTRACKED flag to place them last in the second highest flag bit
if( firstFlags > secondFlags ) return -1;
if( firstFlags < secondFlags ) return 1;

// Then sort them by slot
if( pFirst->IsRegister() )
{
_ASSERTE( pSecond->IsRegister() );
if( pFirst->Slot.RegisterNumber < pSecond->Slot.RegisterNumber ) return -1;
if( pFirst->Slot.RegisterNumber > pSecond->Slot.RegisterNumber ) return 1;
}
else
{
_ASSERTE( !pSecond->IsRegister() );
if( pFirst->Slot.Stack.SpOffset < pSecond->Slot.Stack.SpOffset ) return -1;
if( pFirst->Slot.Stack.SpOffset > pSecond->Slot.Stack.SpOffset ) return 1;
GcSlotDesc m_SlotDesc;
UINT32 m_SlotId;
};

// This is arbitrary, but we want to make sure they are considered separate slots
if( pFirst->Slot.Stack.Base < pSecond->Slot.Stack.Base ) return -1;
if( pFirst->Slot.Stack.Base > pSecond->Slot.Stack.Base ) return 1;
}

// If we get here, the slots are identical
_ASSERTE(!"Duplicate slots definitions found in GC information!");
return 0;
int __cdecl CompareSlotDescAndIdBySlotDesc(const void* p1, const void* p2)
{
const GcSlotDesc* pFirst = &reinterpret_cast<const GcSlotDescAndId*>(p1)->m_SlotDesc;
const GcSlotDesc* pSecond = &reinterpret_cast<const GcSlotDescAndId*>(p2)->m_SlotDesc;

int firstFlags = pFirst->Flags ^ GC_SLOT_UNTRACKED;
int secondFlags = pSecond->Flags ^ GC_SLOT_UNTRACKED;

// All registers come before all stack slots
// All untracked come last
// Then sort them by flags, ensuring that the least-frequent interior/pinned flag combinations are first
// This is accomplished in the comparison of flags, since we encode IsRegister in the highest flag bit
// And we XOR the UNTRACKED flag to place them last in the second highest flag bit
if( firstFlags > secondFlags ) return -1;
if( firstFlags < secondFlags ) return 1;

// Then sort them by slot
if( pFirst->IsRegister() )
{
_ASSERTE( pSecond->IsRegister() );
if( pFirst->Slot.RegisterNumber < pSecond->Slot.RegisterNumber ) return -1;
if( pFirst->Slot.RegisterNumber > pSecond->Slot.RegisterNumber ) return 1;
}
};
else
{
_ASSERTE( !pSecond->IsRegister() );
if( pFirst->Slot.Stack.SpOffset < pSecond->Slot.Stack.SpOffset ) return -1;
if( pFirst->Slot.Stack.SpOffset > pSecond->Slot.Stack.SpOffset ) return 1;

// This is arbitrary, but we want to make sure they are considered separate slots
if( pFirst->Slot.Stack.Base < pSecond->Slot.Stack.Base ) return -1;
if( pFirst->Slot.Stack.Base > pSecond->Slot.Stack.Base ) return 1;
}

// If we get here, the slots are identical
_ASSERTE(!"Duplicate slots definitions found in GC information!");
return 0;
}


int __cdecl CompareLifetimeTransitionsByOffsetThenSlot(const void* p1, const void* p2)
Expand Down Expand Up @@ -1302,31 +1296,26 @@ void GcInfoEncoder::Build()
///////////////////////////////////////////////////////////////////////

{
UINT32* sortedSlotIndexes = (UINT32*) m_pAllocator->Alloc(m_NumSlots * sizeof(UINT32));
GcSlotDescAndId* sortedSlots = (GcSlotDescAndId*) m_pAllocator->Alloc(m_NumSlots * sizeof(GcSlotDescAndId));
UINT32* sortOrder = (UINT32*) m_pAllocator->Alloc(m_NumSlots * sizeof(UINT32));

for(UINT32 i = 0; i < m_NumSlots; i++)
{
sortedSlotIndexes[i] = i;
sortedSlots[i].m_SlotDesc = m_SlotTable[i];
sortedSlots[i].m_SlotId = i;
}

SlotTableIndexesQuickSort slotTableIndexesQuickSort(
m_SlotTable,
sortedSlotIndexes,
m_NumSlots
);
slotTableIndexesQuickSort.Sort();

qsort(sortedSlots, m_NumSlots, sizeof(GcSlotDescAndId), CompareSlotDescAndIdBySlotDesc);

for(UINT32 i = 0; i < m_NumSlots; i++)
{
sortOrder[sortedSlotIndexes[i]] = i;
sortOrder[sortedSlots[i].m_SlotId] = i;
}

// Re-order the slot table
GcSlotDesc* pNewSlotTable = (GcSlotDesc*) m_pAllocator->Alloc(sizeof(GcSlotDesc) * m_NumSlots);
for(UINT32 i = 0; i < m_NumSlots; i++)
{
pNewSlotTable[i] = m_SlotTable[sortedSlotIndexes[i]];
m_SlotTable[i] = sortedSlots[i].m_SlotDesc;
}

// Update transitions to assign new slot ids
Expand All @@ -1337,12 +1326,9 @@ void GcInfoEncoder::Build()
}

#ifdef MUST_CALL_JITALLOCATOR_FREE
m_pAllocator->Free( m_SlotTable );
m_pAllocator->Free( sortedSlotIndexes );
m_pAllocator->Free( sortedSlots );
m_pAllocator->Free( sortOrder );
#endif

m_SlotTable = pNewSlotTable;
}


Expand Down
10 changes: 5 additions & 5 deletions src/inc/gcinfoencoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,23 +149,23 @@ struct GcSlotDesc
} Slot;
GcSlotFlags Flags;

BOOL IsRegister()
BOOL IsRegister() const
{
return (Flags & GC_SLOT_IS_REGISTER);
}
BOOL IsInterior()
BOOL IsInterior() const
{
return (Flags & GC_SLOT_INTERIOR);
}
BOOL IsPinned()
BOOL IsPinned() const
{
return (Flags & GC_SLOT_PINNED);
}
BOOL IsUntracked()
BOOL IsUntracked() const
{
return (Flags & GC_SLOT_UNTRACKED);
}
BOOL IsDeleted()
BOOL IsDeleted() const
{
return (Flags & GC_SLOT_IS_DELETED);
}
Expand Down