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_RELATIVE_STUB_PRECODE
23 PRECODE_RELATIVE_STUB = RelativeStubPrecode::Type,
24 #endif // HAS_RELATIVE_STUB_PRECODE
25 #ifdef HAS_NDIRECT_IMPORT_PRECODE
26 PRECODE_NDIRECT_IMPORT = NDirectImportPrecode::Type,
27 #endif // HAS_NDIRECT_IMPORT_PRECODE
28 #ifdef HAS_FIXUP_PRECODE
29 PRECODE_FIXUP = FixupPrecode::Type,
30 #endif // HAS_FIXUP_PRECODE
31 #ifdef HAS_RELATIVE_FIXUP_PRECODE
32 PRECODE_RELATIVE_FIXUP = RelativeFixupPrecode::Type,
33 #endif // HAS_RELATIVE_FIXUP_PRECODE
34 #ifdef HAS_THISPTR_RETBUF_PRECODE
35 PRECODE_THISPTR_RETBUF = ThisPtrRetBufPrecode::Type,
36 #endif // HAS_THISPTR_RETBUF_PRECODE
39 // For more details see. file:../../doc/BookOfTheRuntime/ClassLoader/MethodDescDesign.doc
41 #ifdef DACCESS_COMPILE
42 friend class NativeImageDumper;
45 BYTE m_data[SIZEOF_PRECODE_BASE];
47 StubPrecode* AsStubPrecode()
49 LIMITED_METHOD_CONTRACT;
52 return dac_cast<PTR_StubPrecode>(this);
55 #ifdef HAS_RELATIVE_STUB_PRECODE
56 RelativeStubPrecode* AsRelativeStubPrecode()
58 LIMITED_METHOD_CONTRACT;
61 return dac_cast<PTR_RelativeStubPrecode>(this);
63 #endif // HAS_RELATIVE_STUB_PRECODE
65 #ifdef HAS_NDIRECT_IMPORT_PRECODE
67 // Fake precodes has to be exposed
68 NDirectImportPrecode* AsNDirectImportPrecode()
70 LIMITED_METHOD_CONTRACT;
73 return dac_cast<PTR_NDirectImportPrecode>(this);
77 #endif // HAS_NDIRECT_IMPORT_PRECODE
79 #ifdef HAS_FIXUP_PRECODE
80 FixupPrecode* AsFixupPrecode()
82 LIMITED_METHOD_CONTRACT;
85 return dac_cast<PTR_FixupPrecode>(this);
87 #endif // HAS_FIXUP_PRECODE
89 #ifdef HAS_RELATIVE_FIXUP_PRECODE
90 RelativeFixupPrecode* AsRelativeFixupPrecode()
92 LIMITED_METHOD_CONTRACT;
95 return dac_cast<PTR_RelativeFixupPrecode>(this);
97 #endif // HAS_RELATIVE_FIXUP_PRECODE
99 #ifdef HAS_THISPTR_RETBUF_PRECODE
100 ThisPtrRetBufPrecode* AsThisPtrRetBufPrecode()
102 LIMITED_METHOD_CONTRACT;
104 return dac_cast<PTR_ThisPtrRetBufPrecode>(this);
106 #endif // HAS_THISPTR_RETBUF_PRECODE
111 LIMITED_METHOD_CONTRACT;
112 return dac_cast<TADDR>(this);
115 static void UnexpectedPrecodeType(const char * originator, PrecodeType precodeType)
119 #ifdef DACCESS_COMPILE
120 DacError(E_UNEXPECTED);
123 // We only use __UNREACHABLE here since otherwise it would be a hint
124 // for the compiler to fold this case with the other cases in a switch
125 // statement. However, we would rather have this case be a separate
126 // code path so that we will get a clean crash sooner.
127 __UNREACHABLE("Unexpected precode type");
129 CONSISTENCY_CHECK_MSGF(false, ("%s: Unexpected precode type: 0x%02x.", originator, precodeType));
134 PrecodeType GetType()
136 LIMITED_METHOD_CONTRACT;
139 #ifdef OFFSETOF_PRECODE_TYPE
141 BYTE type = m_data[OFFSETOF_PRECODE_TYPE];
143 if (type == X86_INSTR_MOV_RM_R)
144 type = m_data[OFFSETOF_PRECODE_TYPE_MOV_RM_R];
145 #endif // _TARGET_X86_
147 #ifdef _TARGET_AMD64_
148 if (type == (X86_INSTR_MOV_R10_IMM64 & 0xFF))
149 type = m_data[OFFSETOF_PRECODE_TYPE_MOV_R10];
150 else if ((type == (X86_INSTR_CALL_REL32 & 0xFF)) || (type == (X86_INSTR_JMP_REL32 & 0xFF)))
151 type = m_data[OFFSETOF_PRECODE_TYPE_CALL_OR_JMP];
154 #if defined(HAS_FIXUP_PRECODE) && (defined(_TARGET_X86_) || defined(_TARGET_AMD64_))
155 if (type == FixupPrecode::TypePrestub)
156 type = FixupPrecode::Type;
160 static_assert_no_msg(offsetof(StubPrecode, m_pTarget) == offsetof(NDirectImportPrecode, m_pMethodDesc));
161 // If the precode does not have thumb bit on target, it must be NDirectImportPrecode.
162 if (type == StubPrecode::Type && ((AsStubPrecode()->m_pTarget & THUMB_CODE) == 0))
163 type = NDirectImportPrecode::Type;
166 return (PrecodeType)type;
168 #else // OFFSETOF_PRECODE_TYPE
170 #endif // OFFSETOF_PRECODE_TYPE
173 static BOOL IsValidType(PrecodeType t);
175 static int AlignOf(PrecodeType t)
178 int align = PRECODE_ALIGNMENT;
180 #if defined(_TARGET_X86_) && defined(HAS_FIXUP_PRECODE)
181 // Fixup precodes has to be aligned to allow atomic patching
182 if (t == PRECODE_FIXUP)
184 #endif // _TARGET_X86_ && HAS_FIXUP_PRECODE
186 #if defined(_TARGET_ARM_) && defined(HAS_COMPACT_ENTRYPOINTS)
187 // Precodes have to be aligned to allow fast compact entry points check
188 _ASSERTE (align >= sizeof(void*));
189 #endif // _TARGET_ARM_ && HAS_COMPACT_ENTRYPOINTS
194 static SIZE_T SizeOf(PrecodeType t);
199 return SizeOf(GetType());
202 // Note: This is immediate target of the precode. It does not follow jump stub if there is one.
205 BOOL IsPointingTo(PCODE target, PCODE addr)
210 #ifdef CROSSGEN_COMPILE
211 // Crossgen does not create jump stubs on AMD64, so just return always false here to
212 // avoid non-deterministic behavior.
214 #else // CROSSGEN_COMPILE
218 #ifdef _TARGET_AMD64_
220 if (isJumpRel64(target)) {
221 target = decodeJump64(target);
225 #endif // _TARGET_AMD64_
228 #endif // CROSSGEN_COMPILE
231 BOOL IsPointingToNativeCode(PCODE pNativeCode)
236 return IsPointingTo(GetTarget(), pNativeCode);
239 BOOL IsPointingToPrestub(PCODE target);
241 BOOL IsPointingToPrestub()
244 return IsPointingToPrestub(GetTarget());
247 PCODE GetEntryPoint()
249 LIMITED_METHOD_CONTRACT;
250 return dac_cast<TADDR>(this) + GetEntryPointOffset();
253 static SIZE_T GetEntryPointOffset()
255 LIMITED_METHOD_CONTRACT;
263 MethodDesc * GetMethodDesc(BOOL fSpeculative = FALSE);
264 BOOL IsCorrectMethodDesc(MethodDesc * pMD);
266 static Precode* Allocate(PrecodeType t, MethodDesc* pMD,
267 LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
268 void Init(PrecodeType t, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
270 #ifndef DACCESS_COMPILE
271 void ResetTargetInterlocked();
272 BOOL SetTargetInterlocked(PCODE target, BOOL fOnlyRedirectFromPrestub = TRUE);
274 // Reset precode to point to prestub
276 #endif // DACCESS_COMPILE
278 static Precode* GetPrecodeFromEntryPoint(PCODE addr, BOOL fSpeculative = FALSE)
280 LIMITED_METHOD_DAC_CONTRACT;
282 #ifdef DACCESS_COMPILE
283 // Always use speculative checks with DAC
287 TADDR pInstr = PCODEToPINSTR(addr);
289 // Always do consistency check in debug
290 if (fSpeculative INDEBUG(|| TRUE))
292 if (!IS_ALIGNED(pInstr, PRECODE_ALIGNMENT) || !IsValidType(PTR_Precode(pInstr)->GetType()))
294 if (fSpeculative) return NULL;
295 _ASSERTE(!"Precode::GetPrecodeFromEntryPoint: Unexpected code in precode");
299 Precode* pPrecode = PTR_Precode(pInstr);
303 g_IBCLogger.LogMethodPrecodeAccess(pPrecode->GetMethodDesc());
309 // If addr is patched fixup precode, returns address that it points to. Otherwise returns NULL.
310 static PCODE TryToSkipFixupPrecode(PCODE addr);
313 // Precode as temporary entrypoint
316 static SIZE_T SizeOfTemporaryEntryPoint(PrecodeType t)
318 LIMITED_METHOD_DAC_CONTRACT;
319 #ifdef HAS_FIXUP_PRECODE_CHUNKS
320 _ASSERTE(t != PRECODE_FIXUP);
322 #ifdef HAS_RELATIVE_FIXUP_PRECODE
323 _ASSERTE(t != PRECODE_RELATIVE_FIXUP);
324 #endif // HAS_RELATIVE_FIXUP_PRECODE
325 #ifdef HAS_RELATIVE_STUB_PRECODE
326 _ASSERTE(t != PRECODE_RELATIVE_STUB);
327 #endif // HAS_RELATIVE_STUB_PRECODE
328 return ALIGN_UP(SizeOf(t), AlignOf(t));
331 static Precode * GetPrecodeForTemporaryEntryPoint(TADDR temporaryEntryPoints, int index);
333 static SIZE_T SizeOfTemporaryEntryPoints(PrecodeType t, bool preallocateJumpStubs, int count);
334 static SIZE_T SizeOfTemporaryEntryPoints(TADDR temporaryEntryPoints, int count);
336 static TADDR AllocateTemporaryEntryPoints(MethodDescChunk* pChunk,
337 LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
339 #ifdef FEATURE_PREJIT
344 void Save(DataImage *image);
345 void Fixup(DataImage *image, MethodDesc * pMD);
347 BOOL IsPrebound(DataImage *image);
349 // Helper class for saving precodes in chunks
352 #ifdef HAS_FIXUP_PRECODE_CHUNKS
353 // Array of methods to be saved in the method desc chunk
354 InlineSArray<MethodDesc *, 20> m_rgPendingChunk;
355 #endif // HAS_FIXUP_PRECODE_CHUNKS
358 void Save(DataImage * image, MethodDesc * pMD);
359 void Flush(DataImage * image);
361 #endif // FEATURE_PREJIT
363 #ifdef DACCESS_COMPILE
364 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
368 #endif // __PRECODE_H__