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 _GCINFO_H_
7 #define _GCINFO_H_
8 /*****************************************************************************/
9 
10 // Keep definitions in this file in sync with Nutc\UTC\gcinfo.h
11 
12 #ifdef _TARGET_ARM_
13 
14 #define NUM_PRESERVED_REGS 9
15 
16 enum RegMask
17 {
18     RBM_R0  = 0x0001,
19     RBM_R1  = 0x0002,
20     RBM_R2  = 0x0004,
21     RBM_R3  = 0x0008,
22     RBM_R4  = 0x0010,   // callee saved
23     RBM_R5  = 0x0020,   // callee saved
24     RBM_R6  = 0x0040,   // callee saved
25     RBM_R7  = 0x0080,   // callee saved
26     RBM_R8  = 0x0100,   // callee saved
27     RBM_R9  = 0x0200,   // callee saved
28     RBM_R10 = 0x0400,   // callee saved
29     RBM_R11 = 0x0800,   // callee saved
30     RBM_R12 = 0x1000,
31     RBM_SP  = 0x2000,
32     RBM_LR  = 0x4000,   // callee saved, but not valid to be alive across a call!
33     RBM_PC  = 0x8000,
34     RBM_RETVAL = RBM_R0,
35     RBM_CALLEE_SAVED_REGS = (RBM_R4|RBM_R5|RBM_R6|RBM_R7|RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_LR),
36     RBM_CALLEE_SAVED_REG_COUNT = 9,
37     // Special case: LR is callee saved, but may not appear as a live GC ref except
38     // in the leaf frame because calls will trash it.  Therefore, we ALSO consider
39     // it a scratch register.
40     RBM_SCRATCH_REGS = (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R12|RBM_LR),
41     RBM_SCRATCH_REG_COUNT = 6,
42 };
43 
44 enum RegNumber
45 {
46     RN_R0   = 0,
47     RN_R1   = 1,
48     RN_R2   = 2,
49     RN_R3   = 3,
50     RN_R4   = 4,
51     RN_R5   = 5,
52     RN_R6   = 6,
53     RN_R7   = 7,
54     RN_R8   = 8,
55     RN_R9   = 9,
56     RN_R10  = 10,
57     RN_R11  = 11,
58     RN_R12  = 12,
59     RN_SP   = 13,
60     RN_LR   = 14,
61     RN_PC   = 15,
62 
63     RN_NONE = 16,
64 };
65 
66 enum CalleeSavedRegNum
67 {
68     CSR_NUM_R4  = 0x00,
69     CSR_NUM_R5  = 0x01,
70     CSR_NUM_R6  = 0x02,
71     CSR_NUM_R7  = 0x03,
72     CSR_NUM_R8  = 0x04,
73     CSR_NUM_R9  = 0x05,
74     CSR_NUM_R10 = 0x06,
75     CSR_NUM_R11 = 0x07,
76     // NOTE: LR is omitted because it may not be live except as a 'scratch' reg
77 };
78 
79 enum CalleeSavedRegMask
80 {
81     CSR_MASK_NONE = 0x00,
82     CSR_MASK_R4   = 0x001,
83     CSR_MASK_R5   = 0x002,
84     CSR_MASK_R6   = 0x004,
85     CSR_MASK_R7   = 0x008,
86     CSR_MASK_R8   = 0x010,
87     CSR_MASK_R9   = 0x020,
88     CSR_MASK_R10  = 0x040,
89     CSR_MASK_R11  = 0x080,
90     CSR_MASK_LR   = 0x100,
91 
92     CSR_MASK_ALL  = 0x1ff,
93     CSR_MASK_HIGHEST = 0x100,
94 };
95 
96 enum ScratchRegNum
97 {
98     SR_NUM_R0   = 0x00,
99     SR_NUM_R1   = 0x01,
100     SR_NUM_R2   = 0x02,
101     SR_NUM_R3   = 0x03,
102     SR_NUM_R12  = 0x04,
103     SR_NUM_LR   = 0x05,
104 };
105 
106 enum ScratchRegMask
107 {
108     SR_MASK_NONE = 0x00,
109     SR_MASK_R0   = 0x01,
110     SR_MASK_R1   = 0x02,
111     SR_MASK_R2   = 0x04,
112     SR_MASK_R3   = 0x08,
113     SR_MASK_R12  = 0x10,
114     SR_MASK_LR   = 0x20,
115 };
116 
117 #elif defined(_TARGET_ARM64_)
118 
119 enum RegMask
120 {
121     RBM_NONE = 0,
122 
123     RBM_X0 = 0x00000001,
124     RBM_X1 = 0x00000002,
125     RBM_X2 = 0x00000004,
126     RBM_X3 = 0x00000008,
127     RBM_X4 = 0x00000010,
128     RBM_X5 = 0x00000020,
129     RBM_X6 = 0x00000040,
130     RBM_X7 = 0x00000080,
131     RBM_X8 = 0x00000100, // ARM64TODO: ARM64 ABI: indirect result register
132     RBM_X9 = 0x00000200,
133     RBM_X10 = 0x00000400,
134     RBM_X11 = 0x00000800,
135     RBM_X12 = 0x00001000,
136     RBM_X13 = 0x00002000,
137     RBM_X14 = 0x00004000,
138     RBM_X15 = 0x00008000,
139 
140     RBM_XIP0 = 0x00010000, // This one is occasionally used as a scratch register (but can be destroyed by branching or a call)
141     RBM_XIP1 = 0x00020000, // This one may be also used as a scratch register (but can be destroyed by branching or a call)
142     RBM_XPR = 0x00040000,
143 
144     RBM_X19 = 0x00080000, // RA_CALLEESAVE
145     RBM_X20 = 0x00100000, // RA_CALLEESAVE
146     RBM_X21 = 0x00200000, // RA_CALLEESAVE
147     RBM_X22 = 0x00400000, // RA_CALLEESAVE
148     RBM_X23 = 0x00800000, // RA_CALLEESAVE
149     RBM_X24 = 0x01000000, // RA_CALLEESAVE
150     RBM_X25 = 0x02000000, // RA_CALLEESAVE
151     RBM_X26 = 0x04000000, // RA_CALLEESAVE
152     RBM_X27 = 0x08000000, // RA_CALLEESAVE
153     RBM_X28 = 0x10000000, // RA_CALLEESAVE
154 
155     RBM_FP = 0x20000000,
156     RBM_LR = 0x40000000,
157     RBM_SP = 0x80000000,
158 
159     RBM_RETVAL = RBM_X8,
160     // Note: Callee saved regs: X19-X28; FP and LR are treated as callee-saved in unwinding code
161     RBM_CALLEE_SAVED_REG_COUNT = 12,
162 
163     // Scratch regs: X0-X15, XIP0, XIP1, LR
164     RBM_SCRATCH_REG_COUNT = 19,
165 };
166 
167 #define NUM_PRESERVED_REGS RBM_CALLEE_SAVED_REG_COUNT
168 
169 // Number of the callee-saved registers stored in the fixed header
170 #define NUM_PRESERVED_REGS_LOW 9
171 #define MASK_PRESERVED_REGS_LOW ((1 << NUM_PRESERVED_REGS_LOW) - 1)
172 
173 enum RegNumber
174 {
175     RN_X0 = 0,
176     RN_X1 = 1,
177     RN_X2 = 2,
178     RN_X3 = 3,
179     RN_X4 = 4,
180     RN_X5 = 5,
181     RN_X6 = 6,
182     RN_X7 = 7,
183     RN_X8 = 8, // indirect result register
184     RN_X9 = 9,
185     RN_X10 = 10,
186     RN_X11 = 11,
187     RN_X12 = 12,
188     RN_X13 = 13,
189     RN_X14 = 14,
190     RN_X15 = 15,
191 
192     RN_XIP0 = 16,
193     RN_XIP1 = 17,
194     RN_XPR = 18,
195 
196     RN_X19 = 19, // RA_CALLEESAVE
197     RN_X20 = 20, // RA_CALLEESAVE
198     RN_X21 = 21, // RA_CALLEESAVE
199     RN_X22 = 22, // RA_CALLEESAVE
200     RN_X23 = 23, // RA_CALLEESAVE
201     RN_X24 = 24, // RA_CALLEESAVE
202     RN_X25 = 25, // RA_CALLEESAVE
203     RN_X26 = 26, // RA_CALLEESAVE
204     RN_X27 = 27, // RA_CALLEESAVE
205     RN_X28 = 28, // RA_CALLEESAVE
206 
207     RN_FP = 29,
208     RN_LR = 30,
209     RN_SP = 31,
210 
211     RN_NONE = 32,
212 };
213 
214 enum CalleeSavedRegNum
215 {
216     // NOTE: LR is omitted because it may not be live except as a 'scratch' reg
217     CSR_NUM_X19 = 1,
218     CSR_NUM_X20 = 2,
219     CSR_NUM_X21 = 3,
220     CSR_NUM_X22 = 4,
221     CSR_NUM_X23 = 5,
222     CSR_NUM_X24 = 6,
223     CSR_NUM_X25 = 7,
224     CSR_NUM_X26 = 8,
225     CSR_NUM_X27 = 9,
226     CSR_NUM_X28 = 10,
227     CSR_NUM_FP = 11,
228     CSR_NUM_NONE = 12,
229 };
230 
231 enum CalleeSavedRegMask
232 {
233     CSR_MASK_NONE = 0x00,
234     // LR is placed here to reduce the frequency of the long encoding
235     CSR_MASK_LR = 0x001,
236     CSR_MASK_X19 = 0x002,
237     CSR_MASK_X20 = 0x004,
238     CSR_MASK_X21 = 0x008,
239     CSR_MASK_X22 = 0x010,
240     CSR_MASK_X23 = 0x020,
241     CSR_MASK_X24 = 0x040,
242     CSR_MASK_X25 = 0x080,
243     CSR_MASK_X26 = 0x100,
244     CSR_MASK_X27 = 0x200,
245     CSR_MASK_X28 = 0x400,
246     CSR_MASK_FP = 0x800,
247 
248     CSR_MASK_ALL = 0xfff,
249     CSR_MASK_HIGHEST = 0x800,
250 };
251 
252 enum ScratchRegNum
253 {
254     SR_NUM_X0 = 0,
255     SR_NUM_X1 = 1,
256     SR_NUM_X2 = 2,
257     SR_NUM_X3 = 3,
258     SR_NUM_X4 = 4,
259     SR_NUM_X5 = 5,
260     SR_NUM_X6 = 6,
261     SR_NUM_X7 = 7,
262     SR_NUM_X8 = 8,
263     SR_NUM_X9 = 9,
264     SR_NUM_X10 = 10,
265     SR_NUM_X11 = 11,
266     SR_NUM_X12 = 12,
267     SR_NUM_X13 = 13,
268     SR_NUM_X14 = 14,
269     SR_NUM_X15 = 15,
270 
271     SR_NUM_XIP0 = 16,
272     SR_NUM_XIP1 = 17,
273     SR_NUM_LR = 18,
274 
275     SR_NUM_NONE = 19,
276 };
277 
278 enum ScratchRegMask
279 {
280     SR_MASK_NONE = 0x00,
281     SR_MASK_X0 = 0x01,
282     SR_MASK_X1 = 0x02,
283     SR_MASK_X2 = 0x04,
284     SR_MASK_X3 = 0x08,
285     SR_MASK_X4 = 0x10,
286     SR_MASK_X5 = 0x20,
287     SR_MASK_X6 = 0x40,
288     SR_MASK_X7 = 0x80,
289     SR_MASK_X8 = 0x100,
290     SR_MASK_X9 = 0x200,
291     SR_MASK_X10 = 0x400,
292     SR_MASK_X11 = 0x800,
293     SR_MASK_X12 = 0x1000,
294     SR_MASK_X13 = 0x2000,
295     SR_MASK_X14 = 0x4000,
296     SR_MASK_X15 = 0x8000,
297 
298     SR_MASK_XIP0 = 0x10000,
299     SR_MASK_XIP1 = 0x20000,
300     SR_MASK_LR = 0x40000,
301 };
302 
303 #else // _TARGET_ARM_
304 
305 #ifdef _TARGET_AMD64_
306 #define NUM_PRESERVED_REGS 8
307 #else
308 #define NUM_PRESERVED_REGS 4
309 #endif
310 
311 enum RegMask
312 {
313     RBM_EAX = 0x0001,
314     RBM_ECX = 0x0002,
315     RBM_EDX = 0x0004,
316     RBM_EBX = 0x0008,   // callee saved
317     RBM_ESP = 0x0010,
318     RBM_EBP = 0x0020,   // callee saved
319     RBM_ESI = 0x0040,   // callee saved
320     RBM_EDI = 0x0080,   // callee saved
321 
322     RBM_R8  = 0x0100,
323     RBM_R9  = 0x0200,
324     RBM_R10 = 0x0400,
325     RBM_R11 = 0x0800,
326     RBM_R12 = 0x1000,   // callee saved
327     RBM_R13 = 0x2000,   // callee saved
328     RBM_R14 = 0x4000,   // callee saved
329     RBM_R15 = 0x8000,   // callee saved
330 
331     RBM_RETVAL = RBM_EAX,
332 
333 #ifdef _TARGET_AMD64_
334     RBM_CALLEE_SAVED_REGS = (RBM_EDI|RBM_ESI|RBM_EBX|RBM_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15),
335     RBM_CALLEE_SAVED_REG_COUNT = 8,
336     RBM_SCRATCH_REGS = (RBM_EAX|RBM_ECX|RBM_EDX|RBM_R8|RBM_R9|RBM_R10|RBM_R11),
337     RBM_SCRATCH_REG_COUNT = 7,
338 #else
339     RBM_CALLEE_SAVED_REGS = (RBM_EDI|RBM_ESI|RBM_EBX|RBM_EBP),
340     RBM_CALLEE_SAVED_REG_COUNT = 4,
341     RBM_SCRATCH_REGS = (RBM_EAX|RBM_ECX|RBM_EDX),
342     RBM_SCRATCH_REG_COUNT = 3,
343 #endif // _TARGET_AMD64_
344 };
345 
346 enum RegNumber
347 {
348     RN_EAX = 0,
349     RN_ECX = 1,
350     RN_EDX = 2,
351     RN_EBX = 3,
352     RN_ESP = 4,
353     RN_EBP = 5,
354     RN_ESI = 6,
355     RN_EDI = 7,
356     RN_R8  = 8,
357     RN_R9  = 9,
358     RN_R10 = 10,
359     RN_R11 = 11,
360     RN_R12 = 12,
361     RN_R13 = 13,
362     RN_R14 = 14,
363     RN_R15 = 15,
364 
365     RN_NONE = 16,
366 };
367 
368 enum CalleeSavedRegNum
369 {
370     CSR_NUM_RBX = 0x00,
371     CSR_NUM_RSI = 0x01,
372     CSR_NUM_RDI = 0x02,
373     CSR_NUM_RBP = 0x03,
374 #ifdef _TARGET_AMD64_
375     CSR_NUM_R12 = 0x04,
376     CSR_NUM_R13 = 0x05,
377     CSR_NUM_R14 = 0x06,
378     CSR_NUM_R15 = 0x07,
379 #endif // _TARGET_AMD64_
380 };
381 
382 enum CalleeSavedRegMask
383 {
384     CSR_MASK_NONE = 0x00,
385     CSR_MASK_RBX = 0x01,
386     CSR_MASK_RSI = 0x02,
387     CSR_MASK_RDI = 0x04,
388     CSR_MASK_RBP = 0x08,
389     CSR_MASK_R12 = 0x10,
390     CSR_MASK_R13 = 0x20,
391     CSR_MASK_R14 = 0x40,
392     CSR_MASK_R15 = 0x80,
393 
394 #ifdef _TARGET_AMD64_
395     CSR_MASK_ALL = 0xFF,
396     CSR_MASK_HIGHEST = 0x80,
397 #else
398     CSR_MASK_ALL = 0x0F,
399     CSR_MASK_HIGHEST = 0x08,
400 #endif
401 };
402 
403 enum ScratchRegNum
404 {
405     SR_NUM_RAX = 0x00,
406     SR_NUM_RCX = 0x01,
407     SR_NUM_RDX = 0x02,
408 #ifdef _TARGET_AMD64_
409     SR_NUM_R8  = 0x03,
410     SR_NUM_R9  = 0x04,
411     SR_NUM_R10 = 0x05,
412     SR_NUM_R11 = 0x06,
413 #endif // _TARGET_AMD64_
414 };
415 
416 enum ScratchRegMask
417 {
418     SR_MASK_NONE = 0x00,
419     SR_MASK_RAX  = 0x01,
420     SR_MASK_RCX  = 0x02,
421     SR_MASK_RDX  = 0x04,
422     SR_MASK_R8   = 0x08,
423     SR_MASK_R9   = 0x10,
424     SR_MASK_R10  = 0x20,
425     SR_MASK_R11  = 0x40,
426 };
427 
428 #endif // _TARGET_ARM_
429 
430 struct GCInfoHeader
431 {
432 private:
433     UInt16  prologSize               : 6; // 0 [0:5]  // @TODO: define an 'overflow' encoding for big prologs?
434     UInt16  hasFunclets              : 1; // 0 [6]
435     UInt16  fixedEpilogSize          : 6; // 0 [7] + 1 [0:4]  '0' encoding implies that epilog size varies and is encoded for each epilog
436     UInt16  epilogCountSmall         : 2; // 1 [5:6] '3' encoding implies the number of epilogs is encoded separately
437     UInt16  hasExtraData             : 1; // 1 [7]  1: more data follows (dynamic alignment, GS cookie, common vars, etc.)
438 
439 #ifdef _TARGET_ARM_
440     UInt16  returnKind              : 2; // 2 [0:1] one of: MethodReturnKind enum
441     UInt16  ebpFrame                : 1; // 2 [2]   on x64, this means "has frame pointer and it is RBP", on ARM R7
442     UInt16  epilogAtEnd             : 1; // 2 [3]
443     UInt16  hasFrameSize            : 1; // 2 [4]   1: frame size is encoded below, 0: frame size is 0
444     UInt16 calleeSavedRegMask       : NUM_PRESERVED_REGS;   // 2 [5:7]    3 [0:5]
445     UInt16 arm_areParmOrVfpRegsPushed:1; // 3 [6]   1: pushed param reg set (R0-R3) and pushed fp reg start and count are encoded below, 0: no pushed param or fp registers
446 #elif defined (_TARGET_ARM64_)
447     UInt16  returnKind              : 2; // 2 [0:1] one of: MethodReturnKind enum
448     UInt16  ebpFrame                : 1; // 2 [2]   1: has frame pointer and it is FP
449     UInt16  epilogAtEnd             : 1; // 2 [3]
450     UInt16  hasFrameSize            : 1; // 2 [4]   1: frame size is encoded below, 0: frame size is 0
451     UInt16  arm64_longCsrMask            : 1; // 2 [5]  1: high bits of calleeSavedRegMask are encoded below
452     UInt16  arm64_areParmOrVfpRegsPushed : 1; // 2 [6]  1: pushed param reg count (X0-X7) and pushed fp reg set (D8-D15) are encoded below, 0: no pushed param or fp registers
453     UInt16  arm64_calleeSavedRegMaskLow  : NUM_PRESERVED_REGS_LOW;  // 2 [7]    3 [0:7]
454 #else
455     UInt8  returnKind               : 2; // 2 [0:1] one of: MethodReturnKind enum
456     UInt8  ebpFrame                 : 1; // 2 [2]   on x64, this means "has frame pointer and it is RBP", on ARM R7
457     UInt8  epilogAtEnd              : 1; // 2 [3]
458 #ifdef _TARGET_AMD64_
459     UInt8  hasFrameSize             : 1; // 2 [4]   1: frame size is encoded below, 0: frame size is 0
460     UInt8  x64_framePtrOffsetSmall  : 2; // 2 [5:6] 00: framePtrOffset = 0x20
461                                          //         01: framePtrOffset = 0x30
462                                          //         10: framePtrOffset = 0x40
463                                          //         11: a variable-length integer 'x64_frameOffset' follows.
464     UInt8  x64_hasSavedXmmRegs      : 1; // 2 [7]   any saved xmm registers?
465 #endif
466                                                             // X86        X64
467     UInt8  calleeSavedRegMask       : NUM_PRESERVED_REGS;   // 2 [4:7]    3 [0:7]
468 
469 #ifdef _TARGET_X86_
470     UInt8  x86_argCountLow          : 5; // 3 [0-4]  expressed in pointer-sized units    // @TODO: steal more bits here?
471     UInt8  x86_argCountIsLarge      : 1; // 3 [5]    if this bit is set, then the high 8 bits are encoded in x86_argCountHigh
472     UInt8  x86_hasStackChanges      : 1; // 3 [6]    x86-only, !ebpFrame-only, this method has pushes
473                                          //          and pops in it, and a string follows this header
474                                          //          which describes them
475     UInt8  hasFrameSize             : 1; // 3 [7]    1: frame size is encoded below, 0: frame size is 0
476 #endif
477 #endif
478 
479     //
480     // OPTIONAL FIELDS FOLLOW
481     //
482     // The following values are encoded with variable-length integers on disk, but are decoded into these
483     // fields in memory.
484     //
485 
486     // For ARM and ARM64 this field stores the offset of the callee-saved area relative to FP/SP
487     UInt32  frameSize;                   // expressed in pointer-sized units, only encoded if hasFrameSize==1
488     // OPTIONAL: only encoded if returnKind = MRK_ReturnsToNative
489     UInt32  reversePinvokeFrameOffset;   // expressed in pointer-sized units away from the frame pointer
490 
491 #ifdef _TARGET_AMD64_
492     // OPTIONAL: only encoded if x64_framePtrOffsetSmall = 11
493     //
494     // ENCODING NOTE: In the encoding, the variable-sized unsigned will be 7 less than the total number
495     // of 16-byte units that make up the frame pointer offset.
496     //
497     // In memory, this value will always be set and will always be the total number of 16-byte units that make
498     // up the frame pointer offset.
499     UInt8   x64_framePtrOffset;       // expressed in 16-byte unit
500 
501     // OPTIONAL: only encoded using a variable-sized unsigned if x64_hasSavedXmmRegs is set.
502     //
503     // An additional optimization is possible because registers xmm0 .. xmm5 should never be saved,
504     // so they are not encoded in the variable-sized unsigned - instead the mask is shifted right 6 bits
505     // for encoding. Thus, any subset of registers xmm6 .. xmm12 can be represented using one byte
506     // - this covers the most frequent cases.
507     //
508     // The shift applies to decoding/encoding only though - the actual header field below uses the
509     // straightforward mapping where bit 0 corresponds to xmm0, bit 1 corresponds to xmm1 and so on.
510     //
511     UInt16  x64_savedXmmRegMask;      // which xmm regs were saved
512 #elif defined(_TARGET_X86_)
513     // OPTIONAL: only encoded if x86_argCountIsLarge = 1
514     // NOTE: because we are using pointer-sized units, only 14 bits are required to represent the entire range
515     // that can be expressed by a 'ret NNNN' instruction.  Therefore, with 6 in the 'low' field and 8 in the
516     // 'high' field, we are not losing any range here.  (Although the need for that full range is debatable.)
517     UInt8   x86_argCountHigh;
518 #elif defined(_TARGET_ARM_)
519     // OPTIONAL: only encoded if arm_areParmOrVfpRegsPushed = 1
520     UInt8   arm_parmRegsPushedSet;
521     UInt8   arm_vfpRegFirstPushed;
522     UInt8   arm_vfpRegPushedCount;
523 #elif defined(_TARGET_ARM64_)
524     // OPTIONAL: high bits of calleeSavedRegMask are encoded only if arm64_longCsrMask = 1; low bits equal to arm64_calleeSavedRegMaskLow
525     UInt16  calleeSavedRegMask;
526 
527     // OPTIONAL: only encoded if arm64_areParmOrVfpRegsPushed = 1
528     UInt8   arm64_parmRegsPushedCount;  // how many of X0-X7 registers are saved
529     UInt8   arm64_vfpRegsPushedMask;    // which of D8-D15 registers are saved
530 #endif
531 
532     //
533     // OPTIONAL: only encoded if hasExtraData = 1
534     union
535     {
536         struct
537         {
538             UInt8 logStackAlignment : 4;    // [0:3]    binary logarithm of frame alignment (3..15) or 0
539             UInt8 hasGSCookie       : 1;    // [4]      1: frame uses GS cookie
540             UInt8 hasCommonVars     : 1;    // [5]      1: method has a list of "common vars"
541                                             //          as an optimization for methods with many call sites and variables
542 #if defined(_TARGET_ARM64_)
543             UInt8 FPLRAreOnTop      : 1;    // [6]      1: FP and LR are saved on top of locals, not at the bottom (see MdmSaveFPAndLRAtTopOfLocalsArea)
544             UInt8 extraDataUnused   : 1;    // [7]      unused bits
545 #else
546             UInt8 extraDataUnused   : 2;    // [6:7]    unused bits
547 #endif
548 #pragma warning(suppress:4201) // nameless struct
549         };
550         UInt8 extraDataHeader;
551     };
552 
553     // OPTIONAL: only encoded if logStackAlignment != 0
554     UInt8 paramPointerReg;
555 
556     // OPTIONAL: only encoded if epilogCountSmall = 3
557     UInt16 epilogCount;
558 
559     // OPTIONAL: only encoded if gsCookie = 1
560     UInt32 gsCookieOffset;      // expressed in pointer-sized units away from the frame pointer
561 
562     //
563     // OPTIONAL: only encoded if hasFunclets = 1
564     //  {numFunclets}           // encoded as variable-length unsigned
565     //      {start-funclet0}    // offset from start of previous funclet, encoded as variable-length unsigned
566     //      {start-funclet1}    //
567     //      {start-funclet2}
568     //       ...
569     //      {sizeof-funclet(N-1)}   // numFunclets == N  (i.e. there are N+1 sizes here)
570     //      -----------------
571     //      {GCInfoHeader-funclet0}  // encoded as normal, must not have 'hasFunclets' set.
572     //      {GCInfoHeader-funclet1}
573     //       ...
574     //      {GCInfoHeader-funclet(N-1)}
575 
576     // WARNING:
577     // WARNING: Do not add fields to the file-format after the funclet header encodings -- these are decoded
578     // WARNING: recursively and 'in-place' when looking for the info associated with a funclet.  Therefore,
579     // WARNING: in that case, we cannot easily continue to decode things associated with the main body
580     // WARNING: GCInfoHeader once we start this recursive decode.
581     // WARNING:
582 
583     // -------------------------------------------------------------------------------------------------------
584     // END of file-encoding-related-fields
585     // -------------------------------------------------------------------------------------------------------
586 
587     // The following fields are not encoded in the file format, they are just used as convenience placeholders
588     // for decode state.
589     UInt32 funcletOffset; // non-zero indicates that this GCInfoHeader is for a funclet
590 
591 #if defined(BINDER)
592 public:
593     UInt32 cbThisCodeBody;
594     GCInfoHeader * pNextFunclet;
595 private:
596     ;
597 #endif // BINDER
598 
599 
600 public:
601     //
602     // CONSTANTS / STATIC STUFF
603     //
604 
605     enum MethodReturnKind
606     {
607         MRK_ReturnsScalar   = 0,
608         MRK_ReturnsObject   = 1,
609         MRK_ReturnsByref    = 2,
610         MRK_ReturnsToNative = 3,
611         MRK_Unknown         = 4,
612     };
613 
614     enum EncodingConstants
615     {
616         EC_SizeOfFixedHeader = 4,
617         EC_MaxFrameByteSize                 = 10*1024*1024,
618         EC_MaxReversePInvokeFrameByteOffset = 10*1024*1024,
619         EC_MaxX64FramePtrByteOffset         = UInt16_MAX * 0x10,
620         EC_MaxEpilogCountSmall              = 3,
621         EC_MaxEpilogCount                   = 64*1024 - 1,
622     };
623 
624     //
625     // MEMBER FUNCTIONS
626     //
627 
InitGCInfoHeader628     void Init()
629     {
630         memset(this, 0, sizeof(GCInfoHeader));
631     }
632 
633     //
634     // SETTERS
635     //
636 
SetPrologSizeGCInfoHeader637     void SetPrologSize(UInt32 sizeInBytes)
638     {
639 #if defined (_TARGET_ARM64_)
640         // For arm64 we encode multiples of 4, rather than raw bytes, since instructions are all same size.
641         ASSERT((sizeInBytes & 3) == 0);
642         prologSize = sizeInBytes >> 2;
643         ASSERT(prologSize == sizeInBytes >> 2);
644 #else
645         prologSize = sizeInBytes;
646         ASSERT(prologSize == sizeInBytes);
647 #endif
648     }
649 
SetHasFuncletsGCInfoHeader650     void SetHasFunclets(bool fHasFunclets)
651     {
652         hasFunclets = fHasFunclets ? 1 : 0;
653     }
654 
PokeFixedEpilogSizeGCInfoHeader655     void PokeFixedEpilogSize(UInt32 sizeInBytes)
656     {
657 #if defined (_TARGET_ARM64_)
658         // For arm64 we encode multiples of 4, rather than raw bytes, since instructions are all same size.
659         ASSERT((sizeInBytes & 3) == 0);
660         fixedEpilogSize = sizeInBytes >> 2;
661         ASSERT(fixedEpilogSize == sizeInBytes >> 2);
662 #else
663         fixedEpilogSize = sizeInBytes;
664         ASSERT(fixedEpilogSize == sizeInBytes);
665 #endif
666     }
667 
SetFixedEpilogSizeGCInfoHeader668     void SetFixedEpilogSize(UInt32 sizeInBytes, bool varyingSizes)
669     {
670         if (varyingSizes)
671             fixedEpilogSize = 0;
672         else
673         {
674             ASSERT(sizeInBytes != 0);
675             PokeFixedEpilogSize(sizeInBytes);
676         }
677     }
678 
SetEpilogCountGCInfoHeader679     void SetEpilogCount(UInt32 count, bool isAtEnd)
680     {
681         epilogCount = ToUInt16(count);
682         epilogAtEnd = isAtEnd ? 1 : 0;
683 
684         ASSERT(epilogCount == count);
685         ASSERT((count == 1) || !isAtEnd);
686         epilogCountSmall = count < EC_MaxEpilogCountSmall ? count : EC_MaxEpilogCountSmall;
687     }
688 
SetReturnKindGCInfoHeader689     void SetReturnKind(MethodReturnKind kind)
690     {
691         ASSERT(kind < MRK_Unknown); // not enough bits to encode 'unknown'
692         returnKind = kind;
693     }
694 
SetDynamicAlignmentGCInfoHeader695     void SetDynamicAlignment(UInt8 logByteAlignment)
696     {
697 #ifdef _TARGET_X86_
698         ASSERT(logByteAlignment >= 3); // 4 byte aligned frames
699 #else
700         ASSERT(logByteAlignment >= 4); // 8 byte aligned frames
701 #endif
702 
703         hasExtraData = 1;
704         logStackAlignment = logByteAlignment;
705         ASSERT(logStackAlignment == logByteAlignment);
706         paramPointerReg = RN_NONE;
707     }
708 
709 #if defined(_TARGET_ARM64_)
SetFPLROnTopGCInfoHeader710     void SetFPLROnTop(void)
711     {
712         hasExtraData = 1;
713         FPLRAreOnTop = 1;
714     }
715 #endif
716 
SetGSCookieOffsetGCInfoHeader717     void SetGSCookieOffset(UInt32 offsetInBytes)
718     {
719         ASSERT(offsetInBytes != 0);
720         ASSERT(0 == (offsetInBytes % POINTER_SIZE));
721         hasExtraData = 1;
722         hasGSCookie = 1;
723         gsCookieOffset = offsetInBytes / POINTER_SIZE;
724     }
725 
SetHasCommonVarsGCInfoHeader726     void SetHasCommonVars()
727     {
728         hasExtraData = 1;
729         hasCommonVars = 1;
730     }
731 
732     void SetParamPointer(RegNumber regNum, UInt32 offsetInBytes, bool isOffsetFromSP = false)
733     {
734         UNREFERENCED_PARAMETER(offsetInBytes);
735         UNREFERENCED_PARAMETER(isOffsetFromSP);
736         ASSERT(HasDynamicAlignment()); // only expected for dynamic aligned frames
737         ASSERT(offsetInBytes==0); // not yet supported
738 
739         paramPointerReg = (UInt8)regNum;
740     }
741 
742     void SetFramePointer(RegNumber regNum, UInt32 offsetInBytes, bool isOffsetFromSP = false)
743     {
744         UNREFERENCED_PARAMETER(offsetInBytes);
745         UNREFERENCED_PARAMETER(isOffsetFromSP);
746 
747         if (regNum == RN_NONE)
748         {
749             ebpFrame = 0;
750         }
751         else
752         {
753 #ifdef _TARGET_ARM_
754             ASSERT(regNum == RN_R7);
755 #elif defined(_TARGET_AMD64_) || defined(_TARGET_X86_)
756             ASSERT(regNum == RN_EBP);
757 #elif defined(_TARGET_ARM64_)
758             ASSERT(regNum == RN_FP);
759 #else
760             ASSERT(!"NYI");
761 #endif
762             ebpFrame = 1;
763         }
764         ASSERT(offsetInBytes == 0 || isOffsetFromSP);
765 
766 #ifdef _TARGET_AMD64_
767         if (isOffsetFromSP)
768             offsetInBytes += SKEW_FOR_OFFSET_FROM_SP;
769 
770         ASSERT((offsetInBytes % 0x10) == 0);
771         UInt32 offsetInSlots = offsetInBytes / 0x10;
772         if (offsetInSlots >= 3 && offsetInSlots <= 3 + 2)
773         {
774             x64_framePtrOffsetSmall = offsetInSlots - 3;
775         }
776         else
777         {
778             x64_framePtrOffsetSmall = 3;
779         }
780         x64_framePtrOffset = (UInt8)offsetInSlots;
781         ASSERT(x64_framePtrOffset == offsetInSlots);
782 #else
783         ASSERT(offsetInBytes == 0 && !isOffsetFromSP);
784 #endif // _TARGET_AMD64_
785     }
786 
SetFrameSizeGCInfoHeader787     void SetFrameSize(UInt32 frameSizeInBytes)
788     {
789         ASSERT(0 == (frameSizeInBytes % POINTER_SIZE));
790         frameSize = (frameSizeInBytes / POINTER_SIZE);
791         ASSERT(frameSize == (frameSizeInBytes / POINTER_SIZE));
792         if (frameSize != 0)
793         {
794             hasFrameSize = 1;
795         }
796     }
797 
SetSavedRegsGCInfoHeader798     void SetSavedRegs(CalleeSavedRegMask regMask)
799     {
800         calleeSavedRegMask = (UInt16)regMask;
801     }
802 
SetRegSavedGCInfoHeader803     void SetRegSaved(CalleeSavedRegMask regMask)
804     {
805         calleeSavedRegMask |= regMask;
806     }
807 
SetReversePinvokeFrameOffsetGCInfoHeader808     void SetReversePinvokeFrameOffset(int offsetInBytes)
809     {
810         ASSERT(HasFramePointer());
811         ASSERT((offsetInBytes % POINTER_SIZE) == 0);
812         ASSERT(GetReturnKind() == MRK_ReturnsToNative);
813 
814 #if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
815         // The offset can be either positive or negative on ARM and x64.
816         bool isNeg = (offsetInBytes < 0);
817         UInt32 uOffsetInBytes = isNeg ? -offsetInBytes : offsetInBytes;
818         UInt32 uEncodedVal = ((uOffsetInBytes / POINTER_SIZE) << 1) | (isNeg ? 1 : 0);
819         reversePinvokeFrameOffset = uEncodedVal;
820         ASSERT(reversePinvokeFrameOffset == uEncodedVal);
821 #elif defined (_TARGET_X86_)
822         // Use a positive number because it encodes better and
823         // the offset is always negative on x86.
824         ASSERT(offsetInBytes < 0);
825         reversePinvokeFrameOffset = (-offsetInBytes / POINTER_SIZE);
826         ASSERT(reversePinvokeFrameOffset == (UInt32)(-offsetInBytes / POINTER_SIZE));
827 #else
828         ASSERT(!"NYI");
829 #endif
830     }
831 
832 #ifdef _TARGET_X86_
SetReturnPopSizeGCInfoHeader833     void SetReturnPopSize(UInt32 popSizeInBytes)
834     {
835         ASSERT(0 == (popSizeInBytes % POINTER_SIZE));
836         ASSERT(GetReturnPopSize() == 0 || GetReturnPopSize() == (int)popSizeInBytes);
837 
838         UInt32 argCount = popSizeInBytes / POINTER_SIZE;
839         x86_argCountLow = argCount & 0x1F;
840         if (argCount != x86_argCountLow)
841         {
842             x86_argCountIsLarge = 1;
843             x86_argCountHigh = (UInt8)(argCount >> 5);
844         }
845     }
846 
SetHasStackChangesGCInfoHeader847     void SetHasStackChanges()
848     {
849         x86_hasStackChanges = 1;
850     }
851 #endif // _TARGET_X86_
852 
853 #ifdef _TARGET_ARM_
SetParmRegsPushedGCInfoHeader854     void SetParmRegsPushed(ScratchRegMask pushedParmRegs)
855     {
856         // should be a subset of {RO-R3}
857         ASSERT((pushedParmRegs & ~(SR_MASK_R0|SR_MASK_R1|SR_MASK_R2|SR_MASK_R3)) == 0);
858         arm_areParmOrVfpRegsPushed = pushedParmRegs != 0 || arm_vfpRegPushedCount != 0;
859         arm_parmRegsPushedSet = (UInt8)pushedParmRegs;
860     }
861 
SetVfpRegsPushedGCInfoHeader862     void SetVfpRegsPushed(UInt8 vfpRegFirstPushed, UInt8 vfpRegPushedCount)
863     {
864         // mrt100.dll really only supports pushing a subinterval of d8-d15
865         // these are the preserved floating point registers according to the ABI spec
866         ASSERT(8 <= vfpRegFirstPushed && vfpRegFirstPushed + vfpRegPushedCount <= 16 || vfpRegPushedCount == 0);
867         arm_vfpRegFirstPushed = vfpRegFirstPushed;
868         arm_vfpRegPushedCount = vfpRegPushedCount;
869         arm_areParmOrVfpRegsPushed = arm_parmRegsPushedSet != 0 || vfpRegPushedCount != 0;
870     }
871 #elif defined(_TARGET_ARM64_)
SetParmRegsPushedCountGCInfoHeader872     void SetParmRegsPushedCount(UInt8 parmRegsPushedCount)
873     {
874         // pushed parameter registers are a subset of {R0-R7}
875         ASSERT(parmRegsPushedCount <= 8);
876         arm64_parmRegsPushedCount = parmRegsPushedCount;
877         arm64_areParmOrVfpRegsPushed = (arm64_parmRegsPushedCount != 0) || (arm64_vfpRegsPushedMask != 0);
878     }
879 
SetVfpRegsPushedGCInfoHeader880     void SetVfpRegsPushed(UInt8 vfpRegsPushedMask)
881     {
882         arm64_vfpRegsPushedMask = vfpRegsPushedMask;
883         arm64_areParmOrVfpRegsPushed = (arm64_parmRegsPushedCount != 0) || (arm64_vfpRegsPushedMask != 0);
884     }
885 #elif defined(_TARGET_AMD64_)
SetSavedXmmRegsGCInfoHeader886     void SetSavedXmmRegs(UInt32 savedXmmRegMask)
887     {
888         // any subset of xmm6-xmm15 may be saved, but no registers in xmm0-xmm5 should be present
889         ASSERT((savedXmmRegMask & 0xffff003f) == 0);
890         x64_hasSavedXmmRegs = savedXmmRegMask != 0;
891         x64_savedXmmRegMask = (UInt16)savedXmmRegMask;
892     }
893 #endif
894 
SetFuncletOffsetGCInfoHeader895     void SetFuncletOffset(UInt32 offset)
896     {
897         funcletOffset = offset;
898     }
899 
900     //
901     // GETTERS
902     //
GetPrologSizeGCInfoHeader903     UInt32 GetPrologSize()
904     {
905 #if defined (_TARGET_ARM64_)
906         return prologSize << 2;
907 #else
908         return prologSize;
909 #endif
910     }
911 
HasFuncletsGCInfoHeader912     bool HasFunclets()
913     {
914         return (hasFunclets != 0);
915     }
916 
HasVaryingEpilogSizesGCInfoHeader917     bool HasVaryingEpilogSizes()
918     {
919         return fixedEpilogSize == 0;
920     }
921 
PeekFixedEpilogSizeGCInfoHeader922     UInt32 PeekFixedEpilogSize()
923     {
924 #if defined (_TARGET_ARM64_)
925         return fixedEpilogSize << 2;
926 #else
927         return fixedEpilogSize;
928 #endif
929     }
930 
GetFixedEpilogSizeGCInfoHeader931     UInt32 GetFixedEpilogSize()
932     {
933         ASSERT(!HasVaryingEpilogSizes());
934         return PeekFixedEpilogSize();
935     }
936 
GetEpilogCountGCInfoHeader937     UInt32 GetEpilogCount()
938     {
939         return epilogCount;
940     }
941 
IsEpilogAtEndGCInfoHeader942     bool IsEpilogAtEnd()
943     {
944         return (epilogAtEnd != 0);
945     }
946 
GetReturnKindGCInfoHeader947     MethodReturnKind GetReturnKind()
948     {
949         return (MethodReturnKind)returnKind;
950     }
951 
ReturnsToNativeGCInfoHeader952     bool ReturnsToNative()
953     {
954         return (GetReturnKind() == MRK_ReturnsToNative);
955     }
956 
HasFramePointerGCInfoHeader957     bool HasFramePointer()
958     {
959         return !!ebpFrame;
960     }
961 
IsFuncletGCInfoHeader962     bool IsFunclet()
963     {
964         return funcletOffset != 0;
965     }
966 
GetFuncletOffsetGCInfoHeader967     UInt32 GetFuncletOffset()
968     {
969         return funcletOffset;
970     }
971 
GetPreservedRegsSaveSizeGCInfoHeader972     int GetPreservedRegsSaveSize() const // returned in bytes
973     {
974         UInt32 count = 0;
975         UInt32 mask = calleeSavedRegMask;
976         while (mask != 0)
977         {
978             count += mask & 1;
979             mask >>= 1;
980         }
981 
982         return count * POINTER_SIZE;
983     }
984 
GetParamPointerRegGCInfoHeader985     int GetParamPointerReg()
986     {
987         return paramPointerReg;
988     }
989 
HasDynamicAlignmentGCInfoHeader990     bool HasDynamicAlignment()
991     {
992         return !!logStackAlignment;
993     }
994 
GetDynamicAlignmentGCInfoHeader995     UInt32 GetDynamicAlignment()
996     {
997         return 1 << logStackAlignment;
998     }
999 
HasGSCookieGCInfoHeader1000     bool HasGSCookie()
1001     {
1002         return hasGSCookie;
1003     }
1004 
1005 #if defined(_TARGET_ARM64_)
AreFPLROnTopGCInfoHeader1006     bool AreFPLROnTop()
1007     {
1008         return FPLRAreOnTop;
1009     }
1010 #endif
1011 
GetGSCookieOffsetGCInfoHeader1012     UInt32 GetGSCookieOffset()
1013     {
1014         ASSERT(hasGSCookie);
1015         return gsCookieOffset * POINTER_SIZE;
1016     }
1017 
HasCommonVarsGCInfoHeader1018     bool HasCommonVars()
1019     {
1020         return hasCommonVars;
1021     }
1022 
1023 #if defined(RHDUMP) && !defined(_TARGET_AMD64_)
1024     // Due to the wackiness of RhDump, we need this method defined, even though it won't ever be called.
GetFramePointerOffsetGCInfoHeader1025     int GetFramePointerOffset() { ASSERT(!"UNREACHABLE"); __assume(0); }
1026 #endif // defined(RHDUMP) && !defined(_TARGET_AMD64_)
1027 
1028 #ifdef _TARGET_AMD64_
1029     static const UInt32 SKEW_FOR_OFFSET_FROM_SP = 0x10;
1030 
GetFramePointerOffsetGCInfoHeader1031     int GetFramePointerOffset() // returned in bytes
1032     {
1033         // traditional frames where FP points to the pushed FP have fp offset == 0
1034         if (x64_framePtrOffset == 0)
1035             return 0;
1036 
1037         // otherwise it's an x64 style frame where the fp offset is measured from the sp
1038         // at the end of the prolog
1039         int offsetFromSP  = GetFramePointerOffsetFromSP();
1040 
1041         int preservedRegsSaveSize = GetPreservedRegsSaveSize();
1042 
1043         // we when called from the binder, rbp isn't set to be a preserved reg,
1044         // when called from the runtime, it is - compensate for this inconsistency
1045         if (IsRegSaved(CSR_MASK_RBP))
1046             preservedRegsSaveSize -= POINTER_SIZE;
1047 
1048         return offsetFromSP - preservedRegsSaveSize - GetFrameSize();
1049     }
1050 
IsFramePointerOffsetFromSPGCInfoHeader1051     bool IsFramePointerOffsetFromSP()
1052     {
1053         return x64_framePtrOffset != 0;
1054     }
1055 
GetFramePointerOffsetFromSPGCInfoHeader1056     int GetFramePointerOffsetFromSP()
1057     {
1058         ASSERT(IsFramePointerOffsetFromSP());
1059         int offsetFromSP;
1060         offsetFromSP = x64_framePtrOffset * 0x10;
1061         ASSERT(offsetFromSP >= SKEW_FOR_OFFSET_FROM_SP);
1062         offsetFromSP -= SKEW_FOR_OFFSET_FROM_SP;
1063 
1064         return offsetFromSP;
1065     }
1066 
GetFramePointerRegGCInfoHeader1067     int GetFramePointerReg()
1068     {
1069         return RN_EBP;
1070     }
1071 
HasSavedXmmRegsGCInfoHeader1072     bool HasSavedXmmRegs()
1073     {
1074         return x64_hasSavedXmmRegs != 0;
1075     }
1076 
GetSavedXmmRegMaskGCInfoHeader1077     UInt16 GetSavedXmmRegMask()
1078     {
1079         ASSERT(x64_hasSavedXmmRegs);
1080         return x64_savedXmmRegMask;
1081     }
1082 #elif defined(_TARGET_X86_)
GetReturnPopSizeGCInfoHeader1083     int GetReturnPopSize() // returned in bytes
1084     {
1085         if (!x86_argCountIsLarge)
1086         {
1087             return x86_argCountLow * POINTER_SIZE;
1088         }
1089         return ((x86_argCountHigh << 5) | x86_argCountLow) * POINTER_SIZE;
1090     }
1091 
HasStackChangesGCInfoHeader1092     bool HasStackChanges()
1093     {
1094         return !!x86_hasStackChanges;
1095     }
1096 #endif
1097 
GetFrameSizeGCInfoHeader1098     int GetFrameSize()
1099     {
1100         return frameSize * POINTER_SIZE;
1101     }
1102 
1103 
GetReversePinvokeFrameOffsetGCInfoHeader1104     int GetReversePinvokeFrameOffset()
1105     {
1106 #if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1107         // The offset can be either positive or negative on ARM.
1108         Int32 offsetInBytes;
1109         UInt32 uEncodedVal = reversePinvokeFrameOffset;
1110         bool isNeg = ((uEncodedVal & 1) == 1);
1111         offsetInBytes = (uEncodedVal >> 1) * POINTER_SIZE;
1112         offsetInBytes = isNeg ? -offsetInBytes : offsetInBytes;
1113         return offsetInBytes;
1114 #elif defined(_TARGET_X86_)
1115         // it's always at "EBP - something", so we encode it as a positive
1116         // number and then apply the negative here.
1117         int unsignedOffset = reversePinvokeFrameOffset * POINTER_SIZE;
1118         return -unsignedOffset;
1119 #else
1120         ASSERT(!"NYI");
1121 #endif
1122     }
1123 
GetSavedRegsGCInfoHeader1124     CalleeSavedRegMask GetSavedRegs()
1125     {
1126         return (CalleeSavedRegMask) calleeSavedRegMask;
1127     }
1128 
IsRegSavedGCInfoHeader1129     bool IsRegSaved(CalleeSavedRegMask reg)
1130     {
1131         return (0 != (calleeSavedRegMask & reg));
1132     }
1133 
1134 #ifdef _TARGET_ARM_
AreParmRegsPushedGCInfoHeader1135     bool AreParmRegsPushed()
1136     {
1137         return arm_parmRegsPushedSet != 0;
1138     }
1139 
ParmRegsPushedCountGCInfoHeader1140     UInt16 ParmRegsPushedCount()
1141     {
1142         UInt8 set = arm_parmRegsPushedSet;
1143         UInt8 count = 0;
1144         while (set != 0)
1145         {
1146             count += set & 1;
1147             set >>= 1;
1148         }
1149         return count;
1150     }
1151 
GetVfpRegFirstPushedGCInfoHeader1152     UInt8 GetVfpRegFirstPushed()
1153     {
1154         return arm_vfpRegFirstPushed;
1155     }
1156 
GetVfpRegPushedCountGCInfoHeader1157     UInt8 GetVfpRegPushedCount()
1158     {
1159         return arm_vfpRegPushedCount;
1160     }
1161 #elif defined(_TARGET_ARM64_)
ParmRegsPushedCountGCInfoHeader1162     UInt8 ParmRegsPushedCount()
1163     {
1164         return arm64_parmRegsPushedCount;
1165     }
1166 
GetVfpRegsPushedMaskGCInfoHeader1167     UInt8 GetVfpRegsPushedMask()
1168     {
1169         return arm64_vfpRegsPushedMask;
1170     }
1171 #endif
1172 
1173     //
1174     // ENCODING HELPERS
1175     //
1176 #ifndef DACCESS_COMPILE
EncodeHeaderGCInfoHeader1177     size_t EncodeHeader(UInt8 * & pDest)
1178     {
1179 #ifdef _DEBUG
1180         UInt8 * pStart = pDest;
1181 #endif // _DEBUG
1182 
1183 #if defined(_TARGET_ARM64_)
1184         UInt8 calleeSavedRegMaskHigh = calleeSavedRegMask >> NUM_PRESERVED_REGS_LOW;
1185         arm64_calleeSavedRegMaskLow = calleeSavedRegMask & MASK_PRESERVED_REGS_LOW;
1186         if (calleeSavedRegMaskHigh)
1187         {
1188             arm64_longCsrMask = 1;
1189         }
1190 #endif
1191 
1192         size_t size = EC_SizeOfFixedHeader;
1193         if (pDest)
1194         {
1195             memcpy(pDest, this, EC_SizeOfFixedHeader);
1196             pDest += EC_SizeOfFixedHeader;
1197         }
1198 
1199         if (hasFrameSize)
1200             size += WriteUnsigned(pDest, frameSize);
1201 
1202         if (returnKind == MRK_ReturnsToNative)
1203             size += WriteUnsigned(pDest, reversePinvokeFrameOffset);
1204 
1205 #ifdef _TARGET_AMD64_
1206         if (x64_framePtrOffsetSmall == 0x3)
1207             size += WriteUnsigned(pDest, x64_framePtrOffset);
1208 
1209         if (x64_hasSavedXmmRegs)
1210         {
1211             ASSERT((x64_savedXmmRegMask & 0x3f) == 0);
1212             UInt32 encodedValue = x64_savedXmmRegMask >> 6;
1213             size += WriteUnsigned(pDest, encodedValue);
1214         }
1215 #elif defined(_TARGET_X86_)
1216         if (x86_argCountIsLarge)
1217         {
1218             size += 1;
1219             if (pDest)
1220                 *pDest++ = x86_argCountHigh;
1221         }
1222         ASSERT(!x86_hasStackChanges || !"NYI -- stack changes for ESP frames");
1223 #elif defined(_TARGET_ARM_)
1224         if (arm_areParmOrVfpRegsPushed)
1225         {
1226             // we encode a bit field where the low 4 bits represent the pushed parameter register
1227             // set, the next 8 bits are the number of pushed floating point registers, and the highest
1228             // bits are the first pushed floating point register plus 1.
1229             // The 0 encoding means the first floating point register is 8 as this is the most frequent.
1230             UInt32 encodedValue = arm_parmRegsPushedSet | (arm_vfpRegPushedCount << 4);
1231             // usually, the first pushed floating point register is d8
1232             if (arm_vfpRegFirstPushed != 8)
1233                 encodedValue |= (arm_vfpRegFirstPushed+1) << (8+4);
1234 
1235             size += WriteUnsigned(pDest, encodedValue);
1236         }
1237 #elif defined(_TARGET_ARM64_)
1238         if (calleeSavedRegMaskHigh)
1239         {
1240             size += 1;
1241             if (pDest)
1242                 *pDest++ = calleeSavedRegMaskHigh;
1243         }
1244 
1245         if (arm64_areParmOrVfpRegsPushed)
1246         {
1247             // At present arm64_parmRegsPushedCount is non-zero only for variadic functions, so place this field higher
1248             UInt32 encodedValue = arm64_vfpRegsPushedMask | (arm64_parmRegsPushedCount << 8);
1249             size += WriteUnsigned(pDest, encodedValue);
1250         }
1251 #endif
1252 
1253         // encode dynamic alignment and GS cookie information
1254         if (hasExtraData)
1255         {
1256             size += WriteUnsigned(pDest, extraDataHeader);
1257         }
1258         if (HasDynamicAlignment())
1259         {
1260             size += WriteUnsigned(pDest, paramPointerReg);
1261         }
1262         if (hasGSCookie)
1263         {
1264             size += WriteUnsigned(pDest, gsCookieOffset);
1265         }
1266 
1267         if (epilogCountSmall == EC_MaxEpilogCountSmall)
1268         {
1269             size += WriteUnsigned(pDest, epilogCount);
1270         }
1271 
1272         // WARNING:
1273         // WARNING: Do not add fields to the file-format after the funclet header encodings -- these are
1274         // WARNING: decoded recursively and 'in-place' when looking for the info associated with a funclet.
1275         // WARNING: Therefore, in that case, we cannot easily continue to decode things associated with the
1276         // WARNING: main body GCInfoHeader once we start this recursive decode.
1277         // WARNING:
1278         size += EncodeFuncletInfo(pDest);
1279 
1280 #ifdef _DEBUG
1281         ASSERT(!pDest || (size == (size_t)(pDest - pStart)));
1282 #endif // _DEBUG
1283 
1284         return size;
1285     }
1286 
WriteUnsignedGCInfoHeader1287     size_t WriteUnsigned(UInt8 * & pDest, UInt32 value)
1288     {
1289         size_t size = (size_t)VarInt::WriteUnsigned(pDest, value);
1290         pDest = pDest ? (pDest + size) : pDest;
1291         return size;
1292     }
1293 
EncodeFuncletInfoGCInfoHeader1294     size_t EncodeFuncletInfo(UInt8 * & pDest)
1295     {
1296         UNREFERENCED_PARAMETER(pDest);
1297         size_t size = 0;
1298 #if defined(BINDER)
1299         if (hasFunclets)
1300         {
1301             UInt32 nFunclets = 0;
1302             for (GCInfoHeader * pCur = pNextFunclet; pCur != NULL; pCur = pCur->pNextFunclet)
1303                 nFunclets++;
1304 
1305             // first write out the number of funclets
1306             size += WriteUnsigned(pDest, nFunclets);
1307 
1308             // cbThisCodeBody is the size, but what we end up encoding is the size of all the code bodies
1309             // except for the last one (because the last one's size can be implicitly figured out by the size
1310             // of the method).  So we have to save the size of the 'main body' and not the size of the last
1311             // funclet.  In the encoding, this will look like the offset of a given funclet from the start of
1312             // the previous code body.  We like relative offsets because they'll encode to be smaller.
1313             for (GCInfoHeader * pCur = this; pCur->pNextFunclet != NULL; pCur = pCur->pNextFunclet)
1314                 size += WriteUnsigned(pDest, pCur->cbThisCodeBody);
1315 
1316             // now encode all the funclet headers
1317             for (GCInfoHeader * pCur = pNextFunclet; pCur != NULL; pCur = pCur->pNextFunclet)
1318                 size += pCur->EncodeHeader(pDest);
1319         }
1320 #else // BINDER
1321         ASSERT(!"NOT REACHABLE");
1322 #endif // BINDER
1323         return size;
1324     }
1325 #endif // DACCESS_COMPILE
1326 
ToUInt16GCInfoHeader1327     UInt16 ToUInt16(UInt32 val)
1328     {
1329         UInt16 result = (UInt16)val;
1330         ASSERT(val == result);
1331         return result;
1332     }
1333 
ToUInt8GCInfoHeader1334     UInt8 ToUInt8(UInt32 val)
1335     {
1336         UInt8 result = (UInt8)val;
1337         ASSERT(val == result);
1338         return result;
1339     }
1340 
1341     //
1342     // DECODING HELPERS
1343     //
1344     // Returns a pointer to the 'stack change string' on x86.
DecodeHeaderGCInfoHeader1345     PTR_UInt8 DecodeHeader(UInt32 methodOffset, PTR_UInt8 pbHeaderEncoding, size_t* pcbHeader)
1346     {
1347         PTR_UInt8 pbStackChangeString = NULL;
1348 
1349         TADDR pbTemp = PTR_TO_TADDR(pbHeaderEncoding);
1350         memcpy(this, PTR_READ(pbTemp, EC_SizeOfFixedHeader), EC_SizeOfFixedHeader);
1351 
1352         PTR_UInt8 pbDecode = pbHeaderEncoding + EC_SizeOfFixedHeader;
1353         frameSize = hasFrameSize
1354             ? VarInt::ReadUnsigned(pbDecode)
1355             : 0;
1356 
1357         reversePinvokeFrameOffset = (returnKind == MRK_ReturnsToNative)
1358             ? VarInt::ReadUnsigned(pbDecode)
1359             : 0;
1360 
1361 #ifdef _TARGET_AMD64_
1362         x64_framePtrOffset = (x64_framePtrOffsetSmall == 0x3)
1363             ? ToUInt8(VarInt::ReadUnsigned(pbDecode))
1364             : x64_framePtrOffsetSmall + 3;
1365 
1366 
1367         x64_savedXmmRegMask = 0;
1368         if (x64_hasSavedXmmRegs)
1369         {
1370             UInt32 encodedValue = VarInt::ReadUnsigned(pbDecode);
1371             ASSERT((encodedValue & ~0x3ff) == 0);
1372             x64_savedXmmRegMask = ToUInt16(encodedValue << 6);
1373         }
1374 
1375 #elif defined(_TARGET_X86_)
1376         if (x86_argCountIsLarge)
1377             x86_argCountHigh = *pbDecode++;
1378         else
1379             x86_argCountHigh = 0;
1380 
1381         if (x86_hasStackChanges)
1382         {
1383             pbStackChangeString = pbDecode;
1384 
1385             bool last = false;
1386             while (!last)
1387             {
1388                 UInt8 b = *pbDecode++;
1389                 // 00111111 {delta}     forwarder
1390                 // 00dddddd             push 1, dddddd = delta
1391                 // nnnldddd             pop nnn-1, l = last, dddd = delta (nnn=0 and nnn=1 are disallowed)
1392                 if (b == 0x3F)
1393                 {
1394                     // 00111111 {delta}     forwarder
1395                     VarInt::ReadUnsigned(pbDecode);
1396                 }
1397                 else if (0 != (b & 0xC0))
1398                 {
1399                     // nnnldddd             pop nnn-1, l = last, dddd = delta (nnn=0 and nnn=1 are disallowed)
1400                     last = ((b & 0x10) == 0x10);
1401                 }
1402             }
1403         }
1404 #elif defined(_TARGET_ARM_)
1405         arm_parmRegsPushedSet = 0;
1406         arm_vfpRegPushedCount = 0;
1407         arm_vfpRegFirstPushed = 0;
1408         if (arm_areParmOrVfpRegsPushed)
1409         {
1410             UInt32 encodedValue = VarInt::ReadUnsigned(pbDecode);
1411             arm_parmRegsPushedSet = encodedValue & 0x0f;
1412             arm_vfpRegPushedCount = (UInt8)(encodedValue >> 4);
1413             UInt32 vfpRegFirstPushed = encodedValue >> (8 + 4);
1414             if (vfpRegFirstPushed == 0)
1415                 arm_vfpRegFirstPushed = 8;
1416             else
1417                 arm_vfpRegFirstPushed = (UInt8)(vfpRegFirstPushed - 1);
1418         }
1419 #elif defined(_TARGET_ARM64_)
1420         calleeSavedRegMask = arm64_calleeSavedRegMaskLow;
1421         if (arm64_longCsrMask)
1422         {
1423             calleeSavedRegMask |= (*pbDecode++ << NUM_PRESERVED_REGS_LOW);
1424         }
1425 
1426         arm64_parmRegsPushedCount = 0;
1427         arm64_vfpRegsPushedMask = 0;
1428         if (arm64_areParmOrVfpRegsPushed)
1429         {
1430             UInt32 encodedValue = VarInt::ReadUnsigned(pbDecode);
1431             arm64_vfpRegsPushedMask = (UInt8)encodedValue;
1432             arm64_parmRegsPushedCount = (UInt8)(encodedValue >> 8);
1433             ASSERT(arm64_parmRegsPushedCount <= 8);
1434         }
1435 #endif
1436 
1437         extraDataHeader = hasExtraData ? ToUInt8(VarInt::ReadUnsigned(pbDecode)) : 0;
1438         paramPointerReg = HasDynamicAlignment() ? ToUInt8(VarInt::ReadUnsigned(pbDecode)) : (UInt8)RN_NONE;
1439         gsCookieOffset = hasGSCookie ? VarInt::ReadUnsigned(pbDecode) : 0;
1440 
1441         epilogCount = epilogCountSmall < EC_MaxEpilogCountSmall ? epilogCountSmall : ToUInt16(VarInt::ReadUnsigned(pbDecode));
1442 
1443         this->funcletOffset = 0;
1444         if (hasFunclets)
1445         {
1446             // WORKAROUND: Epilog tables are still per-method instead of per-funclet, but we don't deal with
1447             //             them here.  So we will simply overwrite the funclet's epilogAtEnd and epilogCount
1448             //             with the values from the main code body -- these were the values used to generate
1449             //             the per-method epilog table, so at least we're consistent with what is encoded.
1450             UInt8  mainEpilogAtEnd      = epilogAtEnd;
1451             UInt16 mainEpilogCount      = epilogCount;
1452             UInt16 mainFixedEpilogSize  = (UInt16) PeekFixedEpilogSize();
1453             UInt8  mainHasCommonVars    = hasCommonVars;
1454             // -------
1455 
1456             int nFunclets = (int)VarInt::ReadUnsigned(pbDecode);
1457             int idxFunclet = -2;
1458             UInt32 offsetFunclet = 0;
1459             // Decode the funclet start offsets, remembering which one is of interest.
1460             UInt32 prevFuncletStart = 0;
1461             for (int i = 0; i < nFunclets; i++)
1462             {
1463                 UInt32 offsetThisFunclet = prevFuncletStart + VarInt::ReadUnsigned(pbDecode);
1464                 if ((idxFunclet == -2) && (methodOffset < offsetThisFunclet))
1465                 {
1466                     idxFunclet = (i - 1);
1467                     offsetFunclet = prevFuncletStart;
1468                 }
1469                 prevFuncletStart = offsetThisFunclet;
1470             }
1471             if ((idxFunclet == -2) && (methodOffset >= prevFuncletStart))
1472             {
1473                 idxFunclet = (nFunclets - 1);
1474                 offsetFunclet = prevFuncletStart;
1475             }
1476 
1477             // Now decode headers until we find the one we want.  Keep decoding if we need to report a size.
1478             if (pcbHeader || (idxFunclet >= 0))
1479             {
1480                 for (int i = 0; i < nFunclets; i++)
1481                 {
1482                     size_t hdrSize;
1483                     if (i == idxFunclet)
1484                     {
1485                         this->DecodeHeader(methodOffset, pbDecode, &hdrSize);
1486                         pbDecode += hdrSize;
1487                         this->funcletOffset = offsetFunclet;
1488                         if (!pcbHeader) // if nobody is going to look at the header size, we don't need to keep going
1489                             break;
1490                     }
1491                     else
1492                     {
1493                         // keep decoding into a temp just to get the right header size
1494                         GCInfoHeader tmp;
1495                         tmp.DecodeHeader(methodOffset, pbDecode, &hdrSize);
1496                         pbDecode += hdrSize;
1497                     }
1498                 }
1499             }
1500 
1501             // WORKAROUND: see above
1502             this->epilogAtEnd      = mainEpilogAtEnd;
1503             this->epilogCount      = mainEpilogCount;
1504             this->PokeFixedEpilogSize(mainFixedEpilogSize);
1505             this->hasCommonVars    = mainHasCommonVars;
1506 
1507             // -------
1508         }
1509 
1510         // WARNING:
1511         // WARNING: Do not add fields to the file-format after the funclet header encodings -- these are
1512         // WARNING: decoded recursively and 'in-place' when looking for the info associated with a funclet.
1513         // WARNING: Therefore, in that case, we cannot easily continue to decode things associated with the
1514         // WARNING: main body GCInfoHeader once we start this recursive decode.
1515         // WARNING:
1516 
1517         if (pcbHeader)
1518             *pcbHeader = pbDecode - pbHeaderEncoding;
1519 
1520         return pbStackChangeString;
1521     }
1522 
GetFuncletInfoGCInfoHeader1523     void GetFuncletInfo(PTR_UInt8 pbHeaderEncoding, UInt32* pnFuncletsOut, PTR_UInt8* pEncodedFuncletStartOffsets)
1524     {
1525         ASSERT(hasFunclets);
1526 
1527         PTR_UInt8 pbDecode = pbHeaderEncoding + EC_SizeOfFixedHeader;
1528         if (hasFrameSize) { VarInt::SkipUnsigned(pbDecode); }
1529         if (returnKind == MRK_ReturnsToNative)  { VarInt::SkipUnsigned(pbDecode); }
1530         if (hasExtraData) { VarInt::SkipUnsigned(pbDecode); }
1531         if (HasDynamicAlignment()) { VarInt::SkipUnsigned(pbDecode); }
1532         if (hasGSCookie) { VarInt::SkipUnsigned(pbDecode); }
1533 
1534 #ifdef _TARGET_AMD64_
1535         if (x64_framePtrOffsetSmall == 0x3) { VarInt::SkipUnsigned(pbDecode); }
1536 #elif defined(_TARGET_X86_)
1537         if (x86_argCountIsLarge)
1538             pbDecode++;
1539 
1540         if (x86_hasStackChanges)
1541         {
1542             bool last = false;
1543             while (!last)
1544             {
1545                 UInt8 b = *pbDecode++;
1546                 // 00111111 {delta}     forwarder
1547                 // 00dddddd             push 1, dddddd = delta
1548                 // nnnldddd             pop nnn-1, l = last, dddd = delta (nnn=0 and nnn=1 are disallowed)
1549                 if (b == 0x3F)
1550                 {
1551                     // 00111111 {delta}     forwarder
1552                     VarInt::SkipUnsigned(pbDecode);
1553                 }
1554                 else if (0 != (b & 0xC0))
1555                 {
1556                     // nnnldddd             pop nnn-1, l = last, dddd = delta (nnn=0 and nnn=1 are disallowed)
1557                     last = ((b & 0x10) == 0x10);
1558                 }
1559             }
1560         }
1561 #elif defined(_TARGET_ARM_)
1562         if (arm_areParmOrVfpRegsPushed) { VarInt::SkipUnsigned(pbDecode); }
1563 #elif defined(_TARGET_ARM64_)
1564         if (arm64_longCsrMask) { pbDecode++; }
1565         if (arm64_areParmOrVfpRegsPushed) { VarInt::SkipUnsigned(pbDecode); }
1566 #endif
1567 
1568         *pnFuncletsOut = VarInt::ReadUnsigned(pbDecode);
1569         *pEncodedFuncletStartOffsets = pbDecode;
1570     }
1571 
1572 #ifdef BINDER
IsOffsetInFuncletGCInfoHeader1573     bool IsOffsetInFunclet(UInt32 offset)
1574     {
1575         if (!hasFunclets)
1576             return false;
1577 
1578         return (offset >= cbThisCodeBody);
1579     }
1580 #endif // BINDER
1581 
IsValidEpilogOffsetGCInfoHeader1582     bool IsValidEpilogOffset(UInt32 epilogOffset, UInt32 epilogSize)
1583     {
1584         if (!this->HasVaryingEpilogSizes())
1585             return (epilogOffset < this->GetFixedEpilogSize());
1586         else
1587             return (epilogOffset < epilogSize);
1588     }
1589 
1590 #ifdef RHDUMP
GetBoolStrGCInfoHeader1591     char const * GetBoolStr(bool val) { return val ? " true" : "false"; }
GetRetKindStrGCInfoHeader1592     char const * GetRetKindStr(int k)
1593     {
1594         switch (k)
1595         {
1596         case MRK_ReturnsScalar:     return "scalar";
1597         case MRK_ReturnsObject:     return "object";
1598         case MRK_ReturnsByref:      return " byref";
1599         case MRK_ReturnsToNative:   return "native";
1600         default:                    return "unknwn";
1601         }
1602     }
1603 
1604 #define PRINT_CALLEE_SAVE(name, mask, val) {if ((val) & (mask)) { printf(name); }}
1605 
PrintCalleeSavedRegsGCInfoHeader1606     void PrintCalleeSavedRegs(UInt32 calleeSavedRegMask)
1607     {
1608 #ifdef _TARGET_ARM_
1609         PRINT_CALLEE_SAVE(" r4" , CSR_MASK_R4 , calleeSavedRegMask);
1610         PRINT_CALLEE_SAVE(" r5" , CSR_MASK_R5 , calleeSavedRegMask);
1611         PRINT_CALLEE_SAVE(" r6" , CSR_MASK_R6 , calleeSavedRegMask);
1612         PRINT_CALLEE_SAVE(" r7" , CSR_MASK_R7 , calleeSavedRegMask);
1613         PRINT_CALLEE_SAVE(" r8" , CSR_MASK_R8 , calleeSavedRegMask);
1614         PRINT_CALLEE_SAVE(" r9" , CSR_MASK_R9 , calleeSavedRegMask);
1615         PRINT_CALLEE_SAVE(" r10", CSR_MASK_R10, calleeSavedRegMask);
1616         PRINT_CALLEE_SAVE(" r11", CSR_MASK_R11, calleeSavedRegMask);
1617         PRINT_CALLEE_SAVE(" lr" , CSR_MASK_LR , calleeSavedRegMask);
1618 #elif defined(_TARGET_ARM64_)
1619         PRINT_CALLEE_SAVE(" lr" , CSR_MASK_LR , calleeSavedRegMask);
1620         PRINT_CALLEE_SAVE(" x19", CSR_MASK_X19, calleeSavedRegMask);
1621         PRINT_CALLEE_SAVE(" x20", CSR_MASK_X20, calleeSavedRegMask);
1622         PRINT_CALLEE_SAVE(" x21", CSR_MASK_X21, calleeSavedRegMask);
1623         PRINT_CALLEE_SAVE(" x22", CSR_MASK_X22, calleeSavedRegMask);
1624         PRINT_CALLEE_SAVE(" x23", CSR_MASK_X23, calleeSavedRegMask);
1625         PRINT_CALLEE_SAVE(" x24", CSR_MASK_X24, calleeSavedRegMask);
1626         PRINT_CALLEE_SAVE(" x25", CSR_MASK_X25, calleeSavedRegMask);
1627         PRINT_CALLEE_SAVE(" x26", CSR_MASK_X26, calleeSavedRegMask);
1628         PRINT_CALLEE_SAVE(" x27", CSR_MASK_X27, calleeSavedRegMask);
1629         PRINT_CALLEE_SAVE(" x28", CSR_MASK_X28, calleeSavedRegMask);
1630         PRINT_CALLEE_SAVE(" fp" , CSR_MASK_FP , calleeSavedRegMask);
1631 #elif defined(_TARGET_X86_)
1632         PRINT_CALLEE_SAVE(" ebx", CSR_MASK_RBX, calleeSavedRegMask);
1633         PRINT_CALLEE_SAVE(" esi", CSR_MASK_RSI, calleeSavedRegMask);
1634         PRINT_CALLEE_SAVE(" edi", CSR_MASK_RDI, calleeSavedRegMask);
1635         PRINT_CALLEE_SAVE(" ebp", CSR_MASK_RBP, calleeSavedRegMask);
1636 #elif defined(_TARGET_AMD64_)
1637         PRINT_CALLEE_SAVE(" rbx", CSR_MASK_RBX, calleeSavedRegMask);
1638         PRINT_CALLEE_SAVE(" rsi", CSR_MASK_RSI, calleeSavedRegMask);
1639         PRINT_CALLEE_SAVE(" rdi", CSR_MASK_RDI, calleeSavedRegMask);
1640         PRINT_CALLEE_SAVE(" rbp", CSR_MASK_RBP, calleeSavedRegMask);
1641         PRINT_CALLEE_SAVE(" r12", CSR_MASK_R12, calleeSavedRegMask);
1642         PRINT_CALLEE_SAVE(" r13", CSR_MASK_R13, calleeSavedRegMask);
1643         PRINT_CALLEE_SAVE(" r14", CSR_MASK_R14, calleeSavedRegMask);
1644         PRINT_CALLEE_SAVE(" r15", CSR_MASK_R15, calleeSavedRegMask);
1645 #else
1646 #error unknown architecture
1647 #endif
1648     }
1649 
PrintRegNumberGCInfoHeader1650     void PrintRegNumber(UInt8 regNumber)
1651     {
1652         switch (regNumber)
1653         {
1654         default: printf("???"); break;
1655 #ifdef _TARGET_ARM_
1656         case RN_R0:     printf(" r0"); break;
1657         case RN_R1:     printf(" r1"); break;
1658         case RN_R2:     printf(" r2"); break;
1659         case RN_R3:     printf(" r3"); break;
1660         case RN_R4:     printf(" r4"); break;
1661         case RN_R5:     printf(" r5"); break;
1662         case RN_R6:     printf(" r6"); break;
1663         case RN_R7:     printf(" r7"); break;
1664         case RN_R8:     printf(" r8"); break;
1665         case RN_R9:     printf(" r9"); break;
1666         case RN_R10:    printf("r10"); break;
1667         case RN_R11:    printf("r11"); break;
1668         case RN_R12:    printf("r12"); break;
1669         case RN_SP:     printf(" sp"); break;
1670         case RN_LR:     printf(" lr"); break;
1671         case RN_PC:     printf(" pc"); break;
1672 #elif defined(_TARGET_ARM64_)
1673         case RN_X0:     printf(" x0"); break;
1674         case RN_X1:     printf(" x1"); break;
1675         case RN_X2:     printf(" x2"); break;
1676         case RN_X3:     printf(" x3"); break;
1677         case RN_X4:     printf(" x4"); break;
1678         case RN_X5:     printf(" x5"); break;
1679         case RN_X6:     printf(" x6"); break;
1680         case RN_X7:     printf(" x7"); break;
1681         case RN_X8:     printf(" x8"); break;
1682         case RN_X9:     printf(" x9"); break;
1683         case RN_X10:    printf("x10"); break;
1684         case RN_X11:    printf("x11"); break;
1685         case RN_X12:    printf("x12"); break;
1686         case RN_X13:    printf("x13"); break;
1687         case RN_X14:    printf("x14"); break;
1688         case RN_X15:    printf("x15"); break;
1689 
1690         case RN_XIP0:   printf("xip0"); break;
1691         case RN_XIP1:   printf("xip1"); break;
1692         case RN_XPR:    printf("xpr"); break;
1693 
1694         case RN_X19:    printf("x19"); break;
1695         case RN_X20:    printf("x20"); break;
1696         case RN_X21:    printf("x21"); break;
1697         case RN_X22:    printf("x22"); break;
1698         case RN_X23:    printf("x23"); break;
1699         case RN_X24:    printf("x24"); break;
1700         case RN_X25:    printf("x25"); break;
1701         case RN_X26:    printf("x26"); break;
1702         case RN_X27:    printf("x27"); break;
1703         case RN_X28:    printf("x28"); break;
1704 
1705         case RN_FP:     printf(" fp"); break;
1706         case RN_LR:     printf(" lr"); break;
1707         case RN_SP:     printf(" sp"); break;
1708 #elif defined(_TARGET_X86_)
1709         case RN_EAX:    printf("eax"); break;
1710         case RN_ECX:    printf("ecx"); break;
1711         case RN_EDX:    printf("edx"); break;
1712         case RN_EBX:    printf("ebx"); break;
1713         case RN_ESP:    printf("esp"); break;
1714         case RN_EBP:    printf("ebp"); break;
1715         case RN_ESI:    printf("esi"); break;
1716         case RN_EDI:    printf("edi"); break;
1717 #elif defined(_TARGET_AMD64_)
1718         case RN_EAX:    printf("rax"); break;
1719         case RN_ECX:    printf("rcx"); break;
1720         case RN_EDX:    printf("rdx"); break;
1721         case RN_EBX:    printf("rbx"); break;
1722         case RN_ESP:    printf("rsp"); break;
1723         case RN_EBP:    printf("rbp"); break;
1724         case RN_ESI:    printf("rsi"); break;
1725         case RN_EDI:    printf("rdi"); break;
1726         case RN_R8:     printf(" r8"); break;
1727         case RN_R9:     printf(" r9"); break;
1728         case RN_R10:    printf("r10"); break;
1729         case RN_R11:    printf("r11"); break;
1730         case RN_R12:    printf("r12"); break;
1731         case RN_R13:    printf("r13"); break;
1732         case RN_R14:    printf("r14"); break;
1733         case RN_R15:    printf("r15"); break;
1734 #else
1735 #error unknown architecture
1736 #endif
1737         }
1738     }
1739 
DumpGCInfoHeader1740     void Dump()
1741     {
1742         printf("  | prologSize:   %02X""  | epilogSize:    %02X""  | epilogCount:    %02X""  | epilogAtEnd:  %s\n",
1743             GetPrologSize(), PeekFixedEpilogSize(), epilogCount, GetBoolStr(epilogAtEnd));
1744         printf("  | frameSize:  %04X""  | ebpFrame:   %s""  | hasFunclets: %s""  | returnKind:  %s\n",
1745             GetFrameSize(), GetBoolStr(ebpFrame), GetBoolStr(hasFunclets), GetRetKindStr(returnKind));
1746         printf("  | regMask:    %04X"  "  {", calleeSavedRegMask);
1747         PrintCalleeSavedRegs(calleeSavedRegMask);
1748         printf(" }\n");
1749         if (HasDynamicAlignment())
1750         {
1751             printf("  | stackAlign:   %02X""  | paramPtrReg:  ", GetDynamicAlignment());
1752             PrintRegNumber(paramPointerReg);
1753             printf("\n");
1754         }
1755         if (hasGSCookie)
1756         {
1757             printf("  | gsCookieOffset:   %04X\n", GetGSCookieOffset());
1758         }
1759 #ifdef _TARGET_ARM_
1760         if (arm_areParmOrVfpRegsPushed)
1761         {
1762             if (arm_parmRegsPushedSet != 0)
1763             {
1764                 printf("  | parmRegs:     %02X  {", arm_parmRegsPushedSet);
1765                 PRINT_CALLEE_SAVE(" r0", SR_MASK_R0, arm_parmRegsPushedSet);
1766                 PRINT_CALLEE_SAVE(" r1", SR_MASK_R1, arm_parmRegsPushedSet);
1767                 PRINT_CALLEE_SAVE(" r2", SR_MASK_R2, arm_parmRegsPushedSet);
1768                 PRINT_CALLEE_SAVE(" r3", SR_MASK_R3, arm_parmRegsPushedSet);
1769                 printf(" }\n");
1770             }
1771             if (arm_vfpRegPushedCount != 0)
1772             {
1773                 printf("  | vfpRegs:    %d(%d)  {", arm_vfpRegFirstPushed, arm_vfpRegPushedCount);
1774                 printf(" d%d", arm_vfpRegFirstPushed);
1775                 if (arm_vfpRegPushedCount > 1)
1776                     printf("-d%d", arm_vfpRegFirstPushed + arm_vfpRegPushedCount - 1);
1777                 printf(" }\n");
1778             }
1779         }
1780 #elif defined(_TARGET_ARM64_)
1781         if (arm64_areParmOrVfpRegsPushed)
1782         {
1783             if (arm64_parmRegsPushedCount != 0)
1784             {
1785                 printf("  | parmRegsCount: %d\n", arm64_parmRegsPushedCount);
1786             }
1787             if (arm64_vfpRegsPushedMask != 0)
1788             {
1789                 printf("  | vfpRegs:      %02X  {", arm64_vfpRegsPushedMask);
1790                 for (int reg = 0; reg < 8; reg++)
1791                 {
1792                     if (arm64_vfpRegsPushedMask & (1 << reg))
1793                         printf(" d%d", reg + 8);
1794                 }
1795                 printf(" }\n");
1796             }
1797         }
1798 #elif defined(_TARGET_AMD64_)
1799         if (x64_hasSavedXmmRegs)
1800         {
1801             printf("  | xmmRegs:    %04X  {", x64_savedXmmRegMask);
1802             for (int reg = 6; reg < 16; reg++)
1803             {
1804                 if (x64_savedXmmRegMask & (1<<reg))
1805                     printf(" xmm%d", reg);
1806             }
1807             printf(" }\n");
1808         }
1809 #endif // _TARGET_ARM_
1810 
1811         // x64_framePtrOffsetSmall / [opt] x64_framePtrOffset
1812         // x86_argCountLow [opt] x86_argCountHigh
1813         // x86_argCountIsLarge
1814         // x86_hasStackChanges
1815         // [opt] reversePinvokeFrameOffset
1816         // [opt] numFunclets
1817     }
1818 #endif // RHDUMP
1819 };
1820 
1821 
1822 
1823 /*****************************************************************************/
1824 #endif //_GCINFO_H_
1825 /*****************************************************************************/
1826