#define VALIDATE_ROOT(isInterior, hCallBack, pObjRef) ((void)0)
#include "../vm/gcinfodecoder.cpp"
#include "../gcinfo/gcinfodumper.cpp"
-#ifdef VERIFY_GCINFO
-#include "../vm/dbggcinfodecoder.cpp"
-#endif
set( GCINFO_SOURCES
arraylist.cpp
gcinfoencoder.cpp
- dbggcinfoencoder.cpp
)
if(CLR_CMAKE_PLATFORM_ARCH_I386)
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-/*****************************************************************************
- *
- * GC Information Encoding API
- *
- * This is an older well-tested implementation
- * now used to verify the real encoding
- * Define VERIFY_GCINFO to enable the verification
- *
- */
-
-#ifdef VERIFY_GCINFO
-
-#include "dbggcinfoencoder.h"
-#include "gcinfoencoder.h"
-
-
-namespace DbgGcInfo {
-
-
-#ifdef _DEBUG
- #ifndef LOGGING
- #define LOGGING
- #endif
-#endif
-#include "log.h"
-
-
-void *GcInfoEncoder::LifetimeTransitionAllocator::Alloc (void *context, SIZE_T cb)
-{
- GcInfoEncoder *pGcInfoEncoder = CONTAINING_RECORD(context, GcInfoEncoder, m_LifetimeTransitions);
- return pGcInfoEncoder->m_pAllocator->Alloc(cb);
-}
-
-void GcInfoEncoder::LifetimeTransitionAllocator::Free (void *context, void *pv)
-{
-#ifdef MUST_CALL_JITALLOCATOR_FREE
- GcInfoEncoder *pGcInfoEncoder = CONTAINING_RECORD(context, GcInfoEncoder, m_LifetimeTransitions);
- pGcInfoEncoder->m_pAllocator->Free(pv);
-#endif
-}
-
-
-BitStreamWriter::MemoryBlockList::MemoryBlockList()
- : m_head(nullptr),
- m_tail(nullptr)
-{
-}
-
-BitStreamWriter::MemoryBlock* BitStreamWriter::MemoryBlockList::AppendNew(IJitAllocator* allocator, size_t bytes)
-{
- auto* memBlock = reinterpret_cast<MemoryBlock*>(allocator->Alloc(sizeof(MemoryBlock) + bytes));
- memBlock->m_next = nullptr;
-
- if (m_tail != nullptr)
- {
- _ASSERTE(m_head != nullptr);
- m_tail->m_next = memBlock;
- }
- else
- {
- _ASSERTE(m_head == nullptr);
- m_head = memBlock;
- }
-
- m_tail = memBlock;
- return memBlock;
-}
-
-void BitStreamWriter::MemoryBlockList::Dispose(IJitAllocator* allocator)
-{
-#ifdef MUST_CALL_JITALLOCATOR_FREE
- for (MemoryBlock* block = m_head, *next; block != nullptr; block = next)
- {
- next = block->m_next;
- allocator->Free(block);
- }
- m_head = nullptr;
- m_tail = nullptr;
-#endif
-}
-
-
-void BitStreamWriter::AllocMemoryBlock()
-{
- _ASSERTE( IS_ALIGNED( m_MemoryBlockSize, sizeof( size_t ) ) );
- m_FullyInterruptibleInfoWriter( pJitAllocator ),
- m_LifetimeTransitions( pJitAllocator )
-{
- _ASSERTE( pCorJitInfo != NULL );
- _ASSERTE( pMethodInfo != NULL );
- _ASSERTE( pJitAllocator != NULL );
-
- m_pCorJitInfo = pCorJitInfo;
- m_pMethodInfo = pMethodInfo;
- m_pAllocator = pJitAllocator;
-
-#ifdef _DEBUG
- CORINFO_METHOD_HANDLE methodHandle = pMethodInfo->ftn;
-
- // Get the name of the current method along with the enclosing class
- // or module name.
- m_MethodName = (char *)
- pCorJitInfo->getMethodName(methodHandle, (const char **)&m_ModuleName);
-#endif
-
-
- m_MappingTableSize = m_MappingTableInitialSize;
- m_SlotMappings = (GcSlotDesc*) m_pAllocator->Alloc( m_MappingTableSize*sizeof(GcSlotDesc) );
- m_NumSlotMappings = 0;
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- m_NumSafePointsWithGcState = 0;
-#endif
-#endif
-
- m_SecurityObjectStackSlot = NO_SECURITY_OBJECT;
- m_PSPSymStackSlot = NO_PSP_SYM;
- m_GenericsInstContextStackSlot = NO_GENERICS_INST_CONTEXT;
- m_StackBaseRegister = NO_STACK_BASE_REGISTER;
- m_SizeOfEditAndContinuePreservedArea = NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA;
- m_IsVarArg = false;
- m_LastInterruptibleRangeStopOffset = 0;
- m_NumInterruptibleRanges = 0;
-
-#ifdef _DEBUG
- m_IsMappingTableFrozen = FALSE;
- m_CodeLength = 0;
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- m_SizeOfStackOutgoingAndScratchArea = -1;
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-#endif //_DEBUG
-}
-
-GcSlotId GcInfoEncoder::GetRegisterSlotId( UINT32 regNum, GcSlotFlags flags )
-{
- // We could lookup an existing identical slot in the mapping table (via some hashtable mechanism).
- // We just create duplicates for now.
-
-#ifdef _DEBUG
- _ASSERTE( !m_IsMappingTableFrozen );
-#endif
-
- if( m_NumSlotMappings == m_MappingTableSize )
- {
- GrowMappingTable();
- }
- _ASSERTE( m_NumSlotMappings < m_MappingTableSize );
-
- m_SlotMappings[ m_NumSlotMappings ].IsRegister = 1;
- m_SlotMappings[ m_NumSlotMappings ].Slot.RegisterNumber = regNum;
- m_SlotMappings[ m_NumSlotMappings ].IsInterior = ( flags & GC_SLOT_INTERIOR ) ? 1 : 0;
- m_SlotMappings[ m_NumSlotMappings ].IsPinned = ( flags & GC_SLOT_PINNED ) ? 1 : 0;
-
- GcSlotId newSlotId;
- newSlotId = m_NumSlotMappings++;
- return newSlotId;
-}
-
-GcSlotId GcInfoEncoder::GetStackSlotId( INT32 spOffset, GcSlotFlags flags, GcStackSlotBase spBase )
-{
- // We could lookup an existing identical slot in the mapping table (via some hashtable mechanism).
- // We just create duplicates for now.
-
-#ifdef _DEBUG
- _ASSERTE( !m_IsMappingTableFrozen );
-#endif
-
- if( m_NumSlotMappings == m_MappingTableSize )
- {
- GrowMappingTable();
- }
- _ASSERTE( m_NumSlotMappings < m_MappingTableSize );
-
- // Not valid to reference anything below the current stack pointer
- _ASSERTE(GC_SP_REL != spBase || spOffset >= 0);
-
- m_SlotMappings[ m_NumSlotMappings ].IsRegister = 0;
- m_SlotMappings[ m_NumSlotMappings ].Slot.Stack.SpOffset = spOffset;
- m_SlotMappings[ m_NumSlotMappings ].Slot.Stack.Base = spBase;
- m_SlotMappings[ m_NumSlotMappings ].IsInterior = ( flags & GC_SLOT_INTERIOR ) ? 1 : 0;
- m_SlotMappings[ m_NumSlotMappings ].IsPinned = ( flags & GC_SLOT_PINNED ) ? 1 : 0;
-
- GcSlotId newSlotId;
- newSlotId = m_NumSlotMappings++;
- return newSlotId;
-}
-
-void GcInfoEncoder::GrowMappingTable()
-{
- m_MappingTableSize *= 2;
- GcSlotDesc* newMappingTable = (GcSlotDesc*) m_pAllocator->Alloc( m_MappingTableSize * sizeof(GcSlotDesc) );
- memcpy( newMappingTable, m_SlotMappings, m_NumSlotMappings * sizeof(GcSlotDesc) );
-
-#ifdef MUST_CALL_JITALLOCATOR_FREE
- m_pAllocator->Free( m_SlotMappings );
-#endif
-
- m_SlotMappings = newMappingTable;
-}
-
-GcSlotSet::GcSlotSet( GcInfoEncoder* pEncoder )
-{
-#ifdef _DEBUG
- _ASSERTE( pEncoder->m_IsMappingTableFrozen );
-#endif
-
- m_pEncoder = pEncoder;
- m_NumBytes = ( pEncoder->m_NumSlotMappings + 7 ) / 8;
- m_Data = (BYTE*) pEncoder->m_pAllocator->Alloc( m_NumBytes );
-}
-
-// Copy constructor
-GcSlotSet::GcSlotSet( GcSlotSet & other )
-{
- m_pEncoder = other.m_pEncoder;
- m_NumBytes = other.m_NumBytes;
- m_Data = (BYTE*) other.m_pEncoder->m_pAllocator->Alloc( m_NumBytes );
- memcpy( m_Data, other.m_Data, m_NumBytes);
-}
-
-void GcSlotSet::Add( GcSlotId slotId )
-{
- _ASSERTE( slotId < m_pEncoder->m_NumSlotMappings );
- m_Data[ slotId / 8 ] |= 1 << ( slotId % 8 );
-}
-
-void GcSlotSet::Remove( GcSlotId slotId )
-{
- _ASSERTE( slotId < m_pEncoder->m_NumSlotMappings );
- m_Data[ slotId / 8 ] &= ~( 1 << ( slotId % 8 ) );
-}
-
-// Not used
-#if 0
-
-void GcSlotSet::Add( GcSlotSet & other )
-{
- _ASSERTE( m_pEncoder == other.m_pEncoder );
-
- for( int i=0; i<m_NumBytes; i++ )
- {
- m_Data[ i ] |= other.m_Data[ i ];
- }
-}
-
-void GcSlotSet::Subtract( GcSlotSet & other )
-{
- _ASSERTE( m_pEncoder == other.m_pEncoder );
-
- for( int i=0; i<m_NumBytes; i++ )
- {
- m_Data[ i ] &= ~( other.m_Data[ i ] );
- }
-}
-
-void GcSlotSet::Intersect( GcSlotSet & other )
-{
- _ASSERTE( m_pEncoder == other.m_pEncoder );
-
- for( int i=0; i<m_NumBytes; i++ )
- {
- m_Data[ i ] &= other.m_Data[ i ];
- }
-}
-
-#endif // unused
-
-
-void GcInfoEncoder::FinalizeSlotIds()
-{
-#ifdef _DEBUG
- m_IsMappingTableFrozen = TRUE;
-#endif
-}
-
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
-void GcInfoEncoder::DefineGcStateAtSafePoint(
- UINT32 instructionOffset,
- GcSlotSet &liveSlots
- )
-{
-#ifdef _DEBUG
- _ASSERTE( m_IsMappingTableFrozen );
-#endif
-
-#ifdef _DEBUG
- // Verify that any slot is not reported multiple times. This is O(n^2) but it executes only under _DEBUG
- for( INT32 i1=0; i1<((INT32)m_NumSlotMappings)-1; i1++ )
- {
- BYTE isLive1 = liveSlots.m_Data[ i1 / 8 ] & ( 1 << ( i1 % 8 ) );
- if( isLive1 )
- for( UINT32 i2=i1+1; i2<m_NumSlotMappings; i2++ )
- {
- BYTE isLive2 = liveSlots.m_Data[ i2 / 8 ] & ( 1 << ( i2 % 8 ) );
- if( isLive2 )
- {
- if( m_SlotMappings[ i1 ].IsRegister && m_SlotMappings[ i2 ].IsRegister )
- {
- _ASSERTE( m_SlotMappings[ i1 ].Slot.RegisterNumber != m_SlotMappings[ i2 ].Slot.RegisterNumber );
- }
- else if( !m_SlotMappings[ i1 ].IsRegister && !m_SlotMappings[ i2 ].IsRegister )
- {
- _ASSERTE( m_SlotMappings[ i1 ].Slot.SpOffset != m_SlotMappings[ i2 ].Slot.SpOffset );
- }
- }
- }
- }
-#endif
-
- m_PartiallyInterruptibleInfoWriter.Write( instructionOffset, 32 );
-
- UINT32 i;
- for( i=0; i<m_NumSlotMappings/8; i++ )
- m_PartiallyInterruptibleInfoWriter.Write( liveSlots.m_Data[ i ], 8 );
-
- if( m_NumSlotMappings % 8 > 0 )
- m_PartiallyInterruptibleInfoWriter.Write( liveSlots.m_Data[ i ], m_NumSlotMappings % 8 );
-
- m_NumSafePointsWithGcState++;
-}
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
-void GcInfoEncoder::DefineInterruptibleRange( UINT32 startInstructionOffset, UINT32 length )
-{
- UINT32 stopInstructionOffset = startInstructionOffset + length;
-
- size_t normStartDelta = NORMALIZE_CODE_OFFSET(startInstructionOffset) - NORMALIZE_CODE_OFFSET(m_LastInterruptibleRangeStopOffset);
- size_t normStopDelta = NORMALIZE_CODE_OFFSET(stopInstructionOffset) - NORMALIZE_CODE_OFFSET(startInstructionOffset);
- _ASSERTE(normStopDelta > 0);
-
- m_LastInterruptibleRangeStopOffset = startInstructionOffset + length;
-
- m_NumInterruptibleRanges++;
-
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normStartDelta, INTERRUPTIBLE_RANGE_DELTA_ENCBASE);
-
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normStopDelta-1, INTERRUPTIBLE_RANGE_DELTA_ENCBASE );
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// Tracking information
-///////////////////////////////////////////////////////////////////////////
-
-
-//
-// For inputs, pass zero as offset
-//
-
-void GcInfoEncoder::SetSlotState(
- UINT32 instructionOffset,
- GcSlotId slotId,
- GcSlotState slotState
- )
-{
- LifetimeTransition transition;
-
- transition.SlotDesc = m_SlotMappings[ slotId ];
- transition.CodeOffset = instructionOffset;
- transition.BecomesLive = ( slotState == GC_SLOT_LIVE );
-
- *( m_LifetimeTransitions.Append() ) = transition;
-}
-
-
-void GcInfoEncoder::SetIsVarArg()
-{
- m_IsVarArg = true;
-}
-
-void GcInfoEncoder::SetCodeLength( UINT32 length )
-{
- _ASSERTE( length > 0 );
- _ASSERTE( m_CodeLength == 0 || m_CodeLength == length );
- m_CodeLength = length;
-}
-
-
-void GcInfoEncoder::SetSecurityObjectStackSlot( INT32 spOffset )
-{
- _ASSERTE( spOffset != NO_SECURITY_OBJECT );
- _ASSERTE( m_SecurityObjectStackSlot == NO_SECURITY_OBJECT || m_SecurityObjectStackSlot == spOffset );
- m_SecurityObjectStackSlot = spOffset;
-}
-
-void GcInfoEncoder::SetPSPSymStackSlot( INT32 spOffsetPSPSym )
-{
- _ASSERTE( spOffsetPSPSym != NO_PSP_SYM );
- _ASSERTE( m_PSPSymStackSlot == NO_PSP_SYM || m_PSPSymStackSlot == spOffsetPSPSym );
-
- m_PSPSymStackSlot = spOffsetPSPSym;
-}
-
-void GcInfoEncoder::SetGenericsInstContextStackSlot( INT32 spOffsetGenericsContext )
-{
- _ASSERTE( spOffsetGenericsContext != NO_GENERICS_INST_CONTEXT);
- _ASSERTE( m_GenericsInstContextStackSlot == NO_GENERICS_INST_CONTEXT || m_GenericsInstContextStackSlot == spOffsetGenericsContext );
-
- m_GenericsInstContextStackSlot = spOffsetGenericsContext;
-}
-
-void GcInfoEncoder::SetStackBaseRegister( UINT32 regNum )
-{
- _ASSERTE( regNum != NO_STACK_BASE_REGISTER );
- _ASSERTE( m_StackBaseRegister == NO_STACK_BASE_REGISTER || m_StackBaseRegister == regNum );
- m_StackBaseRegister = regNum;
-}
-
-void GCInfoEncoder::SetSizeOfEditAndContinuePreservedArea( UINT32 slots )
-{
- _ASSERTE( regNum != NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA );
- _ASSERTE( m_SizeOfEditAndContinuePreservedArea == NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA );
- m_SizeOfEditAndContinuePreservedArea = slots;
-}
-
-
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
-void GcInfoEncoder::SetSizeOfStackOutgoingAndScratchArea( UINT32 size )
-{
- _ASSERTE( size != -1 );
- _ASSERTE( m_SizeOfStackOutgoingAndScratchArea == -1 || m_SizeOfStackOutgoingAndScratchArea == size );
- m_SizeOfStackOutgoingAndScratchArea = size;
-}
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-
-int __cdecl CompareLifetimeTransitionsForQsort(const void* p1, const void* p2)
-{
- const GcInfoEncoder::LifetimeTransition* pFirst = (const GcInfoEncoder::LifetimeTransition*) p1;
- const GcInfoEncoder::LifetimeTransition* pSecond = (const GcInfoEncoder::LifetimeTransition*) p2;
-
- // 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
- {
- _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;
- }
-
- // 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 );
-}
-
-
-void GcInfoEncoder::Build()
-{
- SIZE_T i;
-
- ///////////////////////////////////////////////////////////////////////
- // Method header
- ///////////////////////////////////////////////////////////////////////
-
- m_HeaderInfoWriter.Write( ( m_IsVarArg ? 1 : 0 ), 1 );
-
- if(m_SecurityObjectStackSlot != NO_SECURITY_OBJECT)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthSigned(NORMALIZE_STACK_SLOT(m_SecurityObjectStackSlot), SECURITY_OBJECT_STACK_SLOT_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
- if (m_PSPSymStackSlot != NO_PSP_SYM)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthSigned(NORMALIZE_STACK_SLOT(m_PSPSymStackSlot), PSP_SYM_STACK_SLOT_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
- if (m_GenericsInstContextStackSlot != NO_GENERICS_INST_CONTEXT)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthSigned(NORMALIZE_STACK_SLOT(m_GenericsInstContextStackSlot), GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
- _ASSERTE( m_CodeLength > 0 );
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(NORMALIZE_CODE_LENGTH(m_CodeLength), CODE_LENGTH_ENCBASE);
-
- if(m_StackBaseRegister != NO_STACK_BASE_REGISTER)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(NORMALIZE_STACK_BASE_REGISTER(m_StackBaseRegister), STACK_BASE_REGISTER_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
- if(m_SizeOfEditAndContinuePreservedArea != NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(m_SizeOfEditAndContinuePreservedArea, SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- _ASSERTE( m_SizeOfStackOutgoingAndScratchArea != -1 );
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(NORMALIZE_SIZE_OF_STACK_AREA(m_SizeOfStackOutgoingAndScratchArea), SIZE_OF_STACK_AREA_ENCBASE);
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-
- ///////////////////////////////////////////////////////////////////////
- // Fully-interruptible: encode number of interruptible ranges
- ///////////////////////////////////////////////////////////////////////
-
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(NORMALIZE_NUM_INTERRUPTIBLE_RANGES(m_NumInterruptibleRanges), NUM_INTERRUPTIBLE_RANGES_ENCBASE);
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
- ///////////////////////////////////////////////////////////////////////
- // Partially-interruptible: Encode call sites
- ///////////////////////////////////////////////////////////////////////
-
- m_HeaderInfoWriter.Write( m_NumSafePointsWithGcState, sizeof( m_NumSafePointsWithGcState ) * 8 );
-
- if( m_NumSafePointsWithGcState > 0 )
- {
- m_HeaderInfoWriter.Write( m_NumSlotMappings, sizeof( m_NumSlotMappings ) * 8 );
-
- ///////////////////////////////////////////////////////////////////////
- // Partially-interruptible: Encode slot mappings
- ///////////////////////////////////////////////////////////////////////
-
- // Assert that we can write a GcSlotDesc with a single call to BitStreamWriter.Write()
- _ASSERTE( sizeof( GcSlotDesc ) <= sizeof( size_t ) );
- for( UINT32 i=0; i<m_NumSlotMappings; i++ )
- {
- size_t data = 0;
- *( (GcSlotDesc*) &data ) = m_SlotMappings[ i ];
- m_PartiallyInterruptibleInfoWriter.Write( data, sizeof( GcSlotDesc ) * 8 );
- }
- }
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
- ///////////////////////////////////////////////////////////////////////
- // Fully-interruptible: Encode lifetime transitions
- ///////////////////////////////////////////////////////////////////////
-
- m_rgSortedTransitions = (LifetimeTransition*)m_pAllocator->Alloc(m_LifetimeTransitions.Count() * sizeof(LifetimeTransition));
- m_LifetimeTransitions.CopyTo(m_rgSortedTransitions);
-
- // Sort them first
- size_t numTransitions = m_LifetimeTransitions.Count();
- qsort(m_rgSortedTransitions, numTransitions, sizeof(LifetimeTransition), CompareLifetimeTransitionsForQsort);
-
- //------------------------------------------------------------------
- // Count registers and stack slots
- //------------------------------------------------------------------
-
- int numRegisters = 0;
- int numStackSlots = 0;
-
- if(numTransitions > 0)
- {
- i = 1;
- if(m_rgSortedTransitions[ 0 ].SlotDesc.IsRegister)
- {
- numRegisters++;
-
- for( ; i < numTransitions; i++ )
- {
- if(!(m_rgSortedTransitions[ i ].SlotDesc.IsRegister))
- {
- numStackSlots++;
- i++;
- break;
- }
- _ASSERTE(m_rgSortedTransitions[ i-1 ].SlotDesc.IsRegister);
- if((m_rgSortedTransitions[ i ].SlotDesc.Slot.RegisterNumber) != (m_rgSortedTransitions[ i-1 ].SlotDesc.Slot.RegisterNumber))
- numRegisters++;
- }
- }
- else
- {
- numStackSlots++;
- }
-
- for( ; i < numTransitions; i++ )
- {
- _ASSERTE(!(m_rgSortedTransitions[ i-1 ].SlotDesc.IsRegister));
- if((m_rgSortedTransitions[ i ].SlotDesc.Slot.Stack) != (m_rgSortedTransitions[ i-1 ].SlotDesc.Slot.Stack))
- numStackSlots++;
- }
- }
-
-
- size_t __registerSize = 0;
- size_t __stackSlotSize = 0;
- size_t __transitionSize = 0;
- size_t __numTransitions = 0;
-
-
- //------------------------------------------------------------------
- // Encode registers
- //------------------------------------------------------------------
-
- i = 0;
-
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(numRegisters, NUM_REGISTERS_ENCBASE);
-
- UINT32 lastNormRegNum = 0;
-
- for( int j=0; j < numRegisters; j++ )
- {
- _ASSERTE(m_rgSortedTransitions[ i ].SlotDesc.IsRegister);
-
- UINT32 currentRegNum = m_rgSortedTransitions[ i ].SlotDesc.Slot.RegisterNumber;
-
- // Encode slot identification
- UINT32 currentNormRegNum = NORMALIZE_REGISTER(currentRegNum);
- if( j == 0 )
- __registerSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(currentNormRegNum, REGISTER_ENCBASE);
- else
- __registerSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(currentNormRegNum - lastNormRegNum - 1, REGISTER_DELTA_ENCBASE);
- lastNormRegNum = currentNormRegNum;
-
- LifetimeTransition* pLastEncodedTransition = NULL;
-
- for( ; i < numTransitions; i++)
- {
- LifetimeTransition* pTransition = &(m_rgSortedTransitions[ i ]);
-
- if( !(pTransition->SlotDesc.IsRegister) || (pTransition->SlotDesc.Slot.RegisterNumber != currentRegNum))
- break;
-
- if( (pLastEncodedTransition == NULL) )
- {
- // Skip initial going-dead transitions (if any)
- if(!pTransition->BecomesLive)
- continue;
-
- // Encode first going-live transition
- size_t normCodeOffset = NORMALIZE_CODE_OFFSET(pTransition->CodeOffset)+1; // Leave 0 available as terminator
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normCodeOffset, NORM_CODE_OFFSET_DELTA_ENCBASE);
-
- __transitionSize += EncodeFullyInterruptibleSlotFlags(pTransition->SlotDesc);
-
- __numTransitions++;
- }
- else
- {
- _ASSERTE(pLastEncodedTransition->SlotDesc.IsRegister && pLastEncodedTransition->SlotDesc.Slot.RegisterNumber == currentRegNum);
-
- // Skip transitions on identical offsets
- // If there are multiple transitions on the same code offset, we'll encode the first one only
- _ASSERTE(i > 0);
- LifetimeTransition* pPrevTransition = &(m_rgSortedTransitions[ i-1 ]);
- if( (pPrevTransition->CodeOffset == pTransition->CodeOffset) )
- {
- _ASSERTE((!pPrevTransition->BecomesLive || !pTransition->BecomesLive) ||
- (pPrevTransition->SlotDesc.IsInterior == pTransition->SlotDesc.IsInterior) &&
- (pPrevTransition->SlotDesc.IsPinned == pTransition->SlotDesc.IsPinned));
- continue;
- }
-
- // Also skip redundant transitions
- if( (pLastEncodedTransition->BecomesLive == pTransition->BecomesLive) &&
- (pLastEncodedTransition->SlotDesc.IsInterior == pTransition->SlotDesc.IsInterior) &&
- (pLastEncodedTransition->SlotDesc.IsPinned == pTransition->SlotDesc.IsPinned) )
- continue;
-
- // Encode transition
- size_t normCodeOffsetDelta = NORMALIZE_CODE_OFFSET(pTransition->CodeOffset) - NORMALIZE_CODE_OFFSET(pLastEncodedTransition->CodeOffset);
- _ASSERTE(normCodeOffsetDelta != 0); // Leave 0 available as terminator
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normCodeOffsetDelta, NORM_CODE_OFFSET_DELTA_ENCBASE);
-
- if(pTransition->BecomesLive)
- {
- m_FullyInterruptibleInfoWriter.Write(1, 1);
- __transitionSize += EncodeFullyInterruptibleSlotFlags(pTransition->SlotDesc) + 1;
- }
- else
- {
- m_FullyInterruptibleInfoWriter.Write(0, 1);
- __transitionSize++;
- }
-
- __numTransitions++;
- }
-
- pLastEncodedTransition = pTransition;
- }
-
- // Encode termination for this slot
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(0, NORM_CODE_OFFSET_DELTA_ENCBASE);
- }
-
-
- //------------------------------------------------------------------
- // Encode stack slots
- //------------------------------------------------------------------
-
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(numStackSlots, NUM_STACK_SLOTS_ENCBASE);
-
- INT32 lastNormStackSlot = 0;
-
- for( int j=0; j < numStackSlots; j++ )
- {
- _ASSERTE(!m_rgSortedTransitions[ i ].SlotDesc.IsRegister);
-
- GcStackSlot currentStackSlot = m_rgSortedTransitions[ i ].SlotDesc.Slot.Stack;
-
- // Encode slot identification
- INT32 currentNormStackSlot = NORMALIZE_STACK_SLOT(currentStackSlot.SpOffset);
- if( j == 0 )
- __stackSlotSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthSigned(currentNormStackSlot, STACK_SLOT_ENCBASE);
- else
- __stackSlotSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(currentNormStackSlot - lastNormStackSlot, STACK_SLOT_DELTA_ENCBASE);
- lastNormStackSlot = currentNormStackSlot;
- _ASSERTE((currentStackSlot.Base & ~3) == 0);
- m_FullyInterruptibleInfoWriter.Write(currentStackSlot.Base, 2);
- __stackSlotSize += 2;
-
- LifetimeTransition* pLastEncodedTransition = NULL;
-
- for( ; i < numTransitions; i++)
- {
- LifetimeTransition* pTransition = &(m_rgSortedTransitions[ i ]);
-
- _ASSERTE(!pTransition->SlotDesc.IsRegister);
-
- if(pTransition->SlotDesc.Slot.Stack != currentStackSlot)
- break;
-
- if( (pLastEncodedTransition == NULL) )
- {
- // Skip initial going-dead transitions (if any)
- if(!pTransition->BecomesLive)
- continue;
-
- // Encode first going-live transition
- size_t normCodeOffset = NORMALIZE_CODE_OFFSET(pTransition->CodeOffset)+1; // Leave 0 available as terminator
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normCodeOffset, NORM_CODE_OFFSET_DELTA_ENCBASE);
-
- __transitionSize += EncodeFullyInterruptibleSlotFlags(pTransition->SlotDesc);
-
- __numTransitions++;
- }
- else
- {
- _ASSERTE(!(pLastEncodedTransition->SlotDesc.IsRegister) && pLastEncodedTransition->SlotDesc.Slot.Stack == currentStackSlot);
-
- // Skip transitions on identical offsets
- // If there are multiple transitions on the same code offset, we'll encode the first one only
- _ASSERTE(i > 0);
- LifetimeTransition* pPrevTransition = &(m_rgSortedTransitions[ i-1 ]);
- if( (pPrevTransition->CodeOffset == pTransition->CodeOffset) )
- {
- _ASSERTE((!pPrevTransition->BecomesLive || !pTransition->BecomesLive) ||
- (pPrevTransition->SlotDesc.IsInterior == pTransition->SlotDesc.IsInterior) &&
- (pPrevTransition->SlotDesc.IsPinned == pTransition->SlotDesc.IsPinned));
- continue;
- }
-
- // Also skip redundant transitions
- if( (pLastEncodedTransition->BecomesLive == pTransition->BecomesLive) &&
- (pLastEncodedTransition->SlotDesc.IsInterior == pTransition->SlotDesc.IsInterior) &&
- (pLastEncodedTransition->SlotDesc.IsPinned == pTransition->SlotDesc.IsPinned) )
- continue;
-
- // Encode transition
- size_t normCodeOffsetDelta = NORMALIZE_CODE_OFFSET(pTransition->CodeOffset) - NORMALIZE_CODE_OFFSET(pLastEncodedTransition->CodeOffset);
- _ASSERTE(normCodeOffsetDelta != 0); // Leave 0 available as terminator
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normCodeOffsetDelta, NORM_CODE_OFFSET_DELTA_ENCBASE);
-
- if(pTransition->BecomesLive)
- {
- m_FullyInterruptibleInfoWriter.Write(1, 1);
- __transitionSize += EncodeFullyInterruptibleSlotFlags(pTransition->SlotDesc) + 1;
- }
- else
- {
- m_FullyInterruptibleInfoWriter.Write(0, 1);
- __transitionSize++;
- }
-
- __numTransitions++;
- }
-
- pLastEncodedTransition = pTransition;
- }
-
- // Encode termination for this slot
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(0, NORM_CODE_OFFSET_DELTA_ENCBASE);
- }
-
-}
-
-size_t GcInfoEncoder::GetByteCount()
-{
- return m_HeaderInfoWriter.GetByteCount() +
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- m_PartiallyInterruptibleInfoWriter.GetByteCount() +
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
- m_FullyInterruptibleInfoWriter.GetByteCount();
-}
-
-//
-// Write encoded information to its final destination and frees temporary buffers.
-// The encoder shouldn't be used anymore after calling this method.
-//
-BYTE* GcInfoEncoder::Emit(BYTE* destBuffer)
-{
- size_t cbGcInfoSize = GetByteCount();
-
- _ASSERTE( destBuffer );
-
- m_HeaderInfoWriter.CopyTo( destBuffer );
- destBuffer += m_HeaderInfoWriter.GetByteCount();
- m_HeaderInfoWriter.Dispose();
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- m_PartiallyInterruptibleInfoWriter.CopyTo( destBuffer );
- destBuffer += m_PartiallyInterruptibleInfoWriter.GetByteCount();
- m_PartiallyInterruptibleInfoWriter.Dispose();
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
- m_FullyInterruptibleInfoWriter.CopyTo( destBuffer );
- m_FullyInterruptibleInfoWriter.Dispose();
-
- return destBuffer;
-}
-
-void * GcInfoEncoder::eeAllocGCInfo (size_t blockSize)
-{
- return m_pCorJitInfo->allocGCInfo((ULONG)blockSize);
-}
-
-
-BitStreamWriter::BitStreamWriter( IJitAllocator* pAllocator )
-{
- m_pAllocator = pAllocator;
- m_BitCount = 0;
-#ifdef _DEBUG
- m_MemoryBlocksCount = 0;
-#endif
-
- // We are going to need at least one memory block, so we pre-allocate it
- AllocMemoryBlock();
- InitCurrentSlot();
-}
-
-//
-// bit 0 is the least significative bit
-// The stream encodes the first come bit in the least significant bit of each byte
-//
-void BitStreamWriter::Write( size_t data, int count )
-{
- _ASSERTE( count > 0 );
- _ASSERT( count <= sizeof( size_t )*8 );
-
- // Increment it now as we change count later on
- m_BitCount += count;
-
- if( count > m_FreeBitsInCurrentSlot )
- {
- if( m_FreeBitsInCurrentSlot > 0 )
- {
- WriteInCurrentSlot( data, m_FreeBitsInCurrentSlot );
- count -= m_FreeBitsInCurrentSlot;
- data >>= m_FreeBitsInCurrentSlot;
- }
-
- _ASSERTE( count > 0 );
-
- // Initialize the next slot
- if( ++m_pCurrentSlot >= m_OutOfBlockSlot )
- {
- // Get a new memory block
- AllocMemoryBlock();
- }
-
- InitCurrentSlot();
-
- // Write the remainder
- WriteInCurrentSlot( data, count );
- m_FreeBitsInCurrentSlot -= count;
- }
- else
- {
- WriteInCurrentSlot( data, count );
- m_FreeBitsInCurrentSlot -= count;
- // if m_FreeBitsInCurrentSlot becomes 0 a nwe slot will initialized on the next request
- }
-}
-
-
-void BitStreamWriter::CopyTo( BYTE* buffer )
-{
- int i,c;
- BYTE* source = NULL;
-
- MemoryBlock* pMemBlock = m_MemoryBlocks.Head();
- _ASSERTE( pMemBlockDesc != NULL );
- while (pMemBlock->Next() != NULL)
- {
- source = (BYTE*) pMemBlock->Contents;
- // @TODO: use memcpy instead
- for( i = 0; i < m_MemoryBlockSize; i++ )
- {
- *( buffer++ ) = *( source++ );
- }
-
- pMemBlock = pMemBlock->Next();
- }
-
- source = (BYTE*) pMemBlock->Contents;
- // The number of bytes to copy in the last block
- c = (int) ((BYTE*) ( m_pCurrentSlot + 1 ) - source - m_FreeBitsInCurrentSlot/8);
- _ASSERTE( c >= 0 );
- // @TODO: use memcpy instead
- for( i = 0; i < c; i++ )
- {
- *( buffer++ ) = *( source++ );
- }
-
-}
-
-void BitStreamWriter::Dispose()
-{
- m_MemoryBlocks.Dispose(m_pAllocator);
-}
-
-}
-
-#endif // VERIFY_GCINFO
-
<ItemGroup>
<CppCompile Include="..\ArrayList.cpp" />
<CppCompile Include="..\GCInfoEncoder.cpp" />
- <CppCompile Include="..\DbgGCInfoEncoder.cpp" />
</ItemGroup>
<!-- Import the targets -->
#include "gcinfoencoder.h"
-#ifdef VERIFY_GCINFO
-#include "dbggcinfoencoder.h"
-#endif
-
#ifdef _DEBUG
#ifndef LOGGING
#define LOGGING
m_Info2( pJitAllocator ),
m_InterruptibleRanges( pJitAllocator ),
m_LifetimeTransitions( pJitAllocator )
-#ifdef VERIFY_GCINFO
- , m_DbgEncoder(pCorJitInfo, pMethodInfo, pJitAllocator)
-#endif
{
#ifdef MEASURE_GCINFO
// This causes multiple complus.log files in JIT64. TODO: consider using ICorJitInfo::logMsg instead.
GcSlotId newSlotId;
newSlotId = m_NumSlots++;
-#ifdef VERIFY_GCINFO
- GcSlotId dbgSlotId = m_DbgEncoder.GetRegisterSlotId(regNum, flags);
- _ASSERTE(dbgSlotId == newSlotId);
-#endif
-
return newSlotId;
}
GcSlotId newSlotId;
newSlotId = m_NumSlots++;
-#ifdef VERIFY_GCINFO
- GcSlotId dbgSlotId = m_DbgEncoder.GetStackSlotId(spOffset, flags, spBase);
- _ASSERTE(dbgSlotId == newSlotId);
-#endif
-
return newSlotId;
}
void GcInfoEncoder::DefineInterruptibleRange( UINT32 startInstructionOffset, UINT32 length )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.DefineInterruptibleRange(startInstructionOffset, length);
-#endif
-
UINT32 stopInstructionOffset = startInstructionOffset + length;
UINT32 normStartOffset = NORMALIZE_CODE_OFFSET(startInstructionOffset);
{
_ASSERTE( (m_SlotTable[ slotId ].Flags & GC_SLOT_UNTRACKED) == 0 );
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetSlotState(instructionOffset, slotId, slotState);
-#endif
-
LifetimeTransition transition;
transition.SlotId = slotId;
void GcInfoEncoder::SetIsVarArg()
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetIsVarArg();
-#endif
-
m_IsVarArg = true;
}
void GcInfoEncoder::SetCodeLength( UINT32 length )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetCodeLength(length);
-#endif
-
_ASSERTE( length > 0 );
_ASSERTE( m_CodeLength == 0 || m_CodeLength == length );
m_CodeLength = length;
void GcInfoEncoder::SetSecurityObjectStackSlot( INT32 spOffset )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetSecurityObjectStackSlot(spOffset);
-#endif
-
_ASSERTE( spOffset != NO_SECURITY_OBJECT );
#if defined(_TARGET_AMD64_)
_ASSERTE( spOffset < 0x10 && "The security object cannot reside in an input variable!" );
void GcInfoEncoder::SetPSPSymStackSlot( INT32 spOffsetPSPSym )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetPSPSymStackSlot(spOffsetPSPSym);
-#endif
-
_ASSERTE( spOffsetPSPSym != NO_PSP_SYM );
_ASSERTE( m_PSPSymStackSlot == NO_PSP_SYM || m_PSPSymStackSlot == spOffsetPSPSym );
void GcInfoEncoder::SetGenericsInstContextStackSlot( INT32 spOffsetGenericsContext, GENERIC_CONTEXTPARAM_TYPE type)
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetGenericsInstContextStackSlot(spOffsetGenericsContext);
-#endif
-
_ASSERTE( spOffsetGenericsContext != NO_GENERICS_INST_CONTEXT);
_ASSERTE( m_GenericsInstContextStackSlot == NO_GENERICS_INST_CONTEXT || m_GenericsInstContextStackSlot == spOffsetGenericsContext );
void GcInfoEncoder::SetStackBaseRegister( UINT32 regNum )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetStackBaseRegister(regNum);
-#endif
-
_ASSERTE( regNum != NO_STACK_BASE_REGISTER );
_ASSERTE(DENORMALIZE_STACK_BASE_REGISTER(NORMALIZE_STACK_BASE_REGISTER(regNum)) == regNum);
_ASSERTE( m_StackBaseRegister == NO_STACK_BASE_REGISTER || m_StackBaseRegister == regNum );
void GcInfoEncoder::SetSizeOfEditAndContinuePreservedArea( UINT32 slots )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetSizeOfEditAndContinuePreservedArea(slots);
-#endif
-
_ASSERTE( slots != NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA );
_ASSERTE( m_SizeOfEditAndContinuePreservedArea == NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA );
m_SizeOfEditAndContinuePreservedArea = slots;
#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
void GcInfoEncoder::SetSizeOfStackOutgoingAndScratchArea( UINT32 size )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetSizeOfStackOutgoingAndScratchArea(size);
-#endif
-
_ASSERTE( size != (UINT32)-1 );
_ASSERTE( m_SizeOfStackOutgoingAndScratchArea == (UINT32)-1 || m_SizeOfStackOutgoingAndScratchArea == size );
m_SizeOfStackOutgoingAndScratchArea = size;
void GcInfoEncoder::FinalizeSlotIds()
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.FinalizeSlotIds();
-#endif
-
#ifdef _DEBUG
m_IsSlotTableFrozen = TRUE;
#endif
void GcInfoEncoder::Build()
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.Build();
-#endif
-
#ifdef _DEBUG
_ASSERTE(m_IsSlotTableFrozen || m_NumSlots == 0);
#endif
size_t cbGcInfoSize = m_Info1.GetByteCount() +
m_Info2.GetByteCount();
-#ifdef VERIFY_GCINFO
- cbGcInfoSize += (sizeof(size_t)) + m_DbgEncoder.GetByteCount();
-#endif
-
LOG((LF_GCINFO, LL_INFO100, "GcInfoEncoder::Emit(): Size of GC info is %u bytes, code size %u bytes.\n", (unsigned)cbGcInfoSize, m_CodeLength ));
BYTE* destBuffer = (BYTE *)eeAllocGCInfo(cbGcInfoSize);
BYTE* ptr = destBuffer;
-#ifdef VERIFY_GCINFO
- _ASSERTE(sizeof(size_t) >= sizeof(UINT32));
- size_t __displacement = cbGcInfoSize - m_DbgEncoder.GetByteCount();
- ptr[0] = (BYTE)__displacement;
- ptr[1] = (BYTE) (__displacement >> 8);
- ptr[2] = (BYTE) (__displacement >> 16);
- ptr[3] = (BYTE) (__displacement >> 24);
- ptr += sizeof(size_t);
-#endif
-
m_Info1.CopyTo( ptr );
ptr += m_Info1.GetByteCount();
m_Info1.Dispose();
m_pAllocator->Free( m_SlotTable );
#endif
-#ifdef VERIFY_GCINFO
- _ASSERTE(ptr - destBuffer == __displacement);
- m_DbgEncoder.Emit(ptr);
-#endif
-
return destBuffer;
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-/*****************************************************************
- *
- * GC Information Decoding API
- *
- * This is an older well-tested implementation
- * now used to verify the real encoding
- * Define VERIFY_GCINFO to enable the verification
- *
- *****************************************************************/
-
-#ifdef VERIFY_GCINFO
-
-#ifndef _DBG_GC_INFO_DECODER_
-#define _DBG_GC_INFO_DECODER_
-
-#include "daccess.h"
-
-#ifndef GCINFODECODER_NO_EE
-
-#include "eetwain.h"
-
-#else // GCINFODECODER_NO_EE
-
-#if !defined(_NTAMD64_)
-#include "clrnt.h"
-#endif
-
-// Misc. VM types:
-
-class Object;
-typedef Object *OBJECTREF;
-typedef SIZE_T TADDR;
-
-// Stuff from gc.h:
-
-#ifndef __GC_H
-
-#define GC_CALL_INTERIOR 0x1
-#define GC_CALL_PINNED 0x2
-
-#endif // !__GC_H
-
-
-// Stuff from check.h:
-
-#ifndef UNREACHABLE
-#define UNREACHABLE() __assume(0)
-#endif
-
-// Stuff from eetwain.h:
-
-#ifndef _EETWAIN_H
-
-typedef void (*GCEnumCallback)(
- LPVOID hCallback, // callback data
- OBJECTREF* pObject, // address of obect-reference we are reporting
- uint32_t flags // is this a pinned and/or interior pointer
-);
-
-
-#if !defined(_TARGET_X86_)
-#define USE_GC_INFO_DECODER
-#endif
-
-#include "regdisp.h"
-
-#endif // !_EETWAIN_H
-
-#endif // GCINFODECODER_NO_EE
-
-#include "gcinfotypes.h"
-
-
-namespace DbgGcInfo {
-
-struct GcSlotDesc
-{
- union
- {
- UINT32 RegisterNumber;
- GcStackSlot Stack;
- } Slot;
- GcSlotFlags Flags;
-};
-
-class BitStreamReader
-{
-public:
- BitStreamReader( const BYTE* pBuffer )
- {
- _ASSERTE( pBuffer != NULL );
- m_pBuffer = (PTR_BYTE)(TADDR)pBuffer;
- m_BitsRead = 0;
- }
-
- //
- // bit 0 is the least significative bit
- // count can be negative so that bits are written in most-significative to least-significative order
- //
- size_t Read( int numBits )
- {
- size_t result = 0;
- int curBitsRead = 0;
-
- while( curBitsRead < numBits )
- {
- int currByte = m_BitsRead /8;
- int currBitInCurrentByte = m_BitsRead % 8;
- int bitsLeftInCurrentByte = 8 - currBitInCurrentByte;
- _ASSERTE( bitsLeftInCurrentByte > 0 );
-
- int bitsToReadInCurrentByte = min( numBits - curBitsRead, bitsLeftInCurrentByte );
-
- size_t data = m_pBuffer[ currByte ];
- data >>= currBitInCurrentByte;
- data &= (1<<bitsToReadInCurrentByte) -1;
-
- data <<= curBitsRead;
- result |= data;
-
- curBitsRead += bitsToReadInCurrentByte;
- m_BitsRead += bitsToReadInCurrentByte;
- }
-
- return result;
- }
-
- // Returns the number of bits read so far
- size_t GetCurrentPos()
- {
- return m_BitsRead;
- }
-
- void SetCurrentPos( size_t pos )
- {
- m_BitsRead = pos;
- }
-
- // Can use negative values
- void Skip( SSIZE_T numBitsToSkip )
- {
- m_BitsRead += numBitsToSkip;
- _ASSERTE( m_BitsRead >= 0 );
- }
-
- //--------------------------------------------------------------------------
- // Decode variable length numbers
- // See the corresponding methods on BitStreamWriter for more information on the format
- //--------------------------------------------------------------------------
-
- inline size_t DecodeVarLengthUnsigned( int base )
- {
- _ASSERTE((base > 0) && (base < (int)sizeof(size_t)*8));
- size_t numEncodings = 1 << base;
- size_t result = 0;
- for(int shift=0; ; shift+=base)
- {
- _ASSERTE(shift+base <= (int)sizeof(size_t)*8);
-
- size_t currentChunk = Read(base+1);
- result |= (currentChunk & (numEncodings-1)) << shift;
- if(!(currentChunk & numEncodings))
- {
- // Extension bit is not set, we're done.
- return result;
- }
- }
- }
-
- inline SSIZE_T DecodeVarLengthSigned( int base )
- {
- _ASSERTE((base > 0) && (base < (int)sizeof(SSIZE_T)*8));
- size_t numEncodings = 1 << base;
- SSIZE_T result = 0;
- for(int shift=0; ; shift+=base)
- {
- _ASSERTE(shift+base <= (int)sizeof(SSIZE_T)*8);
-
- size_t currentChunk = Read(base+1);
- result |= (currentChunk & (numEncodings-1)) << shift;
- if(!(currentChunk & numEncodings))
- {
- // Extension bit is not set, sign-extend and we're done.
- int sbits = sizeof(SSIZE_T)*8 - (shift+base);
- result <<= sbits;
- result >>= sbits; // This provides the sign extension
- return result;
- }
- }
- }
-
-private:
- PTR_BYTE m_pBuffer;
- size_t m_BitsRead;
-};
-
-
-class GcInfoDecoder
-{
-public:
-
- // If you are not insterested in interruptibility or gc lifetime information, pass 0 as instructionOffset
- GcInfoDecoder(
- const BYTE* gcInfoAddr,
- GcInfoDecoderFlags flags,
- UINT32 instructionOffset = 0
- );
-
-
- //------------------------------------------------------------------------
- // Interruptibility
- //------------------------------------------------------------------------
-
- bool IsInterruptible();
-
- // Returns true to stop enumerating.
- typedef bool EnumerateInterruptibleRangesCallback (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback);
-
- void EnumerateInterruptibleRanges (
- EnumerateInterruptibleRangesCallback *pCallback,
- LPVOID hCallback);
-
- //------------------------------------------------------------------------
- // GC lifetime information
- //------------------------------------------------------------------------
-
- bool EnumerateLiveSlots(
- PREGDISPLAY pRD,
- bool reportScratchSlots,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack
- );
-
- void VerifyLiveRegister(
- UINT32 regNum,
- GcSlotFlags flags
- );
-
-
- void VerifyLiveStackSlot(
- int spOffset,
- GcStackSlotBase spBase,
- GcSlotFlags flags
- );
-
- void DoFinalVerification();
-
- //------------------------------------------------------------------------
- // Miscellaneous method information
- //------------------------------------------------------------------------
-
- INT32 GetSecurityObjectStackSlot();
- INT32 GetPSPSymStackSlot();
- INT32 GetGenericsInstContextStackSlot();
- bool GetIsVarArg();
- UINT32 GetCodeLength();
- UINT32 GetStackBaseRegister();
- UINT32 GetSizeOfEditAndContinuePreservedArea();
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- UINT32 GetSizeOfStackParameterArea();
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-private:
- BitStreamReader m_Reader;
- UINT32 m_InstructionOffset;
-
- // Pre-decoded information
- bool m_IsInterruptible;
- bool m_IsVarArg;
- INT32 m_SecurityObjectStackSlot;
- INT32 m_PSPSymStackSlot;
- INT32 m_GenericsInstContextStackSlot;
- UINT32 m_CodeLength;
- UINT32 m_StackBaseRegister;
- UINT32 m_SizeOfEditAndContinuePreservedArea;
- UINT32 m_NumInterruptibleRanges;
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- UINT32 m_SizeOfStackOutgoingAndScratchArea;
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-#ifdef _DEBUG
- GcInfoDecoderFlags m_Flags;
-#endif
-
- GcSlotDesc* m_pLiveRegisters;
- GcSlotDesc* m_pLiveStackSlots;
- int m_NumLiveRegisters;
- int m_NumLiveStackSlots;
-
- CQuickBytes qbSlots1;
- CQuickBytes qbSlots2;
-
- static bool SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback);
-
- OBJECTREF* GetRegisterSlot(
- int regNum,
- PREGDISPLAY pRD
- );
-
- OBJECTREF* GetStackSlot(
- INT32 spOffset,
- GcStackSlotBase spBase,
- PREGDISPLAY pRD
- );
-
- bool IsScratchRegister(int regNum, PREGDISPLAY pRD);
- bool IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD);
-
- void ReportRegisterToGC(
- int regNum,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack
- );
-
- void ReportStackSlotToGC(
- INT32 spOffset,
- GcStackSlotBase spBase,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack
- );
-
-
-};
-
-}
-
-#endif // _DBG_GC_INFO_DECODER_
-#endif // VERIFY_GCINFO
-
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-/*****************************************************************************
- *
- * GC Information Encoding API
- *
- * This is an older well-tested implementation
- * now used to verify the real encoding
- * Define VERIFY_GCINFO to enable the verification
- *
- */
-
-#ifdef VERIFY_GCINFO
-
-#ifndef __DBGGCINFOENCODER_H__
-#define __DBGGCINFOENCODER_H__
-
-#include <windows.h>
-
-#include <wchar.h>
-#include <stdio.h>
-
-#include "corjit.h"
-#include "iallocator.h"
-#include "gcinfoarraylist.h"
-
-#include "stdmacros.h"
-#include "gcinfotypes.h"
-
-
-class IJitAllocator;
-
-
-
-namespace DbgGcInfo {
-
-//-----------------------------------------------------------------------------
-// The following macro controls whether the encoder has to call the IJitAllocator::Free method
-// Don't call IJitAllocator::Free for mscorjit64.dll
-//-----------------------------------------------------------------------------
-//#define MUST_CALL_JITALLOCATOR_FREE
-
-
-class BitStreamWriter
-{
-public:
- BitStreamWriter( IJitAllocator* pAllocator );
- void Write( size_t data, int count );
-
- inline size_t GetBitCount()
- {
- return m_BitCount;
- }
-
- inline size_t GetByteCount()
- {
- return ( m_BitCount + 7 ) / 8;
- }
-
-
- void CopyTo( BYTE* buffer );
- void Dispose();
-
- //--------------------------------------------------------
- // Encode variable length numbers
- // Uses base+1 bits at minimum
- // Bits 0..(base-1) represent the encoded quantity
- // If it doesn't fit, set bit #base to 1 and use base+1 more bits
- //--------------------------------------------------------
- int EncodeVarLengthUnsigned( size_t n, int base )
- {
- _ASSERTE((base > 0) && (base < sizeof(size_t)*8));
- size_t numEncodings = 1 << base;
- int bitsUsed = base+1;
- for( ; ; bitsUsed += base+1)
- {
- if( n < numEncodings )
- {
- Write( n, base+1 ); // This sets the extension bit to zero
- return bitsUsed;
- }
- else
- {
- size_t currentChunk = n & (numEncodings-1);
- Write( currentChunk | numEncodings, base+1 );
- n >>= base;
- }
- }
- return bitsUsed;
- }
-
- //--------------------------------------------------------
- // Signed quantities are encoded the same as unsigned
- // The most relevant difference is that a number is considered
- // to fit in base bits if the topmost bit of a base-long chunk
- // matches the sign of the whole number
- //--------------------------------------------------------
- int EncodeVarLengthSigned( SSIZE_T n, int base )
- {
- _ASSERTE((base > 0) && (base < sizeof(SSIZE_T)*8));
- size_t numEncodings = 1 << base;
- for(int bitsUsed = base+1; ; bitsUsed += base+1)
- {
- size_t currentChunk = ((size_t) n) & (numEncodings-1);
- size_t topmostBit = currentChunk & (numEncodings >> 1);
- n >>= base; // signed arithmetic shift
- if( topmostBit && (n == (SSIZE_T)-1) || !topmostBit && (n == 0))
- {
- // The topmost bit correctly represents the sign
- Write( currentChunk, base+1 ); // This sets the extension bit to zero
- return bitsUsed;
- }
- else
- {
- Write( currentChunk | numEncodings, base+1 );
- }
- }
- }
-
-private:
-
- class MemoryBlockList;
- class MemoryBlock
- {
- friend class MemoryBlockList;
- MemoryBlock* m_next;
-
- public:
- size_t Contents[];
-
- inline MemoryBlock* Next()
- {
- return m_next;
- }
- };
-
- class MemoryBlockList
- {
- MemoryBlock* m_head;
- MemoryBlock* m_tail;
-
- public:
- MemoryBlockList();
-
- inline MemoryBlock* Head()
- {
- return m_head;
- }
-
- MemoryBlock* AppendNew(IAllocator* allocator, size_t bytes);
- void Dispose(IAllocator* allocator);
- };
-
- IJitAllocator* m_pAllocator;
- size_t m_BitCount;
- int m_FreeBitsInCurrentSlot;
- MemoryBlockList m_MemoryBlocks;
- const static int m_MemoryBlockSize = 512; // must be a multiple of the pointer size
- size_t* m_pCurrentSlot; // bits are written through this pointer
- size_t* m_OutOfBlockSlot; // sentinel value to determine when the block is full
-#ifdef _DEBUG
- int m_MemoryBlocksCount;
-#endif
-
-private:
- // Writes bits knowing that they will all fit in the current memory slot
- inline void WriteInCurrentSlot( size_t data, int count )
- {
- data &= SAFE_SHIFT_LEFT(1, count) - 1;
-
- data <<= (sizeof( size_t )*8-m_FreeBitsInCurrentSlot);
-
- *m_pCurrentSlot |= data;
- }
-
- void AllocMemoryBlock();
-
- inline void InitCurrentSlot()
- {
- m_FreeBitsInCurrentSlot = sizeof( size_t )*8;
- *m_pCurrentSlot = 0;
- }
-
-};
-
-struct GcSlotDesc
-{
- union
- {
- UINT32 RegisterNumber;
- GcStackSlot Stack;
- } Slot;
- unsigned IsRegister : 1;
- unsigned IsInterior : 1;
- unsigned IsPinned : 1;
-};
-
-
-
-typedef UINT32 GcSlotId;
-
-
-class GcSlotSet
-{
- friend class GcInfoEncoder;
-public:
- GcSlotSet( GcInfoEncoder * pEncoder );
-
- // Copy constructor
- GcSlotSet( GcSlotSet & other );
-
- inline void Add( GcSlotId slotId );
-
- inline void Remove( GcSlotId slotId );
-
-// Not used
-#if 0
- inline void RemoveAll();
-
- void Add( GcSlotSet & other );
- void Subtract( GcSlotSet & other );
- void Intersect( GcSlotSet & other );
-#endif
-
- // Must be called when done with the object
- inline void Dispose();
-
-private:
- // A bit vector representing the set
- BYTE * m_Data;
-
- int m_NumBytes;
-
- GcInfoEncoder* m_pEncoder;
-};
-
-
-class GcInfoEncoder
-{
-public:
- GcInfoEncoder(
- ICorJitInfo* pCorJitInfo,
- CORINFO_METHOD_INFO* pMethodInfo,
- IJitAllocator* pJitAllocator
- );
-
-
- //------------------------------------------------------------------------
- // Interruptibility
- //------------------------------------------------------------------------
-
- // An instruction at offset x will be interruptible
- // if-and-only-if startInstructionOffset <= x < startInstructionOffset+length
- void DefineInterruptibleRange( UINT32 startInstructionOffset, UINT32 length );
-
-
- //------------------------------------------------------------------------
- // Slot information
- //------------------------------------------------------------------------
-
- //
- // spOffset are always relative to the SP of the caller (same as SP at the method entry and exit)
- // Negative offsets describe GC refs in the local and outgoing areas.
- // Positive offsets describe GC refs in the scratch area
- // Note that if the dynamic allocation area is resized, the outgoing area will not be valid anymore
- // Old slots must be declared dead and new ones can be defined.
- // It's up to the JIT to do the right thing. We don't enforce this.
- //
-
- GcSlotId GetRegisterSlotId( UINT32 regNum, GcSlotFlags flags );
- GcSlotId GetStackSlotId( INT32 spOffset, GcSlotFlags flags, GcStackSlotBase spBase = GC_CALLER_SP_REL );
-
- //
- // After a FinalizeSlotIds is called, no more slot definitions can be made.
- // FinalizeSlotIds must be called once and only once before calling DefineGcStateAtCallSite
- // If no call sites are described, calling FinalizeSlotIds can and should (for performance reasons) be avoided
- //
- void FinalizeSlotIds();
-
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
- //------------------------------------------------------------------------
- // Partially-interruptible information
- //------------------------------------------------------------------------
-
-
- void DefineGcStateAtSafePoint(
- UINT32 instructionOffset,
- GcSlotSet &liveSlots
- );
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
- //------------------------------------------------------------------------
- // Fully-interruptible information
- //------------------------------------------------------------------------
-
- //
- // For inputs, pass zero as offset
- //
-
- // This method defines what the GC state of a slot is when a thread's suspension IP
- // is equal to instructionOffset
-
- void SetSlotState( UINT32 instructionOffset,
- GcSlotId slotId,
- GcSlotState slotState
- );
-
-
-
- //------------------------------------------------------------------------
- // Miscellaneous method information
- //------------------------------------------------------------------------
-
- void SetSecurityObjectStackSlot( INT32 spOffset );
- void SetPSPSymStackSlot( INT32 spOffsetPSPSym );
- void SetGenericsInstContextStackSlot( INT32 spOffsetGenericsContext );
- void SetIsVarArg();
- void SetCodeLength( UINT32 length );
-
- // Optional in the general case. Required if the method uses GC_FRAMEREG_REL stack slots
- void SetStackBaseRegister( UINT32 registerNumber );
- void SetSizeOfEditAndContinuePreservedArea( UINT32 size );
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- void SetSizeOfStackOutgoingAndScratchArea( UINT32 size );
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-
- //------------------------------------------------------------------------
- // Encoding
- //------------------------------------------------------------------------
-
- //
- // Build() encodes GC information into temporary buffers.
- // The method description cannot change after Build is called
- //
- void Build();
-
- //
- // Write encoded information to its final destination and frees temporary buffers.
- // The encoder shouldn't be used anymore after calling this method.
- // It returns a pointer to the destination buffer, which address is byte-aligned
- //
- size_t GetByteCount();
- BYTE* Emit(BYTE* dest);
-
-private:
-
- friend class LifetimeTransitionsQuickSort;
- friend class LifetimeTransitionsQuickSortByOffset;
-
- struct LifetimeTransition
- {
- UINT32 CodeOffset;
- GcSlotDesc SlotDesc;
- bool BecomesLive;
- };
-
- ICorJitInfo* m_pCorJitInfo;
- CORINFO_METHOD_INFO* m_pMethodInfo;
- IJitAllocator* m_pAllocator;
-
-#ifdef _DEBUG
- char *m_MethodName, *m_ModuleName;
-#endif
-
- BitStreamWriter m_HeaderInfoWriter;
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- BitStreamWriter m_PartiallyInterruptibleInfoWriter;
-#endif
-#endif
- BitStreamWriter m_FullyInterruptibleInfoWriter;
-
- GcInfoArrayList<LifetimeTransition, 64> m_LifetimeTransitions;
- LifetimeTransition *m_rgSortedTransitions;
-
- bool m_IsVarArg;
- INT32 m_SecurityObjectStackSlot;
- INT32 m_PSPSymStackSlot;
- INT32 m_GenericsInstContextStackSlot;
- UINT32 m_CodeLength;
- UINT32 m_StackBaseRegister;
- UINT32 m_SizeOfEditAndContinuePreservedArea;
- UINT32 m_LastInterruptibleRangeStopOffset;
- UINT32 m_NumInterruptibleRanges;
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- UINT32 m_SizeOfStackOutgoingAndScratchArea;
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
- void * eeAllocGCInfo (size_t blockSize);
-
- inline int EncodeFullyInterruptibleSlotFlags(GcSlotDesc slotDesc)
- {
- int flagEnc = 1;
- if( slotDesc.IsInterior )
- flagEnc |= 0x2;
- if( slotDesc.IsPinned )
- flagEnc |= 0x4;
- if(flagEnc == 1)
- {
- m_FullyInterruptibleInfoWriter.Write(0, 1);
- return 1;
- }
- else
- {
- m_FullyInterruptibleInfoWriter.Write(flagEnc, 3);
- return 3;
- }
- }
-
-
-private:
-
- friend class GcSlotSet;
- friend class EncoderCheckState;
-
- static const UINT32 m_MappingTableInitialSize = 32;
- UINT32 m_MappingTableSize;
- UINT32 m_NumSlotMappings;
- GcSlotDesc *m_SlotMappings;
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- UINT32 m_NumSafePointsWithGcState;
-#endif
-#endif
-
- void GrowMappingTable();
-
-#ifdef _DEBUG
- bool m_IsMappingTableFrozen;
-#endif
-};
-
-
-
-// Not used
-#if 0
-
-void GcSlotSet::RemoveAll()
-{
- ZeroMemory( m_Data, m_NumBytes );
-}
-
-#endif
-
-
-void GcSlotSet::Dispose()
-{
-#ifdef MUST_CALL_JITALLOCATOR_FREE
- m_pEncoder->m_pAllocator->Free( m_Data );
-#endif
-}
-
-
-}
-
-#endif // !__DBGGCINFOENCODER_H__
-
-#endif // VERIFY_GCINFO
-
DECODE_EDIT_AND_CONTINUE = 0x800,
};
-#ifdef VERIFY_GCINFO
-#include "dbggcinfodecoder.h"
-#endif
-
enum GcInfoHeaderFlags
{
GC_INFO_IS_VARARG = 0x1,
UINT32 m_Version;
#endif
-#ifdef VERIFY_GCINFO
- DbgGcInfo::GcInfoDecoder m_DbgDecoder;
-#endif
-
static bool SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback);
OBJECTREF* GetRegisterSlot(
UINT32 regNum = pSlot->Slot.RegisterNumber;
if( reportScratchSlots || !IsScratchRegister( regNum, pRD ) )
{
-#ifdef VERIFY_GCINFO
- m_DbgDecoder.VerifyLiveRegister(
- regNum,
- pSlot->Flags
- );
-#endif
-
ReportRegisterToGC(
regNum,
pSlot->Flags,
GcStackSlotBase spBase = pSlot->Slot.Stack.Base;
if( reportScratchSlots || !IsScratchStackSlot(spOffset, spBase, pRD) )
{
-#ifdef VERIFY_GCINFO
- m_DbgDecoder.VerifyLiveStackSlot(
- spOffset,
- spBase,
- pSlot->Flags
- );
-#endif
-
ReportStackSlotToGC(
spOffset,
spBase,
#include "gcinfotypes.h"
-#ifdef VERIFY_GCINFO
-#include "dbggcinfoencoder.h"
-#endif //VERIFY_GCINFO
-
#ifdef MEASURE_GCINFO
struct GcInfoSize
{
bool m_IsSlotTableFrozen;
#endif
-#ifdef VERIFY_GCINFO
- DbgGcInfo::GcInfoEncoder m_DbgEncoder;
-#endif
-
#ifdef MEASURE_GCINFO
GcInfoSize m_CurrentMethodSize;
#endif
coverage.cpp
customattribute.cpp
custommarshalerinfo.cpp
- dbggcinfodecoder.cpp
dllimportcallback.cpp
eeconfig.cpp
eecontract.cpp
set(VM_SOURCES_DAC_ARCH
gcinfodecoder.cpp
- dbggcinfodecoder.cpp
exceptionhandling.cpp
)
../vars.cpp
../versionresilienthashcode.cpp
../zapsig.cpp
- ../dbggcinfodecoder.cpp
../gcinfodecoder.cpp
../sha1.cpp
../crossgencompile.cpp
<!-- SOURCES_NONPAL -->
<ItemGroup>
- <CppCompile Include="$(VmSourcesDir)\DbgGcInfoDecoder.cpp" />
<CppCompile Include="$(VmSourcesDir)\GcInfoDecoder.cpp" />
<CppCompile Include="$(VmSourcesDir)\Crypto\SHA1.cpp" Condition="'$(FeatureCoreclr)' != 'true'"/>
<CppCompile Include="$(VmSourcesDir)\SHA1.cpp" Condition="'$(FeatureCoreclr)' == 'true'"/>
<ItemGroup Condition="'$(TargetArch)' == 'amd64'" >
<CppCompile Include="$(ClrSrcDirectory)\vm\GcInfoDecoder.cpp" />
- <CppCompile Include="$(ClrSrcDirectory)\vm\DbgGcInfoDecoder.cpp" />
<CppCompile Include="$(ClrSrcDirectory)\vm\amd64\cGenAMD64.cpp" />
<CppCompile Include="$(ClrSrcDirectory)\vm\amd64\ExcepAMD64.cpp" />
<CppCompile Include="$(ClrSrcDirectory)\vm\amd64\gmsAMD64.cpp" />
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-
-
-
-#include "common.h"
-#include "gcinfodecoder.h"
-
-#ifdef VERIFY_GCINFO
-#ifdef USE_GC_INFO_DECODER
-
-#include "dbggcinfodecoder.h"
-
-#ifndef GCINFODECODER_CONTRACT
-#define GCINFODECODER_CONTRACT(contract) contract
-#endif // !GCINFODECODER_CONTRACT
-
-#ifndef GET_CALLER_SP
-#define GET_CALLER_SP(pREGDISPLAY) EECodeManager::GetCallerSp(pREGDISPLAY)
-#endif // !GET_CALLER_SP
-
-#ifndef VALIDATE_OBJECTREF
-#ifdef DACCESS_COMPILE
-#define VALIDATE_OBJECTREF(objref, fDeep)
-#else // DACCESS_COMPILE
-#define VALIDATE_OBJECTREF(objref, fDeep) OBJECTREFToObject(objref)->Validate(fDeep)
-#endif // DACCESS_COMPILE
-#endif // !VALIDATE_OBJECTREF
-
-#ifndef VALIDATE_ROOT
-#define VALIDATE_ROOT(isInterior, hCallBack, pObjRef) \
- do { \
- /* Only call Object::Validate() with bDeep == TRUE if we are in the promote phase. */ \
- /* We should call Validate() with bDeep == FALSE if we are in the relocation phase. */ \
- \
- GCCONTEXT* pGCCtx = (GCCONTEXT*)(hCallBack); \
- \
- if (!(isInterior) && !(m_Flags & DECODE_NO_VALIDATION)) \
- VALIDATE_OBJECTREF(*(pObjRef), pGCCtx->sc->promotion == TRUE); \
- } while (0)
-#endif // !VALIDATE_ROOT
-
-
-
-namespace DbgGcInfo {
-
-
-//static
-bool GcInfoDecoder::SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback)
-{
- GcInfoDecoder *pThis = (GcInfoDecoder*)hCallback;
-
- bool fStop = pThis->m_InstructionOffset >= startOffset && pThis->m_InstructionOffset < stopOffset;
-
- if (fStop)
- pThis->m_IsInterruptible = true;
-
- return fStop;
-}
-
-
-GcInfoDecoder::GcInfoDecoder(
- const BYTE* gcInfoAddr,
- GcInfoDecoderFlags flags,
- UINT32 breakOffset
- )
- : m_Reader( gcInfoAddr )
- , m_InstructionOffset( breakOffset )
- , m_IsInterruptible( false )
- , m_pLiveRegisters( NULL )
- , m_pLiveStackSlots( NULL )
- , m_NumLiveRegisters(0)
- , m_NumLiveStackSlots(0)
-#ifdef _DEBUG
- , m_Flags( flags )
-#endif
-{
-#ifdef _TARGET_ARM_
- _ASSERTE(!"JIT32 is not generating GCInfo in the correct format yet!");
-#endif
-
- _ASSERTE( (flags & (DECODE_INTERRUPTIBILITY | DECODE_GC_LIFETIMES)) || (0 == breakOffset) );
-
- // The current implementation doesn't support the two flags together
- _ASSERTE(
- ((flags & (DECODE_INTERRUPTIBILITY | DECODE_GC_LIFETIMES)) != (DECODE_INTERRUPTIBILITY | DECODE_GC_LIFETIMES))
- );
-
-
- //--------------------------------------------
- // Pre-decode information
- //--------------------------------------------
-
- m_IsVarArg = (m_Reader.Read(1)) ? true : false;
-
- size_t hasSecurityObject = m_Reader.Read(1);
- if(hasSecurityObject)
- m_SecurityObjectStackSlot = (INT32) DENORMALIZE_STACK_SLOT(m_Reader.DecodeVarLengthSigned(SECURITY_OBJECT_STACK_SLOT_ENCBASE));
- else
- m_SecurityObjectStackSlot = NO_SECURITY_OBJECT;
-
- size_t hasPSPSym = m_Reader.Read(1);
- if(hasPSPSym)
- {
- m_PSPSymStackSlot = (INT32) DENORMALIZE_STACK_SLOT(m_Reader.DecodeVarLengthSigned(PSP_SYM_STACK_SLOT_ENCBASE));
- }
- else
- {
- m_PSPSymStackSlot = NO_PSP_SYM;
- }
-
- size_t hasGenericsInstContext = m_Reader.Read(1);
- if(hasGenericsInstContext)
- {
- m_GenericsInstContextStackSlot = (INT32) DENORMALIZE_STACK_SLOT(m_Reader.DecodeVarLengthSigned(GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE));
- }
- else
- {
- m_GenericsInstContextStackSlot = NO_GENERICS_INST_CONTEXT;
- }
-
- m_CodeLength = (UINT32) DENORMALIZE_CODE_LENGTH(m_Reader.DecodeVarLengthUnsigned(CODE_LENGTH_ENCBASE));
-
- size_t hasStackBaseRegister = m_Reader.Read(1);
- if(hasStackBaseRegister)
- m_StackBaseRegister = (UINT32) DENORMALIZE_STACK_BASE_REGISTER(m_Reader.DecodeVarLengthUnsigned(STACK_BASE_REGISTER_ENCBASE));
- else
- m_StackBaseRegister = NO_STACK_BASE_REGISTER;
-
- size_t hasSizeOfEditAndContinuePreservedArea = m_Reader.Read(1);
- if(hasSizeOfEditAndContinuePreservedArea)
- m_SizeOfEditAndContinuePreservedArea = (UINT32) m_Reader.DecodeVarLengthUnsigned(SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE);
- else
- m_SizeOfEditAndContinuePreservedArea = NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA;
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- m_SizeOfStackOutgoingAndScratchArea = (UINT32)DENORMALIZE_SIZE_OF_STACK_AREA(m_Reader.DecodeVarLengthUnsigned(SIZE_OF_STACK_AREA_ENCBASE));
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
- m_NumInterruptibleRanges = (UINT32) DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(m_Reader.DecodeVarLengthUnsigned(NUM_INTERRUPTIBLE_RANGES_ENCBASE));
-
- if( flags & DECODE_INTERRUPTIBILITY )
- {
- EnumerateInterruptibleRanges(&SetIsInterruptibleCB, this);
- }
-}
-
-
-bool GcInfoDecoder::IsInterruptible()
-{
- _ASSERTE( m_Flags & DECODE_INTERRUPTIBILITY );
- return m_IsInterruptible;
-}
-
-
-void GcInfoDecoder::EnumerateInterruptibleRanges (
- EnumerateInterruptibleRangesCallback *pCallback,
- LPVOID hCallback)
-{
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
- //------------------------------------------------------------------------------
- // Try partially interruptible first
- //------------------------------------------------------------------------------
-
- UINT32 numCallSites = (UINT32)m_Reader.Read( sizeof( numCallSites ) * 8 );
- UINT32 callSiteIdx = 0;
-
- if( numCallSites > 0 )
- {
- UINT32 numSlotMappings = (UINT32)m_Reader.Read( sizeof( numSlotMappings ) * 8 );
-
- // Align the reader to the next byte to continue decoding
- m_Reader.Skip( ( 8 - ( m_Reader.GetCurrentPos() % 8 ) ) % 8 );
-
- for( callSiteIdx=0; callSiteIdx<numCallSites; callSiteIdx++ )
- {
- UINT32 instructionOffset = (UINT32)m_Reader.Read( 32 );
-
- bool fStop = pCallback(instructionOffset, instructionOffset+1, hCallback);
- if (fStop)
- return;
-
- m_Reader.Skip( numSlotMappings );
- }
-
- // Call site not found. Skip the slot mapping table in preparation for reading the fully-interruptible information
- m_Reader.Skip( numSlotMappings * sizeof( GcSlotDesc ) * 8 );
- }
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
-
- // If no info is found for the call site, we default to fully-interruptbile
- LOG((LF_GCROOTS, LL_INFO1000000, "No GC info found for call site at offset %x. Defaulting to fully-interruptible information.\n", (int) m_InstructionOffset));
-
- // Align the reader to the next byte to continue decoding
- m_Reader.Skip( ( 8 - ( m_Reader.GetCurrentPos() % 8 ) ) % 8 );
-
- UINT32 lastInterruptibleRangeStopOffsetNormalized = 0;
-
- for(UINT32 i=0; i<m_NumInterruptibleRanges; i++)
- {
- UINT32 normStartDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA_ENCBASE );
- UINT32 normStopDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA_ENCBASE ) + 1;
-
- UINT32 rangeStartOffsetNormalized = lastInterruptibleRangeStopOffsetNormalized + normStartDelta;
- UINT32 rangeStopOffsetNormalized = rangeStartOffsetNormalized + normStopDelta;
-
- UINT32 rangeStartOffset = DENORMALIZE_CODE_OFFSET(rangeStartOffsetNormalized);
- UINT32 rangeStopOffset = DENORMALIZE_CODE_OFFSET(rangeStopOffsetNormalized);
-
- bool fStop = pCallback(rangeStartOffset, rangeStopOffset, hCallback);
- if (fStop)
- return;
-
- lastInterruptibleRangeStopOffsetNormalized = rangeStopOffsetNormalized;
- }
-}
-
-
-INT32 GcInfoDecoder::GetSecurityObjectStackSlot()
-{
- _ASSERTE( m_Flags & DECODE_SECURITY_OBJECT );
- return m_SecurityObjectStackSlot;
-}
-
-INT32 GcInfoDecoder::GetGenericsInstContextStackSlot()
-{
- _ASSERTE( m_Flags & DECODE_GENERICS_INST_CONTEXT );
- return m_GenericsInstContextStackSlot;
-}
-
-INT32 GcInfoDecoder::GetPSPSymStackSlot()
-{
- _ASSERTE( m_Flags & DECODE_PSP_SYM);
- return m_PSPSymStackSlot;
-}
-
-bool GcInfoDecoder::GetIsVarArg()
-{
- _ASSERTE( m_Flags & DECODE_VARARG );
- return m_IsVarArg;
-}
-
-UINT32 GcInfoDecoder::GetCodeLength()
-{
- _ASSERTE( m_Flags & DECODE_CODE_LENGTH );
- return m_CodeLength;
-}
-
-UINT32 GcInfoDecoder::GetStackBaseRegister()
-{
- return m_StackBaseRegister;
-}
-
-UINT32 GcInfoDecoder::GetSizeOfEditAndContinuePreservedArea()
-{
- _ASSERTE( m_Flags & DECODE_EDIT_AND_CONTINUE );
- return m_SizeOfEditAndContinuePreservedArea;
-}
-
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-UINT32 GcInfoDecoder::GetSizeOfStackParameterArea()
-{
- return m_SizeOfStackOutgoingAndScratchArea;
-}
-
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-
-bool GcInfoDecoder::EnumerateLiveSlots(
- PREGDISPLAY pRD,
- bool reportScratchSlots,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack
- )
-{
- _ASSERTE( m_Flags & DECODE_GC_LIFETIMES );
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
- //------------------------------------------------------------------------------
- // Try partially interruptible first
- //------------------------------------------------------------------------------
-
- UINT32 numCallSites = (UINT32)m_Reader.Read( sizeof( numCallSites ) * 8 );
- UINT32 callSiteIdx = 0;
-
- if( numCallSites > 0 )
- {
- UINT32 numSlotMappings = (UINT32)m_Reader.Read( sizeof( numSlotMappings ) * 8 );
-
- // Align the reader to the next byte to continue decoding
- m_Reader.Skip( ( 8 - ( m_Reader.GetCurrentPos() % 8 ) ) % 8 );
-
- for( callSiteIdx=0; callSiteIdx<numCallSites; callSiteIdx++ )
- {
- UINT32 instructionOffset = (UINT32)m_Reader.Read( 32 );
- if( instructionOffset == m_InstructionOffset )
- {
- m_IsInterruptible = true;
-
- BYTE* callSiteLiveSet = (BYTE*) _alloca( ( numSlotMappings + 7 ) / 8 );
-
- UINT32 i;
- for( i=0; i<numSlotMappings/8; i++ )
- callSiteLiveSet[ i ] = (BYTE)m_Reader.Read( 8 );
-
- callSiteLiveSet[ i ] = (BYTE)m_Reader.Read( numSlotMappings % 8 );
-
- m_Reader.Skip( ( numCallSites - callSiteIdx - 1 ) * ( 32 + numSlotMappings ) );
-
- //---------------------------------------------------------------------------
- // Read slot mappings
- //---------------------------------------------------------------------------
-
- GcSlotDesc* slotMappings = (GcSlotDesc*) _alloca( numSlotMappings * sizeof( GcSlotDesc ) );
- // Assert that we can read a GcSlotDesc with a single call to m_Reader.Read()
- _ASSERTE( sizeof( GcSlotDesc ) <= sizeof ( size_t ) );
- for( UINT32 i=0; i<numSlotMappings; i++ )
- {
- size_t data = m_Reader.Read( sizeof( GcSlotDesc ) * 8 );
- slotMappings[ i ] = *( (GcSlotDesc*) &data );
- }
-
- //---------------------------------------------------------------------------
- // Report live slots
- //---------------------------------------------------------------------------
-
- for( UINT32 i=0; i<numSlotMappings; i++ )
- {
- BYTE isLive = callSiteLiveSet[ i / 8 ] & ( 1 << ( i % 8 ) );
- if( isLive )
- {
- GcSlotDesc slotDesc = slotMappings[ i ];
- if( slotDesc.IsRegister )
- {
- if( reportScratchSlots || !IsScratchRegister( slotDesc.Slot.RegisterNumber, pRD ) )
- {
- ReportRegisterToGC(
- slotDesc.Slot.RegisterNumber,
- slotDesc.IsInterior,
- slotDesc.IsPinned,
- pRD,
- flags,
- pCallBack,
- hCallBack
- );
- }
- else
- {
- LOG((LF_GCROOTS, LL_INFO1000, "\"Live\" scratch register " FMT_REG " not reported\n", slotDesc.Slot.RegisterNumber));
- }
- }
- else
- {
- GcStackSlotBase spBase = (GcStackSlotBase) (slotDesc.Slot.SpOffset & 0x3);
- INT32 realSpOffset = slotDesc.Slot.SpOffset ^ (int) spBase;
-
- if( reportScratchSlots || !IsScratchStackSlot(realSpOffset, spBase, pRD) )
- {
- ReportStackSlotToGC(
- realSpOffset,
- spBase,
- slotDesc.IsInterior,
- slotDesc.IsPinned,
- pRD,
- flags,
- pCallBack,
- hCallBack
- );
- }
- else
- {
- LOG((LF_GCROOTS, LL_INFO1000, "\"Live\" scratch stack slot " FMT_STK " not reported\n", DBG_STK(realSpOffset)));
- }
- }
- }
- }
-
- return true;
- }
-
- m_Reader.Skip( numSlotMappings );
- }
-
- // Call site not found. Skip the slot mapping table in preparation for reading the fully-interruptible information
- m_Reader.Skip( numSlotMappings * sizeof( GcSlotDesc ) * 8 );
- }
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
-
- // If no info is found for the call site, we default to fully-interruptbile
- LOG((LF_GCROOTS, LL_INFO1000000, "No GC info found for call site at offset %x. Defaulting to fully-interruptible information.\n", (int) m_InstructionOffset));
-
- // Align the reader to the next byte to continue decoding
- m_Reader.Skip( ( 8 - ( m_Reader.GetCurrentPos() % 8 ) ) % 8 );
-
- // Skip interruptibility information
- for(UINT32 i=0; i<m_NumInterruptibleRanges; i++)
- {
- m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA_ENCBASE );
- m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA_ENCBASE );
- }
-
- //
- // If this is a non-leaf frame and we are executing a call, the unwinder has given us the PC
- // of the call instruction. We should adjust it to the PC of the instruction after the call in order to
- // obtain transition information for scratch slots. However, we always assume scratch slots to be
- // dead for non-leaf frames (except for ResumableFrames), so we don't need to adjust the PC.
- // If this is a non-leaf frame and we are not executing a call (i.e.: a fault occurred in the function),
- // then it would be incorrect to ajust the PC
- //
-
- int lifetimeTransitionsCount = 0;
-
- //--------------------------------------------------------------------
- // Decode registers
- //--------------------------------------------------------------------
-
- size_t numRegisters = m_Reader.DecodeVarLengthUnsigned(NUM_REGISTERS_ENCBASE);
-
- {
-#ifdef ENABLE_CONTRACTS_IMPL
- CONTRACT_VIOLATION(FaultViolation | FaultNotFatal);
-#endif
- m_pLiveRegisters = (GcSlotDesc*) qbSlots1.AllocNoThrow(sizeof(GcSlotDesc)*numRegisters);
- }
- if (m_pLiveRegisters == NULL)
- {
- return false;
- }
-
-
- _ASSERTE(m_pLiveRegisters);
-
- int lastNormRegNum = 0;
-
- for(int i=0; i<numRegisters; i++)
- {
- if( i==0 )
- {
- lastNormRegNum = (int) m_Reader.DecodeVarLengthUnsigned(REGISTER_ENCBASE);
- }
- else
- {
- int normRegDelta = (int) m_Reader.DecodeVarLengthUnsigned(REGISTER_DELTA_ENCBASE) + 1;
- lastNormRegNum += normRegDelta;
- }
- int regNum = DENORMALIZE_REGISTER(lastNormRegNum);
-
- BOOL isInterior = FALSE;
- BOOL isPinned = FALSE;
- BOOL isLive = FALSE;
-
- size_t normCodeOffset = (size_t)(SSIZE_T)(-1);
- BOOL becomesLive = TRUE;
- for(;;)
- {
- size_t normCodeOffsetDelta = m_Reader.DecodeVarLengthUnsigned(NORM_CODE_OFFSET_DELTA_ENCBASE);
- if(normCodeOffsetDelta == 0) // terminator
- break;
-
- if(normCodeOffset != (size_t)(SSIZE_T)(-1))
- becomesLive = (BOOL) m_Reader.Read(1);
-
- normCodeOffset += normCodeOffsetDelta;
-
- UINT32 instructionOffset = DENORMALIZE_CODE_OFFSET((UINT32)normCodeOffset);
-
- BOOL becomesInterior = FALSE;
- BOOL becomesPinned = FALSE;
-
- if(becomesLive)
- {
- if(m_Reader.Read(1))
- {
- size_t flagEnc = m_Reader.Read( 2 );
- becomesInterior = (BOOL)(flagEnc & 0x1);
- becomesPinned = (BOOL)(flagEnc & 0x2);
- }
- }
-
- lifetimeTransitionsCount++;
-
- LOG((LF_GCROOTS, LL_INFO1000000,
- "Transition " FMT_PIPTR "in " FMT_REG "going %s at offset %04x.\n",
- DBG_PIN_NAME(becomesPinned), DBG_IPTR_NAME(becomesInterior), regNum,
- becomesLive ? "live" : "dead",
- (int) instructionOffset ));
-
- if( instructionOffset > m_InstructionOffset )
- continue;
-
- isLive = becomesLive;
- isInterior = becomesInterior;
- isPinned = becomesPinned;
- }
-
- if( isLive )
- {
- if( reportScratchSlots || !IsScratchRegister( regNum, pRD ) )
- {
- m_pLiveRegisters[m_NumLiveRegisters].Slot.RegisterNumber = regNum;
- GcSlotFlags flags = GC_SLOT_BASE;
- if(isInterior)
- flags = (GcSlotFlags) (flags | GC_SLOT_INTERIOR);
- if(isPinned)
- flags = (GcSlotFlags) (flags | GC_SLOT_PINNED);
-
- m_pLiveRegisters[m_NumLiveRegisters].Flags = flags;
- m_NumLiveRegisters++;
- }
- else
- {
- LOG((LF_GCROOTS, LL_INFO1000, "\"Live\" scratch register " FMT_REG " not reported\n", regNum));
- }
- }
- }
-
- //--------------------------------------------------------------------
- // Decode stack slots
- //--------------------------------------------------------------------
-
- size_t numStackSlots = m_Reader.DecodeVarLengthUnsigned(NUM_STACK_SLOTS_ENCBASE);
- {
-#ifdef ENABLE_CONTRACTS_IMPL
- CONTRACT_VIOLATION(FaultViolation | FaultNotFatal);
-#endif
- m_pLiveStackSlots = (GcSlotDesc*) qbSlots2.AllocNoThrow(sizeof(GcSlotDesc)*numStackSlots);
- }
- if (m_pLiveStackSlots == NULL)
- {
- return false;
- }
- _ASSERTE(m_pLiveStackSlots);
-
- INT32 lastNormStackSlot = 0;
-
- for(int i=0; i<numStackSlots; i++)
- {
- if( i==0 )
- {
- lastNormStackSlot = (INT32) m_Reader.DecodeVarLengthSigned(STACK_SLOT_ENCBASE);
- }
- else
- {
- INT32 normStackSlotDelta = (INT32) m_Reader.DecodeVarLengthUnsigned(STACK_SLOT_DELTA_ENCBASE);
- lastNormStackSlot += normStackSlotDelta;
- }
- INT32 spOffset = DENORMALIZE_STACK_SLOT(lastNormStackSlot);
- GcStackSlotBase spBase = (GcStackSlotBase) m_Reader.Read(2);
-
- BOOL isInterior = FALSE;
- BOOL isPinned = FALSE;
- BOOL isLive = FALSE;
-
- size_t normCodeOffset = (size_t)(SSIZE_T)(-1);
- BOOL becomesLive = TRUE;
- for(;;)
- {
- size_t normCodeOffsetDelta = m_Reader.DecodeVarLengthUnsigned(NORM_CODE_OFFSET_DELTA_ENCBASE);
- if(normCodeOffsetDelta == 0) // terminator
- break;
-
- if(normCodeOffset != (size_t)(SSIZE_T)(-1))
- becomesLive = (BOOL) m_Reader.Read(1);
-
- normCodeOffset += normCodeOffsetDelta;
-
- UINT32 instructionOffset = DENORMALIZE_CODE_OFFSET((UINT32)normCodeOffset);
-
- BOOL becomesInterior = FALSE;
- BOOL becomesPinned = FALSE;
-
- if(becomesLive)
- {
- if(m_Reader.Read(1))
- {
- size_t flagEnc = m_Reader.Read( 2 );
- becomesInterior = (BOOL)(flagEnc & 0x1);
- becomesPinned = (BOOL)(flagEnc & 0x2);
- }
- }
-
- lifetimeTransitionsCount++;
-
- LOG((LF_GCROOTS, LL_INFO1000000,
- "Transition " FMT_PIPTR "in " FMT_STK "going %s at offset %04x.\n",
- DBG_PIN_NAME(becomesPinned), DBG_IPTR_NAME(becomesInterior), DBG_STK(spOffset),
- becomesLive ? "live" : "dead",
- (int) instructionOffset ));
-
- if( instructionOffset > m_InstructionOffset )
- continue;
-
- isLive = becomesLive;
- isInterior = becomesInterior;
- isPinned = becomesPinned;
- }
-
- if( isLive )
- {
- if( reportScratchSlots || !IsScratchStackSlot(spOffset, spBase, pRD) )
- {
- m_pLiveStackSlots[m_NumLiveStackSlots].Slot.Stack.SpOffset = spOffset;
- m_pLiveStackSlots[m_NumLiveStackSlots].Slot.Stack.Base = spBase;
- GcSlotFlags flags = GC_SLOT_BASE;
- if(isInterior)
- flags = (GcSlotFlags) (flags | GC_SLOT_INTERIOR);
- if(isPinned)
- flags = (GcSlotFlags) (flags | GC_SLOT_PINNED);
-
- m_pLiveStackSlots[m_NumLiveStackSlots].Flags = flags;
- m_NumLiveStackSlots++;
- }
- else
- {
- LOG((LF_GCROOTS, LL_INFO1000, "\"Live\" scratch stack slot " FMT_STK " not reported\n", DBG_STK(spOffset)));
- }
- }
- }
-
-
- LOG((LF_GCROOTS, LL_INFO1000000, "Decoded %d lifetime transitions.\n", (int) lifetimeTransitionsCount ));
-
- return true;
-}
-
-void GcInfoDecoder::VerifyLiveRegister(
- UINT32 regNum,
- GcSlotFlags flags
- )
-{
- _ASSERTE(m_pLiveRegisters);
-
- // If this assert fails, the slot being passed was not found to be live in this decoder
- _ASSERTE(m_NumLiveRegisters > 0);
-
- int pos;
- for(pos = 0; pos < m_NumLiveRegisters; pos++)
- {
- if(regNum == m_pLiveRegisters[pos].Slot.RegisterNumber &&
- flags == m_pLiveRegisters[pos].Flags)
- {
- break;
- }
- }
-
- // If this assert fails, the slot being passed was not found to be live in this decoder
- _ASSERTE(pos < m_NumLiveRegisters);
-
- m_pLiveRegisters[pos] = m_pLiveRegisters[--m_NumLiveRegisters];
-}
-
-void GcInfoDecoder::VerifyLiveStackSlot(
- INT32 spOffset,
- GcStackSlotBase spBase,
- GcSlotFlags flags
- )
-{
- _ASSERTE(m_pLiveStackSlots);
-
- // If this assert fails, the slot being passed was not found to be live in this decoder
- _ASSERTE(m_NumLiveStackSlots > 0);
-
- int pos;
- for(pos = 0; pos < m_NumLiveStackSlots; pos++)
- {
- if(spOffset == m_pLiveStackSlots[pos].Slot.Stack.SpOffset &&
- spBase == m_pLiveStackSlots[pos].Slot.Stack.Base &&
- flags == m_pLiveStackSlots[pos].Flags)
- {
- break;
- }
- }
-
- // If this assert fails, the slot being passed was not found to be live in this decoder
- _ASSERTE(pos < m_NumLiveStackSlots);
-
- m_pLiveStackSlots[pos] = m_pLiveStackSlots[--m_NumLiveStackSlots];
-}
-
-void GcInfoDecoder::DoFinalVerification()
-{
- // If this assert fails, the m_NumLiveRegisters slots remaining in m_pLiveRegisters
- // were not reported by the calling decoder
- _ASSERTE(m_NumLiveRegisters == 0);
-
- // If this assert fails, the m_NumLiveStackSlots slots remaining in m_pLiveStackSlots
- // were not reported by the calling decoder
- _ASSERTE(m_NumLiveStackSlots == 0);
-
-}
-
-//-----------------------------------------------------------------------------
-// Platform-specific methods
-//-----------------------------------------------------------------------------
-
-#if defined(_TARGET_AMD64_)
-
-
-OBJECTREF* GcInfoDecoder::GetRegisterSlot(
- int regNum,
- PREGDISPLAY pRD
- )
-{
- _ASSERTE(regNum >= 0 && regNum <= 16);
- _ASSERTE(regNum != 4); // rsp
-
- // The fields of KNONVOLATILE_CONTEXT_POINTERS are in the same order as
- // the processor encoding numbers.
-
- ULONGLONG **ppRax;
-#ifdef _NTAMD64_
- ppRax = &pRD->pCurrentContextPointers->Rax;
-#else
- ppRax = &pRD->pCurrentContextPointers->Integer.Register.Rax;
-#endif
-
- return (OBJECTREF*)*(ppRax + regNum);
-}
-
-
-bool GcInfoDecoder::IsScratchRegister(int regNum, PREGDISPLAY pRD)
-{
- _ASSERTE(regNum >= 0 && regNum <= 16);
- _ASSERTE(regNum != 4); // rsp
-
- UINT16 PreservedRegMask =
- (1 << 3) // rbx
- | (1 << 5) // rbp
- | (1 << 6) // rsi
- | (1 << 7) // rdi
- | (1 << 12) // r12
- | (1 << 13) // r13
- | (1 << 14) // r14
- | (1 << 15); // r15
-
- return !(PreservedRegMask & (1 << regNum));
-}
-
-
-bool GcInfoDecoder::IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD)
-{
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- _ASSERTE( m_Flags & DECODE_GC_LIFETIMES );
-
- ULONGLONG pSlot = (ULONGLONG) GetStackSlot(spOffset, spBase, pRD);
- _ASSERTE(pSlot >= pRD->SP);
-
- return (pSlot < pRD->SP + m_SizeOfStackOutgoingAndScratchArea);
-#else
- return FALSE;
-#endif
-}
-
-
-void GcInfoDecoder::ReportRegisterToGC( // AMD64
- int regNum,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack)
-{
- GCINFODECODER_CONTRACT(CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- } CONTRACTL_END);
-
- _ASSERTE(regNum >= 0 && regNum <= 16);
- _ASSERTE(regNum != 4); // rsp
-
- LOG((LF_GCROOTS, LL_INFO1000, "Reporting " FMT_REG, regNum ));
-
- OBJECTREF* pObjRef = GetRegisterSlot( regNum, pRD );
-
-#ifdef _DEBUG
- if(IsScratchRegister(regNum, pRD))
- {
- // Scratch registers cannot be reported for non-leaf frames
- _ASSERTE(flags & ActiveStackFrame);
- }
-
- LOG((LF_GCROOTS, LL_INFO1000, /* Part Two */
- "at" FMT_ADDR "as ", DBG_ADDR(pObjRef) ));
-
- VALIDATE_ROOT(isInterior, hCallBack, pObjRef);
-
- LOG((LF_GCROOTS, LL_INFO1000, /* Part Three */
- LOG_PIPTR_OBJECT_CLASS(OBJECTREF_TO_UNCHECKED_OBJECTREF(*pObjRef), isPinned, isInterior)));
-#endif //_DEBUG
-
- DWORD gcFlags = CHECK_APP_DOMAIN;
-
- if (isInterior)
- gcFlags |= GC_CALL_INTERIOR;
-
- if (isPinned)
- gcFlags |= GC_CALL_PINNED;
-
- pCallBack(hCallBack, pObjRef, gcFlags);
-}
-
-#else // Unknown platform
-
-OBJECTREF* GcInfoDecoder::GetRegisterSlot(
- int regNum,
- PREGDISPLAY pRD
- )
-{
- PORTABILITY_ASSERT("GcInfoDecoder::GetRegisterSlot");
- return NULL;
-}
-
-bool GcInfoDecoder::IsScratchRegister(int regNum, PREGDISPLAY pRD)
-{
- PORTABILITY_ASSERT("GcInfoDecoder::IsScratchRegister");
- return false;
-}
-
-bool GcInfoDecoder::IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD)
-{
- _ASSERTE( !"NYI" );
- return false;
-}
-
-void GcInfoDecoder::ReportRegisterToGC(
- int regNum,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack)
-{
- _ASSERTE( !"NYI" );
-}
-
-#endif // Unknown platform
-
-
-OBJECTREF* GcInfoDecoder::GetStackSlot(
- INT32 spOffset,
- GcStackSlotBase spBase,
- PREGDISPLAY pRD
- )
-{
- OBJECTREF* pObjRef;
-
- if( GC_SP_REL == spBase )
- {
- pObjRef = (OBJECTREF*) ((SIZE_T)GetRegdisplaySP(pRD) + spOffset);
- }
- else if( GC_CALLER_SP_REL == spBase )
- {
- pObjRef = (OBJECTREF*) (GET_CALLER_SP(pRD) + spOffset);
- }
- else
- {
- _ASSERTE( GC_FRAMEREG_REL == spBase );
- _ASSERTE( NO_STACK_BASE_REGISTER != m_StackBaseRegister );
-
- pObjRef = (OBJECTREF*)((*((INT64*)(GetRegisterSlot( m_StackBaseRegister, pRD )))) + spOffset);
- }
-
- return pObjRef;
-}
-
-void GcInfoDecoder::ReportStackSlotToGC(
- INT32 spOffset,
- GcStackSlotBase spBase,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack)
-{
- GCINFODECODER_CONTRACT(CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- } CONTRACTL_END);
-
- OBJECTREF* pObjRef = GetStackSlot(spOffset, spBase, pRD);
- _ASSERTE( IS_ALIGNED( pObjRef, sizeof( Object* ) ) );
-
-#ifdef _DEBUG
- LOG((LF_GCROOTS, LL_INFO1000, /* Part One */
- "Reporting %s" FMT_STK,
- ( (GC_SP_REL == spBase) ? "" :
- ((GC_CALLER_SP_REL == spBase) ? "caller's " :
- ((GC_FRAMEREG_REL == spBase) ? "frame " : "<unrecognized GcStackSlotBase> "))),
- DBG_STK(spOffset) ));
-
- LOG((LF_GCROOTS, LL_INFO1000, /* Part Two */
- "at" FMT_ADDR "as ", DBG_ADDR(pObjRef) ));
-
- VALIDATE_ROOT(isInterior, hCallBack, pObjRef);
-
- LOG((LF_GCROOTS, LL_INFO1000, /* Part Three */
- LOG_PIPTR_OBJECT_CLASS(OBJECTREF_TO_UNCHECKED_OBJECTREF(*pObjRef), isPinned, isInterior)));
-#endif
-
- DWORD gcFlags = CHECK_APP_DOMAIN;
-
- if (isInterior)
- gcFlags |= GC_CALL_INTERIOR;
-
- if (isPinned)
- gcFlags |= GC_CALL_PINNED;
-
- pCallBack(hCallBack, pObjRef, gcFlags);
-}
-
-}
-
-#endif // USE_GC_INFO_DECODER
-#endif // VERIFY_GCINFO
GcInfoDecoderFlags flags,
UINT32 breakOffset
)
- : m_Reader(dac_cast<PTR_CBYTE>(gcInfoToken.Info)
-#ifdef VERIFY_GCINFO
- + sizeof(size_t)
-#endif
- )
+ : m_Reader(dac_cast<PTR_CBYTE>(gcInfoToken.Info))
, m_InstructionOffset(breakOffset)
, m_IsInterruptible(false)
#ifdef _DEBUG
, m_GcInfoAddress(dac_cast<PTR_CBYTE>(gcInfoToken.Info))
, m_Version(gcInfoToken.Version)
#endif
-#ifdef VERIFY_GCINFO
- , m_DbgDecoder(dac_cast<PTR_CBYTE>(gcInfoToken.Info) +
- (((UINT32)((PTR_BYTE)(TADDR)gcInfoToken.Info)[3])<<24)+
- (((UINT32)((PTR_BYTE)(TADDR)gcInfoToken.Info)[2])<<16)+
- (((UINT32)((PTR_BYTE)(TADDR)gcInfoToken.Info)[1])<<8)+
- ((PTR_BYTE)(TADDR)gcInfoAddr)[0],
- flags, breakOffset)
-#endif
{
_ASSERTE( (flags & (DECODE_INTERRUPTIBILITY | DECODE_GC_LIFETIMES)) || (0 == breakOffset) );
{
EnumerateInterruptibleRanges(&SetIsInterruptibleCB, this);
}
-
-#ifdef VERIFY_GCINFO
-#if 0
- if(flags & DECODE_INTERRUPTIBILITY)
- _ASSERTE(IsInterruptible() == m_DbgDecoder.IsInterruptible());
-#endif
- if(flags & DECODE_SECURITY_OBJECT)
- _ASSERTE(GetSecurityObjectStackSlot() == m_DbgDecoder.GetSecurityObjectStackSlot());
- if(flags & DECODE_GENERICS_INST_CONTEXT)
- {
- _ASSERTE(GetGenericsInstContextStackSlot() == m_DbgDecoder.GetGenericsInstContextStackSlot());
- _ASSERTE(GetPSPSymStackSlot() == m_DbgDecoder.GetPSPSymStackSlot());
- }
- if(flags & DECODE_VARARG)
- _ASSERTE(GetIsVarArg() == m_DbgDecoder.GetIsVarArg());
- if(flags & DECODE_CODE_LENGTH)
- _ASSERTE(GetCodeLength() == m_DbgDecoder.GetCodeLength());
- _ASSERTE(GetStackBaseRegister() == m_DbgDecoder.GetStackBaseRegister());
- _ASSERTE(GetSizeOfEditAndContinuePreservedArea() == m_DbgDecoder.GetSizeOfEditAndContinuePreservedArea());
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- _ASSERTE(GetSizeOfStackParameterArea() == m_DbgDecoder.GetSizeOfStackParameterArea());
-#endif
-#endif
-
}
bool GcInfoDecoder::IsInterruptible()
return true;
}
-#ifdef VERIFY_GCINFO
- m_DbgDecoder.EnumerateLiveSlots(
- pRD,
- reportScratchSlots,
- inputFlags,
- pCallBack,
- hCallBack
- );
-#endif
-
//
// If this is a non-leaf frame and we are executing a call, the unwinder has given us the PC
// of the call instruction. We should adjust it to the PC of the instruction after the call in order to
ExitSuccess:
#endif
-#ifdef VERIFY_GCINFO
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- if(!executionAborted)
-#endif
- m_DbgDecoder.DoFinalVerification();
-#endif
-
return true;
}
<ItemGroup>
<CppCompile Include="$(VmSourcesDir)\AssemblyNativeResource.cpp" />
<CppCompile Include="$(VmSourcesDir)\coverage.cpp" />
- <CppCompile Include="$(VmSourcesDir)\DbgGcInfoDecoder.cpp" />
<CppCompile Include="$(VmSourcesDir)\dwreport.cpp" />
<CppCompile Include="$(VmSourcesDir)\EnCEE.cpp" />
<CppCompile Include="$(VmSourcesDir)\ExceptionHandling.cpp" />