Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / gcencode.cpp
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 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                          GCEncode                                         XX
9 XX                                                                           XX
10 XX   Logic to encode the JIT method header and GC pointer tables             XX
11 XX                                                                           XX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14 */
15
16 #include "jitpch.h"
17 #ifdef _MSC_VER
18 #pragma hdrstop
19
20 #pragma warning(disable : 4244) // loss of data int -> char ..
21
22 #endif
23
24 #include "gcinfotypes.h"
25
26 ReturnKind GCTypeToReturnKind(CorInfoGCType gcType)
27 {
28     switch (gcType)
29     {
30         case TYPE_GC_NONE:
31             return RT_Scalar;
32         case TYPE_GC_REF:
33             return RT_Object;
34         case TYPE_GC_BYREF:
35             return RT_ByRef;
36         default:
37             _ASSERTE(!"TYP_GC_OTHER is unexpected");
38             return RT_Illegal;
39     }
40 }
41
42 ReturnKind GCInfo::getReturnKind()
43 {
44     switch (compiler->info.compRetType)
45     {
46         case TYP_REF:
47             return RT_Object;
48         case TYP_BYREF:
49             return RT_ByRef;
50         case TYP_STRUCT:
51         {
52             CORINFO_CLASS_HANDLE structType = compiler->info.compMethodInfo->args.retTypeClass;
53             var_types            retType    = compiler->getReturnTypeForStruct(structType);
54
55             switch (retType)
56             {
57                 case TYP_REF:
58                     return RT_Object;
59
60                 case TYP_BYREF:
61                     return RT_ByRef;
62
63                 case TYP_STRUCT:
64                     if (compiler->IsHfa(structType))
65                     {
66 #ifdef _TARGET_X86_
67                         _ASSERTE(false && "HFAs not expected for X86");
68 #endif // _TARGET_X86_
69
70                         return RT_Scalar;
71                     }
72                     else
73                     {
74                         // Multi-reg return
75                         BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE};
76                         compiler->info.compCompHnd->getClassGClayout(structType, gcPtrs);
77
78                         ReturnKind first  = GCTypeToReturnKind((CorInfoGCType)gcPtrs[0]);
79                         ReturnKind second = GCTypeToReturnKind((CorInfoGCType)gcPtrs[1]);
80
81                         return GetStructReturnKind(first, second);
82                     }
83
84 #ifdef _TARGET_X86_
85                 case TYP_FLOAT:
86                 case TYP_DOUBLE:
87                     return RT_Float;
88 #endif // _TARGET_X86_
89                 default:
90                     return RT_Scalar;
91             }
92         }
93
94 #ifdef _TARGET_X86_
95         case TYP_FLOAT:
96         case TYP_DOUBLE:
97             return RT_Float;
98 #endif // _TARGET_X86_
99
100         default:
101             return RT_Scalar;
102     }
103 }
104
105 #if !defined(JIT32_GCENCODER) || defined(WIN64EXCEPTIONS)
106
107 // gcMarkFilterVarsPinned - Walk all lifetimes and make it so that anything
108 //     live in a filter is marked as pinned (often by splitting the lifetime
109 //     so that *only* the filter region is pinned).  This should only be
110 //     called once (after generating all lifetimes, but before slot ids are
111 //     finalized.
112 //
113 // DevDiv 376329 - The VM has to double report filters and their parent frame
114 // because they occur during the 1st pass and the parent frame doesn't go dead
115 // until we start unwinding in the 2nd pass.
116 //
117 // Untracked locals will only be reported in non-filter funclets and the
118 // parent.
119 // Registers can't be double reported by 2 frames since they're different.
120 // That just leaves stack variables which might be double reported.
121 //
122 // Technically double reporting is only a problem when the GC has to relocate a
123 // reference. So we avoid that problem by marking all live tracked stack
124 // variables as pinned inside the filter.  Thus if they are double reported, it
125 // won't be a problem since they won't be double relocated.
126 //
127 void GCInfo::gcMarkFilterVarsPinned()
128 {
129     assert(compiler->ehAnyFunclets());
130     const EHblkDsc* endHBtab = &(compiler->compHndBBtab[compiler->compHndBBtabCount]);
131
132     for (EHblkDsc* HBtab = compiler->compHndBBtab; HBtab < endHBtab; HBtab++)
133     {
134         if (HBtab->HasFilter())
135         {
136             const UNATIVE_OFFSET filterBeg = compiler->ehCodeOffset(HBtab->ebdFilter);
137             const UNATIVE_OFFSET filterEnd = compiler->ehCodeOffset(HBtab->ebdHndBeg);
138
139             for (varPtrDsc* varTmp = gcVarPtrList; varTmp != nullptr; varTmp = varTmp->vpdNext)
140             {
141                 // Get hold of the variable's flags.
142                 const unsigned lowBits = varTmp->vpdVarNum & OFFSET_MASK;
143
144                 // Compute the actual lifetime offsets.
145                 const unsigned begOffs = varTmp->vpdBegOfs;
146                 const unsigned endOffs = varTmp->vpdEndOfs;
147
148                 // Special case: skip any 0-length lifetimes.
149                 if (endOffs == begOffs)
150                 {
151                     continue;
152                 }
153
154                 // Skip lifetimes with no overlap with the filter
155                 if ((endOffs <= filterBeg) || (begOffs >= filterEnd))
156                 {
157                     continue;
158                 }
159
160 #ifndef JIT32_GCENCODER
161                 // Because there is no nesting within filters, nothing
162                 // should be already pinned.
163                 // For JIT32_GCENCODER, we should not do this check as gcVarPtrList are always sorted by vpdBegOfs
164                 // which means that we could see some varPtrDsc that were already pinned by previous splitting.
165                 assert((lowBits & pinned_OFFSET_FLAG) == 0);
166 #endif // JIT32_GCENCODER
167
168                 if (begOffs < filterBeg)
169                 {
170                     if (endOffs > filterEnd)
171                     {
172                         // The variable lifetime is starts before AND ends after
173                         // the filter, so we need to create 2 new lifetimes:
174                         //     (1) a pinned one for the filter
175                         //     (2) a regular one for after the filter
176                         // and then adjust the original lifetime to end before
177                         // the filter.
178                         CLANG_FORMAT_COMMENT_ANCHOR;
179
180 #ifdef DEBUG
181                         if (compiler->verbose)
182                         {
183                             printf("Splitting lifetime for filter: [%04X, %04X).\nOld: ", filterBeg, filterEnd);
184                             gcDumpVarPtrDsc(varTmp);
185                         }
186 #endif // DEBUG
187
188                         varPtrDsc* desc1 = new (compiler, CMK_GC) varPtrDsc;
189                         desc1->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
190                         desc1->vpdBegOfs = filterBeg;
191                         desc1->vpdEndOfs = filterEnd;
192
193                         varPtrDsc* desc2 = new (compiler, CMK_GC) varPtrDsc;
194                         desc2->vpdVarNum = varTmp->vpdVarNum;
195                         desc2->vpdBegOfs = filterEnd;
196                         desc2->vpdEndOfs = endOffs;
197
198                         varTmp->vpdEndOfs = filterBeg;
199
200                         gcInsertVarPtrDscSplit(desc1, varTmp);
201                         gcInsertVarPtrDscSplit(desc2, varTmp);
202
203 #ifdef DEBUG
204                         if (compiler->verbose)
205                         {
206                             printf("New (1 of 3): ");
207                             gcDumpVarPtrDsc(varTmp);
208                             printf("New (2 of 3): ");
209                             gcDumpVarPtrDsc(desc1);
210                             printf("New (3 of 3): ");
211                             gcDumpVarPtrDsc(desc2);
212                         }
213 #endif // DEBUG
214                     }
215                     else
216                     {
217                         // The variable lifetime started before the filter and ends
218                         // somewhere inside it, so we only create 1 new lifetime,
219                         // and then adjust the original lifetime to end before
220                         // the filter.
221                         CLANG_FORMAT_COMMENT_ANCHOR;
222
223 #ifdef DEBUG
224                         if (compiler->verbose)
225                         {
226                             printf("Splitting lifetime for filter.\nOld: ");
227                             gcDumpVarPtrDsc(varTmp);
228                         }
229 #endif // DEBUG
230
231                         varPtrDsc* desc = new (compiler, CMK_GC) varPtrDsc;
232                         desc->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
233                         desc->vpdBegOfs = filterBeg;
234                         desc->vpdEndOfs = endOffs;
235
236                         varTmp->vpdEndOfs = filterBeg;
237
238                         gcInsertVarPtrDscSplit(desc, varTmp);
239
240 #ifdef DEBUG
241                         if (compiler->verbose)
242                         {
243                             printf("New (1 of 2): ");
244                             gcDumpVarPtrDsc(varTmp);
245                             printf("New (2 of 2): ");
246                             gcDumpVarPtrDsc(desc);
247                         }
248 #endif // DEBUG
249                     }
250                 }
251                 else
252                 {
253                     if (endOffs > filterEnd)
254                     {
255                         // The variable lifetime starts inside the filter and
256                         // ends somewhere after it, so we create 1 new
257                         // lifetime for the part inside the filter and adjust
258                         // the start of the original lifetime to be the end
259                         // of the filter
260                         CLANG_FORMAT_COMMENT_ANCHOR;
261 #ifdef DEBUG
262                         if (compiler->verbose)
263                         {
264                             printf("Splitting lifetime for filter.\nOld: ");
265                             gcDumpVarPtrDsc(varTmp);
266                         }
267 #endif // DEBUG
268
269                         varPtrDsc* desc = new (compiler, CMK_GC) varPtrDsc;
270 #ifndef JIT32_GCENCODER
271                         desc->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
272                         desc->vpdBegOfs = begOffs;
273                         desc->vpdEndOfs = filterEnd;
274
275                         varTmp->vpdBegOfs = filterEnd;
276 #else
277                         // Mark varTmp as pinned and generated use varPtrDsc(desc) as non-pinned
278                         // since gcInsertVarPtrDscSplit requires that varTmp->vpdBegOfs must precede desc->vpdBegOfs
279                         desc->vpdVarNum = varTmp->vpdVarNum;
280                         desc->vpdBegOfs = filterEnd;
281                         desc->vpdEndOfs = endOffs;
282
283                         varTmp->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
284                         varTmp->vpdEndOfs = filterEnd;
285 #endif
286
287                         gcInsertVarPtrDscSplit(desc, varTmp);
288
289 #ifdef DEBUG
290                         if (compiler->verbose)
291                         {
292                             printf("New (1 of 2): ");
293                             gcDumpVarPtrDsc(desc);
294                             printf("New (2 of 2): ");
295                             gcDumpVarPtrDsc(varTmp);
296                         }
297 #endif // DEBUG
298                     }
299                     else
300                     {
301                         // The variable lifetime is completely within the filter,
302                         // so just add the pinned flag.
303                         CLANG_FORMAT_COMMENT_ANCHOR;
304 #ifdef DEBUG
305                         if (compiler->verbose)
306                         {
307                             printf("Pinning lifetime for filter.\nOld: ");
308                             gcDumpVarPtrDsc(varTmp);
309                         }
310 #endif // DEBUG
311
312                         varTmp->vpdVarNum |= pinned_OFFSET_FLAG;
313 #ifdef DEBUG
314                         if (compiler->verbose)
315                         {
316                             printf("New : ");
317                             gcDumpVarPtrDsc(varTmp);
318                         }
319 #endif // DEBUG
320                     }
321                 }
322             }
323         } // HasFilter
324     }     // Foreach EH
325 }
326
327 // gcInsertVarPtrDscSplit - Insert varPtrDsc that were created by splitting lifetimes
328 //     From gcMarkFilterVarsPinned, we may have created one or two `varPtrDsc`s due to splitting lifetimes
329 //     and these newly created `varPtrDsc`s should be inserted in gcVarPtrList.
330 //     However the semantics of this call depend on the architecture.
331 //
332 //     x86-GCInfo requires gcVarPtrList to be sorted by vpdBegOfs.
333 //     Every time inserting an entry we should keep the order of entries.
334 //     So this function searches for a proper insertion point from "begin" then "desc" gets inserted.
335 //
336 //     For other architectures(ones that uses GCInfo{En|De}coder), we don't need any sort.
337 //     So the argument "begin" is unused and "desc" will be inserted at the front of the list.
338
339 void GCInfo::gcInsertVarPtrDscSplit(varPtrDsc* desc, varPtrDsc* begin)
340 {
341 #ifndef JIT32_GCENCODER
342     (void)begin;
343     desc->vpdNext = gcVarPtrList;
344     gcVarPtrList  = desc;
345 #else  // JIT32_GCENCODER
346     // "desc" and "begin" must not be null
347     assert(desc != nullptr);
348     assert(begin != nullptr);
349
350     // The caller must guarantee that desc's BegOfs is equal or greater than begin's
351     // since we will search for insertion point from "begin"
352     assert(desc->vpdBegOfs >= begin->vpdBegOfs);
353
354     varPtrDsc* varTmp    = begin->vpdNext;
355     varPtrDsc* varInsert = begin;
356
357     while (varTmp != nullptr && varTmp->vpdBegOfs < desc->vpdBegOfs)
358     {
359         varInsert = varTmp;
360         varTmp    = varTmp->vpdNext;
361     }
362
363     // Insert point cannot be null
364     assert(varInsert != nullptr);
365
366     desc->vpdNext      = varInsert->vpdNext;
367     varInsert->vpdNext = desc;
368 #endif // JIT32_GCENCODER
369 }
370
371 #ifdef DEBUG
372
373 void GCInfo::gcDumpVarPtrDsc(varPtrDsc* desc)
374 {
375     const int    offs   = (desc->vpdVarNum & ~OFFSET_MASK);
376     const GCtype gcType = (desc->vpdVarNum & byref_OFFSET_FLAG) ? GCT_BYREF : GCT_GCREF;
377     const bool   isPin  = (desc->vpdVarNum & pinned_OFFSET_FLAG) != 0;
378
379     printf("[%08X] %s%s var at [%s", dspPtr(desc), GCtypeStr(gcType), isPin ? "pinned-ptr" : "",
380            compiler->isFramePointerUsed() ? STR_FPBASE : STR_SPBASE);
381
382     if (offs < 0)
383     {
384         printf("-%02XH", -offs);
385     }
386     else if (offs > 0)
387     {
388         printf("+%02XH", +offs);
389     }
390
391     printf("] live from %04X to %04X\n", desc->vpdBegOfs, desc->vpdEndOfs);
392 }
393
394 #endif // DEBUG
395
396 #endif // !defined(JIT32_GCENCODER) || defined(WIN64EXCEPTIONS)
397
398 #ifdef JIT32_GCENCODER
399
400 #include "emit.h"
401
402 /*****************************************************************************/
403 /*****************************************************************************/
404
405 /*****************************************************************************/
406 // (see jit.h) #define REGEN_SHORTCUTS 0
407 // To Regenerate the compressed info header shortcuts, define REGEN_SHORTCUTS
408 // and use the following command line pipe/filter to give you the 128
409 // most useful encodings.
410 //
411 // find . -name regen.txt | xargs cat | grep InfoHdr | sort | uniq -c | sort -r | head -128
412
413 // (see jit.h) #define REGEN_CALLPAT 0
414 // To Regenerate the compressed info header shortcuts, define REGEN_CALLPAT
415 // and use the following command line pipe/filter to give you the 80
416 // most useful encodings.
417 //
418 // find . -name regen.txt | xargs cat | grep CallSite | sort | uniq -c | sort -r | head -80
419
420 #if REGEN_SHORTCUTS || REGEN_CALLPAT
421 static FILE*     logFile = NULL;
422 CRITICAL_SECTION logFileLock;
423 #endif
424
425 #if REGEN_CALLPAT
426 static void regenLog(unsigned codeDelta,
427                      unsigned argMask,
428                      unsigned regMask,
429                      unsigned argCnt,
430                      unsigned byrefArgMask,
431                      unsigned byrefRegMask,
432                      BYTE*    base,
433                      unsigned enSize)
434 {
435     CallPattern pat;
436
437     pat.fld.argCnt    = (argCnt < 0xff) ? argCnt : 0xff;
438     pat.fld.regMask   = (regMask < 0xff) ? regMask : 0xff;
439     pat.fld.argMask   = (argMask < 0xff) ? argMask : 0xff;
440     pat.fld.codeDelta = (codeDelta < 0xff) ? codeDelta : 0xff;
441
442     if (logFile == NULL)
443     {
444         logFile = fopen("regen.txt", "a");
445         InitializeCriticalSection(&logFileLock);
446     }
447
448     assert(((enSize > 0) && (enSize < 256)) && ((pat.val & 0xffffff) != 0xffffff));
449
450     EnterCriticalSection(&logFileLock);
451
452     fprintf(logFile, "CallSite( 0x%08x, 0x%02x%02x, 0x", pat.val, byrefArgMask, byrefRegMask);
453
454     while (enSize > 0)
455     {
456         fprintf(logFile, "%02x", *base++);
457         enSize--;
458     }
459     fprintf(logFile, "),\n");
460     fflush(logFile);
461
462     LeaveCriticalSection(&logFileLock);
463 }
464 #endif
465
466 #if REGEN_SHORTCUTS
467 static void regenLog(unsigned encoding, InfoHdr* header, InfoHdr* state)
468 {
469     if (logFile == NULL)
470     {
471         logFile = fopen("regen.txt", "a");
472         InitializeCriticalSection(&logFileLock);
473     }
474
475     EnterCriticalSection(&logFileLock);
476
477     fprintf(logFile, "InfoHdr( %2d, %2d, %1d, %1d, %1d,"
478                      " %1d, %1d, %1d, %1d, %1d,"
479                      " %1d, %1d, %1d, %1d, %1d, %1d,"
480                      " %1d, %1d, %1d,"
481                      " %1d, %2d, %2d,"
482                      " %2d, %2d, %2d, %2d, %2d, %2d), \n",
483             state->prologSize, state->epilogSize, state->epilogCount, state->epilogAtEnd, state->ediSaved,
484             state->esiSaved, state->ebxSaved, state->ebpSaved, state->ebpFrame, state->interruptible,
485             state->doubleAlign, state->security, state->handlers, state->localloc, state->editNcontinue, state->varargs,
486             state->profCallbacks, state->genericsContext, state->genericsContextIsMethodDesc, state->returnKind,
487             state->argCount, state->frameSize,
488             (state->untrackedCnt <= SET_UNTRACKED_MAX) ? state->untrackedCnt : HAS_UNTRACKED,
489             (state->varPtrTableSize == 0) ? 0 : HAS_VARPTR,
490             (state->gsCookieOffset == INVALID_GS_COOKIE_OFFSET) ? 0 : HAS_GS_COOKIE_OFFSET,
491             (state->syncStartOffset == INVALID_SYNC_OFFSET) ? 0 : HAS_SYNC_OFFSET,
492             (state->syncStartOffset == INVALID_SYNC_OFFSET) ? 0 : HAS_SYNC_OFFSET,
493             (state->revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET) ? 0 : HAS_REV_PINVOKE_FRAME_OFFSET);
494
495     fflush(logFile);
496
497     LeaveCriticalSection(&logFileLock);
498 }
499 #endif
500
501 /*****************************************************************************
502  *
503  *  Given the four parameters return the index into the callPatternTable[]
504  *  that is used to encoding these four items.  If an exact match cannot
505  *  found then ignore the codeDelta and search the table again for a near
506  *  match.
507  *  Returns 0..79 for an exact match or
508  *         (delta<<8) | (0..79) for a near match.
509  *  A near match will be encoded using two bytes, the first byte will
510  *  skip the adjustment delta that prevented an exact match and the
511  *  rest of the delta plus the other three items are encoded in the
512  *  second byte.
513  */
514 int FASTCALL lookupCallPattern(unsigned argCnt, unsigned regMask, unsigned argMask, unsigned codeDelta)
515 {
516     if ((argCnt <= CP_MAX_ARG_CNT) && (argMask <= CP_MAX_ARG_MASK))
517     {
518         CallPattern pat;
519
520         pat.fld.argCnt    = argCnt;
521         pat.fld.regMask   = regMask; // EBP,EBX,ESI,EDI
522         pat.fld.argMask   = argMask;
523         pat.fld.codeDelta = codeDelta;
524
525         bool     codeDeltaOK = (pat.fld.codeDelta == codeDelta);
526         unsigned bestDelta2  = 0xff;
527         unsigned bestPattern = 0xff;
528         unsigned patval      = pat.val;
529         assert(sizeof(CallPattern) == sizeof(unsigned));
530
531         const unsigned* curp = &callPatternTable[0];
532         for (unsigned inx = 0; inx < 80; inx++, curp++)
533         {
534             unsigned curval = *curp;
535             if ((patval == curval) && codeDeltaOK)
536                 return inx;
537
538             if (((patval ^ curval) & 0xffffff) == 0)
539             {
540                 unsigned delta2 = codeDelta - (curval >> 24);
541                 if (delta2 < bestDelta2)
542                 {
543                     bestDelta2  = delta2;
544                     bestPattern = inx;
545                 }
546             }
547         }
548
549         if (bestPattern != 0xff)
550         {
551             return (bestDelta2 << 8) | bestPattern;
552         }
553     }
554     return -1;
555 }
556
557 static bool initNeeded3(unsigned cur, unsigned tgt, unsigned max, unsigned* hint)
558 {
559     assert(cur != tgt);
560
561     unsigned tmp = tgt;
562     unsigned nib = 0;
563     unsigned cnt = 0;
564
565     while (tmp > max)
566     {
567         nib = tmp & 0x07;
568         tmp >>= 3;
569         if (tmp == cur)
570         {
571             *hint = nib;
572             return false;
573         }
574         cnt++;
575     }
576
577     *hint = tmp;
578     return true;
579 }
580
581 static bool initNeeded4(unsigned cur, unsigned tgt, unsigned max, unsigned* hint)
582 {
583     assert(cur != tgt);
584
585     unsigned tmp = tgt;
586     unsigned nib = 0;
587     unsigned cnt = 0;
588
589     while (tmp > max)
590     {
591         nib = tmp & 0x0f;
592         tmp >>= 4;
593         if (tmp == cur)
594         {
595             *hint = nib;
596             return false;
597         }
598         cnt++;
599     }
600
601     *hint = tmp;
602     return true;
603 }
604
605 static int bigEncoding3(unsigned cur, unsigned tgt, unsigned max)
606 {
607     assert(cur != tgt);
608
609     unsigned tmp = tgt;
610     unsigned nib = 0;
611     unsigned cnt = 0;
612
613     while (tmp > max)
614     {
615         nib = tmp & 0x07;
616         tmp >>= 3;
617         if (tmp == cur)
618             break;
619         cnt++;
620     }
621     return cnt;
622 }
623
624 static int bigEncoding4(unsigned cur, unsigned tgt, unsigned max)
625 {
626     assert(cur != tgt);
627
628     unsigned tmp = tgt;
629     unsigned nib = 0;
630     unsigned cnt = 0;
631
632     while (tmp > max)
633     {
634         nib = tmp & 0x0f;
635         tmp >>= 4;
636         if (tmp == cur)
637             break;
638         cnt++;
639     }
640     return cnt;
641 }
642
643 BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state, BYTE& codeSet)
644 {
645     BYTE encoding = 0xff;
646     codeSet       = 1; // codeSet is 1 or 2, depending on whether the returned encoding
647                        // corresponds to InfoHdrAdjust, or InfoHdrAdjust2 enumerations.
648
649     if (state->argCount != header.argCount)
650     {
651         // We have one-byte encodings for 0..8
652         if (header.argCount <= SET_ARGCOUNT_MAX)
653         {
654             state->argCount = header.argCount;
655             encoding        = SET_ARGCOUNT + header.argCount;
656             goto DO_RETURN;
657         }
658         else
659         {
660             unsigned hint;
661             if (initNeeded4(state->argCount, header.argCount, SET_ARGCOUNT_MAX, &hint))
662             {
663                 assert(hint <= SET_ARGCOUNT_MAX);
664                 state->argCount = hint;
665                 encoding        = SET_ARGCOUNT + hint;
666                 goto DO_RETURN;
667             }
668             else
669             {
670                 assert(hint <= 0xf);
671                 state->argCount <<= 4;
672                 state->argCount += hint;
673                 encoding = NEXT_FOUR_ARGCOUNT + hint;
674                 goto DO_RETURN;
675             }
676         }
677     }
678
679     if (state->frameSize != header.frameSize)
680     {
681         // We have one-byte encodings for 0..7
682         if (header.frameSize <= SET_FRAMESIZE_MAX)
683         {
684             state->frameSize = header.frameSize;
685             encoding         = SET_FRAMESIZE + header.frameSize;
686             goto DO_RETURN;
687         }
688         else
689         {
690             unsigned hint;
691             if (initNeeded4(state->frameSize, header.frameSize, SET_FRAMESIZE_MAX, &hint))
692             {
693                 assert(hint <= SET_FRAMESIZE_MAX);
694                 state->frameSize = hint;
695                 encoding         = SET_FRAMESIZE + hint;
696                 goto DO_RETURN;
697             }
698             else
699             {
700                 assert(hint <= 0xf);
701                 state->frameSize <<= 4;
702                 state->frameSize += hint;
703                 encoding = NEXT_FOUR_FRAMESIZE + hint;
704                 goto DO_RETURN;
705             }
706         }
707     }
708
709     if ((state->epilogCount != header.epilogCount) || (state->epilogAtEnd != header.epilogAtEnd))
710     {
711         if (header.epilogCount > SET_EPILOGCNT_MAX)
712             IMPL_LIMITATION("More than SET_EPILOGCNT_MAX epilogs");
713
714         state->epilogCount = header.epilogCount;
715         state->epilogAtEnd = header.epilogAtEnd;
716         encoding           = SET_EPILOGCNT + header.epilogCount * 2;
717         if (header.epilogAtEnd)
718             encoding++;
719         goto DO_RETURN;
720     }
721
722     if (state->varPtrTableSize != header.varPtrTableSize)
723     {
724         assert(state->varPtrTableSize == 0 || state->varPtrTableSize == HAS_VARPTR);
725
726         if (state->varPtrTableSize == 0)
727         {
728             state->varPtrTableSize = HAS_VARPTR;
729             encoding               = FLIP_VAR_PTR_TABLE_SZ;
730             goto DO_RETURN;
731         }
732         else if (header.varPtrTableSize == 0)
733         {
734             state->varPtrTableSize = 0;
735             encoding               = FLIP_VAR_PTR_TABLE_SZ;
736             goto DO_RETURN;
737         }
738     }
739
740     if (state->untrackedCnt != header.untrackedCnt)
741     {
742         assert(state->untrackedCnt <= SET_UNTRACKED_MAX || state->untrackedCnt == HAS_UNTRACKED);
743
744         // We have one-byte encodings for 0..3
745         if (header.untrackedCnt <= SET_UNTRACKED_MAX)
746         {
747             state->untrackedCnt = header.untrackedCnt;
748             encoding            = SET_UNTRACKED + header.untrackedCnt;
749             goto DO_RETURN;
750         }
751         else if (state->untrackedCnt != HAS_UNTRACKED)
752         {
753             state->untrackedCnt = HAS_UNTRACKED;
754             encoding            = FFFF_UNTRACKED_CNT;
755             goto DO_RETURN;
756         }
757     }
758
759     if (state->epilogSize != header.epilogSize)
760     {
761         // We have one-byte encodings for 0..10
762         if (header.epilogSize <= SET_EPILOGSIZE_MAX)
763         {
764             state->epilogSize = header.epilogSize;
765             encoding          = SET_EPILOGSIZE + header.epilogSize;
766             goto DO_RETURN;
767         }
768         else
769         {
770             unsigned hint;
771             if (initNeeded3(state->epilogSize, header.epilogSize, SET_EPILOGSIZE_MAX, &hint))
772             {
773                 assert(hint <= SET_EPILOGSIZE_MAX);
774                 state->epilogSize = hint;
775                 encoding          = SET_EPILOGSIZE + hint;
776                 goto DO_RETURN;
777             }
778             else
779             {
780                 assert(hint <= 0x7);
781                 state->epilogSize <<= 3;
782                 state->epilogSize += hint;
783                 encoding = NEXT_THREE_EPILOGSIZE + hint;
784                 goto DO_RETURN;
785             }
786         }
787     }
788
789     if (state->prologSize != header.prologSize)
790     {
791         // We have one-byte encodings for 0..16
792         if (header.prologSize <= SET_PROLOGSIZE_MAX)
793         {
794             state->prologSize = header.prologSize;
795             encoding          = SET_PROLOGSIZE + header.prologSize;
796             goto DO_RETURN;
797         }
798         else
799         {
800             unsigned hint;
801             assert(SET_PROLOGSIZE_MAX > 15);
802             if (initNeeded3(state->prologSize, header.prologSize, 15, &hint))
803             {
804                 assert(hint <= 15);
805                 state->prologSize = hint;
806                 encoding          = SET_PROLOGSIZE + hint;
807                 goto DO_RETURN;
808             }
809             else
810             {
811                 assert(hint <= 0x7);
812                 state->prologSize <<= 3;
813                 state->prologSize += hint;
814                 encoding = NEXT_THREE_PROLOGSIZE + hint;
815                 goto DO_RETURN;
816             }
817         }
818     }
819
820     if (state->ediSaved != header.ediSaved)
821     {
822         state->ediSaved = header.ediSaved;
823         encoding        = FLIP_EDI_SAVED;
824         goto DO_RETURN;
825     }
826
827     if (state->esiSaved != header.esiSaved)
828     {
829         state->esiSaved = header.esiSaved;
830         encoding        = FLIP_ESI_SAVED;
831         goto DO_RETURN;
832     }
833
834     if (state->ebxSaved != header.ebxSaved)
835     {
836         state->ebxSaved = header.ebxSaved;
837         encoding        = FLIP_EBX_SAVED;
838         goto DO_RETURN;
839     }
840
841     if (state->ebpSaved != header.ebpSaved)
842     {
843         state->ebpSaved = header.ebpSaved;
844         encoding        = FLIP_EBP_SAVED;
845         goto DO_RETURN;
846     }
847
848     if (state->ebpFrame != header.ebpFrame)
849     {
850         state->ebpFrame = header.ebpFrame;
851         encoding        = FLIP_EBP_FRAME;
852         goto DO_RETURN;
853     }
854
855     if (state->interruptible != header.interruptible)
856     {
857         state->interruptible = header.interruptible;
858         encoding             = FLIP_INTERRUPTIBLE;
859         goto DO_RETURN;
860     }
861
862 #if DOUBLE_ALIGN
863     if (state->doubleAlign != header.doubleAlign)
864     {
865         state->doubleAlign = header.doubleAlign;
866         encoding           = FLIP_DOUBLE_ALIGN;
867         goto DO_RETURN;
868     }
869 #endif
870
871     if (state->security != header.security)
872     {
873         state->security = header.security;
874         encoding        = FLIP_SECURITY;
875         goto DO_RETURN;
876     }
877
878     if (state->handlers != header.handlers)
879     {
880         state->handlers = header.handlers;
881         encoding        = FLIP_HANDLERS;
882         goto DO_RETURN;
883     }
884
885     if (state->localloc != header.localloc)
886     {
887         state->localloc = header.localloc;
888         encoding        = FLIP_LOCALLOC;
889         goto DO_RETURN;
890     }
891
892     if (state->editNcontinue != header.editNcontinue)
893     {
894         state->editNcontinue = header.editNcontinue;
895         encoding             = FLIP_EDITnCONTINUE;
896         goto DO_RETURN;
897     }
898
899     if (state->varargs != header.varargs)
900     {
901         state->varargs = header.varargs;
902         encoding       = FLIP_VARARGS;
903         goto DO_RETURN;
904     }
905
906     if (state->profCallbacks != header.profCallbacks)
907     {
908         state->profCallbacks = header.profCallbacks;
909         encoding             = FLIP_PROF_CALLBACKS;
910         goto DO_RETURN;
911     }
912
913     if (state->genericsContext != header.genericsContext)
914     {
915         state->genericsContext = header.genericsContext;
916         encoding               = FLIP_HAS_GENERICS_CONTEXT;
917         goto DO_RETURN;
918     }
919
920     if (state->genericsContextIsMethodDesc != header.genericsContextIsMethodDesc)
921     {
922         state->genericsContextIsMethodDesc = header.genericsContextIsMethodDesc;
923         encoding                           = FLIP_GENERICS_CONTEXT_IS_METHODDESC;
924         goto DO_RETURN;
925     }
926
927     if (GCInfoEncodesReturnKind() && (state->returnKind != header.returnKind))
928     {
929         state->returnKind = header.returnKind;
930         codeSet           = 2; // Two byte encoding
931         encoding          = header.returnKind;
932         _ASSERTE(encoding < SET_RET_KIND_MAX);
933         goto DO_RETURN;
934     }
935
936     if (state->gsCookieOffset != header.gsCookieOffset)
937     {
938         assert(state->gsCookieOffset == INVALID_GS_COOKIE_OFFSET || state->gsCookieOffset == HAS_GS_COOKIE_OFFSET);
939
940         if (state->gsCookieOffset == INVALID_GS_COOKIE_OFFSET)
941         {
942             // header.gsCookieOffset is non-zero. We can set it
943             // to zero using FLIP_HAS_GS_COOKIE
944             state->gsCookieOffset = HAS_GS_COOKIE_OFFSET;
945             encoding              = FLIP_HAS_GS_COOKIE;
946             goto DO_RETURN;
947         }
948         else if (header.gsCookieOffset == INVALID_GS_COOKIE_OFFSET)
949         {
950             state->gsCookieOffset = INVALID_GS_COOKIE_OFFSET;
951             encoding              = FLIP_HAS_GS_COOKIE;
952             goto DO_RETURN;
953         }
954     }
955
956     if (state->syncStartOffset != header.syncStartOffset)
957     {
958         assert(state->syncStartOffset == INVALID_SYNC_OFFSET || state->syncStartOffset == HAS_SYNC_OFFSET);
959
960         if (state->syncStartOffset == INVALID_SYNC_OFFSET)
961         {
962             // header.syncStartOffset is non-zero. We can set it
963             // to zero using FLIP_SYNC
964             state->syncStartOffset = HAS_SYNC_OFFSET;
965             encoding               = FLIP_SYNC;
966             goto DO_RETURN;
967         }
968         else if (header.syncStartOffset == INVALID_SYNC_OFFSET)
969         {
970             state->syncStartOffset = INVALID_SYNC_OFFSET;
971             encoding               = FLIP_SYNC;
972             goto DO_RETURN;
973         }
974     }
975
976     if (GCInfoEncodesRevPInvokeFrame() && (state->revPInvokeOffset != header.revPInvokeOffset))
977     {
978         assert(state->revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET ||
979                state->revPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET);
980
981         if (state->revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET)
982         {
983             // header.revPInvokeOffset is non-zero.
984             state->revPInvokeOffset = HAS_REV_PINVOKE_FRAME_OFFSET;
985             encoding                = FLIP_REV_PINVOKE_FRAME;
986             goto DO_RETURN;
987         }
988         else if (header.revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET)
989         {
990             state->revPInvokeOffset = INVALID_REV_PINVOKE_OFFSET;
991             encoding                = FLIP_REV_PINVOKE_FRAME;
992             goto DO_RETURN;
993         }
994     }
995
996 DO_RETURN:
997     _ASSERTE(encoding < MORE_BYTES_TO_FOLLOW);
998     if (!state->isHeaderMatch(header))
999         encoding |= MORE_BYTES_TO_FOLLOW;
1000
1001     return encoding;
1002 }
1003
1004 static int measureDistance(const InfoHdr& header, const InfoHdrSmall* p, int closeness)
1005 {
1006     int distance = 0;
1007
1008     if (p->untrackedCnt != header.untrackedCnt)
1009     {
1010         if (header.untrackedCnt > 3)
1011         {
1012             if (p->untrackedCnt != HAS_UNTRACKED)
1013                 distance += 1;
1014         }
1015         else
1016         {
1017             distance += 1;
1018         }
1019         if (distance >= closeness)
1020             return distance;
1021     }
1022
1023     if (p->varPtrTableSize != header.varPtrTableSize)
1024     {
1025         if (header.varPtrTableSize != 0)
1026         {
1027             if (p->varPtrTableSize != HAS_VARPTR)
1028                 distance += 1;
1029         }
1030         else
1031         {
1032             assert(p->varPtrTableSize == HAS_VARPTR);
1033             distance += 1;
1034         }
1035         if (distance >= closeness)
1036             return distance;
1037     }
1038
1039     if (p->frameSize != header.frameSize)
1040     {
1041         distance += 1;
1042         if (distance >= closeness)
1043             return distance;
1044
1045         // We have one-byte encodings for 0..7
1046         if (header.frameSize > SET_FRAMESIZE_MAX)
1047         {
1048             distance += bigEncoding4(p->frameSize, header.frameSize, SET_FRAMESIZE_MAX);
1049             if (distance >= closeness)
1050                 return distance;
1051         }
1052     }
1053
1054     if (p->argCount != header.argCount)
1055     {
1056         distance += 1;
1057         if (distance >= closeness)
1058             return distance;
1059
1060         // We have one-byte encodings for 0..8
1061         if (header.argCount > SET_ARGCOUNT_MAX)
1062         {
1063             distance += bigEncoding4(p->argCount, header.argCount, SET_ARGCOUNT_MAX);
1064             if (distance >= closeness)
1065                 return distance;
1066         }
1067     }
1068
1069     if (p->prologSize != header.prologSize)
1070     {
1071         distance += 1;
1072         if (distance >= closeness)
1073             return distance;
1074
1075         // We have one-byte encodings for 0..16
1076         if (header.prologSize > SET_PROLOGSIZE_MAX)
1077         {
1078             assert(SET_PROLOGSIZE_MAX > 15);
1079             distance += bigEncoding3(p->prologSize, header.prologSize, 15);
1080             if (distance >= closeness)
1081                 return distance;
1082         }
1083     }
1084
1085     if (p->epilogSize != header.epilogSize)
1086     {
1087         distance += 1;
1088         if (distance >= closeness)
1089             return distance;
1090         // We have one-byte encodings for 0..10
1091         if (header.epilogSize > SET_EPILOGSIZE_MAX)
1092         {
1093             distance += bigEncoding3(p->epilogSize, header.epilogSize, SET_EPILOGSIZE_MAX);
1094             if (distance >= closeness)
1095                 return distance;
1096         }
1097     }
1098
1099     if ((p->epilogCount != header.epilogCount) || (p->epilogAtEnd != header.epilogAtEnd))
1100     {
1101         distance += 1;
1102         if (distance >= closeness)
1103             return distance;
1104
1105         if (header.epilogCount > SET_EPILOGCNT_MAX)
1106             IMPL_LIMITATION("More than SET_EPILOGCNT_MAX epilogs");
1107     }
1108
1109     if (p->ediSaved != header.ediSaved)
1110     {
1111         distance += 1;
1112         if (distance >= closeness)
1113             return distance;
1114     }
1115
1116     if (p->esiSaved != header.esiSaved)
1117     {
1118         distance += 1;
1119         if (distance >= closeness)
1120             return distance;
1121     }
1122
1123     if (p->ebxSaved != header.ebxSaved)
1124     {
1125         distance += 1;
1126         if (distance >= closeness)
1127             return distance;
1128     }
1129
1130     if (p->ebpSaved != header.ebpSaved)
1131     {
1132         distance += 1;
1133         if (distance >= closeness)
1134             return distance;
1135     }
1136
1137     if (p->ebpFrame != header.ebpFrame)
1138     {
1139         distance += 1;
1140         if (distance >= closeness)
1141             return distance;
1142     }
1143
1144     if (p->interruptible != header.interruptible)
1145     {
1146         distance += 1;
1147         if (distance >= closeness)
1148             return distance;
1149     }
1150
1151 #if DOUBLE_ALIGN
1152     if (p->doubleAlign != header.doubleAlign)
1153     {
1154         distance += 1;
1155         if (distance >= closeness)
1156             return distance;
1157     }
1158 #endif
1159
1160     if (p->security != header.security)
1161     {
1162         distance += 1;
1163         if (distance >= closeness)
1164             return distance;
1165     }
1166
1167     if (p->handlers != header.handlers)
1168     {
1169         distance += 1;
1170         if (distance >= closeness)
1171             return distance;
1172     }
1173
1174     if (p->localloc != header.localloc)
1175     {
1176         distance += 1;
1177         if (distance >= closeness)
1178             return distance;
1179     }
1180
1181     if (p->editNcontinue != header.editNcontinue)
1182     {
1183         distance += 1;
1184         if (distance >= closeness)
1185             return distance;
1186     }
1187
1188     if (p->varargs != header.varargs)
1189     {
1190         distance += 1;
1191         if (distance >= closeness)
1192             return distance;
1193     }
1194
1195     if (p->profCallbacks != header.profCallbacks)
1196     {
1197         distance += 1;
1198         if (distance >= closeness)
1199             return distance;
1200     }
1201
1202     if (p->genericsContext != header.genericsContext)
1203     {
1204         distance += 1;
1205         if (distance >= closeness)
1206             return distance;
1207     }
1208
1209     if (p->genericsContextIsMethodDesc != header.genericsContextIsMethodDesc)
1210     {
1211         distance += 1;
1212         if (distance >= closeness)
1213             return distance;
1214     }
1215
1216     if (p->returnKind != header.returnKind)
1217     {
1218         // Setting the ReturnKind requires two bytes of encoding.
1219         distance += 2;
1220         if (distance >= closeness)
1221             return distance;
1222     }
1223
1224     if (header.gsCookieOffset != INVALID_GS_COOKIE_OFFSET)
1225     {
1226         distance += 1;
1227         if (distance >= closeness)
1228             return distance;
1229     }
1230
1231     if (header.syncStartOffset != INVALID_SYNC_OFFSET)
1232     {
1233         distance += 1;
1234         if (distance >= closeness)
1235             return distance;
1236     }
1237
1238     if (header.revPInvokeOffset != INVALID_REV_PINVOKE_OFFSET)
1239     {
1240         distance += 1;
1241         if (distance >= closeness)
1242             return distance;
1243     }
1244
1245     return distance;
1246 }
1247
1248 // DllMain calls gcInitEncoderLookupTable to fill in this table
1249 /* extern */ int infoHdrLookup[IH_MAX_PROLOG_SIZE + 2];
1250
1251 /* static */ void GCInfo::gcInitEncoderLookupTable()
1252 {
1253     const InfoHdrSmall* p  = &infoHdrShortcut[0];
1254     int                 lo = -1;
1255     int                 hi = 0;
1256     int                 n;
1257
1258     for (n = 0; n < 128; n++, p++)
1259     {
1260         if (p->prologSize != lo)
1261         {
1262             if (p->prologSize < lo)
1263             {
1264                 assert(p->prologSize == 0);
1265                 hi = IH_MAX_PROLOG_SIZE;
1266             }
1267             else
1268                 hi = p->prologSize;
1269
1270             assert(hi <= IH_MAX_PROLOG_SIZE);
1271
1272             while (lo < hi)
1273                 infoHdrLookup[++lo] = n;
1274
1275             if (lo == IH_MAX_PROLOG_SIZE)
1276                 break;
1277         }
1278     }
1279
1280     assert(lo == IH_MAX_PROLOG_SIZE);
1281     assert(infoHdrLookup[IH_MAX_PROLOG_SIZE] < 128);
1282
1283     while (p->prologSize == lo)
1284     {
1285         n++;
1286         if (n >= 128)
1287             break;
1288         p++;
1289     }
1290
1291     infoHdrLookup[++lo] = n;
1292
1293 #ifdef DEBUG
1294     //
1295     // We do some other DEBUG only validity checks here
1296     //
1297     assert(callCommonDelta[0] < callCommonDelta[1]);
1298     assert(callCommonDelta[1] < callCommonDelta[2]);
1299     assert(callCommonDelta[2] < callCommonDelta[3]);
1300     assert(sizeof(CallPattern) == sizeof(unsigned));
1301     unsigned maxMarks = 0;
1302     for (unsigned inx = 0; inx < 80; inx++)
1303     {
1304         CallPattern pat;
1305         pat.val = callPatternTable[inx];
1306
1307         assert(pat.fld.codeDelta <= CP_MAX_CODE_DELTA);
1308         if (pat.fld.codeDelta == CP_MAX_CODE_DELTA)
1309             maxMarks |= 0x01;
1310
1311         assert(pat.fld.argCnt <= CP_MAX_ARG_CNT);
1312         if (pat.fld.argCnt == CP_MAX_ARG_CNT)
1313             maxMarks |= 0x02;
1314
1315         assert(pat.fld.argMask <= CP_MAX_ARG_MASK);
1316         if (pat.fld.argMask == CP_MAX_ARG_MASK)
1317             maxMarks |= 0x04;
1318     }
1319     assert(maxMarks == 0x07);
1320 #endif
1321 }
1322
1323 const int NO_CACHED_HEADER = -1;
1324
1325 BYTE FASTCALL encodeHeaderFirst(const InfoHdr& header, InfoHdr* state, int* more, int* pCached)
1326 {
1327     // First try the cached value for an exact match, if there is one
1328     //
1329     int                 n = *pCached;
1330     const InfoHdrSmall* p;
1331
1332     if (n != NO_CACHED_HEADER)
1333     {
1334         p = &infoHdrShortcut[n];
1335         if (p->isHeaderMatch(header))
1336         {
1337             // exact match found
1338             GetInfoHdr(n, state);
1339             *more = 0;
1340             return n;
1341         }
1342     }
1343
1344     // Next search the table for an exact match
1345     // Only search entries that have a matching prolog size
1346     // Note: lo and hi are saved here as they specify the
1347     // range of entries that have the correct prolog size
1348     //
1349     unsigned psz = header.prologSize;
1350     int      lo  = 0;
1351     int      hi  = 0;
1352
1353     if (psz <= IH_MAX_PROLOG_SIZE)
1354     {
1355         lo = infoHdrLookup[psz];
1356         hi = infoHdrLookup[psz + 1];
1357         p  = &infoHdrShortcut[lo];
1358         for (n = lo; n < hi; n++, p++)
1359         {
1360             assert(psz == p->prologSize);
1361             if (p->isHeaderMatch(header))
1362             {
1363                 // exact match found
1364                 GetInfoHdr(n, state);
1365                 *pCached = n; // cache the value
1366                 *more    = 0;
1367                 return n;
1368             }
1369         }
1370     }
1371
1372     //
1373     // no exact match in infoHdrShortcut[]
1374     //
1375     // find the nearest entry in the table
1376     //
1377     int nearest   = -1;
1378     int closeness = 255; // (i.e. not very close)
1379
1380     //
1381     // Calculate the minimum acceptable distance
1382     // if we find an entry that is at least this close
1383     // we will stop the search and use that value
1384     //
1385     int min_acceptable_distance = 1;
1386
1387     if (header.frameSize > SET_FRAMESIZE_MAX)
1388     {
1389         ++min_acceptable_distance;
1390         if (header.frameSize > 32)
1391             ++min_acceptable_distance;
1392     }
1393     if (header.argCount > SET_ARGCOUNT_MAX)
1394     {
1395         ++min_acceptable_distance;
1396         if (header.argCount > 32)
1397             ++min_acceptable_distance;
1398     }
1399
1400     // First try the cached value
1401     // and see if it meets the minimum acceptable distance
1402     //
1403     if (*pCached != NO_CACHED_HEADER)
1404     {
1405         p            = &infoHdrShortcut[*pCached];
1406         int distance = measureDistance(header, p, closeness);
1407         assert(distance > 0);
1408         if (distance <= min_acceptable_distance)
1409         {
1410             GetInfoHdr(*pCached, state);
1411             *more = distance;
1412             return 0x80 | *pCached;
1413         }
1414         else
1415         {
1416             closeness = distance;
1417             nearest   = *pCached;
1418         }
1419     }
1420
1421     // Then try the ones pointed to by [lo..hi),
1422     // (i.e. the ones that have the correct prolog size)
1423     //
1424     p = &infoHdrShortcut[lo];
1425     for (n = lo; n < hi; n++, p++)
1426     {
1427         if (n == *pCached)
1428             continue; // already tried this one
1429         int distance = measureDistance(header, p, closeness);
1430         assert(distance > 0);
1431         if (distance <= min_acceptable_distance)
1432         {
1433             GetInfoHdr(n, state);
1434             *pCached = n; // Cache this value
1435             *more    = distance;
1436             return 0x80 | n;
1437         }
1438         else if (distance < closeness)
1439         {
1440             closeness = distance;
1441             nearest   = n;
1442         }
1443     }
1444
1445     int last = infoHdrLookup[IH_MAX_PROLOG_SIZE + 1];
1446     assert(last <= 128);
1447
1448     // Then try all the rest [0..last-1]
1449     p = &infoHdrShortcut[0];
1450     for (n = 0; n < last; n++, p++)
1451     {
1452         if (n == *pCached)
1453             continue; // already tried this one
1454         if ((n >= lo) && (n < hi))
1455             continue; // already tried these
1456         int distance = measureDistance(header, p, closeness);
1457         assert(distance > 0);
1458         if (distance <= min_acceptable_distance)
1459         {
1460             GetInfoHdr(n, state);
1461             *pCached = n; // Cache this value
1462             *more    = distance;
1463             return 0x80 | n;
1464         }
1465         else if (distance < closeness)
1466         {
1467             closeness = distance;
1468             nearest   = n;
1469         }
1470     }
1471
1472     //
1473     // If we reach here then there was no adjacent neighbor
1474     //  in infoHdrShortcut[], closeness indicate how many extra
1475     //  bytes we will need to encode this item.
1476     //
1477     assert((nearest >= 0) && (nearest <= 127));
1478     GetInfoHdr(nearest, state);
1479     *pCached = nearest; // Cache this value
1480     *more    = closeness;
1481     return 0x80 | nearest;
1482 }
1483
1484 /*****************************************************************************
1485  *
1486  *  Write the initial part of the method info block. This is called twice;
1487  *  first to compute the size needed for the info (mask=0), the second time
1488  *  to actually generate the contents of the table (mask=-1,dest!=NULL).
1489  */
1490
1491 size_t GCInfo::gcInfoBlockHdrSave(
1492     BYTE* dest, int mask, unsigned methodSize, unsigned prologSize, unsigned epilogSize, InfoHdr* header, int* pCached)
1493 {
1494 #ifdef DEBUG
1495     if (compiler->verbose)
1496         printf("*************** In gcInfoBlockHdrSave()\n");
1497 #endif
1498     size_t size = 0;
1499
1500 #if VERIFY_GC_TABLES
1501     *castto(dest, unsigned short*)++ = 0xFEEF;
1502     size += sizeof(short);
1503 #endif
1504
1505     /* Write the method size first (using between 1 and 5 bytes) */
1506     CLANG_FORMAT_COMMENT_ANCHOR;
1507
1508 #ifdef DEBUG
1509     if (compiler->verbose)
1510     {
1511         if (mask)
1512             printf("GCINFO: methodSize = %04X\n", methodSize);
1513         if (mask)
1514             printf("GCINFO: prologSize = %04X\n", prologSize);
1515         if (mask)
1516             printf("GCINFO: epilogSize = %04X\n", epilogSize);
1517     }
1518 #endif
1519
1520     size_t methSz = encodeUnsigned(dest, methodSize);
1521     size += methSz;
1522     dest += methSz & mask;
1523
1524     //
1525     // New style InfoBlk Header
1526     //
1527     // Typically only uses one-byte to store everything.
1528     //
1529
1530     if (mask == 0)
1531     {
1532         memset(header, 0, sizeof(InfoHdr));
1533         *pCached = NO_CACHED_HEADER;
1534     }
1535
1536     assert(FitsIn<unsigned char>(prologSize));
1537     header->prologSize = static_cast<unsigned char>(prologSize);
1538     assert(FitsIn<unsigned char>(epilogSize));
1539     header->epilogSize  = static_cast<unsigned char>(epilogSize);
1540     header->epilogCount = compiler->getEmitter()->emitGetEpilogCnt();
1541     if (header->epilogCount != compiler->getEmitter()->emitGetEpilogCnt())
1542         IMPL_LIMITATION("emitGetEpilogCnt() does not fit in InfoHdr::epilogCount");
1543     header->epilogAtEnd = compiler->getEmitter()->emitHasEpilogEnd();
1544
1545     if (compiler->codeGen->regSet.rsRegsModified(RBM_EDI))
1546         header->ediSaved = 1;
1547     if (compiler->codeGen->regSet.rsRegsModified(RBM_ESI))
1548         header->esiSaved = 1;
1549     if (compiler->codeGen->regSet.rsRegsModified(RBM_EBX))
1550         header->ebxSaved = 1;
1551
1552     header->interruptible = compiler->codeGen->genInterruptible;
1553
1554     if (!compiler->isFramePointerUsed())
1555     {
1556 #if DOUBLE_ALIGN
1557         if (compiler->genDoubleAlign())
1558         {
1559             header->ebpSaved = true;
1560             assert(!compiler->codeGen->regSet.rsRegsModified(RBM_EBP));
1561         }
1562 #endif
1563         if (compiler->codeGen->regSet.rsRegsModified(RBM_EBP))
1564         {
1565             header->ebpSaved = true;
1566         }
1567     }
1568     else
1569     {
1570         header->ebpSaved = true;
1571         header->ebpFrame = true;
1572     }
1573
1574 #if DOUBLE_ALIGN
1575     header->doubleAlign = compiler->genDoubleAlign();
1576 #endif
1577
1578     header->security = compiler->opts.compNeedSecurityCheck;
1579
1580     header->handlers = compiler->ehHasCallableHandlers();
1581     header->localloc = compiler->compLocallocUsed;
1582
1583     header->varargs         = compiler->info.compIsVarArgs;
1584     header->profCallbacks   = compiler->info.compProfilerCallback;
1585     header->editNcontinue   = compiler->opts.compDbgEnC;
1586     header->genericsContext = compiler->lvaReportParamTypeArg();
1587     header->genericsContextIsMethodDesc =
1588         header->genericsContext && (compiler->info.compMethodInfo->options & (CORINFO_GENERICS_CTXT_FROM_METHODDESC));
1589
1590     if (GCInfoEncodesReturnKind())
1591     {
1592         ReturnKind returnKind = getReturnKind();
1593         _ASSERTE(IsValidReturnKind(returnKind) && "Return Kind must be valid");
1594         _ASSERTE(!IsStructReturnKind(returnKind) && "Struct Return Kinds Unexpected for JIT32");
1595         _ASSERTE(((int)returnKind < (int)SET_RET_KIND_MAX) && "ReturnKind has no legal encoding");
1596         header->returnKind = returnKind;
1597     }
1598
1599     header->gsCookieOffset = INVALID_GS_COOKIE_OFFSET;
1600     if (compiler->getNeedsGSSecurityCookie())
1601     {
1602         assert(compiler->lvaGSSecurityCookie != BAD_VAR_NUM);
1603         int stkOffs            = compiler->lvaTable[compiler->lvaGSSecurityCookie].lvStkOffs;
1604         header->gsCookieOffset = compiler->isFramePointerUsed() ? -stkOffs : stkOffs;
1605         assert(header->gsCookieOffset != INVALID_GS_COOKIE_OFFSET);
1606     }
1607
1608     header->syncStartOffset = INVALID_SYNC_OFFSET;
1609     header->syncEndOffset   = INVALID_SYNC_OFFSET;
1610 #ifndef UNIX_X86_ABI
1611     // JIT is responsible for synchronization on funclet-based EH model that x86/Linux uses.
1612     if (compiler->info.compFlags & CORINFO_FLG_SYNCH)
1613     {
1614         assert(compiler->syncStartEmitCookie != NULL);
1615         header->syncStartOffset = compiler->getEmitter()->emitCodeOffset(compiler->syncStartEmitCookie, 0);
1616         assert(header->syncStartOffset != INVALID_SYNC_OFFSET);
1617
1618         assert(compiler->syncEndEmitCookie != NULL);
1619         header->syncEndOffset = compiler->getEmitter()->emitCodeOffset(compiler->syncEndEmitCookie, 0);
1620         assert(header->syncEndOffset != INVALID_SYNC_OFFSET);
1621
1622         assert(header->syncStartOffset < header->syncEndOffset);
1623         // synchronized methods can't have more than 1 epilog
1624         assert(header->epilogCount <= 1);
1625     }
1626 #endif
1627
1628     header->revPInvokeOffset = INVALID_REV_PINVOKE_OFFSET;
1629
1630     assert((compiler->compArgSize & 0x3) == 0);
1631
1632     size_t argCount =
1633         (compiler->compArgSize - (compiler->codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES)) / REGSIZE_BYTES;
1634     assert(argCount <= MAX_USHORT_SIZE_T);
1635     header->argCount = static_cast<unsigned short>(argCount);
1636
1637     header->frameSize = compiler->compLclFrameSize / sizeof(int);
1638     if (header->frameSize != (compiler->compLclFrameSize / sizeof(int)))
1639         IMPL_LIMITATION("compLclFrameSize does not fit in InfoHdr::frameSize");
1640
1641     if (mask == 0)
1642     {
1643         gcCountForHeader((UNALIGNED unsigned int*)&header->untrackedCnt,
1644                          (UNALIGNED unsigned int*)&header->varPtrTableSize);
1645     }
1646
1647     //
1648     // If the high-order bit of headerEncoding is set
1649     // then additional bytes will update the InfoHdr state
1650     // until the fully state is encoded
1651     //
1652     InfoHdr state;
1653     int     more           = 0;
1654     BYTE    headerEncoding = encodeHeaderFirst(*header, &state, &more, pCached);
1655     ++size;
1656     if (mask)
1657     {
1658 #if REGEN_SHORTCUTS
1659         regenLog(headerEncoding, header, &state);
1660 #endif
1661         *dest++ = headerEncoding;
1662
1663         BYTE encoding = headerEncoding;
1664         BYTE codeSet  = 1;
1665         while (encoding & MORE_BYTES_TO_FOLLOW)
1666         {
1667             encoding = encodeHeaderNext(*header, &state, codeSet);
1668
1669 #if REGEN_SHORTCUTS
1670             regenLog(headerEncoding, header, &state);
1671 #endif
1672             _ASSERTE(codeSet == 1 || codeSet == 2 && "Encoding must correspond to InfoHdrAdjust or InfoHdrAdjust2");
1673             if (codeSet == 2)
1674             {
1675                 *dest++ = NEXT_OPCODE | MORE_BYTES_TO_FOLLOW;
1676                 ++size;
1677             }
1678
1679             *dest++ = encoding;
1680             ++size;
1681         }
1682     }
1683     else
1684     {
1685         size += more;
1686     }
1687
1688     if (header->untrackedCnt > SET_UNTRACKED_MAX)
1689     {
1690         unsigned count = header->untrackedCnt;
1691         unsigned sz    = encodeUnsigned(mask ? dest : NULL, count);
1692         size += sz;
1693         dest += (sz & mask);
1694     }
1695
1696     if (header->varPtrTableSize != 0)
1697     {
1698         unsigned count = header->varPtrTableSize;
1699         unsigned sz    = encodeUnsigned(mask ? dest : NULL, count);
1700         size += sz;
1701         dest += (sz & mask);
1702     }
1703
1704     if (header->gsCookieOffset != INVALID_GS_COOKIE_OFFSET)
1705     {
1706         assert(mask == 0 || state.gsCookieOffset == HAS_GS_COOKIE_OFFSET);
1707         unsigned offset = header->gsCookieOffset;
1708         unsigned sz     = encodeUnsigned(mask ? dest : NULL, offset);
1709         size += sz;
1710         dest += (sz & mask);
1711     }
1712
1713     if (header->syncStartOffset != INVALID_SYNC_OFFSET)
1714     {
1715         assert(mask == 0 || state.syncStartOffset == HAS_SYNC_OFFSET);
1716
1717         {
1718             unsigned offset = header->syncStartOffset;
1719             unsigned sz     = encodeUnsigned(mask ? dest : NULL, offset);
1720             size += sz;
1721             dest += (sz & mask);
1722         }
1723
1724         {
1725             unsigned offset = header->syncEndOffset;
1726             unsigned sz     = encodeUnsigned(mask ? dest : NULL, offset);
1727             size += sz;
1728             dest += (sz & mask);
1729         }
1730     }
1731
1732     if (header->epilogCount)
1733     {
1734         /* Generate table unless one epilog at the end of the method */
1735
1736         if (header->epilogAtEnd == 0 || header->epilogCount != 1)
1737         {
1738 #if VERIFY_GC_TABLES
1739             *castto(dest, unsigned short*)++ = 0xFACE;
1740             size += sizeof(short);
1741 #endif
1742
1743             /* Simply write a sorted array of offsets using encodeUDelta */
1744
1745             gcEpilogTable      = mask ? dest : NULL;
1746             gcEpilogPrevOffset = 0;
1747
1748             size_t sz = compiler->getEmitter()->emitGenEpilogLst(gcRecordEpilog, this);
1749
1750             /* Add the size of the epilog table to the total size */
1751
1752             size += sz;
1753             dest += (sz & mask);
1754         }
1755     }
1756
1757 #if DISPLAY_SIZES
1758
1759     if (mask)
1760     {
1761         if (compiler->codeGen->genInterruptible)
1762         {
1763             genMethodICnt++;
1764         }
1765         else
1766         {
1767             genMethodNCnt++;
1768         }
1769     }
1770
1771 #endif // DISPLAY_SIZES
1772
1773     return size;
1774 }
1775
1776 /*****************************************************************************
1777  *
1778  *  Return the size of the pointer tracking tables.
1779  */
1780
1781 size_t GCInfo::gcPtrTableSize(const InfoHdr& header, unsigned codeSize, size_t* pArgTabOffset)
1782 {
1783     BYTE temp[16 + 1];
1784 #ifdef DEBUG
1785     temp[16] = 0xAB; // Set some marker
1786 #endif
1787
1788     /* Compute the total size of the tables */
1789
1790     size_t size = gcMakeRegPtrTable(temp, 0, header, codeSize, pArgTabOffset);
1791
1792     assert(temp[16] == 0xAB); // Check that marker didnt get overwritten
1793
1794     return size;
1795 }
1796
1797 /*****************************************************************************
1798  * Encode the callee-saved registers into 3 bits.
1799  */
1800
1801 unsigned gceEncodeCalleeSavedRegs(unsigned regs)
1802 {
1803     unsigned encodedRegs = 0;
1804
1805     if (regs & RBM_EBX)
1806         encodedRegs |= 0x04;
1807     if (regs & RBM_ESI)
1808         encodedRegs |= 0x02;
1809     if (regs & RBM_EDI)
1810         encodedRegs |= 0x01;
1811
1812     return encodedRegs;
1813 }
1814
1815 /*****************************************************************************
1816  * Is the next entry for a byref pointer. If so, emit the prefix for the
1817  * interruptible encoding. Check only for pushes and registers
1818  */
1819
1820 inline BYTE* gceByrefPrefixI(GCInfo::regPtrDsc* rpd, BYTE* dest)
1821 {
1822     // For registers, we don't need a prefix if it is going dead.
1823     assert(rpd->rpdArg || rpd->rpdCompiler.rpdDel == 0);
1824
1825     if (!rpd->rpdArg || rpd->rpdArgType == GCInfo::rpdARG_PUSH)
1826         if (rpd->rpdGCtypeGet() == GCT_BYREF)
1827             *dest++ = 0xBF;
1828
1829     return dest;
1830 }
1831
1832 /*****************************************************************************/
1833
1834 /* These functions are needed to work around a VC5.0 compiler bug */
1835 /* DO NOT REMOVE, unless you are sure that the free build works   */
1836 static int zeroFN()
1837 {
1838     return 0;
1839 }
1840 static int (*zeroFunc)() = zeroFN;
1841
1842 /*****************************************************************************
1843  *  Modelling of the GC ptrs pushed on the stack
1844  */
1845
1846 typedef unsigned pasMaskType;
1847 #define BITS_IN_pasMask (BITS_IN_BYTE * sizeof(pasMaskType))
1848 #define HIGHEST_pasMask_BIT (((pasMaskType)0x1) << (BITS_IN_pasMask - 1))
1849
1850 //-----------------------------------------------------------------------------
1851
1852 class PendingArgsStack
1853 {
1854 public:
1855     PendingArgsStack(unsigned maxDepth, Compiler* pComp);
1856
1857     void pasPush(GCtype gcType);
1858     void pasPop(unsigned count);
1859     void pasKill(unsigned gcCount);
1860
1861     unsigned pasCurDepth()
1862     {
1863         return pasDepth;
1864     }
1865     pasMaskType pasArgMask()
1866     {
1867         assert(pasDepth <= BITS_IN_pasMask);
1868         return pasBottomMask;
1869     }
1870     pasMaskType pasByrefArgMask()
1871     {
1872         assert(pasDepth <= BITS_IN_pasMask);
1873         return pasByrefBottomMask;
1874     }
1875     bool pasHasGCptrs();
1876
1877     // Use these in the case where there actually are more ptrs than pasArgMask
1878     unsigned pasEnumGCoffsCount();
1879 #define pasENUM_START ((unsigned)-1)
1880 #define pasENUM_LAST ((unsigned)-2)
1881 #define pasENUM_END ((unsigned)-3)
1882     unsigned pasEnumGCoffs(unsigned iter, unsigned* offs);
1883
1884 protected:
1885     unsigned pasMaxDepth;
1886
1887     unsigned pasDepth;
1888
1889     pasMaskType pasBottomMask;      // The first 32 args
1890     pasMaskType pasByrefBottomMask; // byref qualifier for pasBottomMask
1891
1892     BYTE*    pasTopArray;       // More than 32 args are represented here
1893     unsigned pasPtrsInTopArray; // How many GCptrs here
1894 };
1895
1896 //-----------------------------------------------------------------------------
1897
1898 PendingArgsStack::PendingArgsStack(unsigned maxDepth, Compiler* pComp)
1899     : pasMaxDepth(maxDepth)
1900     , pasDepth(0)
1901     , pasBottomMask(0)
1902     , pasByrefBottomMask(0)
1903     , pasTopArray(NULL)
1904     , pasPtrsInTopArray(0)
1905 {
1906     /* Do we need an array as well as the mask ? */
1907
1908     if (pasMaxDepth > BITS_IN_pasMask)
1909         pasTopArray = (BYTE*)pComp->compGetMem(pasMaxDepth - BITS_IN_pasMask);
1910 }
1911
1912 //-----------------------------------------------------------------------------
1913
1914 void PendingArgsStack::pasPush(GCtype gcType)
1915 {
1916     assert(pasDepth < pasMaxDepth);
1917
1918     if (pasDepth < BITS_IN_pasMask)
1919     {
1920         /* Shift the mask */
1921
1922         pasBottomMask <<= 1;
1923         pasByrefBottomMask <<= 1;
1924
1925         if (needsGC(gcType))
1926         {
1927             pasBottomMask |= 1;
1928
1929             if (gcType == GCT_BYREF)
1930                 pasByrefBottomMask |= 1;
1931         }
1932     }
1933     else
1934     {
1935         /* Push on array */
1936
1937         pasTopArray[pasDepth - BITS_IN_pasMask] = (BYTE)gcType;
1938
1939         if (gcType)
1940             pasPtrsInTopArray++;
1941     }
1942
1943     pasDepth++;
1944 }
1945
1946 //-----------------------------------------------------------------------------
1947
1948 void PendingArgsStack::pasPop(unsigned count)
1949 {
1950     assert(pasDepth >= count);
1951
1952     /* First pop from array (if applicable) */
1953
1954     for (/**/; (pasDepth > BITS_IN_pasMask) && count; pasDepth--, count--)
1955     {
1956         unsigned topIndex = pasDepth - BITS_IN_pasMask - 1;
1957
1958         GCtype topArg = (GCtype)pasTopArray[topIndex];
1959
1960         if (needsGC(topArg))
1961             pasPtrsInTopArray--;
1962     }
1963     if (count == 0)
1964         return;
1965
1966     /* Now un-shift the mask */
1967
1968     assert(pasPtrsInTopArray == 0);
1969     assert(count <= BITS_IN_pasMask);
1970
1971     if (count == BITS_IN_pasMask) // (x>>32) is a nop on x86. So special-case it
1972     {
1973         pasBottomMask = pasByrefBottomMask = 0;
1974         pasDepth                           = 0;
1975     }
1976     else
1977     {
1978         pasBottomMask >>= count;
1979         pasByrefBottomMask >>= count;
1980         pasDepth -= count;
1981     }
1982 }
1983
1984 //-----------------------------------------------------------------------------
1985 // Kill (but don't pop) the top 'gcCount' args
1986
1987 void PendingArgsStack::pasKill(unsigned gcCount)
1988 {
1989     assert(gcCount != 0);
1990
1991     /* First kill args in array (if any) */
1992
1993     for (unsigned curPos = pasDepth; (curPos > BITS_IN_pasMask) && gcCount; curPos--)
1994     {
1995         unsigned curIndex = curPos - BITS_IN_pasMask - 1;
1996
1997         GCtype curArg = (GCtype)pasTopArray[curIndex];
1998
1999         if (needsGC(curArg))
2000         {
2001             pasTopArray[curIndex] = GCT_NONE;
2002             pasPtrsInTopArray--;
2003             gcCount--;
2004         }
2005     }
2006
2007     /* Now kill bits from the mask */
2008
2009     assert(pasPtrsInTopArray == 0);
2010     assert(gcCount <= BITS_IN_pasMask);
2011
2012     for (unsigned bitPos = 1; gcCount; bitPos <<= 1)
2013     {
2014         assert(pasBottomMask != 0);
2015
2016         if (pasBottomMask & bitPos)
2017         {
2018             pasBottomMask &= ~bitPos;
2019             pasByrefBottomMask &= ~bitPos;
2020             --gcCount;
2021         }
2022         else
2023         {
2024             assert(bitPos != HIGHEST_pasMask_BIT);
2025         }
2026     }
2027 }
2028
2029 //-----------------------------------------------------------------------------
2030 // Used for the case where there are more than BITS_IN_pasMask args on stack,
2031 // but none are any pointers. May avoid reporting anything to GCinfo
2032
2033 bool PendingArgsStack::pasHasGCptrs()
2034 {
2035     if (pasDepth <= BITS_IN_pasMask)
2036         return pasBottomMask != 0;
2037     else
2038         return pasBottomMask != 0 || pasPtrsInTopArray != 0;
2039 }
2040
2041 //-----------------------------------------------------------------------------
2042 //  Iterates over mask and array to return total count.
2043 //  Use only when you are going to emit a table of the offsets
2044
2045 unsigned PendingArgsStack::pasEnumGCoffsCount()
2046 {
2047     /* Should only be used in the worst case, when just the mask can't be used */
2048
2049     assert(pasDepth > BITS_IN_pasMask && pasHasGCptrs());
2050
2051     /* Count number of set bits in mask */
2052
2053     unsigned count = 0;
2054
2055     for (pasMaskType mask = 0x1, i = 0; i < BITS_IN_pasMask; mask <<= 1, i++)
2056     {
2057         if (mask & pasBottomMask)
2058             count++;
2059     }
2060
2061     return count + pasPtrsInTopArray;
2062 }
2063
2064 //-----------------------------------------------------------------------------
2065 //  Initalize enumeration by passing in iter=pasENUM_START.
2066 //  Continue by passing in the return value as the new value of iter
2067 //  End of enumeration when pasENUM_END is returned
2068 //  If return value != pasENUM_END, *offs is set to the offset for GCinfo
2069
2070 unsigned PendingArgsStack::pasEnumGCoffs(unsigned iter, unsigned* offs)
2071 {
2072     if (iter == pasENUM_LAST)
2073         return pasENUM_END;
2074
2075     unsigned i = (iter == pasENUM_START) ? pasDepth : iter;
2076
2077     for (/**/; i > BITS_IN_pasMask; i--)
2078     {
2079         GCtype curArg = (GCtype)pasTopArray[i - BITS_IN_pasMask - 1];
2080         if (needsGC(curArg))
2081         {
2082             unsigned offset;
2083
2084             offset = (pasDepth - i) * TARGET_POINTER_SIZE;
2085             if (curArg == GCT_BYREF)
2086                 offset |= byref_OFFSET_FLAG;
2087
2088             *offs = offset;
2089             return i - 1;
2090         }
2091     }
2092
2093     if (!pasBottomMask)
2094         return pasENUM_END;
2095
2096     // Have we already processed some of the bits in pasBottomMask ?
2097
2098     i = (iter == pasENUM_START || iter >= BITS_IN_pasMask) ? 0     // no
2099                                                            : iter; // yes
2100
2101     for (pasMaskType mask = 0x1 << i; mask; i++, mask <<= 1)
2102     {
2103         if (mask & pasBottomMask)
2104         {
2105             unsigned lvl = (pasDepth > BITS_IN_pasMask) ? (pasDepth - BITS_IN_pasMask) : 0; // How many in pasTopArray[]
2106             lvl += i;
2107
2108             unsigned offset;
2109             offset = lvl * TARGET_POINTER_SIZE;
2110             if (mask & pasByrefBottomMask)
2111                 offset |= byref_OFFSET_FLAG;
2112
2113             *offs = offset;
2114
2115             unsigned remMask = -int(mask << 1);
2116             return ((pasBottomMask & remMask) ? (i + 1) : pasENUM_LAST);
2117         }
2118     }
2119
2120     assert(!"Shouldnt reach here");
2121     return pasENUM_END;
2122 }
2123
2124 /*****************************************************************************
2125  *
2126  *  Generate the register pointer map, and return its total size in bytes. If
2127  *  'mask' is 0, we don't actually store any data in 'dest' (except for one
2128  *  entry, which is never more than 10 bytes), so this can be used to merely
2129  *  compute the size of the table.
2130  */
2131
2132 #ifdef _PREFAST_
2133 #pragma warning(push)
2134 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
2135 #endif
2136 size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, unsigned codeSize, size_t* pArgTabOffset)
2137 {
2138     unsigned count;
2139
2140     unsigned   varNum;
2141     LclVarDsc* varDsc;
2142
2143     unsigned pass;
2144
2145     size_t   totalSize = 0;
2146     unsigned lastOffset;
2147
2148     bool thisKeptAliveIsInUntracked = false;
2149
2150     /* The mask should be all 0's or all 1's */
2151
2152     assert(mask == 0 || mask == -1);
2153
2154     /* Start computing the total size of the table */
2155
2156     BOOL emitArgTabOffset = (header.varPtrTableSize != 0 || header.untrackedCnt > SET_UNTRACKED_MAX);
2157     if (mask != 0 && emitArgTabOffset)
2158     {
2159         assert(*pArgTabOffset <= MAX_UNSIGNED_SIZE_T);
2160         unsigned sz = encodeUnsigned(dest, static_cast<unsigned>(*pArgTabOffset));
2161         dest += sz;
2162         totalSize += sz;
2163     }
2164
2165 #if VERIFY_GC_TABLES
2166     if (mask)
2167     {
2168         *(short*)dest = (short)0xBEEF;
2169         dest += sizeof(short);
2170     }
2171     totalSize += sizeof(short);
2172 #endif
2173
2174     /**************************************************************************
2175      *
2176      *                      Untracked ptr variables
2177      *
2178      **************************************************************************
2179      */
2180
2181     count = 0;
2182     for (pass = 0; pass < 2; pass++)
2183     {
2184         /* If pass==0, generate the count
2185          * If pass==1, write the table of untracked pointer variables.
2186          */
2187
2188         int lastoffset = 0;
2189         if (pass == 1)
2190         {
2191             assert(count == header.untrackedCnt);
2192             if (header.untrackedCnt == 0)
2193                 break; // No entries, break exits the loop since pass==1
2194         }
2195
2196         /* Count&Write untracked locals and non-enregistered args */
2197
2198         for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount; varNum++, varDsc++)
2199         {
2200             if (compiler->lvaIsFieldOfDependentlyPromotedStruct(varDsc))
2201             {
2202                 // Field local of a PROMOTION_TYPE_DEPENDENT struct must have been
2203                 // reported through its parent local
2204                 continue;
2205             }
2206
2207             if (varTypeIsGC(varDsc->TypeGet()))
2208             {
2209                 /* Do we have an argument or local variable? */
2210                 if (!varDsc->lvIsParam)
2211                 {
2212                     // If is is pinned, it must be an untracked local
2213                     assert(!varDsc->lvPinned || !varDsc->lvTracked);
2214
2215                     if (varDsc->lvTracked || !varDsc->lvOnFrame)
2216                         continue;
2217                 }
2218                 else
2219                 {
2220 /* Stack-passed arguments which are not enregistered
2221  * are always reported in this "untracked stack
2222  * pointers" section of the GC info even if lvTracked==true
2223  */
2224
2225 /* Has this argument been enregistered? */
2226 #ifndef LEGACY_BACKEND
2227                     if (!varDsc->lvOnFrame)
2228 #else  // LEGACY_BACKEND
2229                     if (varDsc->lvRegister)
2230 #endif // LEGACY_BACKEND
2231                     {
2232                         /* if a CEE_JMP has been used, then we need to report all the arguments
2233                            even if they are enregistered, since we will be using this value
2234                            in JMP call.  Note that this is subtle as we require that
2235                            argument offsets are always fixed up properly even if lvRegister
2236                            is set */
2237                         if (!compiler->compJmpOpUsed)
2238                             continue;
2239                     }
2240                     else
2241                     {
2242                         if (!varDsc->lvOnFrame)
2243                         {
2244                             /* If this non-enregistered pointer arg is never
2245                              * used, we don't need to report it
2246                              */
2247                             assert(varDsc->lvRefCnt == 0); // This assert is currently a known issue for X86-RyuJit
2248                             continue;
2249                         }
2250                         else if (varDsc->lvIsRegArg && varDsc->lvTracked)
2251                         {
2252                             /* If this register-passed arg is tracked, then
2253                              * it has been allocated space near the other
2254                              * pointer variables and we have accurate life-
2255                              * time info. It will be reported with
2256                              * gcVarPtrList in the "tracked-pointer" section
2257                              */
2258
2259                             continue;
2260                         }
2261                     }
2262                 }
2263
2264 #ifndef WIN64EXCEPTIONS
2265                 // For WIN64EXCEPTIONS, "this" must always be in untracked variables
2266                 // so we cannot have "this" in variable lifetimes
2267                 if (compiler->lvaIsOriginalThisArg(varNum) && compiler->lvaKeepAliveAndReportThis())
2268
2269                 {
2270                     // Encoding of untracked variables does not support reporting
2271                     // "this". So report it as a tracked variable with a liveness
2272                     // extending over the entire method.
2273
2274                     thisKeptAliveIsInUntracked = true;
2275                     continue;
2276                 }
2277 #endif
2278
2279                 if (pass == 0)
2280                     count++;
2281                 else
2282                 {
2283                     int offset;
2284                     assert(pass == 1);
2285
2286                     offset = varDsc->lvStkOffs;
2287 #if DOUBLE_ALIGN
2288                     // For genDoubleAlign(), locals are addressed relative to ESP and
2289                     // arguments are addressed relative to EBP.
2290
2291                     if (compiler->genDoubleAlign() && varDsc->lvIsParam && !varDsc->lvIsRegArg)
2292                         offset += compiler->codeGen->genTotalFrameSize();
2293 #endif
2294
2295                     // The lower bits of the offset encode properties of the stk ptr
2296
2297                     assert(~OFFSET_MASK % sizeof(offset) == 0);
2298
2299                     if (varDsc->TypeGet() == TYP_BYREF)
2300                     {
2301                         // Or in byref_OFFSET_FLAG for 'byref' pointer tracking
2302                         offset |= byref_OFFSET_FLAG;
2303                     }
2304
2305                     if (varDsc->lvPinned)
2306                     {
2307                         // Or in pinned_OFFSET_FLAG for 'pinned' pointer tracking
2308                         offset |= pinned_OFFSET_FLAG;
2309                     }
2310
2311                     int encodedoffset = lastoffset - offset;
2312                     lastoffset        = offset;
2313
2314                     if (mask == 0)
2315                         totalSize += encodeSigned(NULL, encodedoffset);
2316                     else
2317                     {
2318                         unsigned sz = encodeSigned(dest, encodedoffset);
2319                         dest += sz;
2320                         totalSize += sz;
2321                     }
2322                 }
2323             }
2324
2325             // A struct will have gcSlots only if it is at least TARGET_POINTER_SIZE.
2326             if (varDsc->lvType == TYP_STRUCT && varDsc->lvOnFrame && (varDsc->lvExactSize >= TARGET_POINTER_SIZE))
2327             {
2328                 unsigned slots  = compiler->lvaLclSize(varNum) / TARGET_POINTER_SIZE;
2329                 BYTE*    gcPtrs = compiler->lvaGetGcLayout(varNum);
2330
2331                 // walk each member of the array
2332                 for (unsigned i = 0; i < slots; i++)
2333                 {
2334                     if (gcPtrs[i] == TYPE_GC_NONE) // skip non-gc slots
2335                         continue;
2336
2337                     if (pass == 0)
2338                         count++;
2339                     else
2340                     {
2341                         assert(pass == 1);
2342
2343                         unsigned offset = varDsc->lvStkOffs + i * TARGET_POINTER_SIZE;
2344 #if DOUBLE_ALIGN
2345                         // For genDoubleAlign(), locals are addressed relative to ESP and
2346                         // arguments are addressed relative to EBP.
2347
2348                         if (compiler->genDoubleAlign() && varDsc->lvIsParam && !varDsc->lvIsRegArg)
2349                             offset += compiler->codeGen->genTotalFrameSize();
2350 #endif
2351                         if (gcPtrs[i] == TYPE_GC_BYREF)
2352                             offset |= byref_OFFSET_FLAG; // indicate it is a byref GC pointer
2353
2354                         int encodedoffset = lastoffset - offset;
2355                         lastoffset        = offset;
2356
2357                         if (mask == 0)
2358                             totalSize += encodeSigned(NULL, encodedoffset);
2359                         else
2360                         {
2361                             unsigned sz = encodeSigned(dest, encodedoffset);
2362                             dest += sz;
2363                             totalSize += sz;
2364                         }
2365                     }
2366                 }
2367             }
2368         }
2369
2370         /* Count&Write spill temps that hold pointers */
2371
2372         assert(compiler->tmpAllFree());
2373         for (TempDsc* tempItem = compiler->tmpListBeg(); tempItem != nullptr; tempItem = compiler->tmpListNxt(tempItem))
2374         {
2375             if (varTypeIsGC(tempItem->tdTempType()))
2376             {
2377                 if (pass == 0)
2378                     count++;
2379                 else
2380                 {
2381                     int offset;
2382                     assert(pass == 1);
2383
2384                     offset = tempItem->tdTempOffs();
2385
2386                     if (tempItem->tdTempType() == TYP_BYREF)
2387                     {
2388                         offset |= byref_OFFSET_FLAG;
2389                     }
2390
2391                     int encodedoffset = lastoffset - offset;
2392                     lastoffset        = offset;
2393
2394                     if (mask == 0)
2395                     {
2396                         totalSize += encodeSigned(NULL, encodedoffset);
2397                     }
2398                     else
2399                     {
2400                         unsigned sz = encodeSigned(dest, encodedoffset);
2401                         dest += sz;
2402                         totalSize += sz;
2403                     }
2404                 }
2405             }
2406         }
2407     }
2408
2409 #if VERIFY_GC_TABLES
2410     if (mask)
2411     {
2412         *(short*)dest = (short)0xCAFE;
2413         dest += sizeof(short);
2414     }
2415     totalSize += sizeof(short);
2416 #endif
2417
2418     /**************************************************************************
2419      *
2420      *  Generate the table of stack pointer variable lifetimes.
2421      *
2422      *  In the first pass we'll count the lifetime entries and note
2423      *  whether there are any that don't fit in a small encoding. In
2424      *  the second pass we actually generate the table contents.
2425      *
2426      **************************************************************************
2427      */
2428
2429     // First we check for the most common case - no lifetimes at all.
2430
2431     if (header.varPtrTableSize == 0)
2432         goto DONE_VLT;
2433
2434     varPtrDsc* varTmp;
2435     count = 0;
2436
2437 #ifndef WIN64EXCEPTIONS
2438     if (thisKeptAliveIsInUntracked)
2439     {
2440         count = 1;
2441
2442         // Encoding of untracked variables does not support reporting
2443         // "this". So report it as a tracked variable with a liveness
2444         // extending over the entire method.
2445
2446         assert(compiler->lvaTable[compiler->info.compThisArg].TypeGet() == TYP_REF);
2447
2448         unsigned varOffs = compiler->lvaTable[compiler->info.compThisArg].lvStkOffs;
2449
2450         /* For negative stack offsets we must reset the low bits,
2451          * take abs and then set them back */
2452
2453         varOffs = abs(static_cast<int>(varOffs));
2454         varOffs |= this_OFFSET_FLAG;
2455
2456         size_t sz = 0;
2457         sz        = encodeUnsigned(mask ? (dest + sz) : NULL, varOffs);
2458         sz += encodeUDelta(mask ? (dest + sz) : NULL, 0, 0);
2459         sz += encodeUDelta(mask ? (dest + sz) : NULL, codeSize, 0);
2460
2461         dest += (sz & mask);
2462         totalSize += sz;
2463     }
2464 #endif
2465
2466     for (pass = 0; pass < 2; pass++)
2467     {
2468         /* If second pass, generate the count */
2469
2470         if (pass)
2471         {
2472             assert(header.varPtrTableSize > 0);
2473             assert(header.varPtrTableSize == count);
2474         }
2475
2476         /* We'll use a delta encoding for the lifetime offsets */
2477
2478         lastOffset = 0;
2479
2480         for (varTmp = gcVarPtrList; varTmp; varTmp = varTmp->vpdNext)
2481         {
2482             unsigned varOffs;
2483             unsigned lowBits;
2484
2485             unsigned begOffs;
2486             unsigned endOffs;
2487
2488             assert(~OFFSET_MASK % TARGET_POINTER_SIZE == 0);
2489
2490             /* Get hold of the variable's stack offset */
2491
2492             lowBits = varTmp->vpdVarNum & OFFSET_MASK;
2493
2494             /* For negative stack offsets we must reset the low bits,
2495              * take abs and then set them back */
2496
2497             varOffs = abs(static_cast<int>(varTmp->vpdVarNum & ~OFFSET_MASK));
2498             varOffs |= lowBits;
2499
2500             /* Compute the actual lifetime offsets */
2501
2502             begOffs = varTmp->vpdBegOfs;
2503             endOffs = varTmp->vpdEndOfs;
2504
2505             /* Special case: skip any 0-length lifetimes */
2506
2507             if (endOffs == begOffs)
2508                 continue;
2509
2510             /* Are we counting or generating? */
2511
2512             if (!pass)
2513             {
2514                 count++;
2515             }
2516             else
2517             {
2518                 size_t sz = 0;
2519                 sz        = encodeUnsigned(mask ? (dest + sz) : NULL, varOffs);
2520                 sz += encodeUDelta(mask ? (dest + sz) : NULL, begOffs, lastOffset);
2521                 sz += encodeUDelta(mask ? (dest + sz) : NULL, endOffs, begOffs);
2522
2523                 dest += (sz & mask);
2524                 totalSize += sz;
2525             }
2526
2527             /* The next entry will be relative to the one we just processed */
2528
2529             lastOffset = begOffs;
2530         }
2531     }
2532
2533 DONE_VLT:
2534
2535     if (pArgTabOffset != NULL)
2536         *pArgTabOffset = totalSize;
2537
2538 #if VERIFY_GC_TABLES
2539     if (mask)
2540     {
2541         *(short*)dest = (short)0xBABE;
2542         dest += sizeof(short);
2543     }
2544     totalSize += sizeof(short);
2545 #endif
2546
2547     if (!mask && emitArgTabOffset)
2548     {
2549         assert(*pArgTabOffset <= MAX_UNSIGNED_SIZE_T);
2550         totalSize += encodeUnsigned(NULL, static_cast<unsigned>(*pArgTabOffset));
2551     }
2552
2553     /**************************************************************************
2554      *
2555      * Prepare to generate the pointer register/argument map
2556      *
2557      **************************************************************************
2558      */
2559
2560     lastOffset = 0;
2561
2562     if (compiler->codeGen->genInterruptible)
2563     {
2564 #ifdef _TARGET_X86_
2565         assert(compiler->genFullPtrRegMap);
2566
2567         unsigned ptrRegs = 0;
2568
2569         regPtrDsc* genRegPtrTemp;
2570
2571         /* Walk the list of pointer register/argument entries */
2572
2573         for (genRegPtrTemp = gcRegPtrList; genRegPtrTemp; genRegPtrTemp = genRegPtrTemp->rpdNext)
2574         {
2575             BYTE* base = dest;
2576
2577             unsigned nextOffset;
2578             DWORD    codeDelta;
2579
2580             nextOffset = genRegPtrTemp->rpdOffs;
2581
2582             /*
2583                 Encoding table for methods that are fully interruptible
2584
2585                 The encoding used is as follows:
2586
2587                 ptr reg dead    00RRRDDD    [RRR != 100]
2588                 ptr reg live    01RRRDDD    [RRR != 100]
2589
2590             non-ptr arg push    10110DDD                    [SSS == 110]
2591                 ptr arg push    10SSSDDD                    [SSS != 110] && [SSS != 111]
2592                 ptr arg pop     11CCCDDD    [CCC != 000] && [CCC != 110] && [CCC != 111]
2593                 little skip     11000DDD    [CCC == 000]
2594                 bigger skip     11110BBB                    [CCC == 110]
2595
2596                 The values used in the above encodings are as follows:
2597
2598                   DDD                 code offset delta from previous entry (0-7)
2599                   BBB                 bigger delta 000=8,001=16,010=24,...,111=64
2600                   RRR                 register number (EAX=000,ECX=001,EDX=010,EBX=011,
2601                                         EBP=101,ESI=110,EDI=111), ESP=100 is reserved
2602                   SSS                 argument offset from base of stack. This is
2603                                         redundant for frameless methods as we can
2604                                         infer it from the previous pushes+pops. However,
2605                                         for EBP-methods, we only report GC pushes, and
2606                                         so we need SSS
2607                   CCC                 argument count being popped (includes only ptrs for EBP methods)
2608
2609                 The following are the 'large' versions:
2610
2611                   large delta skip        10111000 [0xB8] , encodeUnsigned(delta)
2612
2613                   large     ptr arg push  11111000 [0xF8] , encodeUnsigned(pushCount)
2614                   large non-ptr arg push  11111001 [0xF9] , encodeUnsigned(pushCount)
2615                   large     ptr arg pop   11111100 [0xFC] , encodeUnsigned(popCount)
2616                   large         arg dead  11111101 [0xFD] , encodeUnsigned(popCount) for caller-pop args.
2617                                                               Any GC args go dead after the call,
2618                                                               but are still sitting on the stack
2619
2620                   this pointer prefix     10111100 [0xBC]   the next encoding is a ptr live
2621                                                               or a ptr arg push
2622                                                               and contains the this pointer
2623
2624                   interior or by-ref      10111111 [0xBF]   the next encoding is a ptr live
2625                        pointer prefix                         or a ptr arg push
2626                                                               and contains an interior
2627                                                               or by-ref pointer
2628
2629
2630                   The value 11111111 [0xFF] indicates the end of the table.
2631             */
2632
2633             codeDelta = nextOffset - lastOffset;
2634             assert((int)codeDelta >= 0);
2635
2636             // If the code delta is between 8 and (64+7),
2637             // generate a 'bigger delta' encoding
2638
2639             if ((codeDelta >= 8) && (codeDelta <= (64 + 7)))
2640             {
2641                 unsigned biggerDelta = ((codeDelta - 8) & 0x38) + 8;
2642                 *dest++              = 0xF0 | ((biggerDelta - 8) >> 3);
2643                 lastOffset += biggerDelta;
2644                 codeDelta &= 0x07;
2645             }
2646
2647             // If the code delta is still bigger than 7,
2648             // generate a 'large code delta' encoding
2649
2650             if (codeDelta > 7)
2651             {
2652                 *dest++ = 0xB8;
2653                 dest += encodeUnsigned(dest, codeDelta);
2654                 codeDelta = 0;
2655
2656                 /* Remember the new 'last' offset */
2657
2658                 lastOffset = nextOffset;
2659             }
2660
2661             /* Is this a pointer argument or register entry? */
2662
2663             if (genRegPtrTemp->rpdArg)
2664             {
2665                 if (genRegPtrTemp->rpdArgTypeGet() == rpdARG_KILL)
2666                 {
2667                     if (codeDelta)
2668                     {
2669                         /*
2670                             Use the small encoding:
2671                             little delta skip       11000DDD    [0xC0]
2672                          */
2673
2674                         assert((codeDelta & 0x7) == codeDelta);
2675                         *dest++ = 0xC0 | (BYTE)codeDelta;
2676
2677                         /* Remember the new 'last' offset */
2678
2679                         lastOffset = nextOffset;
2680                     }
2681
2682                     /* Caller-pop arguments are dead after call but are still
2683                        sitting on the stack */
2684
2685                     *dest++ = 0xFD;
2686                     assert(genRegPtrTemp->rpdPtrArg != 0);
2687                     dest += encodeUnsigned(dest, genRegPtrTemp->rpdPtrArg);
2688                 }
2689                 else if (genRegPtrTemp->rpdPtrArg < 6 && genRegPtrTemp->rpdGCtypeGet())
2690                 {
2691                     /* Is the argument offset/count smaller than 6 ? */
2692
2693                     dest = gceByrefPrefixI(genRegPtrTemp, dest);
2694
2695                     if (genRegPtrTemp->rpdArgTypeGet() == rpdARG_PUSH || (genRegPtrTemp->rpdPtrArg != 0))
2696                     {
2697                         /*
2698                           Use the small encoding:
2699
2700                             ptr arg push 10SSSDDD [SSS != 110] && [SSS != 111]
2701                             ptr arg pop  11CCCDDD [CCC != 110] && [CCC != 111]
2702                          */
2703
2704                         bool isPop = genRegPtrTemp->rpdArgTypeGet() == rpdARG_POP;
2705
2706                         *dest++ = 0x80 | (BYTE)codeDelta | genRegPtrTemp->rpdPtrArg << 3 | isPop << 6;
2707
2708                         /* Remember the new 'last' offset */
2709
2710                         lastOffset = nextOffset;
2711                     }
2712                     else
2713                     {
2714                         assert(!"Check this");
2715                     }
2716                 }
2717                 else if (genRegPtrTemp->rpdGCtypeGet() == GCT_NONE)
2718                 {
2719                     /*
2720                         Use the small encoding:
2721 `                        non-ptr arg push 10110DDD [0xB0] (push of sizeof(int))
2722                      */
2723
2724                     assert((codeDelta & 0x7) == codeDelta);
2725                     *dest++ = 0xB0 | (BYTE)codeDelta;
2726 #ifndef UNIX_X86_ABI
2727                     assert(!compiler->isFramePointerUsed());
2728 #endif
2729
2730                     /* Remember the new 'last' offset */
2731
2732                     lastOffset = nextOffset;
2733                 }
2734                 else
2735                 {
2736                     /* Will have to use large encoding;
2737                      *   first do the code delta
2738                      */
2739
2740                     if (codeDelta)
2741                     {
2742                         /*
2743                             Use the small encoding:
2744                             little delta skip       11000DDD    [0xC0]
2745                          */
2746
2747                         assert((codeDelta & 0x7) == codeDelta);
2748                         *dest++ = 0xC0 | (BYTE)codeDelta;
2749                     }
2750
2751                     /*
2752                         Now append a large argument record:
2753
2754                             large ptr arg push  11111000 [0xF8]
2755                             large ptr arg pop   11111100 [0xFC]
2756                      */
2757
2758                     bool isPop = genRegPtrTemp->rpdArgTypeGet() == rpdARG_POP;
2759
2760                     dest = gceByrefPrefixI(genRegPtrTemp, dest);
2761
2762                     *dest++ = 0xF8 | (isPop << 2);
2763                     dest += encodeUnsigned(dest, genRegPtrTemp->rpdPtrArg);
2764
2765                     /* Remember the new 'last' offset */
2766
2767                     lastOffset = nextOffset;
2768                 }
2769             }
2770             else
2771             {
2772                 unsigned regMask;
2773
2774                 /* Record any registers that are becoming dead */
2775
2776                 regMask = genRegPtrTemp->rpdCompiler.rpdDel & ptrRegs;
2777
2778                 while (regMask) // EAX,ECX,EDX,EBX,---,EBP,ESI,EDI
2779                 {
2780                     unsigned  tmpMask;
2781                     regNumber regNum;
2782
2783                     /* Get hold of the next register bit */
2784
2785                     tmpMask = genFindLowestReg(regMask);
2786                     assert(tmpMask);
2787
2788                     /* Remember the new state of this register */
2789
2790                     ptrRegs &= ~tmpMask;
2791
2792                     /* Figure out which register the next bit corresponds to */
2793
2794                     regNum = genRegNumFromMask(tmpMask);
2795                     assert(regNum <= 7);
2796
2797                     /* Reserve ESP, regNum==4 for future use */
2798
2799                     assert(regNum != 4);
2800
2801                     /*
2802                         Generate a small encoding:
2803
2804                             ptr reg dead        00RRRDDD
2805                      */
2806
2807                     assert((codeDelta & 0x7) == codeDelta);
2808                     *dest++ = 0x00 | regNum << 3 | (BYTE)codeDelta;
2809
2810                     /* Turn the bit we've just generated off and continue */
2811
2812                     regMask -= tmpMask; // EAX,ECX,EDX,EBX,---,EBP,ESI,EDI
2813
2814                     /* Remember the new 'last' offset */
2815
2816                     lastOffset = nextOffset;
2817
2818                     /* Any entries that follow will be at the same offset */
2819
2820                     codeDelta = zeroFunc(); /* DO NOT REMOVE */
2821                 }
2822
2823                 /* Record any registers that are becoming live */
2824
2825                 regMask = genRegPtrTemp->rpdCompiler.rpdAdd & ~ptrRegs;
2826
2827                 while (regMask) // EAX,ECX,EDX,EBX,---,EBP,ESI,EDI
2828                 {
2829                     unsigned  tmpMask;
2830                     regNumber regNum;
2831
2832                     /* Get hold of the next register bit */
2833
2834                     tmpMask = genFindLowestReg(regMask);
2835                     assert(tmpMask);
2836
2837                     /* Remember the new state of this register */
2838
2839                     ptrRegs |= tmpMask;
2840
2841                     /* Figure out which register the next bit corresponds to */
2842
2843                     regNum = genRegNumFromMask(tmpMask);
2844                     assert(regNum <= 7);
2845
2846                     /*
2847                         Generate a small encoding:
2848
2849                             ptr reg live        01RRRDDD
2850                      */
2851
2852                     dest = gceByrefPrefixI(genRegPtrTemp, dest);
2853
2854                     if (!thisKeptAliveIsInUntracked && genRegPtrTemp->rpdIsThis)
2855                     {
2856                         // Mark with 'this' pointer prefix
2857                         *dest++ = 0xBC;
2858                         // Can only have one bit set in regMask
2859                         assert(regMask == tmpMask);
2860                     }
2861
2862                     assert((codeDelta & 0x7) == codeDelta);
2863                     *dest++ = 0x40 | (regNum << 3) | (BYTE)codeDelta;
2864
2865                     /* Turn the bit we've just generated off and continue */
2866
2867                     regMask -= tmpMask; // EAX,ECX,EDX,EBX,---,EBP,ESI,EDI
2868
2869                     /* Remember the new 'last' offset */
2870
2871                     lastOffset = nextOffset;
2872
2873                     /* Any entries that follow will be at the same offset */
2874
2875                     codeDelta = zeroFunc(); /* DO NOT REMOVE */
2876                 }
2877             }
2878
2879             /* Keep track of the total amount of generated stuff */
2880
2881             totalSize += dest - base;
2882
2883             /* Go back to the buffer start if we're not generating a table */
2884
2885             if (!mask)
2886                 dest = base;
2887         }
2888 #endif // _TARGET_X86_
2889
2890         /* Terminate the table with 0xFF */
2891
2892         *dest = 0xFF;
2893         dest -= mask;
2894         totalSize++;
2895     }
2896     else if (compiler->isFramePointerUsed()) // genInterruptible is false
2897     {
2898 #ifdef _TARGET_X86_
2899         /*
2900             Encoding table for methods with an EBP frame and
2901                                that are not fully interruptible
2902
2903             The encoding used is as follows:
2904
2905             this pointer encodings:
2906
2907                01000000          this pointer in EBX
2908                00100000          this pointer in ESI
2909                00010000          this pointer in EDI
2910
2911             tiny encoding:
2912
2913                0bsdDDDD
2914                                  requires code delta > 0 & delta < 16 (4-bits)
2915                                  requires pushed argmask == 0
2916
2917                  where    DDDD   is code delta
2918                              b   indicates that register EBX is a live pointer
2919                              s   indicates that register ESI is a live pointer
2920                              d   indicates that register EDI is a live pointer
2921
2922
2923             small encoding:
2924
2925                1DDDDDDD bsdAAAAA
2926
2927                                  requires code delta     < 120 (7-bits)
2928                                  requires pushed argmask <  64 (5-bits)
2929
2930                  where DDDDDDD   is code delta
2931                          AAAAA   is the pushed args mask
2932                              b   indicates that register EBX is a live pointer
2933                              s   indicates that register ESI is a live pointer
2934                              d   indicates that register EDI is a live pointer
2935
2936             medium encoding
2937
2938                0xFD aaaaaaaa AAAAdddd bseDDDDD
2939
2940                                  requires code delta     <  512  (9-bits)
2941                                  requires pushed argmask < 2048 (12-bits)
2942
2943                  where    DDDDD  is the upper 5-bits of the code delta
2944                            dddd  is the low   4-bits of the code delta
2945                            AAAA  is the upper 4-bits of the pushed arg mask
2946                        aaaaaaaa  is the low   8-bits of the pushed arg mask
2947                               b  indicates that register EBX is a live pointer
2948                               s  indicates that register ESI is a live pointer
2949                               e  indicates that register EDI is a live pointer
2950
2951             medium encoding with interior pointers
2952
2953                0xF9 DDDDDDDD bsdAAAAAA iiiIIIII
2954
2955                                  requires code delta     < 256 (8-bits)
2956                                  requires pushed argmask <  64 (5-bits)
2957
2958                  where  DDDDDDD  is the code delta
2959                               b  indicates that register EBX is a live pointer
2960                               s  indicates that register ESI is a live pointer
2961                               d  indicates that register EDI is a live pointer
2962                           AAAAA  is the pushed arg mask
2963                             iii  indicates that EBX,EDI,ESI are interior pointers
2964                           IIIII  indicates that bits in the arg mask are interior
2965                                  pointers
2966
2967             large encoding
2968
2969                0xFE [0BSD0bsd][32-bit code delta][32-bit argMask]
2970
2971                               b  indicates that register EBX is a live pointer
2972                               s  indicates that register ESI is a live pointer
2973                               d  indicates that register EDI is a live pointer
2974                               B  indicates that register EBX is an interior pointer
2975                               S  indicates that register ESI is an interior pointer
2976                               D  indicates that register EDI is an interior pointer
2977                                  requires pushed  argmask < 32-bits
2978
2979             large encoding  with interior pointers
2980
2981                0xFA [0BSD0bsd][32-bit code delta][32-bit argMask][32-bit interior pointer mask]
2982
2983
2984                               b  indicates that register EBX is a live pointer
2985                               s  indicates that register ESI is a live pointer
2986                               d  indicates that register EDI is a live pointer
2987                               B  indicates that register EBX is an interior pointer
2988                               S  indicates that register ESI is an interior pointer
2989                               D  indicates that register EDI is an interior pointer
2990                                  requires pushed  argmask < 32-bits
2991                                  requires pushed iArgmask < 32-bits
2992
2993
2994             huge encoding        This is the only encoding that supports
2995                                  a pushed argmask which is greater than
2996                                  32-bits.
2997
2998                0xFB [0BSD0bsd][32-bit code delta]
2999                     [32-bit table count][32-bit table size]
3000                     [pushed ptr offsets table...]
3001
3002                              b   indicates that register EBX is a live pointer
3003                              s   indicates that register ESI is a live pointer
3004                              d   indicates that register EDI is a live pointer
3005                              B   indicates that register EBX is an interior pointer
3006                              S   indicates that register ESI is an interior pointer
3007                              D   indicates that register EDI is an interior pointer
3008                              the list count is the number of entries in the list
3009                              the list size gives the byte-length of the list
3010                              the offsets in the list are variable-length
3011         */
3012
3013         /* If "this" is enregistered, note it. We do this explicitly here as
3014            genFullPtrRegMap==false, and so we don't have any regPtrDsc's. */
3015
3016         if (compiler->lvaKeepAliveAndReportThis() && compiler->lvaTable[compiler->info.compThisArg].lvRegister)
3017         {
3018             unsigned thisRegMask   = genRegMask(compiler->lvaTable[compiler->info.compThisArg].lvRegNum);
3019             unsigned thisPtrRegEnc = gceEncodeCalleeSavedRegs(thisRegMask) << 4;
3020
3021             if (thisPtrRegEnc)
3022             {
3023                 totalSize += 1;
3024                 if (mask)
3025                     *dest++ = thisPtrRegEnc;
3026             }
3027         }
3028
3029         CallDsc* call;
3030
3031         assert(compiler->genFullPtrRegMap == false);
3032
3033         /* Walk the list of pointer register/argument entries */
3034
3035         for (call = gcCallDescList; call; call = call->cdNext)
3036         {
3037             BYTE*    base = dest;
3038             unsigned nextOffset;
3039
3040             /* Figure out the code offset of this entry */
3041
3042             nextOffset = call->cdOffs;
3043
3044             /* Compute the distance from the previous call */
3045
3046             DWORD codeDelta = nextOffset - lastOffset;
3047
3048             assert((int)codeDelta >= 0);
3049
3050             /* Remember the new 'last' offset */
3051
3052             lastOffset = nextOffset;
3053
3054             /* Compute the register mask */
3055
3056             unsigned gcrefRegMask = 0;
3057             unsigned byrefRegMask = 0;
3058
3059             gcrefRegMask |= gceEncodeCalleeSavedRegs(call->cdGCrefRegs);
3060             byrefRegMask |= gceEncodeCalleeSavedRegs(call->cdByrefRegs);
3061
3062             assert((gcrefRegMask & byrefRegMask) == 0);
3063
3064             unsigned regMask = gcrefRegMask | byrefRegMask;
3065
3066             bool byref = (byrefRegMask | call->u1.cdByrefArgMask) != 0;
3067
3068             /* Check for the really large argument offset case */
3069             /* The very rare Huge encodings */
3070
3071             if (call->cdArgCnt)
3072             {
3073                 unsigned argNum;
3074                 DWORD    argCnt    = call->cdArgCnt;
3075                 DWORD    argBytes  = 0;
3076                 BYTE*    pArgBytes = DUMMY_INIT(NULL);
3077
3078                 if (mask != 0)
3079                 {
3080                     *dest++       = 0xFB;
3081                     *dest++       = (byrefRegMask << 4) | regMask;
3082                     *(DWORD*)dest = codeDelta;
3083                     dest += sizeof(DWORD);
3084                     *(DWORD*)dest = argCnt;
3085                     dest += sizeof(DWORD);
3086                     // skip the byte-size for now. Just note where it will go
3087                     pArgBytes = dest;
3088                     dest += sizeof(DWORD);
3089                 }
3090
3091                 for (argNum = 0; argNum < argCnt; argNum++)
3092                 {
3093                     unsigned eltSize;
3094                     eltSize = encodeUnsigned(dest, call->cdArgTable[argNum]);
3095                     argBytes += eltSize;
3096                     if (mask)
3097                         dest += eltSize;
3098                 }
3099
3100                 if (mask == 0)
3101                 {
3102                     dest = base + 1 + 1 + 3 * sizeof(DWORD) + argBytes;
3103                 }
3104                 else
3105                 {
3106                     assert(dest == pArgBytes + sizeof(argBytes) + argBytes);
3107                     *(DWORD*)pArgBytes = argBytes;
3108                 }
3109             }
3110
3111             /* Check if we can use a tiny encoding */
3112             else if ((codeDelta < 16) && (codeDelta != 0) && (call->u1.cdArgMask == 0) && !byref)
3113             {
3114                 *dest++ = (regMask << 4) | (BYTE)codeDelta;
3115             }
3116
3117             /* Check if we can use the small encoding */
3118             else if ((codeDelta < 0x79) && (call->u1.cdArgMask <= 0x1F) && !byref)
3119             {
3120                 *dest++ = 0x80 | (BYTE)codeDelta;
3121                 *dest++ = call->u1.cdArgMask | (regMask << 5);
3122             }
3123
3124             /* Check if we can use the medium encoding */
3125             else if (codeDelta <= 0x01FF && call->u1.cdArgMask <= 0x0FFF && !byref)
3126             {
3127                 *dest++ = 0xFD;
3128                 *dest++ = call->u1.cdArgMask;
3129                 *dest++ = ((call->u1.cdArgMask >> 4) & 0xF0) | ((BYTE)codeDelta & 0x0F);
3130                 *dest++ = (regMask << 5) | (BYTE)((codeDelta >> 4) & 0x1F);
3131             }
3132
3133             /* Check if we can use the medium encoding with byrefs */
3134             else if (codeDelta <= 0x0FF && call->u1.cdArgMask <= 0x01F)
3135             {
3136                 *dest++ = 0xF9;
3137                 *dest++ = (BYTE)codeDelta;
3138                 *dest++ = (regMask << 5) | call->u1.cdArgMask;
3139                 *dest++ = (byrefRegMask << 5) | call->u1.cdByrefArgMask;
3140             }
3141
3142             /* We'll use the large encoding */
3143             else if (!byref)
3144             {
3145                 *dest++       = 0xFE;
3146                 *dest++       = (byrefRegMask << 4) | regMask;
3147                 *(DWORD*)dest = codeDelta;
3148                 dest += sizeof(DWORD);
3149                 *(DWORD*)dest = call->u1.cdArgMask;
3150                 dest += sizeof(DWORD);
3151             }
3152
3153             /* We'll use the large encoding with byrefs */
3154             else
3155             {
3156                 *dest++       = 0xFA;
3157                 *dest++       = (byrefRegMask << 4) | regMask;
3158                 *(DWORD*)dest = codeDelta;
3159                 dest += sizeof(DWORD);
3160                 *(DWORD*)dest = call->u1.cdArgMask;
3161                 dest += sizeof(DWORD);
3162                 *(DWORD*)dest = call->u1.cdByrefArgMask;
3163                 dest += sizeof(DWORD);
3164             }
3165
3166             /* Keep track of the total amount of generated stuff */
3167
3168             totalSize += dest - base;
3169
3170             /* Go back to the buffer start if we're not generating a table */
3171
3172             if (!mask)
3173                 dest = base;
3174         }
3175 #endif // _TARGET_X86_
3176
3177         /* Terminate the table with 0xFF */
3178
3179         *dest = 0xFF;
3180         dest -= mask;
3181         totalSize++;
3182     }
3183     else // genInterruptible is false and we have an EBP-less frame
3184     {
3185         assert(compiler->genFullPtrRegMap);
3186
3187 #ifdef _TARGET_X86_
3188
3189         regPtrDsc*       genRegPtrTemp;
3190         regNumber        thisRegNum = regNumber(0);
3191         PendingArgsStack pasStk(compiler->getEmitter()->emitMaxStackDepth, compiler);
3192
3193         /* Walk the list of pointer register/argument entries */
3194
3195         for (genRegPtrTemp = gcRegPtrList; genRegPtrTemp; genRegPtrTemp = genRegPtrTemp->rpdNext)
3196         {
3197
3198             /*
3199              *    Encoding table for methods without an EBP frame and
3200              *     that are not fully interruptible
3201              *
3202              *               The encoding used is as follows:
3203              *
3204              *  push     000DDDDD                     ESP push one item with 5-bit delta
3205              *  push     00100000 [pushCount]         ESP push multiple items
3206              *  reserved 0010xxxx                     xxxx != 0000
3207              *  reserved 0011xxxx
3208              *  skip     01000000 [Delta]             Skip Delta, arbitrary sized delta
3209              *  skip     0100DDDD                     Skip small Delta, for call (DDDD != 0)
3210              *  pop      01CCDDDD                     ESP pop  CC items with 4-bit delta (CC != 00)
3211              *  call     1PPPPPPP                     Call Pattern, P=[0..79]
3212              *  call     1101pbsd DDCCCMMM            Call RegMask=pbsd,ArgCnt=CCC,
3213              *                                        ArgMask=MMM Delta=commonDelta[DD]
3214              *  call     1110pbsd [ArgCnt] [ArgMask]  Call ArgCnt,RegMask=pbsd,ArgMask
3215              *  call     11111000 [PBSDpbsd][32-bit delta][32-bit ArgCnt]
3216              *                    [32-bit PndCnt][32-bit PndSize][PndOffs...]
3217              *  iptr     11110000 [IPtrMask]          Arbitrary Interior Pointer Mask
3218              *  thisptr  111101RR                     This pointer is in Register RR
3219              *                                        00=EDI,01=ESI,10=EBX,11=EBP
3220              *  reserved 111100xx                     xx  != 00
3221              *  reserved 111110xx                     xx  != 00
3222              *  reserved 11111xxx                     xxx != 000 && xxx != 111(EOT)
3223              *
3224              *   The value 11111111 [0xFF] indicates the end of the table. (EOT)
3225              *
3226              *  An offset (at which stack-walking is performed) without an explicit encoding
3227              *  is assumed to be a trivial call-site (no GC registers, stack empty before and
3228              *  after) to avoid having to encode all trivial calls.
3229              *
3230              * Note on the encoding used for interior pointers
3231              *
3232              *   The iptr encoding must immediately precede a call encoding.  It is used
3233              *   to transform a normal GC pointer addresses into an interior pointers for
3234              *   GC purposes.  The mask supplied to the iptr encoding is read from the
3235              *   least signicant bit to the most signicant bit. (i.e the lowest bit is
3236              *   read first)
3237              *
3238              *   p   indicates that register EBP is a live pointer
3239              *   b   indicates that register EBX is a live pointer
3240              *   s   indicates that register ESI is a live pointer
3241              *   d   indicates that register EDI is a live pointer
3242              *   P   indicates that register EBP is an interior pointer
3243              *   B   indicates that register EBX is an interior pointer
3244              *   S   indicates that register ESI is an interior pointer
3245              *   D   indicates that register EDI is an interior pointer
3246              *
3247              *   As an example the following sequence indicates that EDI.ESI and the
3248              *   second pushed pointer in ArgMask are really interior pointers.  The
3249              *   pointer in ESI in a normal pointer:
3250              *
3251              *   iptr 11110000 00010011           => read Interior Ptr, Interior Ptr,
3252              *                                       Normal Ptr, Normal Ptr, Interior Ptr
3253              *
3254              *   call 11010011 DDCCC011 RRRR=1011 => read EDI is a GC-pointer,
3255              *                                            ESI is a GC-pointer.
3256              *                                            EBP is a GC-pointer
3257              *                           MMM=0011 => read two GC-pointers arguments
3258              *                                         on the stack (nested call)
3259              *
3260              *   Since the call instruction mentions 5 GC-pointers we list them in
3261              *   the required order:  EDI, ESI, EBP, 1st-pushed pointer, 2nd-pushed pointer
3262              *
3263              *   And we apply the Interior Pointer mask mmmm=10011 to the five GC-pointers
3264              *   we learn that EDI and ESI are interior GC-pointers and that
3265              *   the second push arg is an interior GC-pointer.
3266              */
3267
3268             BYTE* base = dest;
3269
3270             bool     usePopEncoding;
3271             unsigned regMask;
3272             unsigned argMask;
3273             unsigned byrefRegMask;
3274             unsigned byrefArgMask;
3275             DWORD    callArgCnt;
3276
3277             unsigned nextOffset;
3278             DWORD    codeDelta;
3279
3280             nextOffset = genRegPtrTemp->rpdOffs;
3281
3282             /* Compute the distance from the previous call */
3283
3284             codeDelta = nextOffset - lastOffset;
3285             assert((int)codeDelta >= 0);
3286
3287 #if REGEN_CALLPAT
3288             // Must initialize this flag to true when REGEN_CALLPAT is on
3289             usePopEncoding         = true;
3290             unsigned origCodeDelta = codeDelta;
3291 #endif
3292
3293             if (!thisKeptAliveIsInUntracked && genRegPtrTemp->rpdIsThis)
3294             {
3295                 unsigned tmpMask = genRegPtrTemp->rpdCompiler.rpdAdd;
3296
3297                 /* tmpMask must have exactly one bit set */
3298
3299                 assert(tmpMask && ((tmpMask & (tmpMask - 1)) == 0));
3300
3301                 thisRegNum = genRegNumFromMask(tmpMask);
3302                 switch (thisRegNum)
3303                 {
3304                     case 0: // EAX
3305                     case 1: // ECX
3306                     case 2: // EDX
3307                     case 4: // ESP
3308                         break;
3309                     case 7:             // EDI
3310                         *dest++ = 0xF4; /* 11110100  This pointer is in EDI */
3311                         break;
3312                     case 6:             // ESI
3313                         *dest++ = 0xF5; /* 11110100  This pointer is in ESI */
3314                         break;
3315                     case 3:             // EBX
3316                         *dest++ = 0xF6; /* 11110100  This pointer is in EBX */
3317                         break;
3318                     case 5:             // EBP
3319                         *dest++ = 0xF7; /* 11110100  This pointer is in EBP */
3320                         break;
3321                     default:
3322                         break;
3323                 }
3324             }
3325
3326             /* Is this a stack pointer change or call? */
3327
3328             if (genRegPtrTemp->rpdArg)
3329             {
3330                 if (genRegPtrTemp->rpdArgTypeGet() == rpdARG_KILL)
3331                 {
3332                     // kill 'rpdPtrArg' number of pointer variables in pasStk
3333                     pasStk.pasKill(genRegPtrTemp->rpdPtrArg);
3334                 }
3335                 /* Is this a call site? */
3336                 else if (genRegPtrTemp->rpdCall)
3337                 {
3338                     /* This is a true call site */
3339
3340                     /* Remember the new 'last' offset */
3341
3342                     lastOffset = nextOffset;
3343
3344                     callArgCnt = genRegPtrTemp->rpdPtrArg;
3345
3346                     unsigned gcrefRegMask = genRegPtrTemp->rpdCallGCrefRegs;
3347
3348                     byrefRegMask = genRegPtrTemp->rpdCallByrefRegs;
3349
3350                     assert((gcrefRegMask & byrefRegMask) == 0);
3351
3352                     regMask = gcrefRegMask | byrefRegMask;
3353
3354                     /* adjust argMask for this call-site */
3355                     pasStk.pasPop(callArgCnt);
3356
3357                     /* Do we have to use the fat encoding */
3358
3359                     if (pasStk.pasCurDepth() > BITS_IN_pasMask && pasStk.pasHasGCptrs())
3360                     {
3361                         /* use fat encoding:
3362                          *   11111000 [PBSDpbsd][32-bit delta][32-bit ArgCnt]
3363                          *            [32-bit PndCnt][32-bit PndSize][PndOffs...]
3364                          */
3365
3366                         DWORD pndCount = pasStk.pasEnumGCoffsCount();
3367                         DWORD pndSize  = 0;
3368                         BYTE* pPndSize = DUMMY_INIT(NULL);
3369
3370                         if (mask)
3371                         {
3372                             *dest++       = 0xF8;
3373                             *dest++       = (byrefRegMask << 4) | regMask;
3374                             *(DWORD*)dest = codeDelta;
3375                             dest += sizeof(DWORD);
3376                             *(DWORD*)dest = callArgCnt;
3377                             dest += sizeof(DWORD);
3378                             *(DWORD*)dest = pndCount;
3379                             dest += sizeof(DWORD);
3380                             pPndSize = dest;
3381                             dest += sizeof(DWORD); // Leave space for pndSize
3382                         }
3383
3384                         unsigned offs, iter;
3385
3386                         for (iter = pasStk.pasEnumGCoffs(pasENUM_START, &offs); pndCount;
3387                              iter = pasStk.pasEnumGCoffs(iter, &offs), pndCount--)
3388                         {
3389                             unsigned eltSize = encodeUnsigned(dest, offs);
3390
3391                             pndSize += eltSize;
3392                             if (mask)
3393                                 dest += eltSize;
3394                         }
3395                         assert(iter == pasENUM_END);
3396
3397                         if (mask == 0)
3398                         {
3399                             dest = base + 2 + 4 * sizeof(DWORD) + pndSize;
3400                         }
3401                         else
3402                         {
3403                             assert(pPndSize + sizeof(pndSize) + pndSize == dest);
3404                             *(DWORD*)pPndSize = pndSize;
3405                         }
3406
3407                         goto NEXT_RPD;
3408                     }
3409
3410                     argMask = byrefArgMask = 0;
3411
3412                     if (pasStk.pasHasGCptrs())
3413                     {
3414                         assert(pasStk.pasCurDepth() <= BITS_IN_pasMask);
3415
3416                         argMask      = pasStk.pasArgMask();
3417                         byrefArgMask = pasStk.pasByrefArgMask();
3418                     }
3419
3420                     /* Shouldn't be reporting trivial call-sites */
3421
3422                     assert(regMask || argMask || callArgCnt || pasStk.pasCurDepth());
3423
3424 // Emit IPtrMask if needed
3425
3426 #define CHK_NON_INTRPT_ESP_IPtrMask                                                                                    \
3427                                                                                                                        \
3428     if (byrefRegMask || byrefArgMask)                                                                                  \
3429     {                                                                                                                  \
3430         *dest++        = 0xF0;                                                                                         \
3431         unsigned imask = (byrefArgMask << 4) | byrefRegMask;                                                           \
3432         dest += encodeUnsigned(dest, imask);                                                                           \
3433     }
3434
3435                     /* When usePopEncoding is true:
3436                      *  this is not an interesting call site
3437                      *   because nothing is live here.
3438                      */
3439                     usePopEncoding = ((callArgCnt < 4) && (regMask == 0) && (argMask == 0));
3440
3441                     if (!usePopEncoding)
3442                     {
3443                         int pattern = lookupCallPattern(callArgCnt, regMask, argMask, codeDelta);
3444                         if (pattern != -1)
3445                         {
3446                             if (pattern > 0xff)
3447                             {
3448                                 codeDelta = pattern >> 8;
3449                                 pattern &= 0xff;
3450                                 if (codeDelta >= 16)
3451                                 {
3452                                     /* use encoding: */
3453                                     /*   skip 01000000 [Delta] */
3454                                     *dest++ = 0x40;
3455                                     dest += encodeUnsigned(dest, codeDelta);
3456                                     codeDelta = 0;
3457                                 }
3458                                 else
3459                                 {
3460                                     /* use encoding: */
3461                                     /*   skip 0100DDDD  small delta=DDDD */
3462                                     *dest++ = 0x40 | (BYTE)codeDelta;
3463                                 }
3464                             }
3465
3466                             // Emit IPtrMask if needed
3467                             CHK_NON_INTRPT_ESP_IPtrMask;
3468
3469                             assert((pattern >= 0) && (pattern < 80));
3470                             *dest++ = 0x80 | pattern;
3471                             goto NEXT_RPD;
3472                         }
3473
3474                         /* See if we can use 2nd call encoding
3475                          *     1101RRRR DDCCCMMM encoding */
3476
3477                         if ((callArgCnt <= 7) && (argMask <= 7))
3478                         {
3479                             unsigned inx; // callCommonDelta[] index
3480                             unsigned maxCommonDelta = callCommonDelta[3];
3481
3482                             if (codeDelta > maxCommonDelta)
3483                             {
3484                                 if (codeDelta > maxCommonDelta + 15)
3485                                 {
3486                                     /* use encoding: */
3487                                     /*   skip    01000000 [Delta] */
3488                                     *dest++ = 0x40;
3489                                     dest += encodeUnsigned(dest, codeDelta - maxCommonDelta);
3490                                 }
3491                                 else
3492                                 {
3493                                     /* use encoding: */
3494                                     /*   skip 0100DDDD  small delta=DDDD */
3495                                     *dest++ = 0x40 | (BYTE)(codeDelta - maxCommonDelta);
3496                                 }
3497
3498                                 codeDelta = maxCommonDelta;
3499                                 inx       = 3;
3500                                 goto EMIT_2ND_CALL_ENCODING;
3501                             }
3502
3503                             for (inx = 0; inx < 4; inx++)
3504                             {
3505                                 if (codeDelta == callCommonDelta[inx])
3506                                 {
3507                                 EMIT_2ND_CALL_ENCODING:
3508                                     // Emit IPtrMask if needed
3509                                     CHK_NON_INTRPT_ESP_IPtrMask;
3510
3511                                     *dest++ = 0xD0 | regMask;
3512                                     *dest++ = (inx << 6) | (callArgCnt << 3) | argMask;
3513                                     goto NEXT_RPD;
3514                                 }
3515                             }
3516
3517                             unsigned minCommonDelta = callCommonDelta[0];
3518
3519                             if ((codeDelta > minCommonDelta) && (codeDelta < maxCommonDelta))
3520                             {
3521                                 assert((minCommonDelta + 16) > maxCommonDelta);
3522                                 /* use encoding: */
3523                                 /*   skip 0100DDDD  small delta=DDDD */
3524                                 *dest++ = 0x40 | (BYTE)(codeDelta - minCommonDelta);
3525
3526                                 codeDelta = minCommonDelta;
3527                                 inx       = 0;
3528                                 goto EMIT_2ND_CALL_ENCODING;
3529                             }
3530                         }
3531                     }
3532
3533                     if (codeDelta >= 16)
3534                     {
3535                         unsigned i = (usePopEncoding ? 15 : 0);
3536                         /* use encoding: */
3537                         /*   skip    01000000 [Delta]  arbitrary sized delta */
3538                         *dest++ = 0x40;
3539                         dest += encodeUnsigned(dest, codeDelta - i);
3540                         codeDelta = i;
3541                     }
3542
3543                     if ((codeDelta > 0) || usePopEncoding)
3544                     {
3545                         if (usePopEncoding)
3546                         {
3547                             /* use encoding: */
3548                             /*   pop 01CCDDDD  ESP pop CC items, 4-bit delta */
3549                             if (callArgCnt || codeDelta)
3550                                 *dest++ = (BYTE)(0x40 | (callArgCnt << 4) | codeDelta);
3551                             goto NEXT_RPD;
3552                         }
3553                         else
3554                         {
3555                             /* use encoding: */
3556                             /*   skip 0100DDDD  small delta=DDDD */
3557                             *dest++ = 0x40 | (BYTE)codeDelta;
3558                         }
3559                     }
3560
3561                     // Emit IPtrMask if needed
3562                     CHK_NON_INTRPT_ESP_IPtrMask;
3563
3564                     /* use encoding:                                   */
3565                     /*   call 1110RRRR [ArgCnt] [ArgMask]              */
3566
3567                     *dest++ = 0xE0 | regMask;
3568                     dest += encodeUnsigned(dest, callArgCnt);
3569
3570                     dest += encodeUnsigned(dest, argMask);
3571                 }
3572                 else
3573                 {
3574                     /* This is a push or a pop site */
3575
3576                     /* Remember the new 'last' offset */
3577
3578                     lastOffset = nextOffset;
3579
3580                     if (genRegPtrTemp->rpdArgTypeGet() == rpdARG_POP)
3581                     {
3582                         /* This must be a gcArgPopSingle */
3583
3584                         assert(genRegPtrTemp->rpdPtrArg == 1);
3585
3586                         if (codeDelta >= 16)
3587                         {
3588                             /* use encoding: */
3589                             /*   skip    01000000 [Delta] */
3590                             *dest++ = 0x40;
3591                             dest += encodeUnsigned(dest, codeDelta - 15);
3592                             codeDelta = 15;
3593                         }
3594
3595                         /* use encoding: */
3596                         /*   pop1    0101DDDD  ESP pop one item, 4-bit delta */
3597
3598                         *dest++ = 0x50 | (BYTE)codeDelta;
3599
3600                         /* adjust argMask for this pop */
3601                         pasStk.pasPop(1);
3602                     }
3603                     else
3604                     {
3605                         /* This is a push */
3606
3607                         if (codeDelta >= 32)
3608                         {
3609                             /* use encoding: */
3610                             /*   skip    01000000 [Delta] */
3611                             *dest++ = 0x40;
3612                             dest += encodeUnsigned(dest, codeDelta - 31);
3613                             codeDelta = 31;
3614                         }
3615
3616                         assert(codeDelta < 32);
3617
3618                         /* use encoding: */
3619                         /*   push    000DDDDD ESP push one item, 5-bit delta */
3620
3621                         *dest++ = (BYTE)codeDelta;
3622
3623                         /* adjust argMask for this push */
3624                         pasStk.pasPush(genRegPtrTemp->rpdGCtypeGet());
3625                     }
3626                 }
3627             }
3628
3629         /*  We ignore the register live/dead information, since the
3630          *  rpdCallRegMask contains all the liveness information
3631          *  that we need
3632          */
3633         NEXT_RPD:
3634
3635             totalSize += dest - base;
3636
3637             /* Go back to the buffer start if we're not generating a table */
3638
3639             if (!mask)
3640                 dest = base;
3641
3642 #if REGEN_CALLPAT
3643             if ((mask == -1) && (usePopEncoding == false) && ((dest - base) > 0))
3644                 regenLog(origCodeDelta, argMask, regMask, callArgCnt, byrefArgMask, byrefRegMask, base, (dest - base));
3645 #endif
3646         }
3647
3648         /* Verify that we pop every arg that was pushed and that argMask is 0 */
3649
3650         assert(pasStk.pasCurDepth() == 0);
3651
3652 #endif // _TARGET_X86_
3653
3654         /* Terminate the table with 0xFF */
3655
3656         *dest = 0xFF;
3657         dest -= mask;
3658         totalSize++;
3659     }
3660
3661 #if VERIFY_GC_TABLES
3662     if (mask)
3663     {
3664         *(short*)dest = (short)0xBEEB;
3665         dest += sizeof(short);
3666     }
3667     totalSize += sizeof(short);
3668 #endif
3669
3670 #if MEASURE_PTRTAB_SIZE
3671
3672     if (mask)
3673         s_gcTotalPtrTabSize += totalSize;
3674
3675 #endif
3676
3677     return totalSize;
3678 }
3679 #ifdef _PREFAST_
3680 #pragma warning(pop)
3681 #endif
3682
3683 /*****************************************************************************/
3684 #if DUMP_GC_TABLES
3685 /*****************************************************************************
3686  *
3687  *  Dump the contents of a GC pointer table.
3688  */
3689
3690 #include "gcdump.h"
3691
3692 #if VERIFY_GC_TABLES
3693 const bool verifyGCTables = true;
3694 #else
3695 const bool verifyGCTables = false;
3696 #endif
3697
3698 /*****************************************************************************
3699  *
3700  *  Dump the info block header.
3701  */
3702
3703 unsigned GCInfo::gcInfoBlockHdrDump(const BYTE* table, InfoHdr* header, unsigned* methodSize)
3704 {
3705     GCDump gcDump(GCINFO_VERSION);
3706
3707     gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
3708     printf("Method info block:\n");
3709
3710     return gcDump.DumpInfoHdr(table, header, methodSize, verifyGCTables);
3711 }
3712
3713 /*****************************************************************************/
3714
3715 unsigned GCInfo::gcDumpPtrTable(const BYTE* table, const InfoHdr& header, unsigned methodSize)
3716 {
3717     printf("Pointer table:\n");
3718
3719     GCDump gcDump(GCINFO_VERSION);
3720     gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
3721
3722     return gcDump.DumpGCTable(table, header, methodSize, verifyGCTables);
3723 }
3724
3725 /*****************************************************************************
3726  *
3727  *  Find all the live pointers in a stack frame.
3728  */
3729
3730 void GCInfo::gcFindPtrsInFrame(const void* infoBlock, const void* codeBlock, unsigned offs)
3731 {
3732     GCDump gcDump(GCINFO_VERSION);
3733     gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
3734
3735     gcDump.DumpPtrsInFrame((PTR_CBYTE)infoBlock, (const BYTE*)codeBlock, offs, verifyGCTables);
3736 }
3737
3738 #endif // DUMP_GC_TABLES
3739
3740 #else // !JIT32_GCENCODER
3741
3742 #include "gcinfoencoder.h"
3743
3744 // Do explicit instantiation.
3745 template class JitHashTable<RegSlotIdKey, RegSlotIdKey, GcSlotId>;
3746 template class JitHashTable<StackSlotIdKey, StackSlotIdKey, GcSlotId>;
3747
3748 #ifdef DEBUG
3749
3750 static const char* const GcSlotFlagsNames[] = {"",
3751                                                "(byref) ",
3752                                                "(pinned) ",
3753                                                "(byref, pinned) ",
3754                                                "(untracked) ",
3755                                                "(byref, untracked) ",
3756                                                "(pinned, untracked) ",
3757                                                "(byref, pinned, untracked) "};
3758
3759 // I'm making a local wrapper class for GcInfoEncoder so that can add logging of my own (DLD).
3760 class GcInfoEncoderWithLogging
3761 {
3762     GcInfoEncoder* m_gcInfoEncoder;
3763     bool           m_doLogging;
3764
3765 public:
3766     GcInfoEncoderWithLogging(GcInfoEncoder* gcInfoEncoder, bool verbose)
3767         : m_gcInfoEncoder(gcInfoEncoder), m_doLogging(verbose || JitConfig.JitGCInfoLogging() != 0)
3768     {
3769     }
3770
3771     GcSlotId GetStackSlotId(INT32 spOffset, GcSlotFlags flags, GcStackSlotBase spBase = GC_CALLER_SP_REL)
3772     {
3773         GcSlotId newSlotId = m_gcInfoEncoder->GetStackSlotId(spOffset, flags, spBase);
3774         if (m_doLogging)
3775         {
3776             printf("Stack slot id for offset %d (0x%x) (%s) %s= %d.\n", spOffset, spOffset,
3777                    GcStackSlotBaseNames[spBase], GcSlotFlagsNames[flags & 7], newSlotId);
3778         }
3779         return newSlotId;
3780     }
3781
3782     GcSlotId GetRegisterSlotId(UINT32 regNum, GcSlotFlags flags)
3783     {
3784         GcSlotId newSlotId = m_gcInfoEncoder->GetRegisterSlotId(regNum, flags);
3785         if (m_doLogging)
3786         {
3787             printf("Register slot id for reg %s %s= %d.\n", getRegName(regNum), GcSlotFlagsNames[flags & 7], newSlotId);
3788         }
3789         return newSlotId;
3790     }
3791
3792     void SetSlotState(UINT32 instructionOffset, GcSlotId slotId, GcSlotState slotState)
3793     {
3794         m_gcInfoEncoder->SetSlotState(instructionOffset, slotId, slotState);
3795         if (m_doLogging)
3796         {
3797             printf("Set state of slot %d at instr offset 0x%x to %s.\n", slotId, instructionOffset,
3798                    (slotState == GC_SLOT_LIVE ? "Live" : "Dead"));
3799         }
3800     }
3801
3802     void DefineCallSites(UINT32* pCallSites, BYTE* pCallSiteSizes, UINT32 numCallSites)
3803     {
3804         m_gcInfoEncoder->DefineCallSites(pCallSites, pCallSiteSizes, numCallSites);
3805         if (m_doLogging)
3806         {
3807             printf("Defining %d call sites:\n", numCallSites);
3808             for (UINT32 k = 0; k < numCallSites; k++)
3809             {
3810                 printf("    Offset 0x%x, size %d.\n", pCallSites[k], pCallSiteSizes[k]);
3811             }
3812         }
3813     }
3814
3815     void DefineInterruptibleRange(UINT32 startInstructionOffset, UINT32 length)
3816     {
3817         m_gcInfoEncoder->DefineInterruptibleRange(startInstructionOffset, length);
3818         if (m_doLogging)
3819         {
3820             printf("Defining interruptible range: [0x%x, 0x%x).\n", startInstructionOffset,
3821                    startInstructionOffset + length);
3822         }
3823     }
3824
3825     void SetCodeLength(UINT32 length)
3826     {
3827         m_gcInfoEncoder->SetCodeLength(length);
3828         if (m_doLogging)
3829         {
3830             printf("Set code length to %d.\n", length);
3831         }
3832     }
3833
3834     void SetReturnKind(ReturnKind returnKind)
3835     {
3836         m_gcInfoEncoder->SetReturnKind(returnKind);
3837         if (m_doLogging)
3838         {
3839             printf("Set ReturnKind to %s.\n", ReturnKindToString(returnKind));
3840         }
3841     }
3842
3843     void SetStackBaseRegister(UINT32 registerNumber)
3844     {
3845         m_gcInfoEncoder->SetStackBaseRegister(registerNumber);
3846         if (m_doLogging)
3847         {
3848             printf("Set stack base register to %s.\n", getRegName(registerNumber));
3849         }
3850     }
3851
3852     void SetPrologSize(UINT32 prologSize)
3853     {
3854         m_gcInfoEncoder->SetPrologSize(prologSize);
3855         if (m_doLogging)
3856         {
3857             printf("Set prolog size 0x%x.\n", prologSize);
3858         }
3859     }
3860
3861     void SetGSCookieStackSlot(INT32 spOffsetGSCookie, UINT32 validRangeStart, UINT32 validRangeEnd)
3862     {
3863         m_gcInfoEncoder->SetGSCookieStackSlot(spOffsetGSCookie, validRangeStart, validRangeEnd);
3864         if (m_doLogging)
3865         {
3866             printf("Set GS Cookie stack slot to %d, valid from 0x%x to 0x%x.\n", spOffsetGSCookie, validRangeStart,
3867                    validRangeEnd);
3868         }
3869     }
3870
3871     void SetPSPSymStackSlot(INT32 spOffsetPSPSym)
3872     {
3873         m_gcInfoEncoder->SetPSPSymStackSlot(spOffsetPSPSym);
3874         if (m_doLogging)
3875         {
3876             printf("Set PSPSym stack slot to %d.\n", spOffsetPSPSym);
3877         }
3878     }
3879
3880     void SetGenericsInstContextStackSlot(INT32 spOffsetGenericsContext, GENERIC_CONTEXTPARAM_TYPE type)
3881     {
3882         m_gcInfoEncoder->SetGenericsInstContextStackSlot(spOffsetGenericsContext, type);
3883         if (m_doLogging)
3884         {
3885             printf("Set generic instantiation context stack slot to %d, type is %s.\n", spOffsetGenericsContext,
3886                    (type == GENERIC_CONTEXTPARAM_THIS
3887                         ? "THIS"
3888                         : (type == GENERIC_CONTEXTPARAM_MT ? "MT"
3889                                                            : (type == GENERIC_CONTEXTPARAM_MD ? "MD" : "UNKNOWN!"))));
3890         }
3891     }
3892
3893     void SetSecurityObjectStackSlot(INT32 spOffset)
3894     {
3895         m_gcInfoEncoder->SetSecurityObjectStackSlot(spOffset);
3896         if (m_doLogging)
3897         {
3898             printf("Set security object stack slot to %d.\n", spOffset);
3899         }
3900     }
3901
3902     void SetIsVarArg()
3903     {
3904         m_gcInfoEncoder->SetIsVarArg();
3905         if (m_doLogging)
3906         {
3907             printf("SetIsVarArg.\n");
3908         }
3909     }
3910
3911 #ifdef _TARGET_AMD64_
3912     void SetWantsReportOnlyLeaf()
3913     {
3914         m_gcInfoEncoder->SetWantsReportOnlyLeaf();
3915         if (m_doLogging)
3916         {
3917             printf("Set WantsReportOnlyLeaf.\n");
3918         }
3919     }
3920 #elif defined(_TARGET_ARMARCH_)
3921     void SetHasTailCalls()
3922     {
3923         m_gcInfoEncoder->SetHasTailCalls();
3924         if (m_doLogging)
3925         {
3926             printf("Set HasTailCalls.\n");
3927         }
3928     }
3929 #endif // _TARGET_AMD64_
3930
3931     void SetSizeOfStackOutgoingAndScratchArea(UINT32 size)
3932     {
3933         m_gcInfoEncoder->SetSizeOfStackOutgoingAndScratchArea(size);
3934         if (m_doLogging)
3935         {
3936             printf("Set Outgoing stack arg area size to %d.\n", size);
3937         }
3938     }
3939 };
3940
3941 #define GCENCODER_WITH_LOGGING(withLog, realEncoder)                                                                   \
3942     GcInfoEncoderWithLogging  withLog##Var(realEncoder, compiler->verbose || compiler->opts.dspGCtbls);                \
3943     GcInfoEncoderWithLogging* withLog = &withLog##Var;
3944
3945 #else // DEBUG
3946
3947 #define GCENCODER_WITH_LOGGING(withLog, realEncoder) GcInfoEncoder* withLog = realEncoder;
3948
3949 #endif // DEBUG
3950
3951 void GCInfo::gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSize, unsigned prologSize)
3952 {
3953 #ifdef DEBUG
3954     if (compiler->verbose)
3955     {
3956         printf("*************** In gcInfoBlockHdrSave()\n");
3957     }
3958 #endif
3959
3960     GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder);
3961
3962     // Can't create tables if we've not saved code.
3963
3964     gcInfoEncoderWithLog->SetCodeLength(methodSize);
3965
3966     gcInfoEncoderWithLog->SetReturnKind(getReturnKind());
3967
3968     if (compiler->isFramePointerUsed())
3969     {
3970         gcInfoEncoderWithLog->SetStackBaseRegister(REG_FPBASE);
3971     }
3972
3973     if (compiler->info.compIsVarArgs)
3974     {
3975         gcInfoEncoderWithLog->SetIsVarArg();
3976     }
3977     // No equivalents.
3978     // header->profCallbacks = compiler->info.compProfilerCallback;
3979     // header->editNcontinue = compiler->opts.compDbgEnC;
3980     //
3981     if (compiler->lvaReportParamTypeArg())
3982     {
3983         // The predicate above is true only if there is an extra generic context parameter, not for
3984         // the case where the generic context is provided by "this."
3985         assert(compiler->info.compTypeCtxtArg != BAD_VAR_NUM);
3986         GENERIC_CONTEXTPARAM_TYPE ctxtParamType = GENERIC_CONTEXTPARAM_NONE;
3987         switch (compiler->info.compMethodInfo->options & CORINFO_GENERICS_CTXT_MASK)
3988         {
3989             case CORINFO_GENERICS_CTXT_FROM_METHODDESC:
3990                 ctxtParamType = GENERIC_CONTEXTPARAM_MD;
3991                 break;
3992             case CORINFO_GENERICS_CTXT_FROM_METHODTABLE:
3993                 ctxtParamType = GENERIC_CONTEXTPARAM_MT;
3994                 break;
3995
3996             case CORINFO_GENERICS_CTXT_FROM_THIS: // See comment above.
3997             default:
3998                 // If we have a generic context parameter, then we should have
3999                 // one of the two options flags handled above.
4000                 assert(false);
4001         }
4002
4003         gcInfoEncoderWithLog->SetGenericsInstContextStackSlot(
4004             compiler->lvaToCallerSPRelativeOffset(compiler->lvaCachedGenericContextArgOffset(),
4005                                                   compiler->isFramePointerUsed()),
4006             ctxtParamType);
4007     }
4008     // As discussed above, handle the case where the generics context is obtained via
4009     // the method table of "this".
4010     else if (compiler->lvaKeepAliveAndReportThis())
4011     {
4012         assert(compiler->info.compThisArg != BAD_VAR_NUM);
4013         gcInfoEncoderWithLog->SetGenericsInstContextStackSlot(
4014             compiler->lvaToCallerSPRelativeOffset(compiler->lvaCachedGenericContextArgOffset(),
4015                                                   compiler->isFramePointerUsed()),
4016             GENERIC_CONTEXTPARAM_THIS);
4017     }
4018
4019     if (compiler->getNeedsGSSecurityCookie())
4020     {
4021         assert(compiler->lvaGSSecurityCookie != BAD_VAR_NUM);
4022
4023         // The lv offset is FP-relative, and the using code expects caller-sp relative, so translate.
4024         // The code offset ranges assume that the GS Cookie slot is initialized in the prolog, and is valid
4025         // through the remainder of the method.  We will not query for the GS Cookie while we're in an epilog,
4026         // so the question of where in the epilog it becomes invalid is moot.
4027         gcInfoEncoderWithLog->SetGSCookieStackSlot(compiler->lvaGetCallerSPRelativeOffset(
4028                                                        compiler->lvaGSSecurityCookie),
4029                                                    prologSize, methodSize);
4030     }
4031     else if (compiler->opts.compNeedSecurityCheck || compiler->lvaReportParamTypeArg() ||
4032              compiler->lvaKeepAliveAndReportThis())
4033     {
4034         gcInfoEncoderWithLog->SetPrologSize(prologSize);
4035     }
4036
4037     if (compiler->opts.compNeedSecurityCheck)
4038     {
4039         assert(compiler->lvaSecurityObject != BAD_VAR_NUM);
4040
4041         // A VM requirement due to how the decoder works (it ignores partially interruptible frames when
4042         // an exception has escaped, but the VM requires the security object to live on).
4043         assert(compiler->codeGen->genInterruptible);
4044
4045         // The lv offset is FP-relative, and the using code expects caller-sp relative, so translate.
4046         // The normal GC lifetime reporting mechanisms will report a proper lifetime to the GC.
4047         // The security subsystem can safely assume that anywhere it might walk the stack, it will be
4048         // valid (null or a live GC ref).
4049         gcInfoEncoderWithLog->SetSecurityObjectStackSlot(
4050             compiler->lvaGetCallerSPRelativeOffset(compiler->lvaSecurityObject));
4051     }
4052
4053 #if FEATURE_EH_FUNCLETS
4054     if (compiler->lvaPSPSym != BAD_VAR_NUM)
4055     {
4056 #ifdef _TARGET_AMD64_
4057         // The PSPSym is relative to InitialSP on X64 and CallerSP on other platforms.
4058         gcInfoEncoderWithLog->SetPSPSymStackSlot(compiler->lvaGetInitialSPRelativeOffset(compiler->lvaPSPSym));
4059 #else  // !_TARGET_AMD64_
4060         gcInfoEncoderWithLog->SetPSPSymStackSlot(compiler->lvaGetCallerSPRelativeOffset(compiler->lvaPSPSym));
4061 #endif // !_TARGET_AMD64_
4062     }
4063
4064 #ifdef _TARGET_AMD64_
4065     if (compiler->ehAnyFunclets())
4066     {
4067         // Set this to avoid double-reporting the parent frame (unlike JIT64)
4068         gcInfoEncoderWithLog->SetWantsReportOnlyLeaf();
4069     }
4070 #endif // _TARGET_AMD64_
4071
4072 #endif // FEATURE_EH_FUNCLETS
4073
4074 #ifdef _TARGET_ARMARCH_
4075     if (compiler->codeGen->hasTailCalls)
4076     {
4077         gcInfoEncoderWithLog->SetHasTailCalls();
4078     }
4079 #endif // _TARGET_ARMARCH_
4080
4081 #if FEATURE_FIXED_OUT_ARGS
4082     // outgoing stack area size
4083     gcInfoEncoderWithLog->SetSizeOfStackOutgoingAndScratchArea(compiler->lvaOutgoingArgSpaceSize);
4084 #endif // FEATURE_FIXED_OUT_ARGS
4085
4086 #if DISPLAY_SIZES
4087
4088     if (compiler->codeGen->genInterruptible)
4089     {
4090         genMethodICnt++;
4091     }
4092     else
4093     {
4094         genMethodNCnt++;
4095     }
4096
4097 #endif // DISPLAY_SIZES
4098 }
4099
4100 #ifdef DEBUG
4101 #define Encoder GcInfoEncoderWithLogging
4102 #else
4103 #define Encoder GcInfoEncoder
4104 #endif
4105
4106 // Small helper class to handle the No-GC-Interrupt callbacks
4107 // when reporting interruptible ranges.
4108 //
4109 // Encoder should be either GcInfoEncoder or GcInfoEncoderWithLogging
4110 //
4111 struct InterruptibleRangeReporter
4112 {
4113     unsigned prevStart;
4114     Encoder* gcInfoEncoderWithLog;
4115
4116     InterruptibleRangeReporter(unsigned _prevStart, Encoder* _gcInfo)
4117         : prevStart(_prevStart), gcInfoEncoderWithLog(_gcInfo)
4118     {
4119     }
4120
4121     // This callback is called for each insGroup marked with
4122     // IGF_NOGCINTERRUPT (currently just prologs and epilogs).
4123     // Report everything between the previous region and the current
4124     // region as interruptible.
4125
4126     bool operator()(unsigned igFuncIdx, unsigned igOffs, unsigned igSize)
4127     {
4128         if (igOffs < prevStart)
4129         {
4130             // We're still in the main method prolog, which has already
4131             // had it's interruptible range reported.
4132             assert(igFuncIdx == 0);
4133             assert(igOffs + igSize <= prevStart);
4134             return true;
4135         }
4136
4137         assert(igOffs >= prevStart);
4138         if (igOffs > prevStart)
4139         {
4140             gcInfoEncoderWithLog->DefineInterruptibleRange(prevStart, igOffs - prevStart);
4141         }
4142         prevStart = igOffs + igSize;
4143         return true;
4144     }
4145 };
4146
4147 void GCInfo::gcMakeRegPtrTable(
4148     GcInfoEncoder* gcInfoEncoder, unsigned codeSize, unsigned prologSize, MakeRegPtrMode mode, unsigned* callCntRef)
4149 {
4150     GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder);
4151
4152     const bool noTrackedGCSlots =
4153         (compiler->opts.MinOpts() && !compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)
4154 #if !defined(JIT32_GCENCODER) || !defined(LEGACY_BACKEND)
4155          && !JitConfig.JitMinOptsTrackGCrefs()
4156 #endif // !defined(JIT32_GCENCODER) || !defined(LEGACY_BACKEND)
4157              );
4158
4159     if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
4160     {
4161         m_regSlotMap   = new (compiler->getAllocator()) RegSlotMap(compiler->getAllocator());
4162         m_stackSlotMap = new (compiler->getAllocator()) StackSlotMap(compiler->getAllocator());
4163     }
4164
4165     /**************************************************************************
4166      *
4167      *                      Untracked ptr variables
4168      *
4169      **************************************************************************
4170      */
4171
4172     unsigned count = 0;
4173
4174     int lastoffset = 0;
4175
4176     /* Count&Write untracked locals and non-enregistered args */
4177
4178     unsigned   varNum;
4179     LclVarDsc* varDsc;
4180     for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount; varNum++, varDsc++)
4181     {
4182         if (compiler->lvaIsFieldOfDependentlyPromotedStruct(varDsc))
4183         {
4184             // Field local of a PROMOTION_TYPE_DEPENDENT struct must have been
4185             // reported through its parent local.
4186             continue;
4187         }
4188
4189         if (varTypeIsGC(varDsc->TypeGet()))
4190         {
4191             // Do we have an argument or local variable?
4192             if (!varDsc->lvIsParam)
4193             {
4194                 // If is is pinned, it must be an untracked local.
4195                 assert(!varDsc->lvPinned || !varDsc->lvTracked);
4196
4197                 if (varDsc->lvTracked || !varDsc->lvOnFrame)
4198                 {
4199                     continue;
4200                 }
4201             }
4202             else
4203             {
4204                 // Stack-passed arguments which are not enregistered
4205                 // are always reported in this "untracked stack
4206                 // pointers" section of the GC info even if lvTracked==true
4207
4208                 // Has this argument been fully enregistered?
4209                 CLANG_FORMAT_COMMENT_ANCHOR;
4210
4211 #ifndef LEGACY_BACKEND
4212                 if (!varDsc->lvOnFrame)
4213 #else  // LEGACY_BACKEND
4214                 if (varDsc->lvRegister)
4215 #endif // LEGACY_BACKEND
4216                 {
4217                     // If a CEE_JMP has been used, then we need to report all the arguments
4218                     // even if they are enregistered, since we will be using this value
4219                     // in a JMP call.  Note that this is subtle as we require that
4220                     // argument offsets are always fixed up properly even if lvRegister
4221                     // is set.
4222                     if (!compiler->compJmpOpUsed)
4223                     {
4224                         continue;
4225                     }
4226                 }
4227                 else
4228                 {
4229                     if (!varDsc->lvOnFrame)
4230                     {
4231                         // If this non-enregistered pointer arg is never
4232                         // used, we don't need to report it.
4233                         assert(varDsc->lvRefCnt == 0);
4234                         continue;
4235                     }
4236                     else if (varDsc->lvIsRegArg && varDsc->lvTracked)
4237                     {
4238                         // If this register-passed arg is tracked, then
4239                         // it has been allocated space near the other
4240                         // pointer variables and we have accurate life-
4241                         // time info. It will be reported with
4242                         // gcVarPtrList in the "tracked-pointer" section.
4243                         continue;
4244                     }
4245                 }
4246             }
4247
4248             // If we haven't continued to the next variable, we should report this as an untracked local.
4249             CLANG_FORMAT_COMMENT_ANCHOR;
4250
4251             GcSlotFlags flags = GC_SLOT_UNTRACKED;
4252
4253             if (varDsc->TypeGet() == TYP_BYREF)
4254             {
4255                 // Or in byref_OFFSET_FLAG for 'byref' pointer tracking
4256                 flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
4257             }
4258
4259             if (varDsc->lvPinned)
4260             {
4261                 // Or in pinned_OFFSET_FLAG for 'pinned' pointer tracking
4262                 flags = (GcSlotFlags)(flags | GC_SLOT_PINNED);
4263             }
4264             GcStackSlotBase stackSlotBase = GC_SP_REL;
4265             if (varDsc->lvFramePointerBased)
4266             {
4267                 stackSlotBase = GC_FRAMEREG_REL;
4268             }
4269             if (noTrackedGCSlots)
4270             {
4271                 // No need to hash/lookup untracked GC refs; just grab a new Slot Id.
4272                 if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
4273                 {
4274                     gcInfoEncoderWithLog->GetStackSlotId(varDsc->lvStkOffs, flags, stackSlotBase);
4275                 }
4276             }
4277             else
4278             {
4279                 StackSlotIdKey sskey(varDsc->lvStkOffs, (stackSlotBase == GC_FRAMEREG_REL), flags);
4280                 GcSlotId       varSlotId;
4281                 if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
4282                 {
4283                     if (!m_stackSlotMap->Lookup(sskey, &varSlotId))
4284                     {
4285                         varSlotId = gcInfoEncoderWithLog->GetStackSlotId(varDsc->lvStkOffs, flags, stackSlotBase);
4286                         m_stackSlotMap->Set(sskey, varSlotId);
4287                     }
4288                 }
4289             }
4290         }
4291
4292         // If this is a TYP_STRUCT, handle its GC pointers.
4293         // Note that the enregisterable struct types cannot have GC pointers in them.
4294         if ((varDsc->lvType == TYP_STRUCT) && varDsc->lvOnFrame && (varDsc->lvExactSize >= TARGET_POINTER_SIZE))
4295         {
4296             unsigned slots  = compiler->lvaLclSize(varNum) / TARGET_POINTER_SIZE;
4297             BYTE*    gcPtrs = compiler->lvaGetGcLayout(varNum);
4298
4299             // walk each member of the array
4300             for (unsigned i = 0; i < slots; i++)
4301             {
4302                 if (gcPtrs[i] == TYPE_GC_NONE)
4303                 { // skip non-gc slots
4304                     continue;
4305                 }
4306
4307                 int offset = varDsc->lvStkOffs + i * TARGET_POINTER_SIZE;
4308 #if DOUBLE_ALIGN
4309                 // For genDoubleAlign(), locals are addressed relative to ESP and
4310                 // arguments are addressed relative to EBP.
4311
4312                 if (compiler->genDoubleAlign() && varDsc->lvIsParam && !varDsc->lvIsRegArg)
4313                     offset += compiler->codeGen->genTotalFrameSize();
4314 #endif
4315                 GcSlotFlags flags = GC_SLOT_UNTRACKED;
4316                 if (gcPtrs[i] == TYPE_GC_BYREF)
4317                 {
4318                     flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
4319                 }
4320
4321                 GcStackSlotBase stackSlotBase = GC_SP_REL;
4322                 if (varDsc->lvFramePointerBased)
4323                 {
4324                     stackSlotBase = GC_FRAMEREG_REL;
4325                 }
4326                 StackSlotIdKey sskey(offset, (stackSlotBase == GC_FRAMEREG_REL), flags);
4327                 GcSlotId       varSlotId;
4328                 if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
4329                 {
4330                     if (!m_stackSlotMap->Lookup(sskey, &varSlotId))
4331                     {
4332                         varSlotId = gcInfoEncoderWithLog->GetStackSlotId(offset, flags, stackSlotBase);
4333                         m_stackSlotMap->Set(sskey, varSlotId);
4334                     }
4335                 }
4336             }
4337         }
4338     }
4339
4340     if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
4341     {
4342         // Count&Write spill temps that hold pointers.
4343
4344         assert(compiler->tmpAllFree());
4345         for (TempDsc* tempItem = compiler->tmpListBeg(); tempItem != nullptr; tempItem = compiler->tmpListNxt(tempItem))
4346         {
4347             if (varTypeIsGC(tempItem->tdTempType()))
4348             {
4349                 int offset = tempItem->tdTempOffs();
4350
4351                 GcSlotFlags flags = GC_SLOT_UNTRACKED;
4352                 if (tempItem->tdTempType() == TYP_BYREF)
4353                 {
4354                     flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
4355                 }
4356
4357                 GcStackSlotBase stackSlotBase = GC_SP_REL;
4358                 if (compiler->isFramePointerUsed())
4359                 {
4360                     stackSlotBase = GC_FRAMEREG_REL;
4361                 }
4362                 StackSlotIdKey sskey(offset, (stackSlotBase == GC_FRAMEREG_REL), flags);
4363                 GcSlotId       varSlotId;
4364                 if (!m_stackSlotMap->Lookup(sskey, &varSlotId))
4365                 {
4366                     varSlotId = gcInfoEncoderWithLog->GetStackSlotId(offset, flags, stackSlotBase);
4367                     m_stackSlotMap->Set(sskey, varSlotId);
4368                 }
4369             }
4370         }
4371
4372         if (compiler->lvaKeepAliveAndReportThis())
4373         {
4374             // We need to report the cached copy as an untracked pointer
4375             assert(compiler->info.compThisArg != BAD_VAR_NUM);
4376             assert(!compiler->lvaReportParamTypeArg());
4377             GcSlotFlags flags = GC_SLOT_UNTRACKED;
4378
4379             if (compiler->lvaTable[compiler->info.compThisArg].TypeGet() == TYP_BYREF)
4380             {
4381                 // Or in GC_SLOT_INTERIOR for 'byref' pointer tracking
4382                 flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
4383             }
4384
4385             GcStackSlotBase stackSlotBase = compiler->isFramePointerUsed() ? GC_FRAMEREG_REL : GC_SP_REL;
4386
4387             gcInfoEncoderWithLog->GetStackSlotId(compiler->lvaCachedGenericContextArgOffset(), flags, stackSlotBase);
4388         }
4389     }
4390
4391     // Generate the table of tracked stack pointer variable lifetimes.
4392     gcMakeVarPtrTable(gcInfoEncoder, mode);
4393
4394     /**************************************************************************
4395      *
4396      * Prepare to generate the pointer register/argument map
4397      *
4398      **************************************************************************
4399      */
4400
4401     if (compiler->codeGen->genInterruptible)
4402     {
4403         assert(compiler->genFullPtrRegMap);
4404
4405         regMaskSmall ptrRegs          = 0;
4406         regPtrDsc*   regStackArgFirst = nullptr;
4407
4408         // Walk the list of pointer register/argument entries.
4409
4410         for (regPtrDsc* genRegPtrTemp = gcRegPtrList; genRegPtrTemp != nullptr; genRegPtrTemp = genRegPtrTemp->rpdNext)
4411         {
4412             int nextOffset = genRegPtrTemp->rpdOffs;
4413
4414             if (genRegPtrTemp->rpdArg)
4415             {
4416                 if (genRegPtrTemp->rpdArgTypeGet() == rpdARG_KILL)
4417                 {
4418                     // Kill all arguments for a call
4419                     if ((mode == MAKE_REG_PTR_MODE_DO_WORK) && (regStackArgFirst != nullptr))
4420                     {
4421                         // Record any outgoing arguments as becoming dead
4422                         gcInfoRecordGCStackArgsDead(gcInfoEncoder, genRegPtrTemp->rpdOffs, regStackArgFirst,
4423                                                     genRegPtrTemp);
4424                     }
4425                     regStackArgFirst = nullptr;
4426                 }
4427                 else if (genRegPtrTemp->rpdGCtypeGet() != GCT_NONE)
4428                 {
4429                     if (genRegPtrTemp->rpdArgTypeGet() == rpdARG_PUSH || (genRegPtrTemp->rpdPtrArg != 0))
4430                     {
4431                         bool isPop = genRegPtrTemp->rpdArgTypeGet() == rpdARG_POP;
4432                         assert(!isPop);
4433                         gcInfoRecordGCStackArgLive(gcInfoEncoder, mode, genRegPtrTemp);
4434                         if (regStackArgFirst == nullptr)
4435                         {
4436                             regStackArgFirst = genRegPtrTemp;
4437                         }
4438                     }
4439                     else
4440                     {
4441                         // We know it's a POP.  Sometimes we'll record a POP for a call, just to make sure
4442                         // the call site is recorded.
4443                         // This is just the negation of the condition:
4444                         assert(genRegPtrTemp->rpdArgTypeGet() == rpdARG_POP && genRegPtrTemp->rpdPtrArg == 0);
4445                         // This asserts that we only get here when we're recording a call site.
4446                         assert(genRegPtrTemp->rpdArg && genRegPtrTemp->rpdIsCallInstr());
4447
4448                         // Kill all arguments for a call
4449                         if ((mode == MAKE_REG_PTR_MODE_DO_WORK) && (regStackArgFirst != nullptr))
4450                         {
4451                             // Record any outgoing arguments as becoming dead
4452                             gcInfoRecordGCStackArgsDead(gcInfoEncoder, genRegPtrTemp->rpdOffs, regStackArgFirst,
4453                                                         genRegPtrTemp);
4454                         }
4455                         regStackArgFirst = nullptr;
4456                     }
4457                 }
4458             }
4459             else
4460             {
4461                 // Record any registers that are becoming dead.
4462
4463                 regMaskSmall regMask   = genRegPtrTemp->rpdCompiler.rpdDel & ptrRegs;
4464                 regMaskSmall byRefMask = 0;
4465                 if (genRegPtrTemp->rpdGCtypeGet() == GCT_BYREF)
4466                 {
4467                     byRefMask = regMask;
4468                 }
4469                 gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, genRegPtrTemp->rpdOffs, regMask, GC_SLOT_DEAD,
4470                                              byRefMask, &ptrRegs);
4471
4472                 // Record any registers that are becoming live.
4473                 regMask   = genRegPtrTemp->rpdCompiler.rpdAdd & ~ptrRegs;
4474                 byRefMask = 0;
4475                 // As far as I (DLD, 2010) can tell, there's one GCtype for the entire genRegPtrTemp, so if
4476                 // it says byref then all the registers in "regMask" contain byrefs.
4477                 if (genRegPtrTemp->rpdGCtypeGet() == GCT_BYREF)
4478                 {
4479                     byRefMask = regMask;
4480                 }
4481                 gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, genRegPtrTemp->rpdOffs, regMask, GC_SLOT_LIVE,
4482                                              byRefMask, &ptrRegs);
4483             }
4484         }
4485
4486         // Now we can declare the entire method body fully interruptible.
4487         if (mode == MAKE_REG_PTR_MODE_DO_WORK)
4488         {
4489             assert(prologSize <= codeSize);
4490
4491             // Now exempt any other region marked as IGF_NOGCINTERRUPT
4492             // Currently just prologs and epilogs.
4493
4494             InterruptibleRangeReporter reporter(prologSize, gcInfoEncoderWithLog);
4495             compiler->getEmitter()->emitGenNoGCLst(reporter);
4496             prologSize = reporter.prevStart;
4497
4498             // Report any remainder
4499             if (prologSize < codeSize)
4500             {
4501                 gcInfoEncoderWithLog->DefineInterruptibleRange(prologSize, codeSize - prologSize);
4502             }
4503         }
4504     }
4505     else if (compiler->isFramePointerUsed()) // genInterruptible is false, and we're using EBP as a frame pointer.
4506     {
4507         assert(compiler->genFullPtrRegMap == false);
4508
4509         // Walk the list of pointer register/argument entries.
4510
4511         // First count them.
4512         unsigned numCallSites = 0;
4513
4514         // Now we can allocate the information.
4515         unsigned* pCallSites     = nullptr;
4516         BYTE*     pCallSiteSizes = nullptr;
4517         unsigned  callSiteNum    = 0;
4518
4519         if (mode == MAKE_REG_PTR_MODE_DO_WORK)
4520         {
4521             if (gcCallDescList != nullptr)
4522             {
4523                 if (noTrackedGCSlots)
4524                 {
4525                     // We have the call count from the previous run.
4526                     numCallSites = *callCntRef;
4527
4528                     // If there are no calls, tell the world and bail.
4529                     if (numCallSites == 0)
4530                     {
4531                         gcInfoEncoderWithLog->DefineCallSites(nullptr, nullptr, 0);
4532                         return;
4533                     }
4534                 }
4535                 else
4536                 {
4537                     for (CallDsc* call = gcCallDescList; call != nullptr; call = call->cdNext)
4538                     {
4539                         numCallSites++;
4540                     }
4541                 }
4542                 pCallSites     = new (compiler, CMK_GC) unsigned[numCallSites];
4543                 pCallSiteSizes = new (compiler, CMK_GC) BYTE[numCallSites];
4544             }
4545         }
4546
4547         // Now consider every call.
4548         for (CallDsc* call = gcCallDescList; call != nullptr; call = call->cdNext)
4549         {
4550             // Figure out the code offset of this entry.
4551             unsigned nextOffset = call->cdOffs;
4552
4553             // As far as I (DLD, 2010) can determine by asking around, the "call->u1.cdArgMask"
4554             // and "cdArgCnt" cases are to handle x86 situations in which a call expression is nested as an
4555             // argument to an outer call.  The "natural" (evaluation-order-preserving) thing to do is to
4556             // evaluate the outer call's arguments, pushing those that are not enregistered, until you
4557             // encounter the nested call.  These parts of the call description, then, describe the "pending"
4558             // pushed arguments.  This situation does not exist outside of x86, where we're going to use a
4559             // fixed-size stack frame: in situations like this nested call, we would evaluate the pending
4560             // arguments to temporaries, and only "push" them (really, write them to the outgoing argument section
4561             // of the stack frame) when it's the outer call's "turn."  So we can assert that these
4562             // situations never occur.
4563             assert(call->u1.cdArgMask == 0 && call->cdArgCnt == 0);
4564
4565             // Other than that, we just have to deal with the regmasks.
4566             regMaskSmall gcrefRegMask = call->cdGCrefRegs & RBM_CALLEE_SAVED;
4567             regMaskSmall byrefRegMask = call->cdByrefRegs & RBM_CALLEE_SAVED;
4568
4569             assert((gcrefRegMask & byrefRegMask) == 0);
4570
4571             regMaskSmall regMask = gcrefRegMask | byrefRegMask;
4572
4573             assert(call->cdOffs >= call->cdCallInstrSize);
4574             // call->cdOffs is actually the offset of the instruction *following* the call, so subtract
4575             // the call instruction size to get the offset of the actual call instruction...
4576             unsigned callOffset = nextOffset - call->cdCallInstrSize;
4577
4578             if (noTrackedGCSlots && regMask == 0)
4579             {
4580                 // No live GC refs in regs at the call -> don't record the call.
4581             }
4582             else
4583             {
4584                 // Append an entry for the call if doing the real thing.
4585                 if (mode == MAKE_REG_PTR_MODE_DO_WORK)
4586                 {
4587                     pCallSites[callSiteNum]     = callOffset;
4588                     pCallSiteSizes[callSiteNum] = call->cdCallInstrSize;
4589                 }
4590                 callSiteNum++;
4591
4592                 // Record that these registers are live before the call...
4593                 gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, callOffset, regMask, GC_SLOT_LIVE, byrefRegMask,
4594                                              nullptr);
4595                 // ...and dead after.
4596                 gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, nextOffset, regMask, GC_SLOT_DEAD, byrefRegMask,
4597                                              nullptr);
4598             }
4599         }
4600         // Make sure we've recorded the expected number of calls
4601         assert(mode != MAKE_REG_PTR_MODE_DO_WORK || numCallSites == callSiteNum);
4602         // Return the actual recorded call count to the caller
4603         *callCntRef = callSiteNum;
4604
4605         // OK, define the call sites.
4606         if (mode == MAKE_REG_PTR_MODE_DO_WORK)
4607         {
4608             gcInfoEncoderWithLog->DefineCallSites(pCallSites, pCallSiteSizes, numCallSites);
4609         }
4610     }
4611     else // genInterruptible is false and we have an EBP-less frame
4612     {
4613         assert(compiler->genFullPtrRegMap);
4614
4615         // Walk the list of pointer register/argument entries */
4616         // First count them.
4617         unsigned numCallSites = 0;
4618
4619         // Now we can allocate the information (if we're in the "DO_WORK" pass...)
4620         unsigned* pCallSites     = nullptr;
4621         BYTE*     pCallSiteSizes = nullptr;
4622         unsigned  callSiteNum    = 0;
4623
4624         if (mode == MAKE_REG_PTR_MODE_DO_WORK)
4625         {
4626             for (regPtrDsc* genRegPtrTemp = gcRegPtrList; genRegPtrTemp != nullptr;
4627                  genRegPtrTemp            = genRegPtrTemp->rpdNext)
4628             {
4629                 if (genRegPtrTemp->rpdArg && genRegPtrTemp->rpdIsCallInstr())
4630                 {
4631                     numCallSites++;
4632                 }
4633             }
4634
4635             if (numCallSites > 0)
4636             {
4637                 pCallSites     = new (compiler, CMK_GC) unsigned[numCallSites];
4638                 pCallSiteSizes = new (compiler, CMK_GC) BYTE[numCallSites];
4639             }
4640         }
4641
4642         for (regPtrDsc* genRegPtrTemp = gcRegPtrList; genRegPtrTemp != nullptr; genRegPtrTemp = genRegPtrTemp->rpdNext)
4643         {
4644             if (genRegPtrTemp->rpdArg)
4645             {
4646                 // Is this a call site?
4647                 if (genRegPtrTemp->rpdIsCallInstr())
4648                 {
4649                     // This is a true call site.
4650
4651                     regMaskSmall gcrefRegMask = genRegMaskFromCalleeSavedMask(genRegPtrTemp->rpdCallGCrefRegs);
4652
4653                     regMaskSmall byrefRegMask = genRegMaskFromCalleeSavedMask(genRegPtrTemp->rpdCallByrefRegs);
4654
4655                     assert((gcrefRegMask & byrefRegMask) == 0);
4656
4657                     regMaskSmall regMask = gcrefRegMask | byrefRegMask;
4658
4659                     // The "rpdOffs" is (apparently) the offset of the following instruction already.
4660                     // GcInfoEncoder wants the call instruction, so subtract the width of the call instruction.
4661                     assert(genRegPtrTemp->rpdOffs >= genRegPtrTemp->rpdCallInstrSize);
4662                     unsigned callOffset = genRegPtrTemp->rpdOffs - genRegPtrTemp->rpdCallInstrSize;
4663
4664                     // Tell the GCInfo encoder about these registers.  We say that the registers become live
4665                     // before the call instruction, and dead after.
4666                     gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, callOffset, regMask, GC_SLOT_LIVE, byrefRegMask,
4667                                                  nullptr);
4668                     gcInfoRecordGCRegStateChange(gcInfoEncoder, mode, genRegPtrTemp->rpdOffs, regMask, GC_SLOT_DEAD,
4669                                                  byrefRegMask, nullptr);
4670
4671                     // Also remember the call site.
4672                     if (mode == MAKE_REG_PTR_MODE_DO_WORK)
4673                     {
4674                         assert(pCallSites != nullptr && pCallSiteSizes != nullptr);
4675                         pCallSites[callSiteNum]     = callOffset;
4676                         pCallSiteSizes[callSiteNum] = genRegPtrTemp->rpdCallInstrSize;
4677                         callSiteNum++;
4678                     }
4679                 }
4680                 else
4681                 {
4682                     // These are reporting outgoing stack arguments, but we don't need to report anything
4683                     // for partially interruptible
4684                     assert(genRegPtrTemp->rpdGCtypeGet() != GCT_NONE);
4685                     assert(genRegPtrTemp->rpdArgTypeGet() == rpdARG_PUSH);
4686                 }
4687             }
4688         }
4689         // The routine is fully interruptible.
4690         if (mode == MAKE_REG_PTR_MODE_DO_WORK)
4691         {
4692             gcInfoEncoderWithLog->DefineCallSites(pCallSites, pCallSiteSizes, numCallSites);
4693         }
4694     }
4695 }
4696
4697 void GCInfo::gcInfoRecordGCRegStateChange(GcInfoEncoder* gcInfoEncoder,
4698                                           MakeRegPtrMode mode,
4699                                           unsigned       instrOffset,
4700                                           regMaskSmall   regMask,
4701                                           GcSlotState    newState,
4702                                           regMaskSmall   byRefMask,
4703                                           regMaskSmall*  pPtrRegs)
4704 {
4705     // Precondition: byRefMask is a subset of regMask.
4706     assert((byRefMask & ~regMask) == 0);
4707
4708     GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder);
4709
4710     while (regMask)
4711     {
4712         // Get hold of the next register bit.
4713         regMaskTP tmpMask = genFindLowestReg(regMask);
4714         assert(tmpMask);
4715
4716         // Remember the new state of this register.
4717         if (pPtrRegs != nullptr)
4718         {
4719             if (newState == GC_SLOT_DEAD)
4720             {
4721                 *pPtrRegs &= ~tmpMask;
4722             }
4723             else
4724             {
4725                 *pPtrRegs |= tmpMask;
4726             }
4727         }
4728
4729         // Figure out which register the next bit corresponds to.
4730         regNumber regNum = genRegNumFromMask(tmpMask);
4731
4732         /* Reserve SP future use */
4733         assert(regNum != REG_SPBASE);
4734
4735         GcSlotFlags regFlags = GC_SLOT_BASE;
4736         if ((tmpMask & byRefMask) != 0)
4737         {
4738             regFlags = (GcSlotFlags)(regFlags | GC_SLOT_INTERIOR);
4739         }
4740
4741         RegSlotIdKey rskey(regNum, regFlags);
4742         GcSlotId     regSlotId;
4743         if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
4744         {
4745             if (!m_regSlotMap->Lookup(rskey, &regSlotId))
4746             {
4747                 regSlotId = gcInfoEncoderWithLog->GetRegisterSlotId(regNum, regFlags);
4748                 m_regSlotMap->Set(rskey, regSlotId);
4749             }
4750         }
4751         else
4752         {
4753             BOOL b = m_regSlotMap->Lookup(rskey, &regSlotId);
4754             assert(b); // Should have been added in the first pass.
4755             gcInfoEncoderWithLog->SetSlotState(instrOffset, regSlotId, newState);
4756         }
4757
4758         // Turn the bit we've just generated off and continue.
4759         regMask -= tmpMask; // EAX,ECX,EDX,EBX,---,EBP,ESI,EDI
4760     }
4761 }
4762
4763 /**************************************************************************
4764  *
4765  *  gcMakeVarPtrTable - Generate the table of tracked stack pointer
4766  *      variable lifetimes.
4767  *
4768  *  In the first pass we'll allocate slot Ids
4769  *  In the second pass we actually generate the lifetimes.
4770  *
4771  **************************************************************************
4772  */
4773
4774 void GCInfo::gcMakeVarPtrTable(GcInfoEncoder* gcInfoEncoder, MakeRegPtrMode mode)
4775 {
4776     GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder);
4777
4778     // Make sure any flags we hide in the offset are in the bits guaranteed
4779     // unused by alignment
4780     C_ASSERT((OFFSET_MASK + 1) <= sizeof(int));
4781
4782 #ifdef DEBUG
4783     if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
4784     {
4785         // Tracked variables can't be pinned, and the encoding takes
4786         // advantage of that by using the same bit for 'pinned' and 'this'
4787         // Since we don't track 'this', we should never see either flag here.
4788         // Check it now before we potentially add some pinned flags.
4789         for (varPtrDsc* varTmp = gcVarPtrList; varTmp != nullptr; varTmp = varTmp->vpdNext)
4790         {
4791             const unsigned flags = varTmp->vpdVarNum & OFFSET_MASK;
4792             assert((flags & pinned_OFFSET_FLAG) == 0);
4793             assert((flags & this_OFFSET_FLAG) == 0);
4794         }
4795     }
4796 #endif // DEBUG
4797
4798     // Only need to do this once, and only if we have EH.
4799     if ((mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS) && compiler->ehAnyFunclets())
4800     {
4801         gcMarkFilterVarsPinned();
4802     }
4803
4804     for (varPtrDsc* varTmp = gcVarPtrList; varTmp != nullptr; varTmp = varTmp->vpdNext)
4805     {
4806         C_ASSERT((OFFSET_MASK + 1) <= sizeof(int));
4807
4808         // Get hold of the variable's stack offset.
4809
4810         unsigned lowBits = varTmp->vpdVarNum & OFFSET_MASK;
4811
4812         // For negative stack offsets we must reset the low bits
4813         int varOffs = static_cast<int>(varTmp->vpdVarNum & ~OFFSET_MASK);
4814
4815         // Compute the actual lifetime offsets.
4816         unsigned begOffs = varTmp->vpdBegOfs;
4817         unsigned endOffs = varTmp->vpdEndOfs;
4818
4819         // Special case: skip any 0-length lifetimes.
4820         if (endOffs == begOffs)
4821         {
4822             continue;
4823         }
4824
4825         GcSlotFlags flags = GC_SLOT_BASE;
4826         if ((lowBits & byref_OFFSET_FLAG) != 0)
4827         {
4828             flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
4829         }
4830         if ((lowBits & pinned_OFFSET_FLAG) != 0)
4831         {
4832             flags = (GcSlotFlags)(flags | GC_SLOT_PINNED);
4833         }
4834
4835         GcStackSlotBase stackSlotBase = GC_SP_REL;
4836         if (compiler->isFramePointerUsed())
4837         {
4838             stackSlotBase = GC_FRAMEREG_REL;
4839         }
4840         StackSlotIdKey sskey(varOffs, (stackSlotBase == GC_FRAMEREG_REL), flags);
4841         GcSlotId       varSlotId;
4842         if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
4843         {
4844             if (!m_stackSlotMap->Lookup(sskey, &varSlotId))
4845             {
4846                 varSlotId = gcInfoEncoderWithLog->GetStackSlotId(varOffs, flags, stackSlotBase);
4847                 m_stackSlotMap->Set(sskey, varSlotId);
4848             }
4849         }
4850         else
4851         {
4852             BOOL b = m_stackSlotMap->Lookup(sskey, &varSlotId);
4853             assert(b); // Should have been added in the first pass.
4854             // Live from the beginning to the end.
4855             gcInfoEncoderWithLog->SetSlotState(begOffs, varSlotId, GC_SLOT_LIVE);
4856             gcInfoEncoderWithLog->SetSlotState(endOffs, varSlotId, GC_SLOT_DEAD);
4857         }
4858     }
4859 }
4860
4861 void GCInfo::gcInfoRecordGCStackArgLive(GcInfoEncoder* gcInfoEncoder, MakeRegPtrMode mode, regPtrDsc* genStackPtr)
4862 {
4863     // On non-x86 platforms, don't have pointer argument push/pop/kill declarations.
4864     // But we use the same mechanism to record writes into the outgoing argument space...
4865     assert(genStackPtr->rpdGCtypeGet() != GCT_NONE);
4866     assert(genStackPtr->rpdArg);
4867     assert(genStackPtr->rpdArgTypeGet() == rpdARG_PUSH);
4868
4869     // We only need to report these when we're doing fuly-interruptible
4870     assert(compiler->codeGen->genInterruptible);
4871
4872     GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder);
4873
4874     StackSlotIdKey sskey(genStackPtr->rpdPtrArg, FALSE,
4875                          GcSlotFlags(genStackPtr->rpdGCtypeGet() == GCT_BYREF ? GC_SLOT_INTERIOR : GC_SLOT_BASE));
4876     GcSlotId varSlotId;
4877     if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
4878     {
4879         if (!m_stackSlotMap->Lookup(sskey, &varSlotId))
4880         {
4881             varSlotId = gcInfoEncoderWithLog->GetStackSlotId(sskey.m_offset, (GcSlotFlags)sskey.m_flags, GC_SP_REL);
4882             m_stackSlotMap->Set(sskey, varSlotId);
4883         }
4884     }
4885     else
4886     {
4887         BOOL b = m_stackSlotMap->Lookup(sskey, &varSlotId);
4888         assert(b); // Should have been added in the first pass.
4889         // Live until the call.
4890         gcInfoEncoderWithLog->SetSlotState(genStackPtr->rpdOffs, varSlotId, GC_SLOT_LIVE);
4891     }
4892 }
4893
4894 void GCInfo::gcInfoRecordGCStackArgsDead(GcInfoEncoder* gcInfoEncoder,
4895                                          unsigned       instrOffset,
4896                                          regPtrDsc*     genStackPtrFirst,
4897                                          regPtrDsc*     genStackPtrLast)
4898 {
4899     // After a call all of the outgoing arguments are marked as dead.
4900     // The calling loop keeps track of the first argument pushed for this call
4901     // and passes it in as genStackPtrFirst.
4902     // genStackPtrLast is the call.
4903     // Re-walk that list and mark all outgoing arguments that we're marked as live
4904     // earlier, as going dead after the call.
4905
4906     // We only need to report these when we're doing fuly-interruptible
4907     assert(compiler->codeGen->genInterruptible);
4908
4909     GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder);
4910
4911     for (regPtrDsc* genRegPtrTemp = genStackPtrFirst; genRegPtrTemp != genStackPtrLast;
4912          genRegPtrTemp            = genRegPtrTemp->rpdNext)
4913     {
4914         if (!genRegPtrTemp->rpdArg)
4915         {
4916             continue;
4917         }
4918
4919         assert(genRegPtrTemp->rpdGCtypeGet() != GCT_NONE);
4920         assert(genRegPtrTemp->rpdArgTypeGet() == rpdARG_PUSH);
4921
4922         StackSlotIdKey sskey(genRegPtrTemp->rpdPtrArg, FALSE,
4923                              genRegPtrTemp->rpdGCtypeGet() == GCT_BYREF ? GC_SLOT_INTERIOR : GC_SLOT_BASE);
4924         GcSlotId varSlotId;
4925         BOOL     b = m_stackSlotMap->Lookup(sskey, &varSlotId);
4926         assert(b); // Should have been added in the first pass.
4927         // Live until the call.
4928         gcInfoEncoderWithLog->SetSlotState(instrOffset, varSlotId, GC_SLOT_DEAD);
4929     }
4930 }
4931
4932 #undef GCENCODER_WITH_LOGGING
4933
4934 #endif // !JIT32_GCENCODER
4935
4936 /*****************************************************************************/
4937 /*****************************************************************************/