Remove relocations for MethodTable's vtable-1st-level-indirection
authorGleb Balykov <g.balykov@samsung.com>
Fri, 23 Jun 2017 12:48:48 +0000 (15:48 +0300)
committerGleb Balykov <g.balykov@samsung.com>
Mon, 10 Jul 2017 13:37:05 +0000 (16:37 +0300)
Commit migrated from https://github.com/dotnet/coreclr/commit/c4c04ea45cda3194cdf2189d757b96602ea344ee

26 files changed:
src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
src/coreclr/src/debug/daccess/nidump.cpp
src/coreclr/src/inc/corinfo.h
src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp
src/coreclr/src/jit/codegenlegacy.cpp
src/coreclr/src/jit/emitarm.cpp
src/coreclr/src/jit/lower.cpp
src/coreclr/src/jit/lower.h
src/coreclr/src/jit/morph.cpp
src/coreclr/src/vm/array.cpp
src/coreclr/src/vm/generics.cpp
src/coreclr/src/vm/jitinterface.cpp
src/coreclr/src/vm/jitinterface.h
src/coreclr/src/vm/methodtable.cpp
src/coreclr/src/vm/methodtable.h
src/coreclr/src/vm/methodtable.inl
src/coreclr/src/vm/methodtablebuilder.cpp
src/coreclr/src/zap/zapinfo.cpp
src/coreclr/src/zap/zapinfo.h

index 00b5c1b..37103bd 100644 (file)
@@ -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.
index 23cdf70..349b6bf 100644 (file)
@@ -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)
index ed5799f..b13e720 100644 (file)
@@ -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));
 }
 
index aa5cd85..524b0dd 100644 (file)
@@ -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,
index 1ba0ed2..311b57f 100644 (file)
@@ -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.
index 6760800..cad7990 100644 (file)
@@ -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.
index b098eb6..7dc3e7e 100644 (file)
@@ -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.
index d88e352..b282a1f 100644 (file)
@@ -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.
index 0d948dd..64c86e3 100644 (file)
@@ -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())
             {
index 9c2e08b..479b8ed 100644 (file)
@@ -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,
index b9fd876..2c34554 100644 (file)
@@ -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);
 }
 
index b2a5a87..65095bd 100644 (file)
@@ -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,
index a0c7196..2928d99 100644 (file)
@@ -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");
index 09a5919..0752872 100644 (file)
@@ -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;
 }
index 76cf481..8422e28 100644 (file)
@@ -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);
 
index d055973..40b609a 100644 (file)
@@ -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 */
index 3f5a8aa..3a33aff 100644 (file)
@@ -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 
             {
index 1a182da..ed53132 100644 (file)
@@ -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
         {
index 67e3656..11b1b18 100644 (file)
@@ -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();
 }
index e34b859..cbb24e0 100644 (file)
@@ -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,
index cf24f19..98c13eb 100644 (file)
@@ -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;
         }
 
index 770dda4..77ec9f5 100644 (file)
@@ -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;
index b69513d..0d0acda 100644 (file)
@@ -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) \
index d7e9818..71248aa 100644 (file)
@@ -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
index 5616212..2f38523 100644 (file)
@@ -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(
index 44ad5de..24ca895 100644 (file)
@@ -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,