[Tizen] Add RelativeFixupPrecode for arm64, which replaces FixupPrecode in FNV images accepted/tizen/unified/20200922.034817 submit/tizen/20200921.230336
authorGleb Balykov <g.balykov@samsung.com>
Mon, 14 Sep 2020 10:30:50 +0000 (13:30 +0300)
committerAlexander Soldatov/Platform Lab /SRR/Staff Engineer/Samsung Electronics <soldatov.a@samsung.com>
Mon, 21 Sep 2020 17:04:27 +0000 (20:04 +0300)
13 files changed:
src/debug/daccess/nidump.cpp
src/inc/daccess.h
src/inc/jithelpers.h
src/vm/arm64/asmconstants.h
src/vm/arm64/asmhelpers.S
src/vm/arm64/asmhelpers.asm
src/vm/arm64/cgencpu.h
src/vm/arm64/stubs.cpp
src/vm/method.cpp
src/vm/precode.cpp
src/vm/precode.h
src/vm/prestub.cpp
src/vm/stubmgr.cpp

index c750969..7812bd7 100644 (file)
@@ -3486,8 +3486,16 @@ size_t NativeImageDumper::TranslateSymbol(IXCLRDisassemblySupport *dis,
 #endif // HAS_NDIRECT_IMPORT_PRECODE
 #ifdef HAS_FIXUP_PRECODE
                 case PRECODE_FIXUP:
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+                    _ASSERTE(!"unreachable"); break;
+#else // HAS_RELATIVE_FIXUP_PRECODE
                     precodeName = "FixupPrecode"; break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #endif // HAS_FIXUP_PRECODE
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+                case PRECODE_RELATIVE_FIXUP:
+                    precodeName = "RelativeFixupPrecode"; break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #ifdef HAS_THISPTR_RETBUF_PRECODE
                 case PRECODE_THISPTR_RETBUF:
                     precodeName = "ThisPtrRetBufPrecode"; break;
@@ -7507,6 +7515,9 @@ void NativeImageDumper::DumpPrecode( PTR_Precode precode, PTR_Module module )
 #endif
 #ifdef HAS_FIXUP_PRECODE
     case PRECODE_FIXUP:
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+        _ASSERTE(!"unreachable"); break;
+#else // HAS_RELATIVE_FIXUP_PRECODE
         IF_OPT_AND(PRECODES, METHODDESCS)
         {
             PTR_FixupPrecode p( precode->AsFixupPrecode() );
@@ -7558,7 +7569,56 @@ void NativeImageDumper::DumpPrecode( PTR_Precode precode, PTR_Module module )
             DisplayEndStructure( ALWAYS ); //FixupPrecode
         }
         break;
-#endif
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+#endif // HAS_FIXUP_PRECODE
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    case PRECODE_RELATIVE_FIXUP:
+        IF_OPT_AND(PRECODES, METHODDESCS)
+        {
+            PTR_RelativeFixupPrecode p( precode->AsRelativeFixupPrecode() );
+            DisplayStartStructure( "RelativeFixupPrecode",
+                                   DPtrToPreferredAddr(p),
+                                   sizeof(*p),
+                                   ALWAYS );
+            PTR_MethodDesc precodeMD(p->GetMethodDesc());
+            {
+                DisplayWriteFieldInt( m_MethodDescChunkIndex,
+                                      p->m_MethodDescChunkIndex, RelativeFixupPrecode,
+                                      ALWAYS );
+                DisplayWriteFieldInt( m_PrecodeChunkIndex,
+                                      p->m_PrecodeChunkIndex, RelativeFixupPrecode,
+                                      ALWAYS );
+                if( p->m_PrecodeChunkIndex == 0 )
+                {
+                    //dump the location of the Base
+                    DisplayWriteElementAddress( "PrecodeChunkBase",
+                                                DataPtrToDisplay(p->GetBase()),
+                                                sizeof(void*), ALWAYS );
+                }
+                //Make sure I align up if there is no code slot to make
+                //sure that I get the padding
+                TADDR mdPtrStart = p->GetBase()
+                    + (p->m_MethodDescChunkIndex * MethodDesc::ALIGNMENT);
+                TADDR mdPtrEnd = ALIGN_UP( mdPtrStart + sizeof(MethodDesc*),
+                                           8 );
+                CoverageRead( mdPtrStart, (ULONG32)(mdPtrEnd - mdPtrStart) );
+                TADDR precodeMDSlot = p->GetBase()
+                    + p->m_MethodDescChunkIndex * MethodDesc::ALIGNMENT;
+                DoWriteFieldMethodDesc( "MethodDesc",
+                                        (DWORD)(precodeMDSlot - PTR_TO_TADDR(p)),
+                                        sizeof(TADDR), precodeMD );
+            }
+            TADDR target = p->GetTarget();
+            DisplayWriteElementPointer("Target",
+                                        DataPtrToDisplay(target),
+                                        ALWAYS );
+            /* REVISIT_TODO Thu 01/05/2006
+             * dump slot with offset if it is here
+             */
+            DisplayEndStructure( ALWAYS ); //RelativeFixupPrecode
+        }
+        break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #ifdef HAS_THISPTR_RETBUF_PRECODE
     case PRECODE_THISPTR_RETBUF:
         DISPLAY_PRECODE(ThisPtrRetBufPrecode); break;
index 802df17..eb0badf 100644 (file)
@@ -620,6 +620,7 @@ typedef struct _DacGlobals
 
     ULONG fn__ThePreStubPatchLabel;
     ULONG fn__PrecodeFixupThunk;
+    ULONG fn__PrecodeRelativeFixupThunk;
 #ifdef FEATURE_PREJIT
     ULONG fn__StubDispatchFixupStub;
     ULONG fn__StubDispatchFixupPatchLabel;
index d7d501f..59d938e 100644 (file)
     JITHELPER(CORINFO_HELP_EE_PRESTUB,          ThePreStub,                 CORINFO_HELP_SIG_NO_ALIGN_STUB)
 
 #if defined(HAS_FIXUP_PRECODE) 
+#if defined(HAS_RELATIVE_FIXUP_PRECODE)
+    JITHELPER(CORINFO_HELP_EE_PRECODE_FIXUP,    PrecodeRelativeFixupThunk,  CORINFO_HELP_SIG_NO_ALIGN_STUB)
+#else // HAS_RELATIVE_FIXUP_PRECODE
     JITHELPER(CORINFO_HELP_EE_PRECODE_FIXUP,    PrecodeFixupThunk,          CORINFO_HELP_SIG_NO_ALIGN_STUB)
-#else
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+#else // HAS_FIXUP_PRECODE
     JITHELPER(CORINFO_HELP_EE_PRECODE_FIXUP,    NULL,                       CORINFO_HELP_SIG_NO_ALIGN_STUB)
-#endif
+#endif // HAS_FIXUP_PRECODE
 
     JITHELPER(CORINFO_HELP_EE_PINVOKE_FIXUP,    NDirectImportThunk,         CORINFO_HELP_SIG_NO_ALIGN_STUB)
 
index 3bb4f64..84b92fa 100644 (file)
@@ -176,19 +176,30 @@ ASMCONSTANTS_C_ASSERT(CONTEXT_Pc == offsetof(T_CONTEXT,Pc))
 ASMCONSTANTS_C_ASSERT(SIZEOF__FaultingExceptionFrame        == sizeof(FaultingExceptionFrame));
 ASMCONSTANTS_C_ASSERT(FaultingExceptionFrame__m_fFilterExecuted == offsetof(FaultingExceptionFrame, m_fFilterExecuted));
 
-#define SIZEOF__FixupPrecode                 24
-#define Offset_PrecodeChunkIndex             15
-#define Offset_MethodDescChunkIndex          14
-#define MethodDesc_ALIGNMENT_SHIFT           3
-#define FixupPrecode_ALIGNMENT_SHIFT_1       3
-#define FixupPrecode_ALIGNMENT_SHIFT_2       4
+#define MethodDesc_ALIGNMENT_SHIFT                3
+ASMCONSTANTS_C_ASSERT(MethodDesc_ALIGNMENT_SHIFT == MethodDesc::ALIGNMENT_SHIFT);
+
+#define SIZEOF__FixupPrecode                      24
+#define Offset_FixupPrecodeChunkIndex             15
+#define Offset_FixupPrecodeMethodDescChunkIndex   14
+#define FixupPrecode_ALIGNMENT_SHIFT_1            3
+#define FixupPrecode_ALIGNMENT_SHIFT_2            4
 
 ASMCONSTANTS_C_ASSERT(SIZEOF__FixupPrecode == sizeof(FixupPrecode));
-ASMCONSTANTS_C_ASSERT(Offset_PrecodeChunkIndex == offsetof(FixupPrecode, m_PrecodeChunkIndex));
-ASMCONSTANTS_C_ASSERT(Offset_MethodDescChunkIndex == offsetof(FixupPrecode, m_MethodDescChunkIndex));
-ASMCONSTANTS_C_ASSERT(MethodDesc_ALIGNMENT_SHIFT == MethodDesc::ALIGNMENT_SHIFT);
+ASMCONSTANTS_C_ASSERT(Offset_FixupPrecodeChunkIndex == offsetof(FixupPrecode, m_PrecodeChunkIndex));
+ASMCONSTANTS_C_ASSERT(Offset_FixupPrecodeMethodDescChunkIndex == offsetof(FixupPrecode, m_MethodDescChunkIndex));
 ASMCONSTANTS_C_ASSERT((1<<FixupPrecode_ALIGNMENT_SHIFT_1) + (1<<FixupPrecode_ALIGNMENT_SHIFT_2)  == sizeof(FixupPrecode));
 
+#define SIZEOF__RelativeFixupPrecode                     32
+#define Offset_RelativeFixupPrecodeChunkIndex            17
+#define Offset_RelativeFixupPrecodeMethodDescChunkIndex  16
+#define RelativeFixupPrecode_ALIGNMENT_SHIFT             4
+
+ASMCONSTANTS_C_ASSERT(SIZEOF__RelativeFixupPrecode == sizeof(RelativeFixupPrecode));
+ASMCONSTANTS_C_ASSERT(Offset_RelativeFixupPrecodeChunkIndex == offsetof(RelativeFixupPrecode, m_PrecodeChunkIndex));
+ASMCONSTANTS_C_ASSERT(Offset_RelativeFixupPrecodeMethodDescChunkIndex == offsetof(RelativeFixupPrecode, m_MethodDescChunkIndex));
+ASMCONSTANTS_C_ASSERT((1<<(RelativeFixupPrecode_ALIGNMENT_SHIFT+1)) == sizeof(RelativeFixupPrecode));
+
 #ifndef CROSSGEN_COMPILE
 #define ResolveCacheElem__target      0x10
 #define ResolveCacheElem__pNext       0x18
index 91aaa5b..15ec192 100644 (file)
@@ -142,15 +142,15 @@ NESTED_END NDirectImportThunk, _TEXT
 
 // ------------------------------------------------------------------
 // The call in fixup precode initally points to this function.
-// The pupose of this function is to load the MethodDesc and forward the call to prestub.
+// The purpose of this function is to load the MethodDesc and forward the call to prestub.
 NESTED_ENTRY PrecodeFixupThunk, _TEXT, NoHandler
     // x12 = FixupPrecode *
     // On Exit
     // x12 = MethodDesc*
     // x13, x14 Trashed
     // Inline computation done by FixupPrecode::GetMethodDesc()
-    ldrb    w13, [x12, #Offset_PrecodeChunkIndex]    //m_PrecodeChunkIndex
-    ldrb    w14, [x12, #Offset_MethodDescChunkIndex] // m_MethodDescChunkIndex
+    ldrb    w13, [x12, #Offset_FixupPrecodeChunkIndex]           //m_PrecodeChunkIndex
+    ldrb    w14, [x12, #Offset_FixupPrecodeMethodDescChunkIndex] // m_MethodDescChunkIndex
 
     add     x12, x12, w13, uxtw #FixupPrecode_ALIGNMENT_SHIFT_1
     add     x13, x12, w13, uxtw #FixupPrecode_ALIGNMENT_SHIFT_2
@@ -161,6 +161,29 @@ NESTED_ENTRY PrecodeFixupThunk, _TEXT, NoHandler
 NESTED_END PrecodeFixupThunk, _TEXT
 // ------------------------------------------------------------------
 
+// ------------------------------------------------------------------
+// The call in fixup precode initally points to this function.
+// The purpose of this function is to load the MethodDesc and forward the call to prestub.
+NESTED_ENTRY PrecodeRelativeFixupThunk, _TEXT, NoHandler
+    // x11 = RelativeFixupPrecode *
+    // On Exit
+    // x12 = MethodDesc*
+    // x11, x13 Trashed
+    // Inline computation done by RelativeFixupPrecode::GetMethodDesc()
+    ldrb    w12, [x11, #Offset_RelativeFixupPrecodeChunkIndex]           //m_PrecodeChunkIndex
+    ldrb    w13, [x11, #Offset_RelativeFixupPrecodeMethodDescChunkIndex] // m_MethodDescChunkIndex
+
+    add     x11, x11, w12, uxtw #RelativeFixupPrecode_ALIGNMENT_SHIFT
+    add     x11, x11, w12, uxtw #RelativeFixupPrecode_ALIGNMENT_SHIFT
+    add     x12, x11, #SIZEOF__RelativeFixupPrecode                    // GetBase()
+    ldr     x11, [x12]                                                 // base
+    add     x12, x12, x11
+    add     x12, x12, w13, uxtw #MethodDesc_ALIGNMENT_SHIFT
+
+    b ThePreStub
+NESTED_END PrecodeRelativeFixupThunk, _TEXT
+// ------------------------------------------------------------------
+
 NESTED_ENTRY ThePreStub, _TEXT, NoHandler
 
     PROLOG_WITH_TRANSITION_BLOCK
index c1f8429..27e284c 100644 (file)
@@ -210,7 +210,7 @@ Done
 
 ; ------------------------------------------------------------------
 ; The call in fixup precode initally points to this function.
-; The pupose of this function is to load the MethodDesc and forward the call to prestub.
+; The purpose of this function is to load the MethodDesc and forward the call to prestub.
         NESTED_ENTRY PrecodeFixupThunk
 
         ; x12 = FixupPrecode *
@@ -218,8 +218,8 @@ Done
         ; x12 = MethodDesc*
         ; x13, x14 Trashed
         ; Inline computation done by FixupPrecode::GetMethodDesc()
-        ldrb    w13, [x12, #Offset_PrecodeChunkIndex]              ; m_PrecodeChunkIndex
-        ldrb    w14, [x12, #Offset_MethodDescChunkIndex]           ; m_MethodDescChunkIndex
+        ldrb    w13, [x12, #Offset_FixupPrecodeChunkIndex]            ; m_PrecodeChunkIndex
+        ldrb    w14, [x12, #Offset_FixupPrecodeMethodDescChunkIndex]  ; m_MethodDescChunkIndex
 
         add     x12,x12,w13,uxtw #FixupPrecode_ALIGNMENT_SHIFT_1
         add     x13,x12,w13,uxtw #FixupPrecode_ALIGNMENT_SHIFT_2
@@ -229,6 +229,30 @@ Done
         b ThePreStub
 
         NESTED_END
+
+; ------------------------------------------------------------------
+; The call in fixup precode initally points to this function.
+; The purpose of this function is to load the MethodDesc and forward the call to prestub.
+        NESTED_ENTRY PrecodeRelativeFixupThunk
+
+        ; x11 = RelativeFixupPrecode *
+        ; On Exit
+        ; x12 = MethodDesc*
+        ; x11, x13 Trashed
+        ; Inline computation done by RelativeFixupPrecode::GetMethodDesc()
+        ldrb    w12, [x11, #Offset_RelativeFixupPrecodeChunkIndex]            ; m_PrecodeChunkIndex
+        ldrb    w13, [x11, #Offset_RelativeFixupPrecodeMethodDescChunkIndex]  ; m_MethodDescChunkIndex
+
+        add     x11, x11, w12, uxtw #RelativeFixupPrecode_ALIGNMENT_SHIFT
+        add     x11, x11, w12, uxtw #RelativeFixupPrecode_ALIGNMENT_SHIFT
+        add     x12, x11, #SIZEOF__RelativeFixupPrecode                    ; GetBase()
+        ldr     x11, [x12]                                                 ; base
+        add     x12, x12, x11
+        add     x12, x12, w13, uxtw #MethodDesc_ALIGNMENT_SHIFT
+
+        b ThePreStub
+
+        NESTED_END
 ; ------------------------------------------------------------------
 
         NESTED_ENTRY ThePreStub
index b30d502..7d01f9d 100644 (file)
@@ -44,6 +44,10 @@ extern PCODE GetPreStubEntryPoint();
 #define HAS_FIXUP_PRECODE                       1
 #define HAS_FIXUP_PRECODE_CHUNKS                1
 
+#if defined(HAS_FIXUP_PRECODE) && defined(HAS_FIXUP_PRECODE_CHUNKS)
+#define HAS_RELATIVE_FIXUP_PRECODE              1
+#endif
+
 // ThisPtrRetBufPrecode one is necessary for closed delegates over static methods with return buffer
 #define HAS_THISPTR_RETBUF_PRECODE              1
 
@@ -561,6 +565,7 @@ struct HijackArgs
 };
 
 EXTERN_C VOID STDCALL PrecodeFixupThunk();
+EXTERN_C VOID STDCALL PrecodeRelativeFixupThunk();
 
 // Invalid precode type
 struct InvalidPrecode {
@@ -677,9 +682,9 @@ struct FixupPrecode {
     // adr x12, #0 
     // ldr x11, [pc, #12]     ; =m_pTarget
     // br  x11
+    // 2 byte padding
     // dcb m_MethodDescChunkIndex
     // dcb m_PrecodeChunkIndex
-    // 2 byte padding
     // dcd m_pTarget
 
 
@@ -771,6 +776,119 @@ struct FixupPrecode {
 typedef DPTR(FixupPrecode) PTR_FixupPrecode;
 
 
+struct RelativeFixupPrecode {
+
+    static const int Type = 0x0B;
+
+    // adr x11, #0      ; registers x11 and x12 are reversed to differentiate from FixupPrecode
+    // ldr x12, #20     ; =m_pTargetOffset, which is relative to "adr x11, #0"
+    // add x12, x11, x12
+    // br  x12
+    // dcb m_MethodDescChunkIndex
+    // dcb m_PrecodeChunkIndex
+    // 6 byte padding
+    // dcd m_pTargetOffset
+
+
+    UINT32  m_rgCode[4];
+    BYTE    m_MethodDescChunkIndex;
+    BYTE    m_PrecodeChunkIndex;
+    BYTE    padding[6];
+    TADDR   m_pTargetOffset;
+
+    void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, int iMethodDescChunkIndex = 0, int iPrecodeChunkIndex = 0);
+    void InitCommon()
+    {
+        WRAPPER_NO_CONTRACT;
+        int n = 0;
+
+        m_rgCode[n++] = 0x1000000B;   // adr x11, #0
+        m_rgCode[n++] = 0x580000AC;   // ldr x12, #20     ; =m_pTargetOffset, which is relative to "adr x11, #0"
+        m_rgCode[n++] = 0x8B0C016C;   // add x12, x11, x12
+
+        _ASSERTE((UINT32*)&m_pTargetOffset == &m_rgCode[n + 3]);
+
+        m_rgCode[n++] = 0xD61F0180;   // br  x12
+
+        _ASSERTE(n == _countof(m_rgCode));
+    }
+
+    TADDR GetBase()
+    {
+        LIMITED_METHOD_CONTRACT;
+        SUPPORTS_DAC;
+
+        return dac_cast<TADDR>(this) + (m_PrecodeChunkIndex + 1) * sizeof(RelativeFixupPrecode);
+    }
+
+    TADDR GetMethodDesc();
+
+    static TADDR GetTargetOffset()
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+        return 0;
+    }
+
+    PCODE GetTarget()
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+        return dac_cast<TADDR>(this) + GetTargetOffset() + m_pTargetOffset;
+    }
+
+    void ResetTargetInterlocked()
+    {
+        CONTRACTL
+        {
+            THROWS;
+            GC_NOTRIGGER;
+        }
+        CONTRACTL_END;
+
+        EnsureWritableExecutablePages(&m_pTargetOffset);
+        TADDR addr = (TADDR)GetEEFuncEntryPoint(PrecodeRelativeFixupThunk) - (TADDR)(this) - GetTargetOffset();
+        InterlockedExchange64((LONGLONG*)&m_pTargetOffset, addr);
+    }
+
+    BOOL SetTargetInterlocked(TADDR target, TADDR expected)
+    {
+        CONTRACTL
+        {
+            THROWS;
+            GC_NOTRIGGER;
+        }
+        CONTRACTL_END;
+
+        EnsureWritableExecutablePages(&m_pTargetOffset);
+        TADDR addrExpected = expected - (TADDR)(this) - GetTargetOffset();
+        TADDR addrTarget = target - (TADDR)(this) - GetTargetOffset();
+        return (TADDR)InterlockedCompareExchange64(
+            (LONGLONG*)&m_pTargetOffset, addrTarget, addrExpected) == addrExpected;
+    }
+
+    static BOOL IsRelativeFixupPrecodeByASM(PCODE addr)
+    {
+        PTR_DWORD pInstr = dac_cast<PTR_DWORD>(PCODEToPINSTR(addr));
+        return
+            (pInstr[0] == 0x1000000B) &&
+            (pInstr[1] == 0x580000AC) &&
+            (pInstr[2] == 0x8B0C016C) &&
+            (pInstr[3] == 0xD61F0180);
+    }
+
+#ifdef FEATURE_PREJIT
+    // Partial initialization. Used to save regrouped chunks.
+    void InitForSave(int iPrecodeChunkIndex);
+
+    void Fixup(DataImage *image, MethodDesc * pMD);
+#endif
+
+#ifdef DACCESS_COMPILE
+    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
+#endif
+};
+typedef DPTR(RelativeFixupPrecode) PTR_RelativeFixupPrecode;
+
+
 // Precode to shuffle this and retbuf for closed delegates over static methods with return buffer
 struct ThisPtrRetBufPrecode {
 
index 6805579..b25dc4d 100644 (file)
@@ -565,6 +565,18 @@ TADDR FixupPrecode::GetMethodDesc()
     return base + (m_MethodDescChunkIndex * MethodDesc::ALIGNMENT);
 }
 
+TADDR RelativeFixupPrecode::GetMethodDesc()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    // This lookup is also manually inlined in PrecodeFixupThunk assembly code
+    TADDR baseAddr = GetBase();
+    TADDR base = *PTR_TADDR(baseAddr);
+    if (base == NULL)
+        return NULL;
+    return baseAddr + base + (m_MethodDescChunkIndex * MethodDesc::ALIGNMENT);
+}
+
 #ifdef DACCESS_COMPILE
 void FixupPrecode::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
 {
@@ -573,6 +585,14 @@ void FixupPrecode::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
 
        DacEnumMemoryRegion(GetBase(), sizeof(TADDR));
 }
+
+void RelativeFixupPrecode::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+       SUPPORTS_DAC;
+       DacEnumMemoryRegion(dac_cast<TADDR>(this), sizeof(RelativeFixupPrecode));
+
+       DacEnumMemoryRegion(GetBase(), sizeof(TADDR));
+}
 #endif // DACCESS_COMPILE
 
 #ifndef DACCESS_COMPILE
@@ -675,6 +695,39 @@ void FixupPrecode::Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, int
     }
 }
 
+void RelativeFixupPrecode::Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, int iMethodDescChunkIndex /*=0*/, int iPrecodeChunkIndex /*=0*/)
+{
+    WRAPPER_NO_CONTRACT;
+
+    InitCommon();
+
+    // Initialize chunk indices only if they are not initialized yet. This is necessary to make MethodDesc::Reset work.
+    if (m_PrecodeChunkIndex == 0)
+    {
+        _ASSERTE(FitsInU1(iPrecodeChunkIndex));
+        m_PrecodeChunkIndex = static_cast<BYTE>(iPrecodeChunkIndex);
+    }
+
+    if (iMethodDescChunkIndex != -1)
+    {
+        if (m_MethodDescChunkIndex == 0)
+        {
+            _ASSERTE(FitsInU1(iMethodDescChunkIndex));
+            m_MethodDescChunkIndex = static_cast<BYTE>(iMethodDescChunkIndex);
+        }
+
+        if (*(void**)GetBase() == NULL)
+            *(void**)GetBase() = (BYTE*)pMD - (iMethodDescChunkIndex * MethodDesc::ALIGNMENT) - GetBase();
+    }
+
+    _ASSERTE(GetMethodDesc() == (TADDR)pMD);
+
+    if (pLoaderAllocator != NULL)
+    {
+        m_pTargetOffset = GetEEFuncEntryPoint(PrecodeRelativeFixupThunk) - (TADDR)this - RelativeFixupPrecode::GetTargetOffset();
+    }
+}
+
 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
 // Partial initialization. Used to save regrouped chunks.
 void FixupPrecode::InitForSave(int iPrecodeChunkIndex)
@@ -688,10 +741,27 @@ void FixupPrecode::InitForSave(int iPrecodeChunkIndex)
     // The rest is initialized in code:FixupPrecode::Fixup
 }
 
+// Partial initialization. Used to save regrouped chunks.
+void RelativeFixupPrecode::InitForSave(int iPrecodeChunkIndex)
+{
+    STANDARD_VM_CONTRACT;
+
+    InitCommon();
+
+    _ASSERTE(FitsInU1(iPrecodeChunkIndex));
+    m_PrecodeChunkIndex = static_cast<BYTE>(iPrecodeChunkIndex);
+    // The rest is initialized in code:RelativeFixupPrecode::Fixup
+}
+
 void FixupPrecode::Fixup(DataImage *image, MethodDesc * pMD)
 {
     STANDARD_VM_CONTRACT;
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    // FixupPrecode is not saved to image in this case
+    _ASSERTE(!"FixupPrecode is not saved to NGENed image, RelativeFixupPrecode is instead");
+#else // HAS_RELATIVE_FIXUP_PRECODE
+
     // Note that GetMethodDesc() does not return the correct value because of 
     // regrouping of MethodDescs into hot and cold blocks. That's why the caller
     // has to supply the actual MethodDesc
@@ -716,6 +786,44 @@ void FixupPrecode::Fixup(DataImage *image, MethodDesc * pMD)
         image->FixupFieldToNode(this, (BYTE *)GetBase() - (BYTE *)this,
             pMDChunkNode, sizeof(MethodDescChunk));
     }
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+}
+
+void RelativeFixupPrecode::Fixup(DataImage *image, MethodDesc * pMD)
+{
+    STANDARD_VM_CONTRACT;
+
+    // Note that GetMethodDesc() does not return the correct value because of
+    // regrouping of MethodDescs into hot and cold blocks. That's why the caller
+    // has to supply the actual MethodDesc
+
+    SSIZE_T mdChunkOffset;
+    ZapNode * pMDChunkNode = image->GetNodeForStructure(pMD, &mdChunkOffset);
+    ZapNode * pHelperThunk = image->GetHelperThunk(CORINFO_HELP_EE_PRECODE_FIXUP);
+
+    image->FixupFieldToNode(this,
+                            offsetof(RelativeFixupPrecode, m_pTargetOffset),
+                            pHelperThunk,
+                            offsetof(RelativeFixupPrecode, m_pTargetOffset) - RelativeFixupPrecode::GetTargetOffset(),
+                            IMAGE_REL_BASED_RELPTR);
+
+    // Set the actual chunk index
+    RelativeFixupPrecode * pNewPrecode = (RelativeFixupPrecode *)image->GetImagePointer(this);
+
+    size_t mdOffset = mdChunkOffset - sizeof(MethodDescChunk);
+    size_t chunkIndex = mdOffset / MethodDesc::ALIGNMENT;
+    _ASSERTE(FitsInU1(chunkIndex));
+    pNewPrecode->m_MethodDescChunkIndex = (BYTE)chunkIndex;
+
+    // Fixup the base of MethodDescChunk
+    if (m_PrecodeChunkIndex == 0)
+    {
+        image->FixupFieldToNode(this,
+                                (BYTE *)GetBase() - (BYTE *)this,
+                                pMDChunkNode,
+                                sizeof(MethodDescChunk),
+                                IMAGE_REL_BASED_RELPTR);
+    }
 }
 #endif // FEATURE_NATIVE_IMAGE_GENERATION
 
@@ -762,6 +870,21 @@ BOOL DoesSlotCallPrestub(PCODE pCode)
     }
 #endif
 
+    //RelativeFixupPrecode
+#if defined(HAS_RELATIVE_FIXUP_PRECODE)
+    if (RelativeFixupPrecode::IsRelativeFixupPrecodeByASM(pCode))
+    {
+        PCODE pTarget = dac_cast<PTR_RelativeFixupPrecode>(pInstr)->GetTarget();
+
+        if (isJump(pTarget))
+        {
+            pTarget = decodeJump(pTarget);
+        }
+
+        return pTarget == (TADDR)PrecodeRelativeFixupThunk;
+    }
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+
     // StubPrecode
     if (pInstr[0] == 0x10000089 && // adr x9, #16
         pInstr[1] == 0xA940312A && // ldp x10,x12,[x9] 
index e4a75d6..923cfc1 100644 (file)
@@ -5747,7 +5747,16 @@ PrecodeType MethodDesc::GetPrecodeType()
     if (!RequiresMethodDescCallingConvention())
     {
         // Use the more efficient fixup precode if possible
-        precodeType = PRECODE_FIXUP;
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+        if (IsZapped())
+        {
+            precodeType = PRECODE_RELATIVE_FIXUP;
+        }
+        else
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+        {
+            precodeType = PRECODE_FIXUP;
+        }
     }
     else
 #endif // HAS_FIXUP_PRECODE
index f0e005a..5ab4ca8 100644 (file)
@@ -35,6 +35,9 @@ BOOL Precode::IsValidType(PrecodeType t)
 #ifdef HAS_FIXUP_PRECODE
     case PRECODE_FIXUP:
 #endif // HAS_FIXUP_PRECODE
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    case PRECODE_RELATIVE_FIXUP:
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #ifdef HAS_THISPTR_RETBUF_PRECODE
     case PRECODE_THISPTR_RETBUF:
 #endif // HAS_THISPTR_RETBUF_PRECODE
@@ -61,6 +64,10 @@ SIZE_T Precode::SizeOf(PrecodeType t)
     case PRECODE_FIXUP:
         return sizeof(FixupPrecode);
 #endif // HAS_FIXUP_PRECODE
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    case PRECODE_RELATIVE_FIXUP:
+        return sizeof(RelativeFixupPrecode);
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #ifdef HAS_THISPTR_RETBUF_PRECODE
     case PRECODE_THISPTR_RETBUF:
         return sizeof(ThisPtrRetBufPrecode);
@@ -92,6 +99,11 @@ PCODE Precode::GetTarget()
         target = AsFixupPrecode()->GetTarget();
         break;
 #endif // HAS_FIXUP_PRECODE
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    case PRECODE_RELATIVE_FIXUP:
+        target = AsRelativeFixupPrecode()->GetTarget();
+        break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #ifdef HAS_THISPTR_RETBUF_PRECODE
     case PRECODE_THISPTR_RETBUF:
         target = AsThisPtrRetBufPrecode()->GetTarget();
@@ -131,6 +143,11 @@ MethodDesc* Precode::GetMethodDesc(BOOL fSpeculative /*= FALSE*/)
         pMD = AsFixupPrecode()->GetMethodDesc();
         break;
 #endif // HAS_FIXUP_PRECODE
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    case PRECODE_RELATIVE_FIXUP:
+        pMD = AsRelativeFixupPrecode()->GetMethodDesc();
+        break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #ifdef HAS_THISPTR_RETBUF_PRECODE
     case PRECODE_THISPTR_RETBUF:
         pMD = AsThisPtrRetBufPrecode()->GetMethodDesc();
@@ -149,6 +166,13 @@ MethodDesc* Precode::GetMethodDesc(BOOL fSpeculative /*= FALSE*/)
             UnexpectedPrecodeType("Precode::GetMethodDesc", precodeType);
     }
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    if (precodeType == PRECODE_RELATIVE_FIXUP)
+    {
+        _ASSERTE(dac_cast<PTR_MethodDesc>(pMD)->IsZapped());
+    }
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+
     // GetMethodDesc() on platform specific precode types returns TADDR. It should return 
     // PTR_MethodDesc instead. It is a workaround to resolve cyclic dependency between headers. 
     // Once we headers factoring of headers cleaned up, we should be able to get rid of it.
@@ -179,11 +203,16 @@ BOOL Precode::IsCorrectMethodDesc(MethodDesc *  pMD)
     {
         PrecodeType precodeType = GetType();
 
-#ifdef HAS_FIXUP_PRECODE_CHUNKS
         // We do not keep track of the MethodDesc in every kind of fixup precode
         if (precodeType == PRECODE_FIXUP)
             return TRUE;
-#endif
+
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+        if (precodeType == PRECODE_RELATIVE_FIXUP)
+        {
+            return TRUE;
+        }
+#endif // HAS_RELATIVE_FIXUP_PRECODE
     }
 #endif // HAS_FIXUP_PRECODE_CHUNKS
 
@@ -208,6 +237,11 @@ BOOL Precode::IsPointingToPrestub(PCODE target)
         return TRUE;
 #endif
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    if (IsPointingTo(target, GetEEFuncEntryPoint(PrecodeRelativeFixupThunk)))
+        return TRUE;
+#endif
+
 #ifdef FEATURE_PREJIT
     Module *pZapModule = GetMethodDesc()->GetZapModule();
     if (pZapModule != NULL)
@@ -237,7 +271,11 @@ PCODE Precode::TryToSkipFixupPrecode(PCODE addr)
 
 #if defined(FEATURE_PREJIT) && defined(HAS_FIXUP_PRECODE)
     // Early out for common cases
-    if (!FixupPrecode::IsFixupPrecodeByASM(addr))
+    if (!FixupPrecode::IsFixupPrecodeByASM(addr)
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+        && !RelativeFixupPrecode::IsRelativeFixupPrecodeByASM(addr)
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+        )
         return NULL;
 
     // This optimization makes sense in NGened code only.
@@ -279,6 +317,11 @@ Precode* Precode::GetPrecodeForTemporaryEntryPoint(TADDR temporaryEntryPoints, i
         return PTR_Precode(temporaryEntryPoints + index * sizeof(FixupPrecode));
     }
 #endif
+
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    _ASSERTE(t != PRECODE_RELATIVE_FIXUP);
+#endif
+
     SIZE_T oneSize = SizeOfTemporaryEntryPoint(t);
     return PTR_Precode(temporaryEntryPoints + index * oneSize);
 }
@@ -313,6 +356,11 @@ SIZE_T Precode::SizeOfTemporaryEntryPoints(PrecodeType t, bool preallocateJumpSt
         _ASSERTE(!preallocateJumpStubs);
     }
 #endif
+
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    _ASSERTE(t != PRECODE_RELATIVE_FIXUP);
+#endif
+
     SIZE_T oneSize = SizeOfTemporaryEntryPoint(t);
     return count * oneSize;
 }
@@ -349,6 +397,10 @@ Precode* Precode::Allocate(PrecodeType t, MethodDesc* pMD,
 
     SIZE_T size;
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    _ASSERTE(t != PRECODE_RELATIVE_FIXUP);
+#endif
+
 #ifdef HAS_FIXUP_PRECODE_CHUNKS
     if (t == PRECODE_FIXUP)
     {
@@ -388,6 +440,11 @@ void Precode::Init(PrecodeType t, MethodDesc* pMD, LoaderAllocator *pLoaderAlloc
         ((FixupPrecode*)this)->Init(pMD, pLoaderAllocator);
         break;
 #endif // HAS_FIXUP_PRECODE
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    case PRECODE_RELATIVE_FIXUP:
+        ((RelativeFixupPrecode*)this)->Init(pMD, pLoaderAllocator);
+        break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #ifdef HAS_THISPTR_RETBUF_PRECODE
     case PRECODE_THISPTR_RETBUF:
         ((ThisPtrRetBufPrecode*)this)->Init(pMD, pLoaderAllocator);
@@ -418,6 +475,12 @@ void Precode::ResetTargetInterlocked()
             break;
 #endif // HAS_FIXUP_PRECODE
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+        case PRECODE_RELATIVE_FIXUP:
+            AsRelativeFixupPrecode()->ResetTargetInterlocked();
+            break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+
         default:
             UnexpectedPrecodeType("Precode::ResetTargetInterlocked", precodeType);
             break;
@@ -453,6 +516,12 @@ BOOL Precode::SetTargetInterlocked(PCODE target, BOOL fOnlyRedirectFromPrestub)
         break;
 #endif // HAS_FIXUP_PRECODE
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    case PRECODE_RELATIVE_FIXUP:
+        ret = AsRelativeFixupPrecode()->SetTargetInterlocked(target, expected);
+        break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+
 #ifdef HAS_THISPTR_RETBUF_PRECODE
     case PRECODE_THISPTR_RETBUF:
         ret = AsThisPtrRetBufPrecode()->SetTargetInterlocked(target, expected);
@@ -672,6 +741,10 @@ void Precode::Save(DataImage *image)
     _ASSERTE(GetType() != PRECODE_FIXUP);
 #endif
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    _ASSERTE(GetType() != PRECODE_RELATIVE_FIXUP);
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+
 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
     // StubPrecode may have straddlers (relocations crossing pages) on x86 and x64. We need 
     // to insert padding to eliminate it. To do that, we need to save these using custom ZapNode that can only
@@ -722,9 +795,15 @@ void Precode::Fixup(DataImage *image, MethodDesc * pMD)
         break;
 #endif // HAS_NDIRECT_IMPORT_PRECODE
 #ifdef HAS_FIXUP_PRECODE
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    case PRECODE_RELATIVE_FIXUP:
+        AsRelativeFixupPrecode()->Fixup(image, pMD);
+        break;
+#else // HAS_RELATIVE_FIXUP_PRECODE
     case PRECODE_FIXUP:
         AsFixupPrecode()->Fixup(image, pMD);
         break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #endif // HAS_FIXUP_PRECODE
     default:
         UnexpectedPrecodeType("Precode::Save", precodeType);
@@ -754,6 +833,10 @@ void Precode::SaveChunk::Save(DataImage* image, MethodDesc * pMD)
     }
 #endif // HAS_FIXUP_PRECODE_CHUNKS
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    _ASSERTE(precodeType != PRECODE_RELATIVE_FIXUP);
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+
     SIZE_T size = Precode::SizeOf(precodeType);
     Precode* pPrecode = (Precode *)new (image->GetHeap()) BYTE[size];
     pPrecode->Init(precodeType, pMD, NULL);
@@ -768,20 +851,38 @@ static void SaveFixupPrecodeChunk(DataImage * image, MethodDesc ** rgMD, COUNT_T
 {
     STANDARD_VM_CONTRACT;
 
-    ULONG size = sizeof(FixupPrecode) * count + sizeof(PTR_MethodDesc);
-    FixupPrecode * pBase = (FixupPrecode *)new (image->GetHeap()) BYTE[size];
+    ULONG sizeSinglePrecode;
+    PrecodeType type;
+
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    sizeSinglePrecode = sizeof(RelativeFixupPrecode);
+    type = PRECODE_RELATIVE_FIXUP;
+#else // HAS_RELATIVE_FIXUP_PRECODE
+    sizeSinglePrecode = sizeof(FixupPrecode);
+    type = PRECODE_FIXUP;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 
-    ZapStoredStructure * pNode = image->StoreStructure(NULL, size, kind,
-        Precode::AlignOf(PRECODE_FIXUP));
+    ULONG size = sizeSinglePrecode * count + sizeof(PTR_MethodDesc);
+    ZapStoredStructure * pNode = image->StoreStructure(NULL, size, kind, Precode::AlignOf(type));
+
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    RelativeFixupPrecode * pBase = (RelativeFixupPrecode *)new (image->GetHeap()) BYTE[size];
+#else // HAS_RELATIVE_FIXUP_PRECODE
+    FixupPrecode * pBase = (FixupPrecode *)new (image->GetHeap()) BYTE[size];
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 
     for (COUNT_T i = 0; i < count; i++)
     {
         MethodDesc * pMD = rgMD[i];
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+        RelativeFixupPrecode * pPrecode = pBase + i;
+#else // HAS_RELATIVE_FIXUP_PRECODE
         FixupPrecode * pPrecode = pBase + i;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 
         pPrecode->InitForSave((count - 1) - i);
 
-        image->BindPointer(pPrecode, pNode, i * sizeof(FixupPrecode));
+        image->BindPointer(pPrecode, pNode, i * sizeSinglePrecode);
 
         // Alias the temporary entrypoint
         image->RegisterSurrogate(pMD, pPrecode);
@@ -871,7 +972,14 @@ void Precode::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
     }
 #endif
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    if (t == PRECODE_RELATIVE_FIXUP)
+    {
+        AsRelativeFixupPrecode()->EnumMemoryRegions(flags);
+        return;
+    }
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+
     DacEnumMemoryRegion(GetStart(), SizeOf(t));
 }
 #endif
-
index fe55d6f..ba51f22 100644 (file)
@@ -25,6 +25,9 @@ enum PrecodeType {
 #ifdef HAS_FIXUP_PRECODE
     PRECODE_FIXUP           = FixupPrecode::Type,
 #endif // HAS_FIXUP_PRECODE
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    PRECODE_RELATIVE_FIXUP  = RelativeFixupPrecode::Type,
+#endif // HAS_RELATIVE_FIXUP_PRECODE
 #ifdef HAS_THISPTR_RETBUF_PRECODE
     PRECODE_THISPTR_RETBUF  = ThisPtrRetBufPrecode::Type,
 #endif // HAS_THISPTR_RETBUF_PRECODE
@@ -70,6 +73,16 @@ private:
     }
 #endif // HAS_FIXUP_PRECODE
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+    RelativeFixupPrecode* AsRelativeFixupPrecode()
+    {
+      LIMITED_METHOD_CONTRACT;
+      SUPPORTS_DAC;
+
+      return dac_cast<PTR_RelativeFixupPrecode>(this);
+    }
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+
 #ifdef HAS_THISPTR_RETBUF_PRECODE
     ThisPtrRetBufPrecode* AsThisPtrRetBufPrecode()
     {
@@ -293,6 +306,9 @@ public:
 #ifdef HAS_FIXUP_PRECODE_CHUNKS
         _ASSERTE(t != PRECODE_FIXUP);
 #endif
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+        _ASSERTE(t != PRECODE_RELATIVE_FIXUP);
+#endif // HAS_RELATIVE_FIXUP_PRECODE
         return ALIGN_UP(SizeOf(t), AlignOf(t));
     }
 
@@ -331,21 +347,6 @@ public:
 #ifdef DACCESS_COMPILE
     void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
 #endif
-
-#ifdef HAS_FIXUP_PRECODE_CHUNKS
-    static DWORD GetOffsetOfBase(PrecodeType t, DWORD count)
-    {
-        assert(t == PRECODE_FIXUP);
-        return (DWORD)(count * sizeof(FixupPrecode));
-    }
-
-    static DWORD GetOffset(PrecodeType t, DWORD index, DWORD count)
-    {
-        assert(t == PRECODE_FIXUP);
-        assert(index < count); 
-        return (DWORD)((count - index - 1)* sizeof(FixupPrecode));
-    }
-#endif
 };
 
 #endif // __PRECODE_H__
index a8e35a2..f121278 100644 (file)
@@ -2254,8 +2254,12 @@ static PCODE PatchNonVirtualExternalMethod(MethodDesc * pMD, PCODE pCode, PTR_CO
     // than code:Precode::TryToSkipFixupPrecode.
     //
 #ifdef HAS_FIXUP_PRECODE
-    if (pMD->HasPrecode() && pMD->GetPrecode()->GetType() == PRECODE_FIXUP
-        && pMD->IsNativeCodeStableAfterInit())
+    if (pMD->HasPrecode()
+        && (pMD->GetPrecode()->GetType() == PRECODE_FIXUP
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+            || pMD->GetPrecode()->GetType() == PRECODE_RELATIVE_FIXUP
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+            ) && pMD->IsNativeCodeStableAfterInit())
     {
         PCODE pDirectTarget = pMD->IsFCall() ? ECall::GetFCallImpl(pMD) : pMD->GetNativeCode();
         if (pDirectTarget != NULL)
index 27ab5cf..ea863c0 100644 (file)
@@ -1058,6 +1058,11 @@ BOOL PrecodeStubManager::DoTraceStub(PCODE stubStartAddress,
             break;
 #endif // HAS_FIXUP_PRECODE
 
+#ifdef HAS_RELATIVE_FIXUP_PRECODE
+        case PRECODE_RELATIVE_FIXUP:
+            break;
+#endif // HAS_RELATIVE_FIXUP_PRECODE
+
 #ifdef HAS_THISPTR_RETBUF_PRECODE
         case PRECODE_THISPTR_RETBUF:
             break;
@@ -2591,4 +2596,3 @@ void TailCallStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags)
 }
 
 #endif // #ifdef DACCESS_COMPILE
-