From 3bf76a8bc479dd90c9f2f75d8941445c2a5ea2b2 Mon Sep 17 00:00:00 2001 From: Gleb Balykov Date: Fri, 23 Jun 2017 15:48:48 +0300 Subject: [PATCH 25/32] Remove relocations for MethodTable's vtable-1st-level-indirection FIX: fix No.5, rebased --- .../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/debug/daccess/nidump.cpp | 9 +-- src/inc/corinfo.h | 3 +- src/jit/ICorJitInfo_API_wrapper.hpp | 5 +- src/jit/codegenlegacy.cpp | 76 ++++++++++++++++++---- src/jit/emitarm.cpp | 10 +++ src/jit/lower.cpp | 46 ++++++++++--- src/jit/lower.h | 6 ++ src/jit/morph.cpp | 20 +++++- src/vm/array.cpp | 4 +- src/vm/generics.cpp | 4 +- src/vm/jitinterface.cpp | 6 +- src/vm/jitinterface.h | 4 +- src/vm/methodtable.cpp | 15 +++-- src/vm/methodtable.h | 19 ++++-- src/vm/methodtable.inl | 14 ++-- src/vm/methodtablebuilder.cpp | 12 ++-- src/zap/zapinfo.cpp | 7 +- src/zap/zapinfo.h | 3 +- 26 files changed, 238 insertions(+), 82 deletions(-) diff --git a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h index 19feffa..44b81aa 100644 --- a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h +++ b/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/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/ToolBox/superpmi/superpmi-shared/lwmlist.h index 6e5f016..6b33681 100644 --- a/src/ToolBox/superpmi/superpmi-shared/lwmlist.h +++ b/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/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index 4406b85..f4130e9 100644 --- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -3382,26 +3382,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); @@ -3411,6 +3414,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/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h index 53227e4..a8612b5 100644 --- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -206,6 +206,12 @@ public: DWORD A; DWORD B; }; + struct DDD + { + DWORD A; + DWORD B; + DWORD C; + }; struct Agnostic_CanTailCall { DWORDLONG callerHnd; @@ -774,11 +780,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/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 4741cf1..1f81883 100644 --- a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/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/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp index 1d45229..5c2e784 100644 --- a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/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/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp index aca7536..df223f4 100644 --- a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/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/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp index 59ad3c5..dc73a75 100644 --- a/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp +++ b/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/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp index d43e9f9..2732c9e 100644 --- a/src/debug/daccess/nidump.cpp +++ b/src/debug/daccess/nidump.cpp @@ -7230,9 +7230,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(); @@ -7251,7 +7251,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 ); @@ -7287,7 +7288,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/inc/corinfo.h b/src/inc/corinfo.h index 58fcdf4..2b1d3a9 100644 --- a/src/inc/corinfo.h +++ b/src/inc/corinfo.h @@ -2067,7 +2067,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/jit/ICorJitInfo_API_wrapper.hpp b/src/jit/ICorJitInfo_API_wrapper.hpp index a3ad211..8e0d1df 100644 --- a/src/jit/ICorJitInfo_API_wrapper.hpp +++ b/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/jit/codegenlegacy.cpp b/src/jit/codegenlegacy.cpp index 178be54..a925c97 100644 --- a/src/jit/codegenlegacy.cpp +++ b/src/jit/codegenlegacy.cpp @@ -18886,35 +18886,68 @@ 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); /* Get the appropriate vtable chunk */ /* The register no longer holds a live pointer value */ gcInfo.gcMarkRegSetNpt(vptrMask); + /* Get the appropriate vtable 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); @@ -18923,16 +18956,36 @@ regMaskTP CodeGen::genCodeForCall(GenTreeCall* call, bool valUsed) 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 @@ -18940,6 +18993,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/jit/emitarm.cpp b/src/jit/emitarm.cpp index 9ec8e07..e765af7 100644 --- a/src/jit/emitarm.cpp +++ b/src/jit/emitarm.cpp @@ -2446,6 +2446,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/jit/lower.cpp b/src/jit/lower.cpp index 9cab5ee..d154f68 100644 --- a/src/jit/lower.cpp +++ b/src/jit/lower.cpp @@ -3401,6 +3401,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()) @@ -3416,19 +3423,40 @@ 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 - // 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)); + } // 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/jit/lower.h b/src/jit/lower.h index 5a55d2d..92d9cfe 100644 --- a/src/jit/lower.h +++ b/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/jit/morph.cpp b/src/jit/morph.cpp index 3475889..c5d1ff2 100644 --- a/src/jit/morph.cpp +++ b/src/jit/morph.cpp @@ -7116,13 +7116,29 @@ 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 */ - 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 */ add = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsAfterIndirection, TYP_I_IMPL)); diff --git a/src/vm/array.cpp b/src/vm/array.cpp index 3f5a8aa..3a33aff 100644 --- a/src/vm/array.cpp +++ b/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/vm/generics.cpp b/src/vm/generics.cpp index 650caef..b110184 100644 --- a/src/vm/generics.cpp +++ b/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/vm/jitinterface.cpp b/src/vm/jitinterface.cpp index e0adf87..72f4131 100644 --- a/src/vm/jitinterface.cpp +++ b/src/vm/jitinterface.cpp @@ -8724,7 +8724,8 @@ CONTRACTL { /*********************************************************************/ void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd, unsigned * pOffsetOfIndirection, - unsigned * pOffsetAfterIndirection) + unsigned * pOffsetAfterIndirection, + unsigned * isRelative) { CONTRACTL { SO_TOLERANT; @@ -8745,8 +8746,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/vm/jitinterface.h b/src/vm/jitinterface.h index d67cfc5..cf1097c 100644 --- a/src/vm/jitinterface.h +++ b/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/vm/methodtable.cpp b/src/vm/methodtable.cpp index 4c1746e..75db911 100644 --- a/src/vm/methodtable.cpp +++ b/src/vm/methodtable.cpp @@ -4915,7 +4915,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()); + } } } @@ -4936,7 +4943,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()) @@ -9414,13 +9421,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/vm/methodtable.h b/src/vm/methodtable.h index 81a9186..8c15d2e 100644 --- a/src/vm/methodtable.h +++ b/src/vm/methodtable.h @@ -1514,7 +1514,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) @@ -1526,7 +1529,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()) { @@ -1610,12 +1615,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 @@ -1623,7 +1634,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/vm/methodtable.inl b/src/vm/methodtable.inl index b69513d..0d0acda 100644 --- a/src/vm/methodtable.inl +++ b/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/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp index 792a19c..970166d 100644 --- a/src/vm/methodtablebuilder.cpp +++ b/src/vm/methodtablebuilder.cpp @@ -9111,7 +9111,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++) { @@ -9138,7 +9138,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 @@ -9149,7 +9149,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; @@ -10006,7 +10006,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; @@ -10155,7 +10155,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 { @@ -10711,7 +10711,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/zap/zapinfo.cpp b/src/zap/zapinfo.cpp index e94dea6..507cc25 100644 --- a/src/zap/zapinfo.cpp +++ b/src/zap/zapinfo.cpp @@ -3708,10 +3708,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/zap/zapinfo.h b/src/zap/zapinfo.h index 6e83657..65c1ddd 100644 --- a/src/zap/zapinfo.h +++ b/src/zap/zapinfo.h @@ -663,7 +663,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