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