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

Implement GcInfo v2 #6522

Merged
merged 1 commit into from
Aug 5, 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
2 changes: 2 additions & 0 deletions clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ elseif (CLR_CMAKE_TARGET_ARCH_ARM64)
add_definitions(-DDBG_TARGET_64BIT=1)
add_definitions(-DDBG_TARGET_ARM64=1)
add_definitions(-DDBG_TARGET_WIN64=1)
add_definitions(-DFEATURE_MULTIREG_RETURN)
elseif (CLR_CMAKE_TARGET_ARCH_ARM)
if (CLR_CMAKE_PLATFORM_UNIX)
add_definitions(-DDBG_TARGET_ARM_UNIX)
Expand Down Expand Up @@ -166,6 +167,7 @@ add_definitions(-DFEATURE_SVR_GC)
add_definitions(-DFEATURE_SYMDIFF)
add_definitions(-DFEATURE_SYNTHETIC_CULTURES)
if(CLR_CMAKE_PLATFORM_UNIX_AMD64)
add_definitions(-DFEATURE_MULTIREG_RETURN)
add_definitions(-DFEATURE_UNIX_AMD64_STRUCT_PASSING)
add_definitions(-DFEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
endif (CLR_CMAKE_PLATFORM_UNIX_AMD64)
Expand Down
6 changes: 4 additions & 2 deletions src/debug/daccess/nidump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3112,7 +3112,7 @@ void NativeImageDumper::DumpCompleteMethod(PTR_Module module, MethodIterator& mi
GCDump gcDump(gcInfoToken.Version);
gcDump.gcPrintf = stringOutFn;
#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_CODE_LENGTH, 0);
GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_CODE_LENGTH);
methodSize = gcInfoDecoder.GetCodeLength();
#endif

Expand Down Expand Up @@ -9440,7 +9440,9 @@ void NativeImageDumper::DumpReadyToRunMethod(PCODE pEntryPoint, PTR_RUNTIME_FUNC
GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = stringOutFn;
#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
GcInfoDecoder gcInfoDecoder({ curGCInfoPtr, GCINFO_VERSION }, DECODE_CODE_LENGTH, 0);
UINT32 r2rversion = m_pReadyToRunHeader->MajorVersion;
UINT32 gcInfoVersion = GCInfoToken::ReadyToRunVersionToGcInfoVersion(r2rversion);
GcInfoDecoder gcInfoDecoder({ curGCInfoPtr, gcInfoVersion }, DECODE_CODE_LENGTH);
methodSize = gcInfoDecoder.GetCodeLength();
#endif

Expand Down
6 changes: 5 additions & 1 deletion src/gcdump/gcdumpnonx86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ size_t GCDump::DumpGCTable(PTR_CBYTE gcInfoBlock,
| DECODE_VARARG
| DECODE_GENERICS_INST_CONTEXT
| DECODE_GC_LIFETIMES
| DECODE_PROLOG_LENGTH),
| DECODE_PROLOG_LENGTH
| DECODE_RETURN_KIND),
0);

if (NO_SECURITY_OBJECT != hdrdecoder.GetSecurityObjectStackSlot() ||
Expand Down Expand Up @@ -438,6 +439,9 @@ size_t GCDump::DumpGCTable(PTR_CBYTE gcInfoBlock,
gcPrintf("Size of parameter area: %x\n", hdrdecoder.GetSizeOfStackParameterArea());
#endif

ReturnKind returnKind = hdrdecoder.GetReturnKind();
gcPrintf("Return Kind: %s\n", ReturnKindToString(returnKind));

UINT32 cbEncodedMethodSize = hdrdecoder.GetCodeLength();
gcPrintf("Code size: %x\n", cbEncodedMethodSize);

Expand Down
63 changes: 57 additions & 6 deletions src/gcinfo/gcinfoencoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,13 +324,17 @@ typedef SimplerHashTable<const BitArray *, LiveStateFuncs, UINT32, GcInfoHashBeh
// Pi = partially-interruptible; methods with zero fully-interruptible ranges
GcInfoSize g_FiGcInfoSize;
GcInfoSize g_PiGcInfoSize;
// Number of methods with GcInfo that have SlimHeader
size_t g_NumSlimHeaders = 0;
// Number of methods with GcInfo that have FatHeader
size_t g_NumFatHeaders = 0;

GcInfoSize::GcInfoSize()
{
memset(this, 0, sizeof(*this));
}

GcInfoSize& operator+=(const GcInfoSize& other)
GcInfoSize& GcInfoSize::operator+=(const GcInfoSize& other)
{
TotalSize += other.TotalSize;

Expand All @@ -351,7 +355,7 @@ GcInfoSize& operator+=(const GcInfoSize& other)
GenericsCtxSize += other.GenericsCtxSize;
PspSymSize += other.PspSymSize;
StackBaseSize += other.StackBaseSize;
FrameMarkerSize += other.FrameMarkerSize;
ReversePInvokeFrameSize += other.ReversePInvokeFrameSize;
FixedAreaSize += other.FixedAreaSize;
NumCallSitesSize += other.NumCallSitesSize;
NumRangesSize += other.NumRangesSize;
Expand Down Expand Up @@ -398,8 +402,9 @@ void GcInfoSize::Log(DWORD level, const char * header)
LogSpew(LF_GCINFO, level, "GsCookie: %Iu\n", GsCookieSize);
LogSpew(LF_GCINFO, level, "PspSym: %Iu\n", PspSymSize);
LogSpew(LF_GCINFO, level, "GenericsCtx: %Iu\n", GenericsCtxSize);
LogSpew(LF_GCINFO, level, "FrameMarker: %Iu\n", FrameMarkerSize);
LogSpew(LF_GCINFO, level, "StackBase: %Iu\n", StackBaseSize);
LogSpew(LF_GCINFO, level, "FixedArea: %Iu\n", FixedAreaSize);
LogSpew(LF_GCINFO, level, "ReversePInvokeFrame: %Iu\n", ReversePInvokeFrameSize);
LogSpew(LF_GCINFO, level, "NumCallSites: %Iu\n", NumCallSitesSize);
LogSpew(LF_GCINFO, level, "NumRanges: %Iu\n", NumRangesSize);
LogSpew(LF_GCINFO, level, "CallSiteOffsets: %Iu\n", CallSitePosSize);
Expand Down Expand Up @@ -488,17 +493,27 @@ GcInfoEncoder::GcInfoEncoder(

m_StackBaseRegister = NO_STACK_BASE_REGISTER;
m_SizeOfEditAndContinuePreservedArea = NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA;
m_ReversePInvokeFrameSlot = NO_REVERSE_PINVOKE_FRAME;
m_WantsReportOnlyLeaf = false;
m_IsVarArg = false;
m_pLastInterruptibleRange = NULL;

#ifdef _DEBUG
m_IsSlotTableFrozen = FALSE;
#endif //_DEBUG

#ifndef _TARGET_X86_
// If the compiler doesn't set the GCInfo, report RT_Unset.
// This is used for compatibility with JITs that aren't updated to use the new API.
m_ReturnKind = RT_Unset;
#else
m_ReturnKind = RT_Illegal;
#endif // _TARGET_X86_
m_CodeLength = 0;
#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
m_SizeOfStackOutgoingAndScratchArea = -1;
#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
#endif //_DEBUG

}

#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
Expand Down Expand Up @@ -758,14 +773,24 @@ void GcInfoEncoder::SetSizeOfStackOutgoingAndScratchArea( UINT32 size )
}
#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA

void GcInfoEncoder::SetReversePInvokeFrameSlot(INT32 spOffset)
{
m_ReversePInvokeFrameSlot = spOffset;
}

void GcInfoEncoder::SetReturnKind(ReturnKind returnKind)
{
_ASSERTE(IsValidReturnKind(returnKind));

m_ReturnKind = returnKind;
}

struct GcSlotDescAndId
{
GcSlotDesc m_SlotDesc;
UINT32 m_SlotId;
};


int __cdecl CompareSlotDescAndIdBySlotDesc(const void* p1, const void* p2)
{
const GcSlotDesc* pFirst = &reinterpret_cast<const GcSlotDescAndId*>(p1)->m_SlotDesc;
Expand Down Expand Up @@ -985,20 +1010,26 @@ void GcInfoEncoder::Build()
// Method header
///////////////////////////////////////////////////////////////////////


UINT32 hasSecurityObject = (m_SecurityObjectStackSlot != NO_SECURITY_OBJECT);
UINT32 hasGSCookie = (m_GSCookieStackSlot != NO_GS_COOKIE);
UINT32 hasContextParamType = (m_GenericsInstContextStackSlot != NO_GENERICS_INST_CONTEXT);
UINT32 hasReversePInvokeFrame = (m_ReversePInvokeFrameSlot != NO_REVERSE_PINVOKE_FRAME);

BOOL slimHeader = (!m_IsVarArg && !hasSecurityObject && !hasGSCookie && (m_PSPSymStackSlot == NO_PSP_SYM) &&
!hasContextParamType && !m_WantsReportOnlyLeaf && (m_InterruptibleRanges.Count() == 0) &&
!hasContextParamType && !m_WantsReportOnlyLeaf && (m_InterruptibleRanges.Count() == 0) && !hasReversePInvokeFrame &&
((m_StackBaseRegister == NO_STACK_BASE_REGISTER) || (NORMALIZE_STACK_BASE_REGISTER(m_StackBaseRegister) == 0))) &&
(m_SizeOfEditAndContinuePreservedArea == NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA);

// All new code is generated for the latest GCINFO_VERSION.
// So, always encode RetunrKind and encode ReversePInvokeFrameSlot where applicable.
if (slimHeader)
{
// Slim encoding means nothing special, partially interruptible, maybe a default frame register
GCINFO_WRITE(m_Info1, 0, 1, FlagsSize); // Slim encoding
GCINFO_WRITE(m_Info1, (m_StackBaseRegister == NO_STACK_BASE_REGISTER) ? 0 : 1, 1, FlagsSize);

GCINFO_WRITE(m_Info1, m_ReturnKind, SIZE_OF_RETURN_KIND_IN_SLIM_HEADER, RetKindSize);
}
else
{
Expand All @@ -1011,6 +1042,9 @@ void GcInfoEncoder::Build()
GCINFO_WRITE(m_Info1, ((m_StackBaseRegister != NO_STACK_BASE_REGISTER) ? 1 : 0), 1, FlagsSize);
GCINFO_WRITE(m_Info1, (m_WantsReportOnlyLeaf ? 1 : 0), 1, FlagsSize);
GCINFO_WRITE(m_Info1, ((m_SizeOfEditAndContinuePreservedArea != NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA) ? 1 : 0), 1, FlagsSize);
GCINFO_WRITE(m_Info1, (hasReversePInvokeFrame ? 1 : 0), 1, FlagsSize);

GCINFO_WRITE(m_Info1, m_ReturnKind, SIZE_OF_RETURN_KIND_IN_FAT_HEADER, RetKindSize);
}

_ASSERTE( m_CodeLength > 0 );
Expand Down Expand Up @@ -1109,6 +1143,12 @@ void GcInfoEncoder::Build()
GCINFO_WRITE_VARL_U(m_Info1, m_SizeOfEditAndContinuePreservedArea, SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE, EncPreservedSlots);
}

if (hasReversePInvokeFrame)
{
_ASSERTE(!slimHeader);
GCINFO_WRITE_VARL_S(m_Info1, NORMALIZE_STACK_SLOT(m_ReversePInvokeFrameSlot), REVERSE_PINVOKE_FRAME_ENCBASE, ReversePInvokeFrameSize);
}

#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
if (!slimHeader)
{
Expand Down Expand Up @@ -2305,6 +2345,15 @@ lExitSuccess:;
//-------------------------------------------------------------------

#ifdef MEASURE_GCINFO
if (slimHeader)
{
g_NumSlimHeaders++;
}
else
{
g_NumFatHeaders++;
}

m_CurrentMethodSize.NumMethods = 1;
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
m_CurrentMethodSize.NumCallSites = m_NumCallSites;
Expand All @@ -2331,6 +2380,8 @@ lExitSuccess:;
m_CurrentMethodSize.Log(LL_INFO100, "=== PartiallyInterruptible method breakdown ===\r\n");
g_PiGcInfoSize.Log(LL_INFO10, "=== PartiallyInterruptible global breakdown ===\r\n");
}
LogSpew(LF_GCINFO, LL_INFO10, "Total SlimHeaders: %Iu\n", g_NumSlimHeaders);
LogSpew(LF_GCINFO, LL_INFO10, "NumMethods: %Iu\n", g_NumFatHeaders);
#endif
}

Expand Down
26 changes: 24 additions & 2 deletions src/inc/gcinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,15 @@ const unsigned this_OFFSET_FLAG = 0x2; // the offset is "this"
// The current GCInfo Version
//-----------------------------------------------------------------------------

#ifdef _TARGET_X86_
// X86 GcInfo encoding is yet to be changed.
#define GCINFO_VERSION 1
#else
#define GCINFO_VERSION 2
#endif // _TARGET_X86_

#define MIN_GCINFO_VERSION_WITH_RETURN_KIND 2
#define MIN_GCINFO_VERSION_WITH_REV_PINVOKE_FRAME 2
//-----------------------------------------------------------------------------
// GCInfoToken: A wrapper that contains the GcInfo data and version number.
//
Expand All @@ -45,14 +52,29 @@ const unsigned this_OFFSET_FLAG = 0x2; // the offset is "this"
// 1) The current GCINFO_VERSION for JITted and Ngened images
// 2) A function of the Ready - to - run major version stored in READYTORUN_HEADER
// for ready - to - run images.ReadyToRunJitManager::JitTokenToGCInfoVersion()
// provides the GcInfo version for any Method.Currently, there's only one
// version of GCInfo.
// provides the GcInfo version for any Method.
//-----------------------------------------------------------------------------

struct GCInfoToken
{
PTR_VOID Info;
UINT32 Version;

BOOL IsReturnKindAvailable()
{
return (Version >= MIN_GCINFO_VERSION_WITH_RETURN_KIND);
}
BOOL IsReversePInvokeFrameAvailable()
{
return (Version >= MIN_GCINFO_VERSION_WITH_REV_PINVOKE_FRAME);
}

static UINT32 ReadyToRunVersionToGcInfoVersion(UINT32 readyToRunMajorVersion)
{
// GcInfo version is 1 up to ReadyTorun version 1.x
// GcInfo version is current from ReadyToRun version 2.0
return (readyToRunMajorVersion == 1) ? 1 : GCINFO_VERSION;
}
};

/*****************************************************************************/
Expand Down
17 changes: 13 additions & 4 deletions src/inc/gcinfodecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ enum ICodeManagerFlags

enum GcInfoDecoderFlags
{
DECODE_EVERYTHING = 0x0,
DECODE_SECURITY_OBJECT = 0x01, // stack location of security object
DECODE_CODE_LENGTH = 0x02,
DECODE_VARARG = 0x04,
Expand All @@ -174,6 +175,8 @@ enum GcInfoDecoderFlags
DECODE_FOR_RANGES_CALLBACK = 0x200,
DECODE_PROLOG_LENGTH = 0x400, // length of the prolog (used to avoid reporting generics context)
DECODE_EDIT_AND_CONTINUE = 0x800,
DECODE_REVERSE_PINVOKE_VAR = 0x1000,
DECODE_RETURN_KIND = 0x2000
};

enum GcInfoHeaderFlags
Expand All @@ -190,11 +193,12 @@ enum GcInfoHeaderFlags
GC_INFO_HAS_STACK_BASE_REGISTER = 0x40,
GC_INFO_WANTS_REPORT_ONLY_LEAF = 0x80,
GC_INFO_HAS_EDIT_AND_CONTINUE_PRESERVED_SLOTS = 0x100,
GC_INFO_REVERSE_PINVOKE_FRAME = 0x200,

GC_INFO_FLAGS_BIT_SIZE = 9,
GC_INFO_FLAGS_BIT_SIZE_VERSION_1 = 9,
GC_INFO_FLAGS_BIT_SIZE = 10,
};


class BitStreamReader
{
public:
Expand Down Expand Up @@ -430,7 +434,7 @@ class GcInfoDecoder
// If you are not insterested in interruptibility or gc lifetime information, pass 0 as instructionOffset
GcInfoDecoder(
GCInfoToken gcInfoToken,
GcInfoDecoderFlags flags,
GcInfoDecoderFlags flags = DECODE_EVERYTHING,
UINT32 instructionOffset = 0
);

Expand Down Expand Up @@ -486,10 +490,12 @@ class GcInfoDecoder
UINT32 GetPrologSize();
INT32 GetPSPSymStackSlot();
INT32 GetGenericsInstContextStackSlot();
INT32 GetReversePInvokeStackSlot();
bool HasMethodDescGenericsInstContext();
bool HasMethodTableGenericsInstContext();
bool GetIsVarArg();
bool WantsReportOnlyLeaf();
ReturnKind GetReturnKind();
UINT32 GetCodeLength();
UINT32 GetStackBaseRegister();
UINT32 GetSizeOfEditAndContinuePreservedArea();
Expand All @@ -512,13 +518,16 @@ class GcInfoDecoder
bool m_WantsReportOnlyLeaf;
INT32 m_SecurityObjectStackSlot;
INT32 m_GSCookieStackSlot;
INT32 m_ReversePInvokeStackSlot;
UINT32 m_ValidRangeStart;
UINT32 m_ValidRangeEnd;
INT32 m_PSPSymStackSlot;
INT32 m_GenericsInstContextStackSlot;
UINT32 m_CodeLength;
UINT32 m_StackBaseRegister;
UINT32 m_SizeOfEditAndContinuePreservedArea;
INT32 m_ReversePInvokeFrameSlot;
ReturnKind m_ReturnKind;
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
UINT32 m_NumSafePoints;
UINT32 m_SafePointIndex;
Expand All @@ -533,8 +542,8 @@ class GcInfoDecoder
#ifdef _DEBUG
GcInfoDecoderFlags m_Flags;
PTR_CBYTE m_GcInfoAddress;
UINT32 m_Version;
#endif
UINT32 m_Version;

static bool SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback);

Expand Down
Loading