summaryrefslogtreecommitdiff
path: root/src/inc/gcinfo.h
blob: 4db4ab57285ceba48e05faefe333e1cde57ae2c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//


/*****************************************************************************/
#ifndef _GCINFO_H_
#define _GCINFO_H_
/*****************************************************************************/

#include <stdlib.h>     // For memcmp()
#include "windef.h"     // For BYTE
#include "daccess.h"

#include "bitvector.h"  // for ptrArgTP

// Some declarations in this file are used on non-x86 platforms, but most are x86-specific.

// Use the lower 2 bits of the offsets stored in the tables
// to encode properties

const unsigned        OFFSET_MASK  = 0x3;  // mask to access the low 2 bits

//
//  Note for untracked locals the flags allowed are "pinned" and "byref"
//   and for tracked locals the flags allowed are "this" and "byref"
//  Note that these definitions should also match the definitions of
//   GC_CALL_INTERIOR and GC_CALL_PINNED in VM/gc.h
//
const unsigned  byref_OFFSET_FLAG  = 0x1;  // the offset is an interior ptr
const unsigned pinned_OFFSET_FLAG  = 0x2;  // the offset is a pinned ptr
const unsigned   this_OFFSET_FLAG  = 0x2;  // the offset is "this"

#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)

#ifndef FASTCALL
#define FASTCALL __fastcall
#endif

// we use offsetof to get the offset of a field
#include <stddef.h> // offsetof
#ifndef offsetof
#define offsetof(s,m)   ((size_t)&(((s *)0)->m))
#endif

enum infoHdrAdjustConstants {
    // Constants
    SET_FRAMESIZE_MAX  =  7,
    SET_ARGCOUNT_MAX   =  8,  // Change to 6
    SET_PROLOGSIZE_MAX = 16,
    SET_EPILOGSIZE_MAX = 10,  // Change to 6
    SET_EPILOGCNT_MAX  =  4,
    SET_UNTRACKED_MAX  =  3
};

//
// Enum to define the 128 codes that are used to incrementally adjust the InfoHdr structure
//
enum infoHdrAdjust {

    SET_FRAMESIZE   = 0,                                            // 0x00
    SET_ARGCOUNT    = SET_FRAMESIZE  + SET_FRAMESIZE_MAX  + 1,      // 0x08
    SET_PROLOGSIZE  = SET_ARGCOUNT   + SET_ARGCOUNT_MAX   + 1,      // 0x11
    SET_EPILOGSIZE  = SET_PROLOGSIZE + SET_PROLOGSIZE_MAX + 1,      // 0x22
    SET_EPILOGCNT   = SET_EPILOGSIZE + SET_EPILOGSIZE_MAX + 1,      // 0x2d
    SET_UNTRACKED   = SET_EPILOGCNT  + (SET_EPILOGCNT_MAX + 1) * 2, // 0x37

    FIRST_FLIP      = SET_UNTRACKED  + SET_UNTRACKED_MAX + 1,

    FLIP_EDI_SAVED = FIRST_FLIP, // 0x3b
    FLIP_ESI_SAVED,           // 0x3c
    FLIP_EBX_SAVED,           // 0x3d
    FLIP_EBP_SAVED,           // 0x3e
    FLIP_EBP_FRAME,           // 0x3f
    FLIP_INTERRUPTIBLE,       // 0x40
    FLIP_DOUBLE_ALIGN,        // 0x41
    FLIP_SECURITY,            // 0x42
    FLIP_HANDLERS,            // 0x43
    FLIP_LOCALLOC,            // 0x44
    FLIP_EDITnCONTINUE,       // 0x45
    FLIP_VAR_PTR_TABLE_SZ,    // 0x46 Flip whether a table-size exits after the header encoding
    FFFF_UNTRACKED_CNT,       // 0x47 There is a count (>SET_UNTRACKED_MAX) after the header encoding
    FLIP_VARARGS,             // 0x48
    FLIP_PROF_CALLBACKS,      // 0x49
    FLIP_HAS_GS_COOKIE,       // 0x4A - The offset of the GuardStack cookie follows after the header encoding
    FLIP_SYNC,                // 0x4B
    FLIP_HAS_GENERICS_CONTEXT,// 0x4C
    FLIP_GENERICS_CONTEXT_IS_METHODDESC,// 0x4D

                              // 0x4E .. 0x4f unused

    NEXT_FOUR_START       = 0x50,
    NEXT_FOUR_FRAMESIZE   = 0x50,
    NEXT_FOUR_ARGCOUNT    = 0x60,
    NEXT_THREE_PROLOGSIZE = 0x70,
    NEXT_THREE_EPILOGSIZE = 0x78
};

#define HAS_UNTRACKED               ((unsigned int) -1)
#define HAS_VARPTR                  ((unsigned int) -1)
// 0 is not a valid offset for EBP-frames as all locals are at a negative offset
// For ESP frames, the cookie is above (at a higher address than) the buffers, 
// and so cannot be at offset 0.
#define INVALID_GS_COOKIE_OFFSET    0
// Temporary value to indicate that the offset needs to be read after the header
#define HAS_GS_COOKIE_OFFSET        ((unsigned int) -1)

// 0 is not a valid sync offset
#define INVALID_SYNC_OFFSET         0
// Temporary value to indicate that the offset needs to be read after the header
#define HAS_SYNC_OFFSET             ((unsigned int) -1)

#define INVALID_ARGTAB_OFFSET       0

#include <pshpack1.h>

#ifdef BINDER
#ifdef TARGET_ARM

#define NUM_PRESERVED_REGS 9

enum RegMask
{
    RBM_NONE= 0x0000,
    RBM_R0  = 0x0001,
    RBM_R1  = 0x0002,
    RBM_R2  = 0x0004,
    RBM_R3  = 0x0008,
    RBM_R4  = 0x0010,   // callee saved
    RBM_R5  = 0x0020,   // callee saved
    RBM_R6  = 0x0040,   // callee saved
    RBM_R7  = 0x0080,   // callee saved
    RBM_R8  = 0x0100,   // callee saved
    RBM_R9  = 0x0200,   // callee saved
    RBM_R10 = 0x0400,   // callee saved
    RBM_R11 = 0x0800,   // callee saved
    RBM_R12 = 0x1000,
    RBM_SP  = 0x2000,
    RBM_LR  = 0x4000,   // callee saved, but not valid to be alive across a call!
    RBM_PC  = 0x8000,
    RBM_RETVAL = RBM_R0,
    RBM_CALLEE_SAVED_REGS = (RBM_R4|RBM_R5|RBM_R6|RBM_R7|RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_LR),
    RBM_CALLEE_SAVED_REG_COUNT = 9,
    // Special case: LR is callee saved, but may not appear as a live GC ref except 
    // in the leaf frame because calls will trash it.  Therefore, we ALSO consider 
    // it a scratch register.
    RBM_SCRATCH_REGS = (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R12|RBM_LR),
    RBM_SCRATCH_REG_COUNT = 6,

    // TritonToDo: is frame pointer part of the saved registers? (stackwalker related)
    RBM_SAVED  = (RBM_R4|RBM_R5|RBM_R6|RBM_R7|RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_LR),
    // TritonToDo: CHECK: is this the correct set of registers?
    RBM_VOLATILE = (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R12|RBM_LR),
    RBM_ALLCODEGEN = (RBM_SAVED | RBM_VOLATILE),
};

enum RegNumber
{
    RN_R0   = 0,
    RN_R1   = 1,
    RN_R2   = 2,
    RN_R3   = 3,
    RN_R4   = 4,
    RN_R5   = 5,
    RN_R6   = 6,
    RN_R7   = 7,
    RN_R8   = 8,
    RN_R9   = 9,
    RN_R10  = 10,
    RN_R11  = 11,
    RN_R12  = 12,
    RN_SP   = 13,
    RN_LR   = 14,
    RN_PC   = 15,

    RN_NONE = 16,
};

enum CalleeSavedRegNum
{
    CSR_NUM_R4  = 0x00,
    CSR_NUM_R5  = 0x01,
    CSR_NUM_R6  = 0x02,
    CSR_NUM_R7  = 0x03,
    CSR_NUM_R8  = 0x04,
    CSR_NUM_R9  = 0x05,
    CSR_NUM_R10 = 0x06,
    CSR_NUM_R11 = 0x07,
    // NOTE: LR is omitted because it may not be live except as a 'scratch' reg
};

enum CalleeSavedRegMask
{
    CSR_MASK_NONE = 0x00,
    CSR_MASK_R4   = 0x001,
    CSR_MASK_R5   = 0x002,
    CSR_MASK_R6   = 0x004,
    CSR_MASK_R7   = 0x008,
    CSR_MASK_R8   = 0x010,
    CSR_MASK_R9   = 0x020,
    CSR_MASK_R10  = 0x040,
    CSR_MASK_R11  = 0x080,
    CSR_MASK_LR   = 0x100,

    CSR_MASK_ALL  = 0x1ff,
    CSR_MASK_HIGHEST = 0x100,
};

enum ScratchRegNum
{
    SR_NUM_R0   = 0x00,
    SR_NUM_R1   = 0x01,
    SR_NUM_R2   = 0x02,
    SR_NUM_R3   = 0x03,
    SR_NUM_R12  = 0x04,
    SR_NUM_LR   = 0x05,
};

enum ScratchRegMask
{
    SR_MASK_NONE = 0x00,
    SR_MASK_R0   = 0x01,
    SR_MASK_R1   = 0x02,
    SR_MASK_R2   = 0x04,
    SR_MASK_R3   = 0x08,
    SR_MASK_R12  = 0x10,
    SR_MASK_LR   = 0x20,
};

#else // TARGET_ARM

#ifdef TARGET_X64
#define NUM_PRESERVED_REGS 8
#else
#define NUM_PRESERVED_REGS 4
#endif

enum RegMask
{
    RBM_NONE = 0x0000,
    RBM_EAX  = 0x0001,
    RBM_ECX  = 0x0002,
    RBM_EDX  = 0x0004,
    RBM_EBX  = 0x0008,   // callee saved
    RBM_ESP  = 0x0010,
    RBM_EBP  = 0x0020,   // callee saved
    RBM_ESI  = 0x0040,   // callee saved
    RBM_EDI  = 0x0080,   // callee saved

    RBM_R8   = 0x0100,
    RBM_R9   = 0x0200,
    RBM_R10  = 0x0400,
    RBM_R11  = 0x0800,
    RBM_R12  = 0x1000,   // callee saved
    RBM_R13  = 0x2000,   // callee saved
    RBM_R14  = 0x4000,   // callee saved
    RBM_R15  = 0x8000,   // callee saved

    RBM_RETVAL = RBM_EAX,

#ifdef TARGET_X64
    // TritonToDo: is RBM_EBP part of the saved registers? (stackwalker related)
    RBM_SAVED  = (RBM_EDI|RBM_ESI|RBM_EBX|RBM_R12|RBM_R13|RBM_R14|RBM_R15),
    //TritonToDo: CHECK: is this the correct set?
    RBM_VOLATILE = (RBM_EAX|RBM_ECX|RBM_EDX|RBM_R8|RBM_R9|RBM_R10|RBM_R11),
    RBM_ALLCODEGEN = (RBM_SAVED | RBM_VOLATILE),

    RBM_CALLEE_SAVED_REGS = (RBM_EDI|RBM_ESI|RBM_EBX|RBM_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15),
    RBM_CALLEE_SAVED_REG_COUNT = 8,
    RBM_SCRATCH_REGS = (RBM_EAX|RBM_ECX|RBM_EDX|RBM_R8|RBM_R9|RBM_R10|RBM_R11),
    RBM_SCRATCH_REG_COUNT = 7,
#else
    RBM_SAVED = (RBM_ESI | RBM_EDI | RBM_EBX),
    RBM_VOLATILE = (RBM_EAX | RBM_ECX | RBM_EDX),
    RBM_ALLCODEGEN = (RBM_SAVED | RBM_VOLATILE),

    RBM_CALLEE_SAVED_REGS = (RBM_EDI|RBM_ESI|RBM_EBX|RBM_EBP),
    RBM_CALLEE_SAVED_REG_COUNT = 4,
    RBM_SCRATCH_REGS = (RBM_EAX|RBM_ECX|RBM_EDX),
    RBM_SCRATCH_REG_COUNT = 3,
#endif // TARGET_X64
};

enum RegNumber
{
    RN_EAX = 0,
    RN_ECX = 1,
    RN_EDX = 2,
    RN_EBX = 3,
    RN_ESP = 4,
    RN_EBP = 5,
    RN_ESI = 6,
    RN_EDI = 7,
    RN_R8  = 8,
    RN_R9  = 9,
    RN_R10 = 10,
    RN_R11 = 11,
    RN_R12 = 12,
    RN_R13 = 13,
    RN_R14 = 14,
    RN_R15 = 15,

    RN_NONE = 16,
};

enum CalleeSavedRegNum
{
    CSR_NUM_RBX = 0x00,
    CSR_NUM_RSI = 0x01,
    CSR_NUM_RDI = 0x02,
    CSR_NUM_RBP = 0x03,
    CSR_NUM_R12 = 0x04,
    CSR_NUM_R13 = 0x05,
    CSR_NUM_R14 = 0x06,
    CSR_NUM_R15 = 0x07,
};

enum CalleeSavedRegMask
{
    CSR_MASK_NONE = 0x00,
    CSR_MASK_RBX = 0x01,
    CSR_MASK_RSI = 0x02,
    CSR_MASK_RDI = 0x04,
    CSR_MASK_RBP = 0x08,
    CSR_MASK_R12 = 0x10,
    CSR_MASK_R13 = 0x20,
    CSR_MASK_R14 = 0x40,
    CSR_MASK_R15 = 0x80,

#ifdef TARGET_X64
    CSR_MASK_ALL = 0xFF,
    CSR_MASK_HIGHEST = 0x80,
#else
    CSR_MASK_ALL = 0x0F,
    CSR_MASK_HIGHEST = 0x08,
#endif
};

enum ScratchRegNum
{
    SR_NUM_RAX = 0x00,
    SR_NUM_RCX = 0x01,
    SR_NUM_RDX = 0x02,
    SR_NUM_R8  = 0x03,
    SR_NUM_R9  = 0x04,
    SR_NUM_R10 = 0x05,
    SR_NUM_R11 = 0x06,
};

enum ScratchRegMask
{
    SR_MASK_NONE = 0x00,
    SR_MASK_RAX  = 0x01,
    SR_MASK_RCX  = 0x02,
    SR_MASK_RDX  = 0x04,
    SR_MASK_R8   = 0x08,
    SR_MASK_R9   = 0x10,
    SR_MASK_R10  = 0x20,
    SR_MASK_R11  = 0x40,
};

#endif // TARGET_ARM

#endif // BINDER

// Working set optimization: saving 12 * 128 = 1536 bytes in infoHdrShortcut
struct InfoHdr;

struct InfoHdrSmall {
    unsigned char  prologSize;        // 0
    unsigned char  epilogSize;        // 1
#if !defined(BINDER) || !defined(TARGET_ARM)
    unsigned char  epilogCount   : 3; // 2 [0:2]
#endif
    unsigned char  epilogAtEnd   : 1; // 2 [3]
    unsigned char  ediSaved      : 1; // 2 [4]      which callee-saved regs are pushed onto stack
    unsigned char  esiSaved      : 1; // 2 [5]
    unsigned char  ebxSaved      : 1; // 2 [6]
    unsigned char  ebpSaved      : 1; // 2 [7]
    unsigned char  ebpFrame      : 1; // 3 [0]      locals accessed relative to ebp
    unsigned char  interruptible : 1; // 3 [1]      is intr. at all points (except prolog/epilog), not just call-sites
    unsigned char  doubleAlign   : 1; // 3 [2]      uses double-aligned stack (ebpFrame will be false)
    unsigned char  security      : 1; // 3 [3]      has slot for security object
    unsigned char  handlers      : 1; // 3 [4]      has callable handlers
    unsigned char  localloc      : 1; // 3 [5]      uses localloc
    unsigned char  editNcontinue : 1; // 3 [6]      was JITed in EnC mode
    unsigned char  varargs       : 1; // 3 [7]      function uses varargs calling convention
    unsigned char  profCallbacks : 1; // 4 [0]
    unsigned char  genericsContext : 1;//4 [1]      function reports a generics context parameter is present
    unsigned char  genericsContextIsMethodDesc : 1;//4[2]
    unsigned short argCount;          // 5,6        in bytes
    unsigned int   frameSize;         // 7,8,9,10   in bytes
    unsigned int   untrackedCnt;      // 11,12,13,14
    unsigned int   varPtrTableSize;   // 15.16,17,18

    // Checks whether "this" is compatible with "target".
    // It is not an exact bit match as "this" could have some 
    // marker/place-holder values, which will have to be written out
    // after the header.

    bool isHeaderMatch(const InfoHdr& target) const;
};


struct InfoHdr : public InfoHdrSmall {
    // 0 (zero) means that there is no GuardStack cookie
    // The cookie is either at ESP+gsCookieOffset or EBP-gsCookieOffset
    unsigned int   gsCookieOffset;    // 19,20,21,22
    unsigned int   syncStartOffset;   // 23,24,25,26
    unsigned int   syncEndOffset;     // 27,28,29,30

                                      // 31 bytes total
#ifdef BINDER
#ifdef TARGET_ARM
    unsigned int   calleeSavedRegMask : NUM_PRESERVED_REGS;  // 9 bits
    unsigned int   parmRegsPushed     : 1; // 1 if the prolog pushed R0-R3 on entry, 0 otherwise
    unsigned int   genericContextFlags : 2;
    unsigned int   epilogCount;
             int   callerSpToPspSlotOffset; // offset of PSP slot relative to incoming SP
                                            // only valid if handlers == 1
             int   outgoingArgSize;         // >= 0

             int   genericContextOffset;
             int   securityObjectOffset;    // relative to caller SP
#endif
#endif

    // Checks whether "this" is compatible with "target".
    // It is not an exact bit match as "this" could have some 
    // marker/place-holder values, which will have to be written out
    // after the header.

    bool isHeaderMatch(const InfoHdr& target) const
    {
#ifdef _ASSERTE
        // target cannot have place-holder values.
        _ASSERTE(target.untrackedCnt != HAS_UNTRACKED &&
                 target.varPtrTableSize != HAS_VARPTR &&
                 target.gsCookieOffset != HAS_GS_COOKIE_OFFSET &&
                 target.syncStartOffset != HAS_SYNC_OFFSET);
#endif

        // compare two InfoHdr's up to but not including the untrackCnt field
        if (memcmp(this, &target, offsetof(InfoHdr, untrackedCnt)) != 0)
            return false;

        if (untrackedCnt != target.untrackedCnt) {
            if (target.untrackedCnt <= SET_UNTRACKED_MAX)
                return false;
            else if (untrackedCnt != HAS_UNTRACKED)
                return false;
        }
        
        if (varPtrTableSize != target.varPtrTableSize) {
            if ((varPtrTableSize != 0) != (target.varPtrTableSize != 0))
                return false;
        }

        if ((gsCookieOffset == INVALID_GS_COOKIE_OFFSET) !=
            (target.gsCookieOffset == INVALID_GS_COOKIE_OFFSET))
            return false;

        if ((syncStartOffset == INVALID_SYNC_OFFSET) !=
            (target.syncStartOffset == INVALID_SYNC_OFFSET))
            return false;

        return true;
    }

#ifdef  BINDER
    void Init()
    {
        memset(this, 0, sizeof(InfoHdr));
    }

    void SetPrologSize(UInt32 sizeInBytes)
    {
        prologSize = sizeInBytes;
        _ASSERTE(prologSize == sizeInBytes);
    }

    void SetEpilogSize(UInt32 sizeInBytes)
    {
        epilogSize = sizeInBytes;
        _ASSERTE(epilogSize == sizeInBytes);
    }

    void SetEpilogCount(UInt32 count, bool isAtEnd)
    {
        epilogCount = count;
        epilogAtEnd = isAtEnd ? 1 : 0;

        _ASSERTE(epilogCount == count);
        _ASSERTE((count == 1) || !isAtEnd);
    }

    void SetReturnPopSize(UInt32 popSizeInBytes)
    {
        _ASSERTE(0 == (popSizeInBytes % POINTER_SIZE));
#ifdef  TARGET_ARM
        _ASSERTE(GetReturnPopSize() <= (int)popSizeInBytes);
#else
        _ASSERTE(GetReturnPopSize() == 0 || GetReturnPopSize() == (int)popSizeInBytes);
#endif
        argCount = popSizeInBytes / POINTER_SIZE;
    }

    void SetFrameSize(UInt32 frameSizeInBytes)
    {
        _ASSERTE(0 == (frameSizeInBytes % POINTER_SIZE));
        frameSize = frameSizeInBytes / POINTER_SIZE;
    }

    void SetRegSaved(CalleeSavedRegMask regMask)
    {
        _ASSERTE((regMask & ~CSR_MASK_ALL) == CSR_MASK_NONE);
#ifndef TARGET_ARM   //TritonToDo
        if (regMask & CSR_MASK_RSI)
            esiSaved = true;
        if (regMask & CSR_MASK_RDI)
            ediSaved = true;
        if (regMask & CSR_MASK_RBX)
            ebxSaved = true;
        if (regMask & CSR_MASK_RBP)
            ebpSaved = true;
#else
        calleeSavedRegMask = regMask;
#endif
    }

    void SetSavedRegs(CalleeSavedRegMask regMask)
    {
#ifndef TARGET_ARM   //TritonToDo
        esiSaved = (regMask & CSR_MASK_RSI) != 0;
        ediSaved = (regMask & CSR_MASK_RDI) != 0;
        ebxSaved = (regMask & CSR_MASK_RBX) != 0;
        ebpSaved = (regMask & CSR_MASK_RBP) != 0;
#else
        calleeSavedRegMask |= regMask;
#endif
    }

    void SetFramePointer(RegNumber regNum, UInt32 offsetInBytes)
    {
        if (regNum == RN_NONE)
        {
            ebpFrame = 0;
        }
        else
        {
#ifndef TARGET_ARM   //TritonToDo
            _ASSERTE(regNum == RN_EBP);
#else
#ifdef CLR_STANDALONE_BINDER
            _ASSERTE(regNum == RN_R11);
#else
            _ASSERTE(regNum == RN_R7); // REDHAWK
#endif
#endif
            ebpFrame = 1;
        }

#ifdef TARGET_X64
        ASSERT((offsetInBytes % 0x10) == 0);
        UInt32 offsetInSlots = offsetInBytes / 0x10;
        if (offsetInSlots < 7)
        {
            x64_framePtrOffsetSmall = offsetInSlots;
            x64_framePtrOffset = 0;
        }
        else
        {
            x64_framePtrOffsetSmall = 7;
            x64_framePtrOffset = offsetInSlots - 7;
        }
#else
        _ASSERTE(offsetInBytes == 0);
#endif // TARGET_X64
    }

    int GetFrameSize()
    {
        return frameSize*POINTER_SIZE;
    }

    int GetReturnPopSize() // returned in bytes
    {
        return argCount*POINTER_SIZE;
    }

    int GetPreservedRegsSaveSize() const // returned in bytes
    {
#ifndef TARGET_ARM   //TritonToDo
        return (ediSaved + esiSaved + ebxSaved + ebpSaved)*POINTER_SIZE;
#else
        UInt32 count = 0;
        UInt32 mask = calleeSavedRegMask;
        while (mask != 0)
        {
            count += mask & 1;
            mask >>= 1;
        }
        return (int) count * POINTER_SIZE;
#endif
    }

    CalleeSavedRegMask GetSavedRegs()
    {
        unsigned result = CSR_MASK_NONE;
#ifndef TARGET_ARM   //TritonToDo
        if (ediSaved)
            result |= CSR_MASK_RDI;
        if (esiSaved)
            result |= CSR_MASK_RSI;
        if (ebxSaved)
            result |= CSR_MASK_RBX;
        if (ebpSaved)
            result |= CSR_MASK_RBP;
        return (CalleeSavedRegMask)result;
#else
        return (CalleeSavedRegMask) calleeSavedRegMask;
#endif
    }

    bool HasFramePointer()
    {
        return ebpFrame;
    }

    bool IsRegSaved(CalleeSavedRegMask reg)
    {
        return (0 != (GetSavedRegs() & reg));
    }

#ifdef TARGET_ARM
    UInt32 GetEpilogCount()
    {
        return epilogCount;
    }

    bool IsEpilogAtEnd()
    {
        return epilogAtEnd != 0;
    }
#endif // TARGET_ARM

#endif // BINDER
};


union CallPattern {
    struct {
        unsigned char argCnt;
        unsigned char regMask;  // EBP=0x8, EBX=0x4, ESI=0x2, EDI=0x1
        unsigned char argMask;
        unsigned char codeDelta;
    }            fld;
    unsigned     val;
};

#include <poppack.h>

#define IH_MAX_PROLOG_SIZE (51)

extern const InfoHdrSmall infoHdrShortcut[];
extern int                infoHdrLookup[];

inline void GetInfoHdr(int index, InfoHdr * header)
{
    * ((InfoHdrSmall *) header) = infoHdrShortcut[index];

    header->gsCookieOffset  = 0;
    header->syncStartOffset = 0;
    header->syncEndOffset   = 0;
}

PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header);

BYTE FASTCALL encodeHeaderFirst(const InfoHdr& header, InfoHdr* state, int* more, int *pCached);
BYTE FASTCALL encodeHeaderNext (const InfoHdr& header, InfoHdr* state);

size_t FASTCALL decodeUnsigned (PTR_CBYTE src, unsigned* value);
size_t FASTCALL decodeUDelta   (PTR_CBYTE src, unsigned* value, unsigned lastValue);
size_t FASTCALL decodeSigned   (PTR_CBYTE src, int     * value);

#define CP_MAX_CODE_DELTA  (0x23)
#define CP_MAX_ARG_CNT     (0x02)
#define CP_MAX_ARG_MASK    (0x00)

extern const unsigned callPatternTable[];
extern const unsigned callCommonDelta[];


int  FASTCALL lookupCallPattern(unsigned    argCnt,
                                unsigned    regMask,
                                unsigned    argMask,
                                unsigned    codeDelta);

void FASTCALL decodeCallPattern(int         pattern,
                                unsigned *  argCnt,
                                unsigned *  regMask,
                                unsigned *  argMask,
                                unsigned *  codeDelta);

#endif // _TARGET_86_ || _TARGET_ARM_

/*****************************************************************************/
#endif //_GCINFO_H_
/*****************************************************************************/