1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
8 // Stub that runs before the actual native code
13 typedef DPTR(class Precode) PTR_Precode;
15 #ifndef PRECODE_ALIGNMENT
16 #define PRECODE_ALIGNMENT sizeof(void*)
20 PRECODE_INVALID = InvalidPrecode::Type,
21 PRECODE_STUB = StubPrecode::Type,
22 #ifdef HAS_NDIRECT_IMPORT_PRECODE
23 PRECODE_NDIRECT_IMPORT = NDirectImportPrecode::Type,
24 #endif // HAS_NDIRECT_IMPORT_PRECODE
25 #ifdef HAS_FIXUP_PRECODE
26 PRECODE_FIXUP = FixupPrecode::Type,
27 #endif // HAS_FIXUP_PRECODE
28 #ifdef HAS_RELATIVE_FIXUP_PRECODE
29 PRECODE_RELATIVE_FIXUP = RelativeFixupPrecode::Type,
30 #endif // HAS_RELATIVE_FIXUP_PRECODE
31 #ifdef HAS_THISPTR_RETBUF_PRECODE
32 PRECODE_THISPTR_RETBUF = ThisPtrRetBufPrecode::Type,
33 #endif // HAS_THISPTR_RETBUF_PRECODE
36 // For more details see. file:../../doc/BookOfTheRuntime/ClassLoader/MethodDescDesign.doc
38 #ifdef DACCESS_COMPILE
39 friend class NativeImageDumper;
42 BYTE m_data[SIZEOF_PRECODE_BASE];
44 StubPrecode* AsStubPrecode()
46 LIMITED_METHOD_CONTRACT;
49 return dac_cast<PTR_StubPrecode>(this);
52 #ifdef HAS_NDIRECT_IMPORT_PRECODE
54 // Fake precodes has to be exposed
55 NDirectImportPrecode* AsNDirectImportPrecode()
57 LIMITED_METHOD_CONTRACT;
60 return dac_cast<PTR_NDirectImportPrecode>(this);
64 #endif // HAS_NDIRECT_IMPORT_PRECODE
66 #ifdef HAS_FIXUP_PRECODE
67 FixupPrecode* AsFixupPrecode()
69 LIMITED_METHOD_CONTRACT;
72 return dac_cast<PTR_FixupPrecode>(this);
74 #endif // HAS_FIXUP_PRECODE
76 #ifdef HAS_RELATIVE_FIXUP_PRECODE
77 RelativeFixupPrecode* AsRelativeFixupPrecode()
79 LIMITED_METHOD_CONTRACT;
82 return dac_cast<PTR_RelativeFixupPrecode>(this);
84 #endif // HAS_RELATIVE_FIXUP_PRECODE
86 #ifdef HAS_THISPTR_RETBUF_PRECODE
87 ThisPtrRetBufPrecode* AsThisPtrRetBufPrecode()
89 LIMITED_METHOD_CONTRACT;
91 return dac_cast<PTR_ThisPtrRetBufPrecode>(this);
93 #endif // HAS_THISPTR_RETBUF_PRECODE
98 LIMITED_METHOD_CONTRACT;
99 return dac_cast<TADDR>(this);
102 static void UnexpectedPrecodeType(const char * originator, PrecodeType precodeType)
106 #ifdef DACCESS_COMPILE
107 DacError(E_UNEXPECTED);
110 // We only use __UNREACHABLE here since otherwise it would be a hint
111 // for the compiler to fold this case with the other cases in a switch
112 // statement. However, we would rather have this case be a separate
113 // code path so that we will get a clean crash sooner.
114 __UNREACHABLE("Unexpected precode type");
116 CONSISTENCY_CHECK_MSGF(false, ("%s: Unexpected precode type: 0x%02x.", originator, precodeType));
121 PrecodeType GetType()
123 LIMITED_METHOD_CONTRACT;
126 #ifdef OFFSETOF_PRECODE_TYPE
128 BYTE type = m_data[OFFSETOF_PRECODE_TYPE];
130 if (type == X86_INSTR_MOV_RM_R)
131 type = m_data[OFFSETOF_PRECODE_TYPE_MOV_RM_R];
132 #endif // _TARGET_X86_
134 #ifdef _TARGET_AMD64_
135 if (type == (X86_INSTR_MOV_R10_IMM64 & 0xFF))
136 type = m_data[OFFSETOF_PRECODE_TYPE_MOV_R10];
137 else if ((type == (X86_INSTR_CALL_REL32 & 0xFF)) || (type == (X86_INSTR_JMP_REL32 & 0xFF)))
138 type = m_data[OFFSETOF_PRECODE_TYPE_CALL_OR_JMP];
141 #if defined(HAS_FIXUP_PRECODE) && (defined(_TARGET_X86_) || defined(_TARGET_AMD64_))
142 if (type == FixupPrecode::TypePrestub)
143 type = FixupPrecode::Type;
147 static_assert_no_msg(offsetof(StubPrecode, m_pTarget) == offsetof(NDirectImportPrecode, m_pMethodDesc));
148 // If the precode does not have thumb bit on target, it must be NDirectImportPrecode.
149 if (type == StubPrecode::Type && ((AsStubPrecode()->m_pTarget & THUMB_CODE) == 0))
150 type = NDirectImportPrecode::Type;
153 return (PrecodeType)type;
155 #else // OFFSETOF_PRECODE_TYPE
157 #endif // OFFSETOF_PRECODE_TYPE
160 static BOOL IsValidType(PrecodeType t);
162 static int AlignOf(PrecodeType t)
165 int align = PRECODE_ALIGNMENT;
167 #if defined(_TARGET_X86_) && defined(HAS_FIXUP_PRECODE)
168 // Fixup precodes has to be aligned to allow atomic patching
169 if (t == PRECODE_FIXUP)
171 #endif // _TARGET_X86_ && HAS_FIXUP_PRECODE
173 #if defined(_TARGET_ARM_) && defined(HAS_COMPACT_ENTRYPOINTS)
174 // Precodes have to be aligned to allow fast compact entry points check
175 _ASSERTE (align >= sizeof(void*));
176 #endif // _TARGET_ARM_ && HAS_COMPACT_ENTRYPOINTS
181 static SIZE_T SizeOf(PrecodeType t);
186 return SizeOf(GetType());
189 // Note: This is immediate target of the precode. It does not follow jump stub if there is one.
192 BOOL IsPointingTo(PCODE target, PCODE addr)
197 #ifdef CROSSGEN_COMPILE
198 // Crossgen does not create jump stubs on AMD64, so just return always false here to
199 // avoid non-deterministic behavior.
201 #else // CROSSGEN_COMPILE
205 #ifdef _TARGET_AMD64_
207 if (isJumpRel64(target)) {
208 target = decodeJump64(target);
212 #endif // _TARGET_AMD64_
215 #endif // CROSSGEN_COMPILE
218 BOOL IsPointingToNativeCode(PCODE pNativeCode)
223 return IsPointingTo(GetTarget(), pNativeCode);
226 BOOL IsPointingToPrestub(PCODE target);
228 BOOL IsPointingToPrestub()
231 return IsPointingToPrestub(GetTarget());
234 PCODE GetEntryPoint()
236 LIMITED_METHOD_CONTRACT;
237 return dac_cast<TADDR>(this) + GetEntryPointOffset();
240 static SIZE_T GetEntryPointOffset()
242 LIMITED_METHOD_CONTRACT;
250 MethodDesc * GetMethodDesc(BOOL fSpeculative = FALSE);
251 BOOL IsCorrectMethodDesc(MethodDesc * pMD);
253 static Precode* Allocate(PrecodeType t, MethodDesc* pMD,
254 LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
255 void Init(PrecodeType t, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
257 #ifndef DACCESS_COMPILE
258 void ResetTargetInterlocked();
259 BOOL SetTargetInterlocked(PCODE target, BOOL fOnlyRedirectFromPrestub = TRUE);
261 // Reset precode to point to prestub
263 #endif // DACCESS_COMPILE
265 static Precode* GetPrecodeFromEntryPoint(PCODE addr, BOOL fSpeculative = FALSE)
267 LIMITED_METHOD_DAC_CONTRACT;
269 #ifdef DACCESS_COMPILE
270 // Always use speculative checks with DAC
274 TADDR pInstr = PCODEToPINSTR(addr);
276 // Always do consistency check in debug
277 if (fSpeculative INDEBUG(|| TRUE))
279 if (!IS_ALIGNED(pInstr, PRECODE_ALIGNMENT) || !IsValidType(PTR_Precode(pInstr)->GetType()))
281 if (fSpeculative) return NULL;
282 _ASSERTE(!"Precode::GetPrecodeFromEntryPoint: Unexpected code in precode");
286 Precode* pPrecode = PTR_Precode(pInstr);
290 g_IBCLogger.LogMethodPrecodeAccess(pPrecode->GetMethodDesc());
296 // If addr is patched fixup precode, returns address that it points to. Otherwise returns NULL.
297 static PCODE TryToSkipFixupPrecode(PCODE addr);
300 // Precode as temporary entrypoint
303 static SIZE_T SizeOfTemporaryEntryPoint(PrecodeType t)
305 LIMITED_METHOD_DAC_CONTRACT;
306 #ifdef HAS_FIXUP_PRECODE_CHUNKS
307 _ASSERTE(t != PRECODE_FIXUP);
309 #ifdef HAS_RELATIVE_FIXUP_PRECODE
310 _ASSERTE(t != PRECODE_RELATIVE_FIXUP);
311 #endif // HAS_RELATIVE_FIXUP_PRECODE
312 return ALIGN_UP(SizeOf(t), AlignOf(t));
315 static Precode * GetPrecodeForTemporaryEntryPoint(TADDR temporaryEntryPoints, int index);
317 static SIZE_T SizeOfTemporaryEntryPoints(PrecodeType t, bool preallocateJumpStubs, int count);
318 static SIZE_T SizeOfTemporaryEntryPoints(TADDR temporaryEntryPoints, int count);
320 static TADDR AllocateTemporaryEntryPoints(MethodDescChunk* pChunk,
321 LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
323 #ifdef FEATURE_PREJIT
328 void Save(DataImage *image);
329 void Fixup(DataImage *image, MethodDesc * pMD);
331 BOOL IsPrebound(DataImage *image);
333 // Helper class for saving precodes in chunks
336 #ifdef HAS_FIXUP_PRECODE_CHUNKS
337 // Array of methods to be saved in the method desc chunk
338 InlineSArray<MethodDesc *, 20> m_rgPendingChunk;
339 #endif // HAS_FIXUP_PRECODE_CHUNKS
342 void Save(DataImage * image, MethodDesc * pMD);
343 void Flush(DataImage * image);
345 #endif // FEATURE_PREJIT
347 #ifdef DACCESS_COMPILE
348 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
352 #endif // __PRECODE_H__