From 441162b0cce6a871b7f20412f5beb930d5c3257c Mon Sep 17 00:00:00 2001 From: Gleb Balykov Date: Fri, 23 Jun 2017 15:48:48 +0300 Subject: [PATCH] Remove relocations for MethodTable's vtable-1st-level-indirection Commit migrated from https://github.com/dotnet/coreclr/commit/c4c04ea45cda3194cdf2189d757b96602ea344ee --- .../superpmi/superpmi-shared/icorjitinfoimpl.h | 3 +- .../src/ToolBox/superpmi/superpmi-shared/lwmlist.h | 2 +- .../superpmi/superpmi-shared/methodcontext.cpp | 16 +++-- .../superpmi/superpmi-shared/methodcontext.h | 14 +++- .../superpmi-shim-collector/icorjitinfo.cpp | 7 +- .../superpmi/superpmi-shim-counter/icorjitinfo.cpp | 5 +- .../superpmi/superpmi-shim-simple/icorjitinfo.cpp | 5 +- .../src/ToolBox/superpmi/superpmi/icorjitinfo.cpp | 5 +- src/coreclr/src/debug/daccess/nidump.cpp | 9 +-- src/coreclr/src/inc/corinfo.h | 3 +- src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp | 5 +- src/coreclr/src/jit/codegenlegacy.cpp | 78 +++++++++++++++++++--- src/coreclr/src/jit/emitarm.cpp | 10 +++ src/coreclr/src/jit/lower.cpp | 50 +++++++++++--- src/coreclr/src/jit/lower.h | 6 ++ src/coreclr/src/jit/morph.cpp | 20 +++++- src/coreclr/src/vm/array.cpp | 4 +- src/coreclr/src/vm/generics.cpp | 4 +- src/coreclr/src/vm/jitinterface.cpp | 6 +- src/coreclr/src/vm/jitinterface.h | 4 +- src/coreclr/src/vm/methodtable.cpp | 15 +++-- src/coreclr/src/vm/methodtable.h | 19 ++++-- src/coreclr/src/vm/methodtable.inl | 14 ++-- src/coreclr/src/vm/methodtablebuilder.cpp | 12 ++-- src/coreclr/src/zap/zapinfo.cpp | 7 +- src/coreclr/src/zap/zapinfo.h | 3 +- 26 files changed, 244 insertions(+), 82 deletions(-) diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h index 00b5c1b..37103bd 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h @@ -109,7 +109,8 @@ CORINFO_MODULE_HANDLE getMethodModule(CORINFO_METHOD_HANDLE method); // vtable of it's owning class or interface. void getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */ unsigned* offsetOfIndirection, /* OUT */ - unsigned* offsetAfterIndirection /* OUT */ + unsigned* offsetAfterIndirection,/* OUT */ + unsigned* isRelative /* OUT */ ); // Find the virtual method in implementingClass that overrides virtualMethod. diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h index 23cdf70..349b6bf 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h @@ -102,7 +102,7 @@ LWM(GetMethodInfo, DWORDLONG, Agnostic_GetMethodInfo) LWM(GetMethodName, DLD, DD) LWM(GetMethodSig, DLDL, Agnostic_CORINFO_SIG_INFO) LWM(GetMethodSync, DWORDLONG, DLDL) -LWM(GetMethodVTableOffset, DWORDLONG, DD) +LWM(GetMethodVTableOffset, DWORDLONG, DDD) LWM(GetNewArrHelper, DWORDLONG, DWORD) LWM(GetNewHelper, Agnostic_GetNewHelper, DWORD) LWM(GetParentType, DWORDLONG, DWORDLONG) diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index ed5799f..b13e720 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -2971,26 +2971,29 @@ void MethodContext::repGetEHinfo(CORINFO_METHOD_HANDLE ftn, unsigned EHnumber, C void MethodContext::recGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection) + unsigned* offsetAfterIndirection, + unsigned* isRelative) { if (GetMethodVTableOffset == nullptr) - GetMethodVTableOffset = new LightWeightMap(); + GetMethodVTableOffset = new LightWeightMap(); - DD value; + DDD value; value.A = (DWORD)*offsetOfIndirection; value.B = (DWORD)*offsetAfterIndirection; + value.C = (DWORD)*isRelative; GetMethodVTableOffset->Add((DWORDLONG)method, value); DEBUG_REC(dmpGetMethodVTableOffset((DWORDLONG)method, value)); } -void MethodContext::dmpGetMethodVTableOffset(DWORDLONG key, DD value) +void MethodContext::dmpGetMethodVTableOffset(DWORDLONG key, DDD value) { printf("GetMethodVTableOffset key ftn-%016llX, value offi-%u, offa-%u", key, value.A, value.B); } void MethodContext::repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection) + unsigned* offsetAfterIndirection, + unsigned* isRelative) { - DD value; + DDD value; AssertCodeMsg(GetMethodVTableOffset != nullptr, EXCEPTIONCODE_MC, "Didn't find anything for %016llX", (DWORDLONG)method); @@ -3000,6 +3003,7 @@ void MethodContext::repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, *offsetOfIndirection = (unsigned)value.A; *offsetAfterIndirection = (unsigned)value.B; + *isRelative = (unsigned)value.C; DEBUG_REP(dmpGetMethodVTableOffset((DWORDLONG)method, value)); } diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h index aa5cd85..524b0dd 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -237,6 +237,12 @@ public: DWORD A; DWORD B; }; + struct DDD + { + DWORD A; + DWORD B; + DWORD C; + }; struct Agnostic_CanTailCall { DWORDLONG callerHnd; @@ -844,11 +850,13 @@ public: void recGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection); - void dmpGetMethodVTableOffset(DWORDLONG key, DD value); + unsigned* offsetAfterIndirection, + unsigned* isRelative); + void dmpGetMethodVTableOffset(DWORDLONG key, DDD value); void repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection); + unsigned* offsetAfterIndirection, + unsigned* isRelative); void recResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass, diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 1ba0ed2..311b57f 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -214,12 +214,13 @@ CORINFO_MODULE_HANDLE interceptor_ICJI::getMethodModule(CORINFO_METHOD_HANDLE me // vtable of it's owning class or interface. void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */ unsigned* offsetOfIndirection, /* OUT */ - unsigned* offsetAfterIndirection /* OUT */ + unsigned* offsetAfterIndirection,/* OUT */ + unsigned* isRelative /* OUT */ ) { mc->cr->AddCall("getMethodVTableOffset"); - original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection); - mc->recGetMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection); + original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); + mc->recGetMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); } // Find the virtual method in implementingClass that overrides virtualMethod. diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp index 6760800..cad7990 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -145,11 +145,12 @@ CORINFO_MODULE_HANDLE interceptor_ICJI::getMethodModule(CORINFO_METHOD_HANDLE me // vtable of it's owning class or interface. void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */ unsigned* offsetOfIndirection, /* OUT */ - unsigned* offsetAfterIndirection /* OUT */ + unsigned* offsetAfterIndirection,/* OUT */ + unsigned* isRelative /* OUT */ ) { mcs->AddCall("getMethodVTableOffset"); - original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection); + original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); } // Find the virtual method in implementingClass that overrides virtualMethod. diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp index b098eb6..7dc3e7e 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -134,10 +134,11 @@ CORINFO_MODULE_HANDLE interceptor_ICJI::getMethodModule(CORINFO_METHOD_HANDLE me // vtable of it's owning class or interface. void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */ unsigned* offsetOfIndirection, /* OUT */ - unsigned* offsetAfterIndirection /* OUT */ + unsigned* offsetAfterIndirection,/* OUT */ + unsigned* isRelative /* OUT */ ) { - original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection); + original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); } // Find the virtual method in implementingClass that overrides virtualMethod. diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp index d88e352..b282a1f 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp @@ -165,11 +165,12 @@ CORINFO_MODULE_HANDLE MyICJI::getMethodModule(CORINFO_METHOD_HANDLE method) // vtable of it's owning class or interface. void MyICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */ unsigned* offsetOfIndirection, /* OUT */ - unsigned* offsetAfterIndirection /* OUT */ + unsigned* offsetAfterIndirection,/* OUT */ + unsigned* isRelative /* OUT */ ) { jitInstance->mc->cr->AddCall("getMethodVTableOffset"); - jitInstance->mc->repGetMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection); + jitInstance->mc->repGetMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); } // Find the virtual method in implementingClass that overrides virtualMethod. diff --git a/src/coreclr/src/debug/daccess/nidump.cpp b/src/coreclr/src/debug/daccess/nidump.cpp index 0d948dd..64c86e3 100644 --- a/src/coreclr/src/debug/daccess/nidump.cpp +++ b/src/coreclr/src/debug/daccess/nidump.cpp @@ -7188,9 +7188,9 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name, { m_display->StartStructureWithOffset("Vtable", mt->GetVtableOffset(), - mt->GetNumVtableIndirections() * sizeof(PTR_PCODE), + mt->GetNumVtableIndirections() * sizeof(MethodTable::VTableIndir_t), DataPtrToDisplay(PTR_TO_TADDR(mt) + mt->GetVtableOffset()), - mt->GetNumVtableIndirections() * sizeof(PTR_PCODE)); + mt->GetNumVtableIndirections() * sizeof(MethodTable::VTableIndir_t)); MethodTable::VtableIndirectionSlotIterator itIndirect = mt->IterateVtableIndirectionSlots(); @@ -7209,7 +7209,8 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name, { DisplayStartElement( "Slot", ALWAYS ); DisplayWriteElementInt( "Index", i, ALWAYS ); - PTR_PCODE tgt = mt->GetVtableIndirections()[i]; + TADDR base = dac_cast(&(mt->GetVtableIndirections()[i])); + PTR_PCODE tgt = MethodTable::VTableIndir_t::GetValueMaybeNullAtPtr(base); DisplayWriteElementPointer( "Pointer", DataPtrToDisplay(dac_cast(tgt)), ALWAYS ); @@ -7245,7 +7246,7 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name, else { CoverageRead( PTR_TO_TADDR(mt) + mt->GetVtableOffset(), - mt->GetNumVtableIndirections() * sizeof(PTR_PCODE) ); + mt->GetNumVtableIndirections() * sizeof(MethodTable::VTableIndir_t) ); if (mt->HasNonVirtualSlotsArray()) { diff --git a/src/coreclr/src/inc/corinfo.h b/src/coreclr/src/inc/corinfo.h index 9c2e08b3..479b8ed 100644 --- a/src/coreclr/src/inc/corinfo.h +++ b/src/coreclr/src/inc/corinfo.h @@ -2069,7 +2069,8 @@ public: virtual void getMethodVTableOffset ( CORINFO_METHOD_HANDLE method, /* IN */ unsigned* offsetOfIndirection, /* OUT */ - unsigned* offsetAfterIndirection /* OUT */ + unsigned* offsetAfterIndirection, /* OUT */ + unsigned* isRelative /* OUT */ ) = 0; // Find the virtual method in implementingClass that overrides virtualMethod, diff --git a/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp index b9fd876..2c34554 100644 --- a/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp @@ -122,10 +122,11 @@ CORINFO_MODULE_HANDLE WrapICorJitInfo::getMethodModule( void WrapICorJitInfo::getMethodVTableOffset( CORINFO_METHOD_HANDLE method, /* IN */ unsigned* offsetOfIndirection, /* OUT */ - unsigned* offsetAfterIndirection /* OUT */) + unsigned* offsetAfterIndirection, /* OUT */ + unsigned* isRelative /* OUT */) { API_ENTER(getMethodVTableOffset); - wrapHnd->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection); + wrapHnd->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); API_LEAVE(getMethodVTableOffset); } diff --git a/src/coreclr/src/jit/codegenlegacy.cpp b/src/coreclr/src/jit/codegenlegacy.cpp index b2a5a87..65095bd 100644 --- a/src/coreclr/src/jit/codegenlegacy.cpp +++ b/src/coreclr/src/jit/codegenlegacy.cpp @@ -18849,29 +18849,48 @@ regMaskTP CodeGen::genCodeForCall(GenTreeCall* call, bool valUsed) // stub dispatching is off or this is not a virtual call (could be a tailcall) { regNumber vptrReg; + regNumber vptrReg1; + regMaskTP vptrMask1; unsigned vtabOffsOfIndirection; unsigned vtabOffsAfterIndirection; + unsigned isRelative; noway_assert(callType == CT_USER_FUNC); + /* Get hold of the vtable offset (note: this might be expensive) */ + + compiler->info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection, + &vtabOffsAfterIndirection, &isRelative); + vptrReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection vptrMask = genRegMask(vptrReg); + if (isRelative) + { + vptrReg1 = regSet.rsGrabReg(RBM_ALLINT & ~vptrMask); + vptrMask1 = genRegMask(vptrReg1); + } + /* The register no longer holds a live pointer value */ gcInfo.gcMarkRegSetNpt(vptrMask); + if (isRelative) + { + gcInfo.gcMarkRegSetNpt(vptrMask1); + } + // MOV vptrReg, [REG_CALL_THIS + offs] getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, genGetThisArgReg(call), VPTR_OFFS); regTracker.rsTrackRegTrash(vptrReg); - noway_assert(vptrMask & ~call->gtCallRegUsedMask); - - /* Get hold of the vtable offset (note: this might be expensive) */ + if (isRelative) + { + regTracker.rsTrackRegTrash(vptrReg1); + } - compiler->info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection, - &vtabOffsAfterIndirection); + noway_assert(vptrMask & ~call->gtCallRegUsedMask); /* The register no longer holds a live pointer value */ gcInfo.gcMarkRegSetNpt(vptrMask); @@ -18880,25 +18899,61 @@ regMaskTP CodeGen::genCodeForCall(GenTreeCall* call, bool valUsed) if (vtabOffsOfIndirection != CORINFO_VIRTUALCALL_NO_CHUNK) { + if (isRelative) + { +#if defined(_TARGET_ARM_) + unsigned offset = vtabOffsOfIndirection + vtabOffsAfterIndirection; + + // ADD vptrReg1, REG_CALL_IND_SCRATCH, vtabOffsOfIndirection + vtabOffsAfterIndirection + getEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, vptrReg1, vptrReg, offset); +#else + _ASSERTE(false); +#endif + } + // MOV vptrReg, [REG_CALL_IND_SCRATCH + vtabOffsOfIndirection] getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg, vtabOffsOfIndirection); } + else + { + _ASSERTE(!isRelative); + } /* Call through the appropriate vtable slot */ if (fTailCall) { - /* Load the function address: "[vptrReg+vtabOffs] -> reg_intret" */ - - getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_TAILCALL_ADDR, vptrReg, - vtabOffsAfterIndirection); + if (isRelative) + { +#if defined(_TARGET_ARM_) + /* Load the function address: "[vptrReg1 + vptrReg] -> reg_intret" */ + getEmitter()->emitIns_R_ARR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_TAILCALL_ADDR, vptrReg1, + vptrReg, 0); +#else + _ASSERTE(false); +#endif + } + else + { + /* Load the function address: "[vptrReg+vtabOffs] -> reg_intret" */ + getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_TAILCALL_ADDR, vptrReg, + vtabOffsAfterIndirection); + } } else { #if CPU_LOAD_STORE_ARCH - getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg, - vtabOffsAfterIndirection); + if (isRelative) + { + getEmitter()->emitIns_R_ARR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg1, vptrReg, + 0); + } + else + { + getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg, + vtabOffsAfterIndirection); + } getEmitter()->emitIns_Call(emitter::EC_INDIR_R, call->gtCallMethHnd, INDEBUG_LDISASM_COMMA(sigInfo) NULL, // addr @@ -18906,6 +18961,7 @@ regMaskTP CodeGen::genCodeForCall(GenTreeCall* call, bool valUsed) gcInfo.gcRegByrefSetCur, ilOffset, vptrReg); // ireg #else + _ASSERTE(!isRelative); getEmitter()->emitIns_Call(emitter::EC_FUNC_VIRTUAL, call->gtCallMethHnd, INDEBUG_LDISASM_COMMA(sigInfo) NULL, // addr args, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, diff --git a/src/coreclr/src/jit/emitarm.cpp b/src/coreclr/src/jit/emitarm.cpp index a0c7196..2928d99 100644 --- a/src/coreclr/src/jit/emitarm.cpp +++ b/src/coreclr/src/jit/emitarm.cpp @@ -2459,6 +2459,16 @@ void emitter::emitIns_R_R_I(instruction ins, fmt = IF_T2_M0; sf = INS_FLAGS_NOT_SET; } + else if (insDoesNotSetFlags(flags) && reg1 != REG_SP && reg1 != REG_PC) + { + // movw,movt reg1, imm + codeGen->instGen_Set_Reg_To_Imm(attr, reg1, imm); + + // ins reg1, reg2 + emitIns_R_R(ins, attr, reg1, reg2); + + return; + } else { assert(!"Instruction cannot be encoded"); diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index 09a5919..0752872 100644 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -3458,6 +3458,13 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call) // We'll introduce another use of this local so increase its ref count. comp->lvaTable[lclNum].incRefCnts(comp->compCurBB->getBBWeight(comp), comp); + // Get hold of the vtable offset (note: this might be expensive) + unsigned vtabOffsOfIndirection; + unsigned vtabOffsAfterIndirection; + unsigned isRelative; + comp->info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection, + &vtabOffsAfterIndirection, &isRelative); + // If the thisPtr is a local field, then construct a local field type node GenTree* local; if (thisPtr->isLclField()) @@ -3473,22 +3480,47 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call) // pointer to virtual table = [REG_CALL_THIS + offs] GenTree* result = Ind(Offset(local, VPTR_OFFS)); - // Get hold of the vtable offset (note: this might be expensive) - unsigned vtabOffsOfIndirection; - unsigned vtabOffsAfterIndirection; - comp->info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection, - &vtabOffsAfterIndirection); - // Get the appropriate vtable chunk if (vtabOffsOfIndirection != CORINFO_VIRTUALCALL_NO_CHUNK) { - // result = [REG_CALL_IND_SCRATCH + vtabOffsOfIndirection] - result = Ind(Offset(result, vtabOffsOfIndirection)); + if (isRelative) + { + unsigned lclNumTmp = comp->lvaGrabTemp(true DEBUGARG("lclNumTmp")); + + comp->lvaTable[lclNumTmp].incRefCnts(comp->compCurBB->getBBWeight(comp), comp); + GenTree* lclvNodeStore = comp->gtNewTempAssign(lclNumTmp, result); + + LIR::Range range = LIR::SeqTree(comp, lclvNodeStore); + JITDUMP("results of lowering call interm:\n"); + DISPRANGE(range); + BlockRange().InsertBefore(call, std::move(range)); + + GenTree* tmpTree = comp->gtNewLclvNode(lclNumTmp, result->TypeGet()); + tmpTree = Offset(tmpTree, vtabOffsOfIndirection); + + tmpTree = comp->gtNewOperNode(GT_IND, TYP_I_IMPL, tmpTree, false); + GenTree* offs = comp->gtNewIconNode(vtabOffsOfIndirection + vtabOffsAfterIndirection, TYP_INT); + result = comp->gtNewOperNode(GT_ADD, TYP_I_IMPL, comp->gtNewLclvNode(lclNumTmp, result->TypeGet()), offs); + + result = Ind(OffsetByIndex(result, tmpTree)); + } + else + { + // result = [REG_CALL_IND_SCRATCH + vtabOffsOfIndirection] + result = Ind(Offset(result, vtabOffsOfIndirection)); + } + } + else + { + _ASSERTE(!isRelative); } // Load the function address // result = [reg+vtabOffs] - result = Ind(Offset(result, vtabOffsAfterIndirection)); + if (!isRelative) + { + result = Ind(Offset(result, vtabOffsAfterIndirection)); + } return result; } diff --git a/src/coreclr/src/jit/lower.h b/src/coreclr/src/jit/lower.h index 76cf481..8422e28 100644 --- a/src/coreclr/src/jit/lower.h +++ b/src/coreclr/src/jit/lower.h @@ -120,6 +120,12 @@ private: return new (comp, GT_LEA) GenTreeAddrMode(resultType, base, nullptr, 0, offset); } + GenTree* OffsetByIndex(GenTree* base, GenTree* index) + { + var_types resultType = (base->TypeGet() == TYP_REF) ? TYP_BYREF : base->TypeGet(); + return new (comp, GT_LEA) GenTreeAddrMode(resultType, base, index, 0, 0); + } + // returns true if the tree can use the read-modify-write memory instruction form bool isRMWRegOper(GenTreePtr tree); diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index d055973..40b609a 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -7170,14 +7170,30 @@ void Compiler::fgMorphTailCall(GenTreeCall* call) unsigned vtabOffsOfIndirection; unsigned vtabOffsAfterIndirection; - info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection, &vtabOffsAfterIndirection); + unsigned isRelative; + info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection, &vtabOffsAfterIndirection, + &isRelative); /* Get the appropriate vtable chunk */ if (vtabOffsOfIndirection != CORINFO_VIRTUALCALL_NO_CHUNK) { - add = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsOfIndirection, TYP_I_IMPL)); + add = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsOfIndirection, TYP_I_IMPL)); + + GenTreePtr indOffTree; + + if (isRelative) + { + indOffTree = impCloneExpr(add, &add, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("virtual table call")); + } + vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add); + + if (isRelative) + { + vtbl = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, indOffTree); + } } /* Now the appropriate vtable slot */ diff --git a/src/coreclr/src/vm/array.cpp b/src/coreclr/src/vm/array.cpp index 3f5a8aa..3a33aff 100644 --- a/src/coreclr/src/vm/array.cpp +++ b/src/coreclr/src/vm/array.cpp @@ -310,7 +310,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy DWORD numNonVirtualSlots = numCtors + 3; // 3 for the proper rank Get, Set, Address size_t cbMT = sizeof(MethodTable); - cbMT += MethodTable::GetNumVtableIndirections(numVirtuals) * sizeof(PTR_PCODE); + cbMT += MethodTable::GetNumVtableIndirections(numVirtuals) * sizeof(MethodTable::VTableIndir_t); // GC info size_t cbCGCDescData = 0; @@ -539,7 +539,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy if (canShareVtableChunks) { // Share the parent chunk - it.SetIndirectionSlot(pParentClass->GetVtableIndirections()[it.GetIndex()]); + it.SetIndirectionSlot(pParentClass->GetVtableIndirections()[it.GetIndex()].GetValueMaybeNull()); } else { diff --git a/src/coreclr/src/vm/generics.cpp b/src/coreclr/src/vm/generics.cpp index 1a182da..ed53132 100644 --- a/src/coreclr/src/vm/generics.cpp +++ b/src/coreclr/src/vm/generics.cpp @@ -255,7 +255,7 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation( // Bytes are required for the vtable itself S_SIZE_T safe_cbMT = S_SIZE_T( cbGC ) + S_SIZE_T( sizeof(MethodTable) ); - safe_cbMT += MethodTable::GetNumVtableIndirections(cSlots) * sizeof(PTR_PCODE); + safe_cbMT += MethodTable::GetNumVtableIndirections(cSlots) * sizeof(MethodTable::VTableIndir_t); if (safe_cbMT.IsOverflow()) { ThrowHR(COR_E_OVERFLOW); @@ -440,7 +440,7 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation( if (canShareVtableChunks) { // Share the canonical chunk - it.SetIndirectionSlot(pOldMT->GetVtableIndirections()[it.GetIndex()]); + it.SetIndirectionSlot(pOldMT->GetVtableIndirections()[it.GetIndex()].GetValueMaybeNull()); } else { diff --git a/src/coreclr/src/vm/jitinterface.cpp b/src/coreclr/src/vm/jitinterface.cpp index 67e3656..11b1b18 100644 --- a/src/coreclr/src/vm/jitinterface.cpp +++ b/src/coreclr/src/vm/jitinterface.cpp @@ -8586,7 +8586,8 @@ CONTRACTL { /*********************************************************************/ void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd, unsigned * pOffsetOfIndirection, - unsigned * pOffsetAfterIndirection) + unsigned * pOffsetAfterIndirection, + unsigned * isRelative) { CONTRACTL { SO_TOLERANT; @@ -8607,8 +8608,9 @@ void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd, // better be in the vtable _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals()); - *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * sizeof(PTR_PCODE); + *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * sizeof(MethodTable::VTableIndir_t); *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * sizeof(PCODE); + *isRelative = MethodTable::VTableIndir_t::isRelative ? 1 : 0; EE_TO_JIT_TRANSITION_LEAF(); } diff --git a/src/coreclr/src/vm/jitinterface.h b/src/coreclr/src/vm/jitinterface.h index e34b859..cbb24e0 100644 --- a/src/coreclr/src/vm/jitinterface.h +++ b/src/coreclr/src/vm/jitinterface.h @@ -727,8 +727,8 @@ public: void getMethodVTableOffset ( CORINFO_METHOD_HANDLE methodHnd, unsigned * pOffsetOfIndirection, - unsigned * pOffsetAfterIndirection - ); + unsigned * pOffsetAfterIndirection, + unsigned * isRelative); CORINFO_METHOD_HANDLE resolveVirtualMethod( CORINFO_METHOD_HANDLE virtualMethod, diff --git a/src/coreclr/src/vm/methodtable.cpp b/src/coreclr/src/vm/methodtable.cpp index cf24f19..98c13eb 100644 --- a/src/coreclr/src/vm/methodtable.cpp +++ b/src/coreclr/src/vm/methodtable.cpp @@ -4928,7 +4928,14 @@ void MethodTable::Fixup(DataImage *image) VtableIndirectionSlotIterator it = IterateVtableIndirectionSlots(); while (it.Next()) { - image->FixupPointerField(this, it.GetOffsetFromMethodTable()); + if (VTableIndir_t::isRelative) + { + image->FixupRelativePointerField(this, it.GetOffsetFromMethodTable()); + } + else + { + image->FixupPointerField(this, it.GetOffsetFromMethodTable()); + } } } @@ -4949,7 +4956,7 @@ void MethodTable::Fixup(DataImage *image) { // Virtual slots live in chunks pointed to by vtable indirections - slotBase = (PVOID) GetVtableIndirections()[GetIndexOfVtableIndirection(slotNumber)]; + slotBase = (PVOID) GetVtableIndirections()[GetIndexOfVtableIndirection(slotNumber)].GetValueMaybeNull(); slotOffset = GetIndexAfterVtableIndirection(slotNumber) * sizeof(PCODE); } else if (HasSingleNonVirtualSlot()) @@ -9422,13 +9429,13 @@ void MethodTable::SetSlot(UINT32 slotNumber, PCODE slotCode) if (!IsCanonicalMethodTable()) { - if (GetVtableIndirections()[indirectionIndex] == GetCanonicalMethodTable()->GetVtableIndirections()[indirectionIndex]) + if (GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() == GetCanonicalMethodTable()->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull()) fSharedVtableChunk = TRUE; } if (slotNumber < GetNumParentVirtuals()) { - if (GetVtableIndirections()[indirectionIndex] == GetParentMethodTable()->GetVtableIndirections()[indirectionIndex]) + if (GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() == GetParentMethodTable()->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull()) fSharedVtableChunk = TRUE; } diff --git a/src/coreclr/src/vm/methodtable.h b/src/coreclr/src/vm/methodtable.h index 770dda4..77ec9f5 100644 --- a/src/coreclr/src/vm/methodtable.h +++ b/src/coreclr/src/vm/methodtable.h @@ -1513,7 +1513,10 @@ public: CONSISTENCY_CHECK(slotNum < GetNumVirtuals()); // Virtual slots live in chunks pointed to by vtable indirections - return *(GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum)); + + DWORD index = GetIndexOfVtableIndirection(slotNum); + TADDR base = dac_cast(&(GetVtableIndirections()[index])); + return *(VTableIndir_t::GetValueMaybeNullAtPtr(base) + GetIndexAfterVtableIndirection(slotNum)); } PTR_PCODE GetSlotPtrRaw(UINT32 slotNum) @@ -1525,7 +1528,9 @@ public: if (slotNum < GetNumVirtuals()) { // Virtual slots live in chunks pointed to by vtable indirections - return GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum); + DWORD index = GetIndexOfVtableIndirection(slotNum); + TADDR base = dac_cast(&(GetVtableIndirections()[index])); + return VTableIndir_t::GetValueMaybeNullAtPtr(base) + GetIndexAfterVtableIndirection(slotNum); } else if (HasSingleNonVirtualSlot()) { @@ -1609,12 +1614,18 @@ public: #define VTABLE_SLOTS_PER_CHUNK 8 #define VTABLE_SLOTS_PER_CHUNK_LOG2 3 +#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_) + typedef RelativePointer VTableIndir_t; +#else + typedef PlainPointer VTableIndir_t; +#endif + static DWORD GetIndexOfVtableIndirection(DWORD slotNum); static DWORD GetStartSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals); static DWORD GetEndSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals); static UINT32 GetIndexAfterVtableIndirection(UINT32 slotNum); static DWORD GetNumVtableIndirections(DWORD wNumVirtuals); - PTR_PTR_PCODE GetVtableIndirections(); + DPTR(VTableIndir_t) GetVtableIndirections(); DWORD GetNumVtableIndirections(); class VtableIndirectionSlotIterator @@ -1622,7 +1633,7 @@ public: friend class MethodTable; private: - PTR_PTR_PCODE m_pSlot; + DPTR(VTableIndir_t) m_pSlot; DWORD m_i; DWORD m_count; PTR_MethodTable m_pMT; diff --git a/src/coreclr/src/vm/methodtable.inl b/src/coreclr/src/vm/methodtable.inl index b69513d..0d0acda 100644 --- a/src/coreclr/src/vm/methodtable.inl +++ b/src/coreclr/src/vm/methodtable.inl @@ -887,10 +887,10 @@ inline DWORD MethodTable::GetNumVtableIndirections(DWORD wNumVirtuals) } //========================================================================================== -inline PTR_PTR_PCODE MethodTable::GetVtableIndirections() +inline DPTR(MethodTable::VTableIndir_t) MethodTable::GetVtableIndirections() { LIMITED_METHOD_DAC_CONTRACT; - return dac_cast(dac_cast(this) + sizeof(MethodTable)); + return dac_cast(dac_cast(this) + sizeof(MethodTable)); } //========================================================================================== @@ -952,7 +952,7 @@ inline DWORD MethodTable::VtableIndirectionSlotIterator::GetOffsetFromMethodTabl WRAPPER_NO_CONTRACT; PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); - return GetVtableOffset() + sizeof(PTR_PCODE) * m_i; + return GetVtableOffset() + sizeof(VTableIndir_t) * m_i; } //========================================================================================== @@ -961,7 +961,7 @@ inline PTR_PCODE MethodTable::VtableIndirectionSlotIterator::GetIndirectionSlot( LIMITED_METHOD_DAC_CONTRACT; PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); - return *m_pSlot; + return m_pSlot->GetValueMaybeNull(dac_cast(m_pSlot)); } //========================================================================================== @@ -969,7 +969,7 @@ inline PTR_PCODE MethodTable::VtableIndirectionSlotIterator::GetIndirectionSlot( inline void MethodTable::VtableIndirectionSlotIterator::SetIndirectionSlot(PTR_PCODE pChunk) { LIMITED_METHOD_CONTRACT; - *m_pSlot = pChunk; + m_pSlot->SetValueMaybeNull(pChunk); } #endif @@ -1355,7 +1355,7 @@ FORCEINLINE TADDR MethodTable::GetMultipurposeSlotPtr(WFLAGS2_ENUM flag, const B DWORD offset = offsets[GetFlag((WFLAGS2_ENUM)(flag - 1))]; if (offset >= sizeof(MethodTable)) { - offset += GetNumVtableIndirections() * sizeof(PTR_PCODE); + offset += GetNumVtableIndirections() * sizeof(VTableIndir_t); } return dac_cast(this) + offset; @@ -1370,7 +1370,7 @@ FORCEINLINE DWORD MethodTable::GetOffsetOfOptionalMember(OptionalMemberId id) DWORD offset = c_OptionalMembersStartOffsets[GetFlag(enum_flag_MultipurposeSlotsMask)]; - offset += GetNumVtableIndirections() * sizeof(PTR_PCODE); + offset += GetNumVtableIndirections() * sizeof(VTableIndir_t); #undef METHODTABLE_OPTIONAL_MEMBER #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) \ diff --git a/src/coreclr/src/vm/methodtablebuilder.cpp b/src/coreclr/src/vm/methodtablebuilder.cpp index d7e9818..71248aa 100644 --- a/src/coreclr/src/vm/methodtablebuilder.cpp +++ b/src/coreclr/src/vm/methodtablebuilder.cpp @@ -8903,7 +8903,7 @@ void MethodTableBuilder::CopyExactParentSlots(MethodTable *pMT, MethodTable *pAp // // Non-canonical method tables either share everything or nothing so it is sufficient to check // just the first indirection to detect sharing. - if (pMT->GetVtableIndirections()[0] != pCanonMT->GetVtableIndirections()[0]) + if (pMT->GetVtableIndirections()[0].GetValueMaybeNull() != pCanonMT->GetVtableIndirections()[0].GetValueMaybeNull()) { for (DWORD i = 0; i < nParentVirtuals; i++) { @@ -8930,7 +8930,7 @@ void MethodTableBuilder::CopyExactParentSlots(MethodTable *pMT, MethodTable *pAp // We need to re-inherit this slot from the exact parent. DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(i); - if (pMT->GetVtableIndirections()[indirectionIndex] == pApproxParentMT->GetVtableIndirections()[indirectionIndex]) + if (pMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() == pApproxParentMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull()) { // The slot lives in a chunk shared from the approximate parent MT // If so, we need to change to share the chunk from the exact parent MT @@ -8941,7 +8941,7 @@ void MethodTableBuilder::CopyExactParentSlots(MethodTable *pMT, MethodTable *pAp _ASSERTE(MethodTable::CanShareVtableChunksFrom(pParentMT, pMT->GetLoaderModule())); #endif - pMT->GetVtableIndirections()[indirectionIndex] = pParentMT->GetVtableIndirections()[indirectionIndex]; + pMT->GetVtableIndirections()[indirectionIndex].SetValueMaybeNull(pParentMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull()); i = MethodTable::GetEndSlotForVtableIndirection(indirectionIndex, nParentVirtuals) - 1; continue; @@ -9798,7 +9798,7 @@ MethodTable * MethodTableBuilder::AllocateNewMT(Module *pLoaderModule, S_SIZE_T cbTotalSize = S_SIZE_T(dwGCSize) + S_SIZE_T(sizeof(MethodTable)); // vtable - cbTotalSize += MethodTable::GetNumVtableIndirections(dwVirtuals) * sizeof(PTR_PCODE); + cbTotalSize += MethodTable::GetNumVtableIndirections(dwVirtuals) * sizeof(MethodTable::VTableIndir_t); DWORD dwMultipurposeSlotsMask = 0; @@ -9947,7 +9947,7 @@ MethodTable * MethodTableBuilder::AllocateNewMT(Module *pLoaderModule, { // Share the parent chunk _ASSERTE(it.GetEndSlot() <= pMTParent->GetNumVirtuals()); - it.SetIndirectionSlot(pMTParent->GetVtableIndirections()[it.GetIndex()]); + it.SetIndirectionSlot(pMTParent->GetVtableIndirections()[it.GetIndex()].GetValueMaybeNull()); } else { @@ -10497,7 +10497,7 @@ MethodTableBuilder::SetupMethodTable2( // with code:MethodDesc::SetStableEntryPointInterlocked. // DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(iCurSlot); - if (GetParentMethodTable()->GetVtableIndirections()[indirectionIndex] != pMT->GetVtableIndirections()[indirectionIndex]) + if (GetParentMethodTable()->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() != pMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull()) pMT->SetSlot(iCurSlot, pMD->GetMethodEntryPoint()); } else diff --git a/src/coreclr/src/zap/zapinfo.cpp b/src/coreclr/src/zap/zapinfo.cpp index 5616212..2f38523 100644 --- a/src/coreclr/src/zap/zapinfo.cpp +++ b/src/coreclr/src/zap/zapinfo.cpp @@ -3702,10 +3702,11 @@ CORINFO_MODULE_HANDLE ZapInfo::getMethodModule(CORINFO_METHOD_HANDLE method) } void ZapInfo::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, - unsigned * pOffsetOfIndirection, - unsigned * pOffsetAfterIndirection) + unsigned * pOffsetOfIndirection, + unsigned * pOffsetAfterIndirection, + unsigned * isRelative) { - m_pEEJitInfo->getMethodVTableOffset(method, pOffsetOfIndirection, pOffsetAfterIndirection); + m_pEEJitInfo->getMethodVTableOffset(method, pOffsetOfIndirection, pOffsetAfterIndirection, isRelative); } CORINFO_METHOD_HANDLE ZapInfo::resolveVirtualMethod( diff --git a/src/coreclr/src/zap/zapinfo.h b/src/coreclr/src/zap/zapinfo.h index 44ad5de..24ca895 100644 --- a/src/coreclr/src/zap/zapinfo.h +++ b/src/coreclr/src/zap/zapinfo.h @@ -662,7 +662,8 @@ public: void getMethodVTableOffset(CORINFO_METHOD_HANDLE method, unsigned * pOffsetOfIndirection, - unsigned * pOffsetAfterIndirection); + unsigned * pOffsetAfterIndirection, + unsigned * isRelative); CORINFO_METHOD_HANDLE resolveVirtualMethod( CORINFO_METHOD_HANDLE virtualMethod, -- 2.7.4