[Tizen] Add RelativeFixupPrecode for arm64, which replaces FixupPrecode in FNV images
[platform/upstream/coreclr.git] / src / vm / precode.h
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.
4 // precode.h
5 //
6
7 //
8 // Stub that runs before the actual native code
9
10 #ifndef __PRECODE_H__
11 #define __PRECODE_H__
12
13 typedef DPTR(class Precode) PTR_Precode;
14
15 #ifndef PRECODE_ALIGNMENT
16 #define PRECODE_ALIGNMENT sizeof(void*)
17 #endif
18
19 enum PrecodeType {
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
34 };
35
36 // For more details see. file:../../doc/BookOfTheRuntime/ClassLoader/MethodDescDesign.doc
37 class Precode {
38 #ifdef DACCESS_COMPILE
39     friend class NativeImageDumper;
40 #endif
41
42     BYTE m_data[SIZEOF_PRECODE_BASE];
43
44     StubPrecode* AsStubPrecode()
45     {
46         LIMITED_METHOD_CONTRACT;
47         SUPPORTS_DAC;
48
49         return dac_cast<PTR_StubPrecode>(this);
50     }
51
52 #ifdef HAS_NDIRECT_IMPORT_PRECODE
53 public:
54     // Fake precodes has to be exposed
55     NDirectImportPrecode* AsNDirectImportPrecode()
56     {
57         LIMITED_METHOD_CONTRACT;
58         SUPPORTS_DAC;
59
60         return dac_cast<PTR_NDirectImportPrecode>(this);
61     }
62
63 private:
64 #endif // HAS_NDIRECT_IMPORT_PRECODE
65
66 #ifdef HAS_FIXUP_PRECODE
67     FixupPrecode* AsFixupPrecode()
68     {
69         LIMITED_METHOD_CONTRACT;
70         SUPPORTS_DAC;
71
72         return dac_cast<PTR_FixupPrecode>(this);
73     }
74 #endif // HAS_FIXUP_PRECODE
75
76 #ifdef HAS_RELATIVE_FIXUP_PRECODE
77     RelativeFixupPrecode* AsRelativeFixupPrecode()
78     {
79       LIMITED_METHOD_CONTRACT;
80       SUPPORTS_DAC;
81
82       return dac_cast<PTR_RelativeFixupPrecode>(this);
83     }
84 #endif // HAS_RELATIVE_FIXUP_PRECODE
85
86 #ifdef HAS_THISPTR_RETBUF_PRECODE
87     ThisPtrRetBufPrecode* AsThisPtrRetBufPrecode()
88     {
89         LIMITED_METHOD_CONTRACT;
90         SUPPORTS_DAC;
91         return dac_cast<PTR_ThisPtrRetBufPrecode>(this);
92     }
93 #endif // HAS_THISPTR_RETBUF_PRECODE
94
95     TADDR GetStart()
96     {
97         SUPPORTS_DAC;
98         LIMITED_METHOD_CONTRACT;
99         return dac_cast<TADDR>(this);
100     }
101
102     static void UnexpectedPrecodeType(const char * originator, PrecodeType precodeType)
103
104     {
105         SUPPORTS_DAC;
106 #ifdef DACCESS_COMPILE
107         DacError(E_UNEXPECTED);
108 #else
109 #ifdef _PREFIX_
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");
115 #endif
116         CONSISTENCY_CHECK_MSGF(false, ("%s: Unexpected precode type: 0x%02x.", originator, precodeType));
117 #endif
118     }
119
120 public:
121     PrecodeType GetType()
122     {
123         LIMITED_METHOD_CONTRACT;
124         SUPPORTS_DAC;
125
126 #ifdef OFFSETOF_PRECODE_TYPE
127
128         BYTE type = m_data[OFFSETOF_PRECODE_TYPE];
129 #ifdef _TARGET_X86_
130         if (type == X86_INSTR_MOV_RM_R)
131             type = m_data[OFFSETOF_PRECODE_TYPE_MOV_RM_R];
132 #endif //  _TARGET_X86_
133
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];
139 #endif // _AMD64
140
141 #if defined(HAS_FIXUP_PRECODE) && (defined(_TARGET_X86_) || defined(_TARGET_AMD64_))
142         if (type == FixupPrecode::TypePrestub)
143             type = FixupPrecode::Type;
144 #endif
145
146 #ifdef _TARGET_ARM_
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;
151 #endif
152
153         return (PrecodeType)type;
154
155 #else // OFFSETOF_PRECODE_TYPE
156         return PRECODE_STUB;
157 #endif // OFFSETOF_PRECODE_TYPE
158     }
159
160     static BOOL IsValidType(PrecodeType t);
161
162     static int AlignOf(PrecodeType t)
163     {
164         SUPPORTS_DAC;
165         int align = PRECODE_ALIGNMENT;
166
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)
170             align = 8;
171 #endif // _TARGET_X86_ && HAS_FIXUP_PRECODE
172
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
177
178         return align;
179     }
180
181     static SIZE_T SizeOf(PrecodeType t);
182
183     SIZE_T SizeOf()
184     {
185         WRAPPER_NO_CONTRACT;
186         return SizeOf(GetType());
187     }
188
189     // Note: This is immediate target of the precode. It does not follow jump stub if there is one.
190     PCODE GetTarget();
191
192     BOOL IsPointingTo(PCODE target, PCODE addr)
193     {
194         WRAPPER_NO_CONTRACT;
195         SUPPORTS_DAC;
196
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.
200         return FALSE;
201 #else // CROSSGEN_COMPILE
202         if (target == addr)
203             return TRUE;
204
205 #ifdef _TARGET_AMD64_
206         // Handle jump stubs
207         if (isJumpRel64(target)) {
208             target = decodeJump64(target);
209             if (target == addr)
210                 return TRUE;
211         }
212 #endif // _TARGET_AMD64_
213
214         return FALSE;
215 #endif // CROSSGEN_COMPILE
216     }
217
218     BOOL IsPointingToNativeCode(PCODE pNativeCode)
219     {
220         WRAPPER_NO_CONTRACT;
221         SUPPORTS_DAC;
222
223         return IsPointingTo(GetTarget(), pNativeCode);
224     }
225
226     BOOL IsPointingToPrestub(PCODE target);
227
228     BOOL IsPointingToPrestub()
229     {
230         WRAPPER_NO_CONTRACT;
231         return IsPointingToPrestub(GetTarget());
232     }
233
234     PCODE GetEntryPoint()
235     {
236         LIMITED_METHOD_CONTRACT;
237         return dac_cast<TADDR>(this) + GetEntryPointOffset();
238     }
239
240     static SIZE_T GetEntryPointOffset()
241     {
242         LIMITED_METHOD_CONTRACT;
243 #ifdef _TARGET_ARM_
244         return THUMB_CODE;
245 #else
246         return 0;
247 #endif
248     }
249
250     MethodDesc *  GetMethodDesc(BOOL fSpeculative = FALSE);
251     BOOL          IsCorrectMethodDesc(MethodDesc *  pMD);
252
253     static Precode* Allocate(PrecodeType t, MethodDesc* pMD,
254         LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
255     void Init(PrecodeType t, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
256
257 #ifndef DACCESS_COMPILE
258     void ResetTargetInterlocked();
259     BOOL SetTargetInterlocked(PCODE target, BOOL fOnlyRedirectFromPrestub = TRUE);
260
261     // Reset precode to point to prestub
262     void Reset();
263 #endif // DACCESS_COMPILE
264
265     static Precode* GetPrecodeFromEntryPoint(PCODE addr, BOOL fSpeculative = FALSE)
266     {
267         LIMITED_METHOD_DAC_CONTRACT;
268
269 #ifdef DACCESS_COMPILE
270         // Always use speculative checks with DAC
271         fSpeculative = TRUE;
272 #endif
273
274         TADDR pInstr = PCODEToPINSTR(addr);
275
276         // Always do consistency check in debug
277         if (fSpeculative INDEBUG(|| TRUE))
278         {
279             if (!IS_ALIGNED(pInstr, PRECODE_ALIGNMENT) || !IsValidType(PTR_Precode(pInstr)->GetType()))
280             {
281                 if (fSpeculative) return NULL;
282                 _ASSERTE(!"Precode::GetPrecodeFromEntryPoint: Unexpected code in precode");
283             }
284         }
285
286         Precode* pPrecode = PTR_Precode(pInstr);
287
288         if (!fSpeculative)
289         {
290             g_IBCLogger.LogMethodPrecodeAccess(pPrecode->GetMethodDesc());
291         }
292
293         return pPrecode;
294     }
295
296     // If addr is patched fixup precode, returns address that it points to. Otherwise returns NULL.
297     static PCODE TryToSkipFixupPrecode(PCODE addr);
298
299     //
300     // Precode as temporary entrypoint
301     // 
302
303     static SIZE_T SizeOfTemporaryEntryPoint(PrecodeType t)
304     {
305         LIMITED_METHOD_DAC_CONTRACT;
306 #ifdef HAS_FIXUP_PRECODE_CHUNKS
307         _ASSERTE(t != PRECODE_FIXUP);
308 #endif
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));
313     }
314
315     static Precode * GetPrecodeForTemporaryEntryPoint(TADDR temporaryEntryPoints, int index);
316
317     static SIZE_T SizeOfTemporaryEntryPoints(PrecodeType t, bool preallocateJumpStubs, int count);
318     static SIZE_T SizeOfTemporaryEntryPoints(TADDR temporaryEntryPoints, int count);
319
320     static TADDR AllocateTemporaryEntryPoints(MethodDescChunk* pChunk,
321         LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
322
323 #ifdef FEATURE_PREJIT
324     //
325     // NGEN stuff
326     // 
327
328     void Save(DataImage *image);
329     void Fixup(DataImage *image, MethodDesc * pMD);
330
331     BOOL IsPrebound(DataImage *image);
332
333     // Helper class for saving precodes in chunks
334     class SaveChunk
335     {
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
340
341     public:
342         void Save(DataImage * image, MethodDesc * pMD);
343         void Flush(DataImage * image);
344     };
345 #endif // FEATURE_PREJIT
346
347 #ifdef DACCESS_COMPILE
348     void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
349 #endif
350 };
351
352 #endif // __PRECODE_H__