diff options
Diffstat (limited to 'packaging/0025-Remove-relocations-for-MethodTable-s-vtable-1st-leve.patch')
-rw-r--r-- | packaging/0025-Remove-relocations-for-MethodTable-s-vtable-1st-leve.patch | 901 |
1 files changed, 901 insertions, 0 deletions
diff --git a/packaging/0025-Remove-relocations-for-MethodTable-s-vtable-1st-leve.patch b/packaging/0025-Remove-relocations-for-MethodTable-s-vtable-1st-leve.patch new file mode 100644 index 0000000000..97f2ebbb84 --- /dev/null +++ b/packaging/0025-Remove-relocations-for-MethodTable-s-vtable-1st-leve.patch @@ -0,0 +1,901 @@ +From 3bf76a8bc479dd90c9f2f75d8941445c2a5ea2b2 Mon Sep 17 00:00:00 2001 +From: Gleb Balykov <g.balykov@samsung.com> +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<DWORDLONG, DD>(); ++ GetMethodVTableOffset = new LightWeightMap<DWORDLONG, DDD>(); + +- 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<TADDR>(&(mt->GetVtableIndirections()[i])); ++ PTR_PCODE tgt = MethodTable::VTableIndir_t::GetValueMaybeNullAtPtr(base); + DisplayWriteElementPointer( "Pointer", + DataPtrToDisplay(dac_cast<TADDR>(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<TADDR>(&(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<TADDR>(&(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<PTR_PCODE> VTableIndir_t; ++#else ++ typedef PlainPointer<PTR_PCODE> 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<PTR_PTR_PCODE>(dac_cast<TADDR>(this) + sizeof(MethodTable)); ++ return dac_cast<DPTR(VTableIndir_t)>(dac_cast<TADDR>(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<TADDR>(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<TADDR>(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 + |