summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Balykov <g.balykov@samsung.com>2017-06-23 15:48:48 +0300
committerGleb Balykov <g.balykov@samsung.com>2017-07-10 16:37:05 +0300
commitc4c04ea45cda3194cdf2189d757b96602ea344ee (patch)
treee04539919b2ce293ec81397ab5715ea8455d69b9
parentcf1fb9e17fc8b6ee849edab5a696d0ec5c6eadd2 (diff)
downloadcoreclr-c4c04ea45cda3194cdf2189d757b96602ea344ee.tar.gz
coreclr-c4c04ea45cda3194cdf2189d757b96602ea344ee.tar.bz2
coreclr-c4c04ea45cda3194cdf2189d757b96602ea344ee.zip
Remove relocations for MethodTable's vtable-1st-level-indirection
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h3
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/lwmlist.h2
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp16
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.h14
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp7
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp5
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp5
-rw-r--r--src/ToolBox/superpmi/superpmi/icorjitinfo.cpp5
-rw-r--r--src/debug/daccess/nidump.cpp9
-rw-r--r--src/inc/corinfo.h3
-rw-r--r--src/jit/ICorJitInfo_API_wrapper.hpp5
-rw-r--r--src/jit/codegenlegacy.cpp78
-rw-r--r--src/jit/emitarm.cpp10
-rw-r--r--src/jit/lower.cpp50
-rw-r--r--src/jit/lower.h6
-rw-r--r--src/jit/morph.cpp20
-rw-r--r--src/vm/array.cpp4
-rw-r--r--src/vm/generics.cpp4
-rw-r--r--src/vm/jitinterface.cpp6
-rw-r--r--src/vm/jitinterface.h4
-rw-r--r--src/vm/methodtable.cpp15
-rw-r--r--src/vm/methodtable.h19
-rw-r--r--src/vm/methodtable.inl14
-rw-r--r--src/vm/methodtablebuilder.cpp12
-rw-r--r--src/zap/zapinfo.cpp7
-rw-r--r--src/zap/zapinfo.h3
26 files changed, 244 insertions, 82 deletions
diff --git a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
index 00b5c1b965..37103bd912 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 23cdf70922..349b6bf105 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 ed5799f710..b13e720ded 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+++ b/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<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);
@@ -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/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
index aa5cd85431..524b0dde70 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
+++ b/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/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
index 1ba0ed2a65..311b57ffc5 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 6760800d59..cad7990c44 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 b098eb6b46..7dc3e7e0d9 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 d88e35299a..b282a1f910 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 0d948ddf6c..64c86e305e 100644
--- a/src/debug/daccess/nidump.cpp
+++ b/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<TADDR>(&(mt->GetVtableIndirections()[i]));
+ PTR_PCODE tgt = MethodTable::VTableIndir_t::GetValueMaybeNullAtPtr(base);
DisplayWriteElementPointer( "Pointer",
DataPtrToDisplay(dac_cast<TADDR>(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/inc/corinfo.h b/src/inc/corinfo.h
index 9c2e08b373..479b8ed898 100644
--- a/src/inc/corinfo.h
+++ b/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/jit/ICorJitInfo_API_wrapper.hpp b/src/jit/ICorJitInfo_API_wrapper.hpp
index b9fd876995..2c345540cf 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 b2a5a87a39..65095bd5f1 100644
--- a/src/jit/codegenlegacy.cpp
+++ b/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/jit/emitarm.cpp b/src/jit/emitarm.cpp
index a0c7196ecb..2928d9957e 100644
--- a/src/jit/emitarm.cpp
+++ b/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/jit/lower.cpp b/src/jit/lower.cpp
index 09a59193b5..0752872339 100644
--- a/src/jit/lower.cpp
+++ b/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/jit/lower.h b/src/jit/lower.h
index 76cf481319..8422e280a3 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 d0559734c0..40b609a0c0 100644
--- a/src/jit/morph.cpp
+++ b/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/vm/array.cpp b/src/vm/array.cpp
index 3f5a8aab00..3a33aff43a 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 1a182da718..ed5313263f 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 67e36560fd..11b1b18143 100644
--- a/src/vm/jitinterface.cpp
+++ b/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/vm/jitinterface.h b/src/vm/jitinterface.h
index e34b859c3f..cbb24e0913 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 cf24f19239..98c13eba7c 100644
--- a/src/vm/methodtable.cpp
+++ b/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/vm/methodtable.h b/src/vm/methodtable.h
index 770dda4031..77ec9f51ea 100644
--- a/src/vm/methodtable.h
+++ b/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<TADDR>(&(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<TADDR>(&(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<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
@@ -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/vm/methodtable.inl b/src/vm/methodtable.inl
index b69513d662..0d0acda885 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 d7e9818888..71248aa897 100644
--- a/src/vm/methodtablebuilder.cpp
+++ b/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/zap/zapinfo.cpp b/src/zap/zapinfo.cpp
index 5616212f25..2f3852398c 100644
--- a/src/zap/zapinfo.cpp
+++ b/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/zap/zapinfo.h b/src/zap/zapinfo.h
index 44ad5de52d..24ca895b6d 100644
--- a/src/zap/zapinfo.h
+++ b/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,