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

Remove relocations for vtable chunks #17147

Merged
merged 6 commits into from
Jun 29, 2018
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
3 changes: 3 additions & 0 deletions clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ add_definitions(-DFEATURE_STRONGNAME_MIGRATION)
if (CLR_CMAKE_PLATFORM_UNIX OR CLR_CMAKE_TARGET_ARCH_ARM64)
add_definitions(-DFEATURE_STUBS_AS_IL)
endif ()
if (FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
add_definitions(-DFEATURE_NGEN_RELOCS_OPTIMIZATIONS)
endif(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
add_definitions(-DFEATURE_SVR_GC)
add_definitions(-DFEATURE_SYMDIFF)
add_definitions(-DFEATURE_TIERED_COMPILATION)
Expand Down
43 changes: 32 additions & 11 deletions src/debug/daccess/nidump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5907,7 +5907,9 @@ void NativeImageDumper::DumpTypes(PTR_Module module)

for (COUNT_T i = 0; i < slotChunkCount; ++i)
{
DumpMethodTableSlotChunk(m_discoveredSlotChunks[i].addr, m_discoveredSlotChunks[i].nSlots);
DumpMethodTableSlotChunk(m_discoveredSlotChunks[i].addr,
m_discoveredSlotChunks[i].nSlots,
m_discoveredSlotChunks[i].isRelative);
}
}
DisplayEndArray( "Total MethodTableSlotChunks", METHODTABLES );
Expand Down Expand Up @@ -7172,8 +7174,9 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
while (itIndirect.Next())
{
SlotChunk sc;
sc.addr = itIndirect.GetIndirectionSlot();
sc.addr = dac_cast<TADDR>(itIndirect.GetIndirectionSlot());
sc.nSlots = (WORD)itIndirect.GetNumSlots();
sc.isRelative = MethodTable::VTableIndir2_t::isRelative;
m_discoveredSlotChunks.AppendEx(sc);
}

Expand All @@ -7185,7 +7188,7 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
DisplayStartElement( "Slot", ALWAYS );
DisplayWriteElementInt( "Index", i, ALWAYS );
TADDR base = dac_cast<TADDR>(&(mt->GetVtableIndirections()[i]));
PTR_PCODE tgt = MethodTable::VTableIndir_t::GetValueMaybeNullAtPtr(base);
DPTR(MethodTable::VTableIndir2_t) tgt = MethodTable::VTableIndir_t::GetValueMaybeNullAtPtr(base);
DisplayWriteElementPointer( "Pointer",
DataPtrToDisplay(dac_cast<TADDR>(tgt)),
ALWAYS );
Expand All @@ -7207,8 +7210,9 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
DisplayEndElement( ALWAYS ); //Slot

SlotChunk sc;
sc.addr = tgt;
sc.addr = dac_cast<TADDR>(tgt);
sc.nSlots = (mt->GetNumVtableSlots() - mt->GetNumVirtuals());
sc.isRelative = false;
m_discoveredSlotChunks.AppendEx(sc);
}
else if (mt->HasSingleNonVirtualSlot())
Expand Down Expand Up @@ -7344,25 +7348,42 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
#endif

void
NativeImageDumper::DumpMethodTableSlotChunk( PTR_PCODE slotChunk, COUNT_T numSlots )
NativeImageDumper::DumpMethodTableSlotChunk( TADDR slotChunk, COUNT_T numSlots, bool isRelative )
{
IF_OPT( METHODTABLES )
{
DisplayStartStructure( "MethodTableSlotChunk", DPtrToPreferredAddr(slotChunk), numSlots * sizeof(PCODE),
METHODTABLES );
COUNT_T slotsSize;
if (isRelative)
{
slotsSize = numSlots * sizeof(RelativePointer<PCODE>);
}
else
{
slotsSize = numSlots * sizeof(PCODE);
}
DisplayStartStructure( "MethodTableSlotChunk", DataPtrToDisplay(slotChunk), slotsSize, METHODTABLES );

IF_OPT(VERBOSE_TYPES)
{
DisplayStartList( W("[%-4s]: %s (%s)"), ALWAYS );
for( unsigned i = 0; i < numSlots; ++i )
{
DumpSlot(i, slotChunk[i]);
PCODE target;
if (isRelative)
{
target = RelativePointer<PCODE>::GetValueMaybeNullAtPtr(slotChunk + i * sizeof(RelativePointer<PCODE>));
}
else
{
target = dac_cast<PTR_PCODE>(slotChunk)[i];
}

DumpSlot(i, target);
}
DisplayEndList( ALWAYS ); //Slot list
}
else
CoverageRead( PTR_TO_TADDR(slotChunk),
numSlots * sizeof(PCODE) );
CoverageRead( slotChunk, slotsSize );
DisplayEndStructure(ALWAYS); //Slot chunk
}
}
Expand Down Expand Up @@ -7735,7 +7756,7 @@ void NativeImageDumper::DumpMethodDesc( PTR_MethodDesc md, PTR_Module module )
}
if ( md->HasNonVtableSlot() )
{
DisplayWriteElementInt( "Slot", (DWORD)(PTR_TO_TADDR(md->GetAddrOfSlot()) - PTR_TO_TADDR(md)), ALWAYS);
DisplayWriteElementInt( "Slot", (DWORD)(md->GetAddrOfSlot() - PTR_TO_TADDR(md)), ALWAYS);
}
if (md->HasNativeCodeSlot())
{
Expand Down
9 changes: 6 additions & 3 deletions src/debug/daccess/nidump.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class NativeImageDumper
PTR_Module module );

#ifndef STUB_DISPATCH_ALL
void DumpMethodTableSlotChunk( PTR_PCODE slotChunk, COUNT_T size );
void DumpMethodTableSlotChunk( TADDR slotChunk, COUNT_T size, bool );
#endif

void DumpSlot( unsigned index, PCODE tgt );
Expand Down Expand Up @@ -478,6 +478,8 @@ class NativeImageDumper
template<typename T>
TADDR DPtrToPreferredAddr( T ptr );

TADDR DPtrToPreferredAddr( TADDR tptr );

void DumpAssemblySignature(CORCOMPILE_ASSEMBLY_SIGNATURE & assemblySignature);

SIZE_T CountFields( PTR_MethodTable mt );
Expand All @@ -500,12 +502,13 @@ class NativeImageDumper

struct SlotChunk
{
PTR_PCODE addr;
TADDR addr;
WORD nSlots;
bool isRelative;

inline bool operator==(const SlotChunk& sc) const
{
return (addr == sc.addr) && (nSlots == sc.nSlots);
return (addr == sc.addr) && (nSlots == sc.nSlots) && (isRelative == sc.isRelative);
}

inline bool operator<(const SlotChunk& sc) const
Expand Down
3 changes: 2 additions & 1 deletion src/inc/corcompile.h
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,8 @@ class ICorCompilePreloader
CORCOMPILE_SECTION(READONLY_HOT) \
CORCOMPILE_SECTION(READONLY_WARM) \
CORCOMPILE_SECTION(READONLY_COLD) \
CORCOMPILE_SECTION(READONLY_VCHUNKS_AND_DICTIONARY) \
CORCOMPILE_SECTION(READONLY_VCHUNKS) \
CORCOMPILE_SECTION(READONLY_DICTIONARY) \
CORCOMPILE_SECTION(CLASS_COLD) \
CORCOMPILE_SECTION(CROSS_DOMAIN_INFO) \
CORCOMPILE_SECTION(METHOD_PRECODE_COLD) \
Expand Down
24 changes: 14 additions & 10 deletions src/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,11 @@ TODO: Talk about initializing strutures before use
#define SELECTANY extern __declspec(selectany)
#endif

SELECTANY const GUID JITEEVersionIdentifier = { /* dc72a60f-22f2-49fb-809f-00077f3eb1a8 */
0xdc72a60f,
0x22f2,
0x49fb,
{ 0x80, 0x9f, 0x0, 0x7, 0x7f, 0x3e, 0xb1, 0xa8}
SELECTANY const GUID JITEEVersionIdentifier = { /* 45aafd4d-1d23-4647-9ce1-cf09a2677ca0 */
0x45aafd4d,
0x1d23,
0x4647,
{0x9c, 0xe1, 0xcf, 0x09, 0xa2, 0x67, 0x7c, 0xa0}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -977,8 +977,9 @@ enum CorInfoIntrinsics
enum InfoAccessType
{
IAT_VALUE, // The info value is directly available
IAT_PVALUE, // The value needs to be accessed via an indirection
IAT_PPVALUE // The value needs to be accessed via a double indirection
IAT_PVALUE, // The value needs to be accessed via an indirection
IAT_PPVALUE, // The value needs to be accessed via a double indirection
IAT_RELPVALUE // The value needs to be accessed via a relative indirection
};

enum CorInfoGCType
Expand Down Expand Up @@ -1243,6 +1244,7 @@ struct CORINFO_METHOD_INFO
// Constant Lookups are either:
// IAT_VALUE: immediate (relocatable) values,
// IAT_PVALUE: immediate values access via an indirection through an immediate (relocatable) address
// IAT_RELPVALUE: immediate values access via a relative indirection through an immediate offset
// IAT_PPVALUE: immediate values access via a double indirection through an immediate (relocatable) address
//
// Runtime Lookups
Expand All @@ -1268,9 +1270,10 @@ struct CORINFO_CONST_LOOKUP
// If the handle is obtained at compile-time, then this handle is the "exact" handle (class, method, or field)
// Otherwise, it's a representative...
// If accessType is
// IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address
// IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle
// IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle
// IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address
// IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle
// IAT_RELPVALUE --> "addr" stores a relative pointer to a location which will hold the real handle
// IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle

InfoAccessType accessType;
union
Expand Down Expand Up @@ -1361,6 +1364,7 @@ struct CORINFO_LOOKUP
// Otherwise, it's a representative... If accessType is
// IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address
// IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle
// IAT_RELPVALUE --> "addr" stores a relative pointer to a location which will hold the real handle
// IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle
CORINFO_CONST_LOOKUP constLookup;
};
Expand Down
33 changes: 33 additions & 0 deletions src/inc/fixuppointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,26 @@ class RelativePointer
}
#endif // DACCESS_COMPILE

static TADDR GetRelativeMaybeNull(TADDR base, TADDR addr)
{
LIMITED_METHOD_DAC_CONTRACT;
if (addr == NULL)
{
return NULL;
}
else
{
return addr - base;
}
}

static TADDR GetRelative(TADDR base, TADDR addr)
{
LIMITED_METHOD_DAC_CONTRACT;
PRECONDITION(addr != NULL);
return addr - base;
}

private:
#ifndef DACCESS_COMPILE
Volatile<TADDR> m_delta;
Expand Down Expand Up @@ -721,6 +741,19 @@ class PlainPointer
}
#endif

static TADDR GetRelativeMaybeNull(TADDR base, TADDR addr)
{
LIMITED_METHOD_DAC_CONTRACT;
return addr;
}

static TADDR GetRelative(TADDR base, TADDR addr)
{
LIMITED_METHOD_DAC_CONTRACT;
PRECONDITION(addr != NULL);
return addr;
}

private:
TADDR m_ptr;
};
Expand Down
72 changes: 60 additions & 12 deletions src/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8600,6 +8600,19 @@ void CodeGen::genFnEpilog(BasicBlock* block)

bool jmpEpilog = ((block->bbFlags & BBF_HAS_JMP) != 0);

GenTree* lastNode = block->lastNode();

// Method handle and address info used in case of jump epilog
CORINFO_METHOD_HANDLE methHnd = nullptr;
CORINFO_CONST_LOOKUP addrInfo;
addrInfo.addr = nullptr;

if (jmpEpilog && lastNode->gtOper == GT_JMP)
{
methHnd = (CORINFO_METHOD_HANDLE)lastNode->gtVal.gtVal1;
compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &addrInfo);
}

#ifdef _TARGET_ARM_
// We delay starting the unwind codes until we have an instruction which we know
// needs an unwind code. In particular, for large stack frames in methods without
Expand Down Expand Up @@ -8644,6 +8657,30 @@ void CodeGen::genFnEpilog(BasicBlock* block)
unwindStarted = true;
}

if (jmpEpilog && lastNode->gtOper == GT_JMP && addrInfo.accessType == IAT_RELPVALUE)
{
// IAT_RELPVALUE jump at the end is done using relative indirection, so,
// additional helper register is required.
// We use LR just before it is going to be restored from stack, i.e.
//
// movw r12, laddr
// movt r12, haddr
// mov lr, r12
// ldr r12, [r12]
// add r12, r12, lr
// pop {lr}
// ...
// bx r12

regNumber indCallReg = REG_R12;
regNumber vptrReg1 = REG_LR;

instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addrInfo.addr);
getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, vptrReg1, indCallReg);
getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
getEmitter()->emitIns_R_R(INS_add, EA_PTRSIZE, indCallReg, vptrReg1);
}

genPopCalleeSavedRegisters(jmpEpilog);

if (regSet.rsMaskPreSpillRegs(true) != RBM_NONE)
Expand All @@ -8656,6 +8693,12 @@ void CodeGen::genFnEpilog(BasicBlock* block)
compiler->unwindAllocStack(preSpillRegArgSize);
}

if (jmpEpilog)
{
// We better not have used a pop PC to return otherwise this will be unreachable code
noway_assert(!genUsedPopToReturn);
}

#else // _TARGET_ARM64_
compiler->unwindBegEpilog();

Expand All @@ -8664,20 +8707,13 @@ void CodeGen::genFnEpilog(BasicBlock* block)

if (jmpEpilog)
{
#ifdef _TARGET_ARMARCH_
hasTailCalls = true;
#endif // _TARGET_ARMARCH_

noway_assert(block->bbJumpKind == BBJ_RETURN);
noway_assert(block->bbTreeList != nullptr);

#ifdef _TARGET_ARM_
// We better not have used a pop PC to return otherwise this will be unreachable code
noway_assert(!genUsedPopToReturn);
#endif // _TARGET_ARM_

/* figure out what jump we have */
GenTree* jmpNode = block->lastNode();
GenTree* jmpNode = lastNode;
#if !FEATURE_FASTTAILCALL
noway_assert(jmpNode->gtOper == GT_JMP);
#else // FEATURE_FASTTAILCALL
Expand All @@ -8696,10 +8732,8 @@ void CodeGen::genFnEpilog(BasicBlock* block)
{
// Simply emit a jump to the methodHnd. This is similar to a call so we can use
// the same descriptor with some minor adjustments.
CORINFO_METHOD_HANDLE methHnd = (CORINFO_METHOD_HANDLE)jmpNode->gtVal.gtVal1;

CORINFO_CONST_LOOKUP addrInfo;
compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &addrInfo);
assert(methHnd != nullptr);
assert(addrInfo.addr != nullptr);

#ifdef _TARGET_ARM_
emitter::EmitCallType callType;
Expand Down Expand Up @@ -8735,6 +8769,20 @@ void CodeGen::genFnEpilog(BasicBlock* block)
}
break;

case IAT_RELPVALUE:
{
// Load the address into a register, load relative indirect and call through a register
// We have to use R12 since we assume the argument registers are in use
// LR is used as helper register right before it is restored from stack, thus,
// all relative address calculations are performed before LR is restored.
callType = emitter::EC_INDIR_R;
indCallReg = REG_R12;
addr = NULL;

regSet.verifyRegUsed(indCallReg);
break;
}

case IAT_PPVALUE:
default:
NO_WAY("Unsupported JMP indirection");
Expand Down
Loading