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 | |
5 | /*****************************************************************************/ |
6 | #ifndef _JIT_H_ |
7 | #define _JIT_H_ |
8 | /*****************************************************************************/ |
9 | |
10 | // |
11 | // clr.sln only defines _DEBUG |
12 | // The jit uses DEBUG rather than _DEBUG |
13 | // So we make sure that _DEBUG implies DEBUG |
14 | // |
15 | #ifdef _DEBUG |
16 | #ifndef DEBUG |
17 | #define DEBUG 1 |
18 | #endif |
19 | #endif |
20 | |
21 | // Clang-format messes with the indentation of comments if they directly precede an |
22 | // ifdef. This macro allows us to anchor the comments to the regular flow of code. |
23 | #define ; |
24 | |
25 | // Clang-tidy replaces 0 with nullptr in some templated functions, causing a build |
26 | // break. Replacing those instances with ZERO avoids this change |
27 | #define ZERO 0 |
28 | |
29 | #ifdef _MSC_VER |
30 | // These don't seem useful, so turning them off is no big deal |
31 | #pragma warning(disable : 4065) // "switch statement contains 'default' but no 'case' labels" (happens due to #ifdefs) |
32 | #pragma warning(disable : 4510) // can't generate default constructor |
33 | #pragma warning(disable : 4511) // can't generate copy constructor |
34 | #pragma warning(disable : 4512) // can't generate assignment constructor |
35 | #pragma warning(disable : 4610) // user defined constructor required |
36 | #pragma warning(disable : 4211) // nonstandard extension used (char name[0] in structs) |
37 | #pragma warning(disable : 4127) // conditional expression constant |
38 | #pragma warning(disable : 4201) // "nonstandard extension used : nameless struct/union" |
39 | |
40 | // Depending on the code base, you may want to not disable these |
41 | #pragma warning(disable : 4245) // assigning signed / unsigned |
42 | #pragma warning(disable : 4146) // unary minus applied to unsigned |
43 | |
44 | #pragma warning(disable : 4100) // unreferenced formal parameter |
45 | #pragma warning(disable : 4291) // new operator without delete (only in emitX86.cpp) |
46 | #endif |
47 | |
48 | #ifdef _MSC_VER |
49 | #define CHECK_STRUCT_PADDING 0 // Set this to '1' to enable warning C4820 "'bytes' bytes padding added after |
50 | // construct 'member_name'" on interesting structs/classes |
51 | #else |
52 | #define CHECK_STRUCT_PADDING 0 // Never enable it for non-MSFT compilers |
53 | #endif |
54 | |
55 | #if defined(_X86_) |
56 | #if defined(_ARM_) |
57 | #error Cannot define both _X86_ and _ARM_ |
58 | #endif |
59 | #if defined(_AMD64_) |
60 | #error Cannot define both _X86_ and _AMD64_ |
61 | #endif |
62 | #if defined(_ARM64_) |
63 | #error Cannot define both _X86_ and _ARM64_ |
64 | #endif |
65 | #define _HOST_X86_ |
66 | #elif defined(_AMD64_) |
67 | #if defined(_X86_) |
68 | #error Cannot define both _AMD64_ and _X86_ |
69 | #endif |
70 | #if defined(_ARM_) |
71 | #error Cannot define both _AMD64_ and _ARM_ |
72 | #endif |
73 | #if defined(_ARM64_) |
74 | #error Cannot define both _AMD64_ and _ARM64_ |
75 | #endif |
76 | #define _HOST_AMD64_ |
77 | #elif defined(_ARM_) |
78 | #if defined(_X86_) |
79 | #error Cannot define both _ARM_ and _X86_ |
80 | #endif |
81 | #if defined(_AMD64_) |
82 | #error Cannot define both _ARM_ and _AMD64_ |
83 | #endif |
84 | #if defined(_ARM64_) |
85 | #error Cannot define both _ARM_ and _ARM64_ |
86 | #endif |
87 | #define _HOST_ARM_ |
88 | #elif defined(_ARM64_) |
89 | #if defined(_X86_) |
90 | #error Cannot define both _ARM64_ and _X86_ |
91 | #endif |
92 | #if defined(_AMD64_) |
93 | #error Cannot define both _ARM64_ and _AMD64_ |
94 | #endif |
95 | #if defined(_ARM_) |
96 | #error Cannot define both _ARM64_ and _ARM_ |
97 | #endif |
98 | #define _HOST_ARM64_ |
99 | #else |
100 | #error Unsupported or unset host architecture |
101 | #endif |
102 | |
103 | #if defined(_HOST_AMD64_) || defined(_HOST_ARM64_) |
104 | #define _HOST_64BIT_ |
105 | #endif |
106 | |
107 | #if defined(_TARGET_X86_) |
108 | #if defined(_TARGET_ARM_) |
109 | #error Cannot define both _TARGET_X86_ and _TARGET_ARM_ |
110 | #endif |
111 | #if defined(_TARGET_AMD64_) |
112 | #error Cannot define both _TARGET_X86_ and _TARGET_AMD64_ |
113 | #endif |
114 | #if defined(_TARGET_ARM64_) |
115 | #error Cannot define both _TARGET_X86_ and _TARGET_ARM64_ |
116 | #endif |
117 | #if !defined(_HOST_X86_) |
118 | #define _CROSS_COMPILER_ |
119 | #endif |
120 | #elif defined(_TARGET_AMD64_) |
121 | #if defined(_TARGET_X86_) |
122 | #error Cannot define both _TARGET_AMD64_ and _TARGET_X86_ |
123 | #endif |
124 | #if defined(_TARGET_ARM_) |
125 | #error Cannot define both _TARGET_AMD64_ and _TARGET_ARM_ |
126 | #endif |
127 | #if defined(_TARGET_ARM64_) |
128 | #error Cannot define both _TARGET_AMD64_ and _TARGET_ARM64_ |
129 | #endif |
130 | #if !defined(_HOST_AMD64_) |
131 | #define _CROSS_COMPILER_ |
132 | #endif |
133 | #elif defined(_TARGET_ARM_) |
134 | #if defined(_TARGET_X86_) |
135 | #error Cannot define both _TARGET_ARM_ and _TARGET_X86_ |
136 | #endif |
137 | #if defined(_TARGET_AMD64_) |
138 | #error Cannot define both _TARGET_ARM_ and _TARGET_AMD64_ |
139 | #endif |
140 | #if defined(_TARGET_ARM64_) |
141 | #error Cannot define both _TARGET_ARM_ and _TARGET_ARM64_ |
142 | #endif |
143 | #if !defined(_HOST_ARM_) |
144 | #define _CROSS_COMPILER_ |
145 | #endif |
146 | #elif defined(_TARGET_ARM64_) |
147 | #if defined(_TARGET_X86_) |
148 | #error Cannot define both _TARGET_ARM64_ and _TARGET_X86_ |
149 | #endif |
150 | #if defined(_TARGET_AMD64_) |
151 | #error Cannot define both _TARGET_ARM64_ and _TARGET_AMD64_ |
152 | #endif |
153 | #if defined(_TARGET_ARM_) |
154 | #error Cannot define both _TARGET_ARM64_ and _TARGET_ARM_ |
155 | #endif |
156 | #if !defined(_HOST_ARM64_) |
157 | #define _CROSS_COMPILER_ |
158 | #endif |
159 | #else |
160 | #error Unsupported or unset target architecture |
161 | #endif |
162 | |
163 | #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) |
164 | #ifndef _TARGET_64BIT_ |
165 | #define _TARGET_64BIT_ |
166 | #endif // _TARGET_64BIT_ |
167 | #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) |
168 | |
169 | #ifdef _TARGET_64BIT_ |
170 | #ifdef _TARGET_X86_ |
171 | #error Cannot define both _TARGET_X86_ and _TARGET_64BIT_ |
172 | #endif // _TARGET_X86_ |
173 | #ifdef _TARGET_ARM_ |
174 | #error Cannot define both _TARGET_ARM_ and _TARGET_64BIT_ |
175 | #endif // _TARGET_ARM_ |
176 | #endif // _TARGET_64BIT_ |
177 | |
178 | #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) |
179 | #define _TARGET_XARCH_ |
180 | #endif |
181 | |
182 | #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_) |
183 | #define _TARGET_ARMARCH_ |
184 | #endif |
185 | |
186 | // If the UNIX_AMD64_ABI is defined make sure that _TARGET_AMD64_ is also defined. |
187 | #if defined(UNIX_AMD64_ABI) |
188 | #if !defined(_TARGET_AMD64_) |
189 | #error When UNIX_AMD64_ABI is defined you must define _TARGET_AMD64_ defined as well. |
190 | #endif |
191 | #endif |
192 | |
193 | // If the UNIX_X86_ABI is defined make sure that _TARGET_X86_ is also defined. |
194 | #if defined(UNIX_X86_ABI) |
195 | #if !defined(_TARGET_X86_) |
196 | #error When UNIX_X86_ABI is defined you must define _TARGET_X86_ defined as well. |
197 | #endif |
198 | #endif |
199 | |
200 | #if defined(PLATFORM_UNIX) |
201 | #define _HOST_UNIX_ |
202 | #endif |
203 | |
204 | // Are we generating code to target Unix? This is true if we will run on Unix (_HOST_UNIX_ is defined). |
205 | // It's also true if we are building an altjit targetting Unix, which we determine by checking if either |
206 | // UNIX_AMD64_ABI or UNIX_X86_ABI is defined. |
207 | #if defined(_HOST_UNIX_) || ((defined(UNIX_AMD64_ABI) || defined(UNIX_X86_ABI)) && defined(ALT_JIT)) |
208 | #define _TARGET_UNIX_ |
209 | #endif |
210 | |
211 | #ifndef _TARGET_UNIX_ |
212 | #define _TARGET_WINDOWS_ |
213 | #endif // !_TARGET_UNIX_ |
214 | |
215 | // -------------------------------------------------------------------------------- |
216 | // IMAGE_FILE_MACHINE_TARGET |
217 | // -------------------------------------------------------------------------------- |
218 | |
219 | #if defined(_TARGET_X86_) |
220 | #define IMAGE_FILE_MACHINE_TARGET IMAGE_FILE_MACHINE_I386 |
221 | #elif defined(_TARGET_AMD64_) |
222 | #define IMAGE_FILE_MACHINE_TARGET IMAGE_FILE_MACHINE_AMD64 |
223 | #elif defined(_TARGET_ARM_) |
224 | #define IMAGE_FILE_MACHINE_TARGET IMAGE_FILE_MACHINE_ARMNT |
225 | #elif defined(_TARGET_ARM64_) |
226 | #define IMAGE_FILE_MACHINE_TARGET IMAGE_FILE_MACHINE_ARM64 // 0xAA64 |
227 | #else |
228 | #error Unsupported or unset target architecture |
229 | #endif |
230 | |
231 | // Include the AMD64 unwind codes when appropriate. |
232 | #if defined(_TARGET_AMD64_) |
233 | // We need to temporarily set PLATFORM_UNIX, if necessary, to get the Unix-specific unwind codes. |
234 | #if defined(_TARGET_UNIX_) && !defined(_HOST_UNIX_) |
235 | #define PLATFORM_UNIX |
236 | #endif |
237 | #include "win64unwind.h" |
238 | #if defined(_TARGET_UNIX_) && !defined(_HOST_UNIX_) |
239 | #undef PLATFORM_UNIX |
240 | #endif |
241 | #endif |
242 | |
243 | #include "corhdr.h" |
244 | #include "corjit.h" |
245 | #include "jitee.h" |
246 | |
247 | #define __OPERATOR_NEW_INLINE 1 // indicate that I will define these |
248 | #define __PLACEMENT_NEW_INLINE // don't bring in the global placement new, it is easy to make a mistake |
249 | // with our new(compiler*) pattern. |
250 | |
251 | #include "utilcode.h" // this defines assert as _ASSERTE |
252 | #include "host.h" // this redefines assert for the JIT to use assertAbort |
253 | #include "utils.h" |
254 | |
255 | #ifdef DEBUG |
256 | #define INDEBUG(x) x |
257 | #define INDEBUG_COMMA(x) x, |
258 | #define DEBUGARG(x) , x |
259 | #else |
260 | #define INDEBUG(x) |
261 | #define INDEBUG_COMMA(x) |
262 | #define DEBUGARG(x) |
263 | #endif |
264 | |
265 | #if defined(DEBUG) || defined(LATE_DISASM) |
266 | #define INDEBUG_LDISASM_COMMA(x) x, |
267 | #else |
268 | #define INDEBUG_LDISASM_COMMA(x) |
269 | #endif |
270 | |
271 | #if defined(UNIX_AMD64_ABI) |
272 | #define UNIX_AMD64_ABI_ONLY_ARG(x) , x |
273 | #define UNIX_AMD64_ABI_ONLY(x) x |
274 | #else // !defined(UNIX_AMD64_ABI) |
275 | #define UNIX_AMD64_ABI_ONLY_ARG(x) |
276 | #define UNIX_AMD64_ABI_ONLY(x) |
277 | #endif // defined(UNIX_AMD64_ABI) |
278 | |
279 | #if defined(UNIX_AMD64_ABI) || !defined(_TARGET_64BIT_) || (defined(_TARGET_WINDOWS_) && defined(_TARGET_ARM64_)) |
280 | #define FEATURE_PUT_STRUCT_ARG_STK 1 |
281 | #define PUT_STRUCT_ARG_STK_ONLY_ARG(x) , x |
282 | #define PUT_STRUCT_ARG_STK_ONLY(x) x |
283 | #else // !(defined(UNIX_AMD64_ABI) && defined(_TARGET_64BIT_) && !(defined(_TARGET_WINDOWS_) && defined(_TARGET_ARM64_)) |
284 | #define PUT_STRUCT_ARG_STK_ONLY_ARG(x) |
285 | #define PUT_STRUCT_ARG_STK_ONLY(x) |
286 | #endif // !(defined(UNIX_AMD64_ABI) && defined(_TARGET_64BIT_) && !(defined(_TARGET_WINDOWS_) && |
287 | // defined(_TARGET_ARM64_)) |
288 | |
289 | #if defined(UNIX_AMD64_ABI) |
290 | #define UNIX_AMD64_ABI_ONLY_ARG(x) , x |
291 | #define UNIX_AMD64_ABI_ONLY(x) x |
292 | #else // !defined(UNIX_AMD64_ABI) |
293 | #define UNIX_AMD64_ABI_ONLY_ARG(x) |
294 | #define UNIX_AMD64_ABI_ONLY(x) |
295 | #endif // defined(UNIX_AMD64_ABI) |
296 | |
297 | #if defined(UNIX_AMD64_ABI) || defined(_TARGET_ARM64_) |
298 | #define MULTIREG_HAS_SECOND_GC_RET 1 |
299 | #define MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(x) , x |
300 | #define MULTIREG_HAS_SECOND_GC_RET_ONLY(x) x |
301 | #else // !defined(UNIX_AMD64_ABI) |
302 | #define MULTIREG_HAS_SECOND_GC_RET 0 |
303 | #define MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(x) |
304 | #define MULTIREG_HAS_SECOND_GC_RET_ONLY(x) |
305 | #endif // defined(UNIX_AMD64_ABI) |
306 | |
307 | // Arm64 Windows supports FEATURE_ARG_SPLIT, note this is different from |
308 | // the official Arm64 ABI. |
309 | // Case: splitting 16 byte struct between x7 and stack |
310 | #if (defined(_TARGET_ARM_) || (defined(_TARGET_WINDOWS_) && defined(_TARGET_ARM64_))) |
311 | #define FEATURE_ARG_SPLIT 1 |
312 | #else |
313 | #define FEATURE_ARG_SPLIT 0 |
314 | #endif // (defined(_TARGET_ARM_) || (defined(_TARGET_WINDOWS_) && defined(_TARGET_ARM64_))) |
315 | |
316 | // To get rid of warning 4701 : local variable may be used without being initialized |
317 | #define DUMMY_INIT(x) (x) |
318 | |
319 | #define REGEN_SHORTCUTS 0 |
320 | #define REGEN_CALLPAT 0 |
321 | |
322 | /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
323 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
324 | XX XX |
325 | XX jit.h XX |
326 | XX XX |
327 | XX Interface of the JIT with jit.cpp XX |
328 | XX XX |
329 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
330 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
331 | */ |
332 | |
333 | /*****************************************************************************/ |
334 | #if defined(DEBUG) |
335 | #include "log.h" |
336 | |
337 | #define INFO6 LL_INFO10000 // Did Jit or Inline succeeded? |
338 | #define INFO7 LL_INFO100000 // NYI stuff |
339 | #define INFO8 LL_INFO1000000 // Weird failures |
340 | #define INFO9 LL_EVERYTHING // Info about incoming settings |
341 | #define INFO10 LL_EVERYTHING // Totally verbose |
342 | |
343 | #endif // DEBUG |
344 | |
345 | typedef class ICorJitInfo* COMP_HANDLE; |
346 | |
347 | const CORINFO_CLASS_HANDLE NO_CLASS_HANDLE = (CORINFO_CLASS_HANDLE) nullptr; |
348 | |
349 | /*****************************************************************************/ |
350 | |
351 | inline bool False() |
352 | { |
353 | return false; |
354 | } // Use to disable code while keeping prefast happy |
355 | |
356 | // We define two IL offset types, as follows: |
357 | // |
358 | // IL_OFFSET: either a distinguished value, or an IL offset. |
359 | // IL_OFFSETX: either a distinguished value, or the top two bits are a flags, and the remaining bottom |
360 | // bits are a IL offset. |
361 | // |
362 | // In both cases, the set of legal distinguished values is: |
363 | // BAD_IL_OFFSET -- A unique illegal IL offset number. Note that it must be different from |
364 | // the ICorDebugInfo values, below, and must also not be a legal IL offset. |
365 | // ICorDebugInfo::NO_MAPPING -- The IL offset corresponds to no source code (such as EH step blocks). |
366 | // ICorDebugInfo::PROLOG -- The IL offset indicates a prolog |
367 | // ICorDebugInfo::EPILOG -- The IL offset indicates an epilog |
368 | // |
369 | // The IL offset must be in the range [0 .. 0x3fffffff]. This is because we steal |
370 | // the top two bits in IL_OFFSETX for flags, but we want the maximum range to be the same |
371 | // for both types. The IL value can't be larger than the maximum IL offset of the function |
372 | // being compiled. |
373 | // |
374 | // Blocks and statements never store one of the ICorDebugInfo values, even for IL_OFFSETX types. These are |
375 | // only stored in the IPmappingDsc struct, ipmdILoffsx field. |
376 | |
377 | typedef unsigned IL_OFFSET; |
378 | |
379 | const IL_OFFSET BAD_IL_OFFSET = 0x80000000; |
380 | const IL_OFFSET MAX_IL_OFFSET = 0x3fffffff; |
381 | |
382 | typedef unsigned IL_OFFSETX; // IL_OFFSET with stack-empty or call-instruction bit |
383 | const IL_OFFSETX IL_OFFSETX_STKBIT = 0x80000000; // Note: this bit is set when the stack is NOT empty! |
384 | const IL_OFFSETX IL_OFFSETX_CALLINSTRUCTIONBIT = 0x40000000; // Set when the IL offset is for a call instruction. |
385 | const IL_OFFSETX IL_OFFSETX_BITS = IL_OFFSETX_STKBIT | IL_OFFSETX_CALLINSTRUCTIONBIT; |
386 | |
387 | IL_OFFSET jitGetILoffs(IL_OFFSETX offsx); |
388 | IL_OFFSET jitGetILoffsAny(IL_OFFSETX offsx); |
389 | bool jitIsStackEmpty(IL_OFFSETX offsx); |
390 | bool jitIsCallInstruction(IL_OFFSETX offsx); |
391 | |
392 | const unsigned BAD_VAR_NUM = UINT_MAX; |
393 | |
394 | // Code can't be more than 2^31 in any direction. This is signed, so it should be used for anything that is |
395 | // relative to something else. |
396 | typedef int NATIVE_OFFSET; |
397 | |
398 | // This is the same as the above, but it's used in absolute contexts (i.e. offset from the start). Also, |
399 | // this is used for native code sizes. |
400 | typedef unsigned UNATIVE_OFFSET; |
401 | |
402 | typedef ptrdiff_t ssize_t; |
403 | |
404 | // For the following specially handled FIELD_HANDLES we need |
405 | // values that are negative and have the low two bits zero |
406 | // See eeFindJitDataOffs and eeGetJitDataOffs in Compiler.hpp |
407 | #define FLD_GLOBAL_DS ((CORINFO_FIELD_HANDLE)-4) |
408 | #define FLD_GLOBAL_FS ((CORINFO_FIELD_HANDLE)-8) |
409 | |
410 | /*****************************************************************************/ |
411 | |
412 | #include "vartype.h" |
413 | |
414 | /*****************************************************************************/ |
415 | |
416 | // Late disassembly is OFF by default. Can be turned ON by |
417 | // adding /DLATE_DISASM=1 on the command line. |
418 | // Always OFF in the non-debug version |
419 | |
420 | #if defined(LATE_DISASM) && (LATE_DISASM == 0) |
421 | #undef LATE_DISASM |
422 | #endif |
423 | |
424 | /*****************************************************************************/ |
425 | |
426 | /*****************************************************************************/ |
427 | |
428 | #define FEATURE_VALNUM_CSE 1 // enable the Value Number CSE optimization logic |
429 | |
430 | // true if Value Number CSE is enabled |
431 | #define FEATURE_ANYCSE FEATURE_VALNUM_CSE |
432 | |
433 | #define CSE_INTO_HANDLERS 0 |
434 | |
435 | #define LARGE_EXPSET 1 // Track 64 or 32 assertions/copies/consts/rangechecks |
436 | #define ASSERTION_PROP 1 // Enable value/assertion propagation |
437 | |
438 | #define LOCAL_ASSERTION_PROP ASSERTION_PROP // Enable local assertion propagation |
439 | |
440 | //============================================================================= |
441 | |
442 | #define OPT_BOOL_OPS 1 // optimize boolean operations |
443 | |
444 | //============================================================================= |
445 | |
446 | #define REDUNDANT_LOAD 1 // track locals in regs, suppress loads |
447 | #define STACK_PROBES 0 // Support for stack probes |
448 | #define DUMP_FLOWGRAPHS DEBUG // Support for creating Xml Flowgraph reports in *.fgx files |
449 | |
450 | #define HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION 1 // if 1 we must have all handler entry points in the Hot code section |
451 | |
452 | /*****************************************************************************/ |
453 | |
454 | #define VPTR_OFFS 0 // offset of vtable pointer from obj ptr |
455 | |
456 | /*****************************************************************************/ |
457 | |
458 | #define DUMP_GC_TABLES DEBUG |
459 | #define VERIFY_GC_TABLES 0 |
460 | #define REARRANGE_ADDS 1 |
461 | |
462 | #define FUNC_INFO_LOGGING 1 // Support dumping function info to a file. In retail, only NYIs, with no function name, |
463 | // are dumped. |
464 | |
465 | /*****************************************************************************/ |
466 | /*****************************************************************************/ |
467 | /* Set these to 1 to collect and output various statistics about the JIT */ |
468 | |
469 | #define CALL_ARG_STATS 0 // Collect stats about calls and call arguments. |
470 | #define COUNT_BASIC_BLOCKS 0 // Create a histogram of basic block sizes, and a histogram of IL sizes in the simple |
471 | // case of single block methods. |
472 | #define COUNT_LOOPS 0 // Collect stats about loops, such as the total number of natural loops, a histogram of |
473 | // the number of loop exits, etc. |
474 | #define DATAFLOW_ITER 0 // Count iterations in lexical CSE and constant folding dataflow. |
475 | #define DISPLAY_SIZES 0 // Display generated code, data, and GC information sizes. |
476 | #define MEASURE_BLOCK_SIZE 0 // Collect stats about basic block and flowList node sizes and memory allocations. |
477 | #define MEASURE_FATAL 0 // Count the number of calls to fatal(), including NYIs and noway_asserts. |
478 | #define MEASURE_NODE_SIZE 0 // Collect stats about GenTree node allocations. |
479 | #define MEASURE_PTRTAB_SIZE 0 // Collect stats about GC pointer table allocations. |
480 | #define EMITTER_STATS 0 // Collect stats on the emitter. |
481 | #define NODEBASH_STATS 0 // Collect stats on changed gtOper values in GenTree's. |
482 | #define COUNT_AST_OPERS 0 // Display use counts for GenTree operators. |
483 | |
484 | #define VERBOSE_SIZES 0 // Always display GC info sizes. If set, DISPLAY_SIZES must also be set. |
485 | #define VERBOSE_VERIFY 0 // Dump additional information when verifying code. Useful to debug verification bugs. |
486 | |
487 | #ifdef DEBUG |
488 | #define MEASURE_MEM_ALLOC 1 // Collect memory allocation stats. |
489 | #define LOOP_HOIST_STATS 1 // Collect loop hoisting stats. |
490 | #define TRACK_LSRA_STATS 1 // Collect LSRA stats |
491 | #else |
492 | #define MEASURE_MEM_ALLOC 0 // You can set this to 1 to get memory stats in retail, as well |
493 | #define LOOP_HOIST_STATS 0 // You can set this to 1 to get loop hoist stats in retail, as well |
494 | #define TRACK_LSRA_STATS 0 // You can set this to 1 to get LSRA stats in retail, as well |
495 | #endif |
496 | |
497 | // Timing calls to clr.dll is only available under certain conditions. |
498 | #ifndef FEATURE_JIT_METHOD_PERF |
499 | #define MEASURE_CLRAPI_CALLS 0 // Can't time these calls without METHOD_PERF. |
500 | #endif |
501 | #ifdef DEBUG |
502 | #define MEASURE_CLRAPI_CALLS 0 // No point in measuring DEBUG code. |
503 | #endif |
504 | #if !defined(_HOST_X86_) && !defined(_HOST_AMD64_) |
505 | #define MEASURE_CLRAPI_CALLS 0 // Cycle counters only hooked up on x86/x64. |
506 | #endif |
507 | #if !defined(_MSC_VER) && !defined(__clang__) |
508 | #define MEASURE_CLRAPI_CALLS 0 // Only know how to do this with VC and Clang. |
509 | #endif |
510 | |
511 | // If none of the above set the flag to 0, it's available. |
512 | #ifndef MEASURE_CLRAPI_CALLS |
513 | #define MEASURE_CLRAPI_CALLS 0 // Set to 1 to measure time in ICorJitInfo calls. |
514 | #endif |
515 | |
516 | /*****************************************************************************/ |
517 | /* Portability Defines */ |
518 | /*****************************************************************************/ |
519 | #ifdef _TARGET_X86_ |
520 | #define JIT32_GCENCODER |
521 | #endif |
522 | |
523 | /*****************************************************************************/ |
524 | #ifdef DEBUG |
525 | /*****************************************************************************/ |
526 | |
527 | #define DUMPER |
528 | |
529 | #else // !DEBUG |
530 | |
531 | #if DUMP_GC_TABLES |
532 | #pragma message("NOTE: this non-debug build has GC ptr table dumping always enabled!") |
533 | const bool dspGCtbls = true; |
534 | #endif |
535 | |
536 | /*****************************************************************************/ |
537 | #endif // !DEBUG |
538 | |
539 | #ifdef DEBUG |
540 | #define JITDUMP(...) \ |
541 | { \ |
542 | if (JitTls::GetCompiler()->verbose) \ |
543 | logf(__VA_ARGS__); \ |
544 | } |
545 | #define JITLOG(x) \ |
546 | { \ |
547 | JitLogEE x; \ |
548 | } |
549 | #define JITLOG_THIS(t, x) \ |
550 | { \ |
551 | (t)->JitLogEE x; \ |
552 | } |
553 | #define DBEXEC(flg, expr) \ |
554 | if (flg) \ |
555 | { \ |
556 | expr; \ |
557 | } |
558 | #define DISPNODE(t) \ |
559 | if (JitTls::GetCompiler()->verbose) \ |
560 | JitTls::GetCompiler()->gtDispTree(t, nullptr, nullptr, true); |
561 | #define DISPTREE(t) \ |
562 | if (JitTls::GetCompiler()->verbose) \ |
563 | JitTls::GetCompiler()->gtDispTree(t); |
564 | #define DISPRANGE(range) \ |
565 | if (JitTls::GetCompiler()->verbose) \ |
566 | JitTls::GetCompiler()->gtDispRange(range); |
567 | #define DISPTREERANGE(range, t) \ |
568 | if (JitTls::GetCompiler()->verbose) \ |
569 | JitTls::GetCompiler()->gtDispTreeRange(range, t); |
570 | #define VERBOSE JitTls::GetCompiler()->verbose |
571 | #else // !DEBUG |
572 | #define JITDUMP(...) |
573 | #define JITLOG(x) |
574 | #define JITLOG_THIS(t, x) |
575 | #define DBEXEC(flg, expr) |
576 | #define DISPNODE(t) |
577 | #define DISPTREE(t) |
578 | #define DISPRANGE(range) |
579 | #define DISPTREERANGE(range, t) |
580 | #define VERBOSE 0 |
581 | #endif // !DEBUG |
582 | |
583 | /***************************************************************************** |
584 | * |
585 | * Double alignment. This aligns ESP to 0 mod 8 in function prolog, then uses ESP |
586 | * to reference locals, EBP to reference parameters. |
587 | * It only makes sense if frameless method support is on. |
588 | * (frameless method support is now always on) |
589 | */ |
590 | |
591 | #ifdef _TARGET_X86_ |
592 | #define DOUBLE_ALIGN 1 // permit the double alignment of ESP in prolog, |
593 | // and permit the double alignment of local offsets |
594 | #else |
595 | #define DOUBLE_ALIGN 0 // no special handling for double alignment |
596 | #endif |
597 | |
598 | #ifdef DEBUG |
599 | |
600 | struct JitOptions |
601 | { |
602 | const char* methodName; // Method to display output for |
603 | const char* className; // Class to display output for |
604 | |
605 | double CGknob; // Tweakable knob for testing |
606 | unsigned testMask; // Tweakable mask for testing |
607 | |
608 | JitOptions* lastDummyField; // Ensures instantiation uses right order of arguments |
609 | }; |
610 | |
611 | extern JitOptions jitOpts; |
612 | |
613 | // Forward declarations for UninitializedWord and IsUninitialized are needed by alloc.h |
614 | template <typename T> |
615 | inline T UninitializedWord(Compiler* comp); |
616 | |
617 | template <typename T> |
618 | inline bool IsUninitialized(T data); |
619 | |
620 | #endif // DEBUG |
621 | |
622 | /*****************************************************************************/ |
623 | |
624 | enum accessLevel |
625 | { |
626 | ACL_NONE, |
627 | ACL_PRIVATE, |
628 | ACL_DEFAULT, |
629 | ACL_PROTECTED, |
630 | ACL_PUBLIC, |
631 | }; |
632 | |
633 | /*****************************************************************************/ |
634 | |
635 | #define castto(var, typ) (*(typ*)&var) |
636 | |
637 | #define sizeto(typ, mem) (offsetof(typ, mem) + sizeof(((typ*)0)->mem)) |
638 | |
639 | /*****************************************************************************/ |
640 | |
641 | #ifdef NO_MISALIGNED_ACCESS |
642 | |
643 | #define MISALIGNED_RD_I2(src) (*castto(src, char*) | *castto(src + 1, char*) << 8) |
644 | |
645 | #define MISALIGNED_RD_U2(src) (*castto(src, char*) | *castto(src + 1, char*) << 8) |
646 | |
647 | #define MISALIGNED_WR_I2(dst, val) \ |
648 | *castto(dst, char*) = val; \ |
649 | *castto(dst + 1, char*) = val >> 8; |
650 | |
651 | #define MISALIGNED_WR_I4(dst, val) \ |
652 | *castto(dst, char*) = val; \ |
653 | *castto(dst + 1, char*) = val >> 8; \ |
654 | *castto(dst + 2, char*) = val >> 16; \ |
655 | *castto(dst + 3, char*) = val >> 24; |
656 | |
657 | #else |
658 | |
659 | #define MISALIGNED_RD_I2(src) (*castto(src, short*)) |
660 | #define MISALIGNED_RD_U2(src) (*castto(src, unsigned short*)) |
661 | |
662 | #define MISALIGNED_WR_I2(dst, val) *castto(dst, short*) = val; |
663 | #define MISALIGNED_WR_I4(dst, val) *castto(dst, int*) = val; |
664 | |
665 | #define MISALIGNED_WR_ST(dst, val) *castto(dst, ssize_t*) = val; |
666 | |
667 | #endif |
668 | |
669 | /*****************************************************************************/ |
670 | |
671 | inline size_t roundUp(size_t size, size_t mult = sizeof(size_t)) |
672 | { |
673 | assert(mult && ((mult & (mult - 1)) == 0)); // power of two test |
674 | |
675 | return (size + (mult - 1)) & ~(mult - 1); |
676 | } |
677 | |
678 | inline size_t roundDn(size_t size, size_t mult = sizeof(size_t)) |
679 | { |
680 | assert(mult && ((mult & (mult - 1)) == 0)); // power of two test |
681 | |
682 | return (size) & ~(mult - 1); |
683 | } |
684 | |
685 | #ifdef _HOST_64BIT_ |
686 | inline unsigned int roundUp(unsigned size, unsigned mult) |
687 | { |
688 | return (unsigned int)roundUp((size_t)size, (size_t)mult); |
689 | } |
690 | |
691 | inline unsigned int roundDn(unsigned size, unsigned mult) |
692 | { |
693 | return (unsigned int)roundDn((size_t)size, (size_t)mult); |
694 | } |
695 | #endif // _HOST_64BIT_ |
696 | |
697 | inline unsigned int unsigned_abs(int x) |
698 | { |
699 | return ((unsigned int)abs(x)); |
700 | } |
701 | |
702 | #ifdef _TARGET_64BIT_ |
703 | inline size_t unsigned_abs(ssize_t x) |
704 | { |
705 | return ((size_t)abs(x)); |
706 | } |
707 | #endif // _TARGET_64BIT_ |
708 | |
709 | /*****************************************************************************/ |
710 | |
711 | #if CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE || MEASURE_MEM_ALLOC |
712 | |
713 | #define HISTOGRAM_MAX_SIZE_COUNT 64 |
714 | |
715 | class Histogram |
716 | { |
717 | public: |
718 | Histogram(const unsigned* const sizeTable); |
719 | |
720 | void dump(FILE* output); |
721 | void record(unsigned size); |
722 | |
723 | private: |
724 | unsigned m_sizeCount; |
725 | const unsigned* const m_sizeTable; |
726 | unsigned m_counts[HISTOGRAM_MAX_SIZE_COUNT]; |
727 | }; |
728 | |
729 | #endif // CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE |
730 | |
731 | /*****************************************************************************/ |
732 | #ifdef ICECAP |
733 | #include "icapexp.h" |
734 | #include "icapctrl.h" |
735 | #endif |
736 | |
737 | /*****************************************************************************/ |
738 | |
739 | #include "error.h" |
740 | |
741 | /*****************************************************************************/ |
742 | |
743 | #if CHECK_STRUCT_PADDING |
744 | #pragma warning(push) |
745 | #pragma warning(default : 4820) // 'bytes' bytes padding added after construct 'member_name' |
746 | #endif // CHECK_STRUCT_PADDING |
747 | #include "alloc.h" |
748 | #include "target.h" |
749 | |
750 | #if FEATURE_TAILCALL_OPT |
751 | |
752 | #ifdef FEATURE_CORECLR |
753 | // CoreCLR - enable tail call opt for the following IL pattern |
754 | // |
755 | // call someFunc |
756 | // jmp/jcc RetBlock |
757 | // ... |
758 | // RetBlock: |
759 | // ret |
760 | #define FEATURE_TAILCALL_OPT_SHARED_RETURN 1 |
761 | #else |
762 | // Desktop: Keep this to zero as one of app-compat apps that is using GetCallingAssembly() |
763 | // has an issue turning this ON. |
764 | // |
765 | // Refer to TF: Bug: 824625 and its associated regression TF Bug: 1113265 |
766 | #define FEATURE_TAILCALL_OPT_SHARED_RETURN 0 |
767 | #endif // FEATURE_CORECLR |
768 | |
769 | #else // !FEATURE_TAILCALL_OPT |
770 | #define FEATURE_TAILCALL_OPT_SHARED_RETURN 0 |
771 | #endif // !FEATURE_TAILCALL_OPT |
772 | |
773 | #define CLFLG_CODESIZE 0x00001 |
774 | #define CLFLG_CODESPEED 0x00002 |
775 | #define CLFLG_CSE 0x00004 |
776 | #define CLFLG_REGVAR 0x00008 |
777 | #define CLFLG_RNGCHKOPT 0x00010 |
778 | #define CLFLG_DEADASGN 0x00020 |
779 | #define CLFLG_CODEMOTION 0x00040 |
780 | #define CLFLG_QMARK 0x00080 |
781 | #define CLFLG_TREETRANS 0x00100 |
782 | #define CLFLG_INLINING 0x00200 |
783 | #define CLFLG_CONSTANTFOLD 0x00800 |
784 | |
785 | #if FEATURE_STRUCTPROMOTE |
786 | #define CLFLG_STRUCTPROMOTE 0x00400 |
787 | #else |
788 | #define CLFLG_STRUCTPROMOTE 0x00000 |
789 | #endif |
790 | |
791 | #define CLFLG_MAXOPT \ |
792 | (CLFLG_CSE | CLFLG_REGVAR | CLFLG_RNGCHKOPT | CLFLG_DEADASGN | CLFLG_CODEMOTION | CLFLG_QMARK | CLFLG_TREETRANS | \ |
793 | CLFLG_INLINING | CLFLG_STRUCTPROMOTE | CLFLG_CONSTANTFOLD) |
794 | |
795 | #define CLFLG_MINOPT (CLFLG_TREETRANS) |
796 | |
797 | #define JIT_RESERVED_STACK 64 // Reserved for arguments of calls and hidden |
798 | // pushes for finallys so that we don't |
799 | // probe on every call site. See comment in |
800 | // for CORINFO_STACKPROBE_DEPTH in corjit.h |
801 | |
802 | /*****************************************************************************/ |
803 | |
804 | extern void dumpILBytes(const BYTE* const codeAddr, unsigned codeSize, unsigned alignSize); |
805 | |
806 | extern unsigned dumpSingleInstr(const BYTE* const codeAddr, IL_OFFSET offs, const char* prefix = nullptr); |
807 | |
808 | extern void dumpILRange(const BYTE* const codeAddr, unsigned codeSize); // in bytes |
809 | |
810 | /*****************************************************************************/ |
811 | |
812 | extern int jitNativeCode(CORINFO_METHOD_HANDLE methodHnd, |
813 | CORINFO_MODULE_HANDLE classHnd, |
814 | COMP_HANDLE compHnd, |
815 | CORINFO_METHOD_INFO* methodInfo, |
816 | void** methodCodePtr, |
817 | ULONG* methodCodeSize, |
818 | JitFlags* compileFlags, |
819 | void* inlineInfoPtr); |
820 | |
821 | #ifdef _HOST_64BIT_ |
822 | const size_t INVALID_POINTER_VALUE = 0xFEEDFACEABADF00D; |
823 | #else |
824 | const size_t INVALID_POINTER_VALUE = 0xFEEDFACE; |
825 | #endif |
826 | |
827 | // Constants for making sure size_t fit into smaller types. |
828 | const size_t MAX_USHORT_SIZE_T = static_cast<size_t>(static_cast<unsigned short>(-1)); |
829 | const size_t MAX_UNSIGNED_SIZE_T = static_cast<size_t>(static_cast<unsigned>(-1)); |
830 | |
831 | // These assume 2's complement... |
832 | const int MAX_SHORT_AS_INT = 32767; |
833 | const int MIN_SHORT_AS_INT = -32768; |
834 | |
835 | /*****************************************************************************/ |
836 | |
837 | class Compiler; |
838 | |
839 | class JitTls |
840 | { |
841 | #ifdef DEBUG |
842 | Compiler* m_compiler; |
843 | LogEnv m_logEnv; |
844 | JitTls* m_next; |
845 | #endif |
846 | |
847 | public: |
848 | JitTls(ICorJitInfo* jitInfo); |
849 | ~JitTls(); |
850 | |
851 | #ifdef DEBUG |
852 | static LogEnv* GetLogEnv(); |
853 | #endif |
854 | |
855 | static Compiler* GetCompiler(); |
856 | static void SetCompiler(Compiler* compiler); |
857 | }; |
858 | |
859 | #if defined(DEBUG) |
860 | // Include the definition of Compiler for use by these template functions |
861 | // |
862 | #include "compiler.h" |
863 | |
864 | //**************************************************************************** |
865 | // |
866 | // Returns a word filled with the JITs allocator default fill value. |
867 | // |
868 | template <typename T> |
869 | inline T UninitializedWord(Compiler* comp) |
870 | { |
871 | unsigned char defaultFill = 0xdd; |
872 | if (comp == nullptr) |
873 | { |
874 | comp = JitTls::GetCompiler(); |
875 | } |
876 | defaultFill = comp->compGetJitDefaultFill(); |
877 | assert(defaultFill <= 0xff); |
878 | __int64 word = 0x0101010101010101LL * defaultFill; |
879 | return (T)word; |
880 | } |
881 | |
882 | //**************************************************************************** |
883 | // |
884 | // Tries to determine if this value is coming from uninitialized JIT memory |
885 | // - Returns true if the value matches what we initialized the memory to. |
886 | // |
887 | // Notes: |
888 | // - Asserts that use this are assuming that the UninitializedWord value |
889 | // isn't a legal value for 'data'. Thus using a default fill value of |
890 | // 0x00 will often trigger such asserts. |
891 | // |
892 | template <typename T> |
893 | inline bool IsUninitialized(T data) |
894 | { |
895 | return data == UninitializedWord<T>(JitTls::GetCompiler()); |
896 | } |
897 | |
898 | #pragma warning(push) |
899 | #pragma warning(disable : 4312) |
900 | //**************************************************************************** |
901 | // |
902 | // Debug template definitions for dspPtr, dspOffset |
903 | // - Used to format pointer/offset values for diffable Disasm |
904 | // |
905 | template <typename T> |
906 | T dspPtr(T p) |
907 | { |
908 | return (p == ZERO) ? ZERO : (JitTls::GetCompiler()->opts.dspDiffable ? T(0xD1FFAB1E) : p); |
909 | } |
910 | |
911 | template <typename T> |
912 | T dspOffset(T o) |
913 | { |
914 | return (o == ZERO) ? ZERO : (JitTls::GetCompiler()->opts.dspDiffable ? T(0xD1FFAB1E) : o); |
915 | } |
916 | #pragma warning(pop) |
917 | |
918 | #else // !defined(DEBUG) |
919 | |
920 | //**************************************************************************** |
921 | // |
922 | // Non-Debug template definitions for dspPtr, dspOffset |
923 | // - This is a nop in non-Debug builds |
924 | // |
925 | template <typename T> |
926 | T dspPtr(T p) |
927 | { |
928 | return p; |
929 | } |
930 | |
931 | template <typename T> |
932 | T dspOffset(T o) |
933 | { |
934 | return o; |
935 | } |
936 | |
937 | #endif // !defined(DEBUG) |
938 | |
939 | /*****************************************************************************/ |
940 | #endif //_JIT_H_ |
941 | /*****************************************************************************/ |
942 | |