Implement GcInfo v2 for X86
authorSwaroop Sridhar <swaroops@microsoft.com>
Mon, 22 Aug 2016 22:06:44 +0000 (15:06 -0700)
committerSwaroop Sridhar <swaroops@microsoft.com>
Wed, 14 Sep 2016 17:16:00 +0000 (10:16 -0700)
This commit includes the following changes:
1) Thread GcInfo version through X86 specific APIs
2) Add ReturnKind and ReversePinvokeOffset fields to InfoHdr structure
   GcInfo v1 and v2 use the same InfoHdr structures, because:
   InfoHdrSmall: ReturnKind is encoded within previously unused bits.
   InfoHdr: revPInvokeOffset will never be written to the image,
            since ReversePinvokeOffset==INVALID_REV_PINVOKE_OFFSET for V1.
3) Update the Pre-computed header table to include bits for the above
   [The default setting of ReturnKind=RT_Scalar is used for all entries in the table.
    Optimizing this table based in most frequent usage scenarios is to be done separately]
4) Change the GC encoder/decoder to handle the above two fields
5) Use the ReturnKind in the GCInfo from thread-suspension code.

GcInfo version is changed for CoreCLR X86 only, not for Desktop JIT
Fixes dotnet/coreclr#4379

Commit migrated from https://github.com/dotnet/coreclr/commit/4871121dbb7d1ee3282f9beb950cd73fb4f8a95b

20 files changed:
src/coreclr/src/debug/daccess/nidump.cpp
src/coreclr/src/gcdump/gcdumpnonx86.cpp
src/coreclr/src/gcdump/i386/gcdumpx86.cpp
src/coreclr/src/inc/eetwain.h
src/coreclr/src/inc/gcdecoder.cpp
src/coreclr/src/inc/gcdump.h
src/coreclr/src/inc/gcinfo.h
src/coreclr/src/inc/gcinfotypes.h
src/coreclr/src/jit/gcencode.cpp
src/coreclr/src/jit/jitgcinfo.h
src/coreclr/src/vm/codeman.h
src/coreclr/src/vm/debughelp.cpp
src/coreclr/src/vm/eedbginterfaceimpl.cpp
src/coreclr/src/vm/eetwain.cpp
src/coreclr/src/vm/excep.cpp
src/coreclr/src/vm/gccover.cpp
src/coreclr/src/vm/gcenv.ee.cpp
src/coreclr/src/vm/proftoeeinterfaceimpl.cpp
src/coreclr/src/vm/stackwalk.cpp
src/coreclr/src/vm/threadsuspend.cpp

index 32eab49..5c6c4e4 100644 (file)
@@ -3120,7 +3120,7 @@ void NativeImageDumper::DumpCompleteMethod(PTR_Module module, MethodIterator& mi
 #ifdef _TARGET_X86_
         InfoHdr hdr;
         stringOutFn( "method info Block:\n" );
-        curGCInfoPtr += gcDump.DumpInfoHdr(PTR_CBYTE(gcInfoToken.Info), &hdr, &methodSize, 0);
+        curGCInfoPtr += gcDump.DumpInfoHdr(curGCInfoPtr, &hdr, &methodSize, 0);
         stringOutFn( "\n" );
 #endif
 
@@ -9439,10 +9439,12 @@ void NativeImageDumper::DumpReadyToRunMethod(PCODE pEntryPoint, PTR_RUNTIME_FUNC
         g_holdStringOutData.Clear();
         GCDump gcDump(GCINFO_VERSION);
         gcDump.gcPrintf = stringOutFn;
-#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
         UINT32 r2rversion = m_pReadyToRunHeader->MajorVersion;
         UINT32 gcInfoVersion = GCInfoToken::ReadyToRunVersionToGcInfoVersion(r2rversion);
-        GcInfoDecoder gcInfoDecoder({ curGCInfoPtr, gcInfoVersion }, DECODE_CODE_LENGTH);
+        GCInfoToken gcInfoToken = { curGCInfoPtr, gcInfoVersion };
+
+#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
+        GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_CODE_LENGTH);
         methodSize = gcInfoDecoder.GetCodeLength();
 #endif
 
index 7343ac9..c2f41c9 100644 (file)
@@ -505,7 +505,7 @@ size_t      GCDump::DumpGCTable(PTR_CBYTE      gcInfoBlock,
 
 /*****************************************************************************/
 
-void    GCDump::DumpPtrsInFrame(PTR_CBYTE   infoBlock,
+void    GCDump::DumpPtrsInFrame(PTR_CBYTE   gcInfoBlock,
                                 PTR_CBYTE   codeBlock,
                                 unsigned    offs,
                                 bool        verifyGCTables)
index 70334de..0c90397 100644 (file)
@@ -60,12 +60,13 @@ const char *        CalleeSavedRegName(unsigned reg)
 
 /*****************************************************************************/
 
-unsigned            GCDump::DumpInfoHdr (PTR_CBYTE      table,
+unsigned            GCDump::DumpInfoHdr (PTR_CBYTE      gcInfoBlock,
                                          InfoHdr*       header,
                                          unsigned *     methodSize,
                                          bool           verifyGCTables)
 {
     unsigned        count;
+    PTR_CBYTE       table       = gcInfoBlock;
     PTR_CBYTE       tableStart  = table;
     PTR_CBYTE       bp          = table;
 
@@ -76,7 +77,7 @@ unsigned            GCDump::DumpInfoHdr (PTR_CBYTE      table,
 
     table += decodeUnsigned(table, methodSize);
 
-    table = decodeHeader(table, header);
+    table = decodeHeader(table, gcInfoVersion, header);
 
     BOOL hasArgTabOffset = FALSE;
     if (header->untrackedCnt == HAS_UNTRACKED)
@@ -107,6 +108,12 @@ unsigned            GCDump::DumpInfoHdr (PTR_CBYTE      table,
         header->syncEndOffset = count;
     }
 
+    if (header->revPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET)
+    {
+        table += decodeUnsigned(table, &count);
+        header->revPInvokeOffset = count;
+    }
+
     //
     // First print out all the basic information
     //
@@ -931,12 +938,12 @@ DONE_REGTAB:
 
 /*****************************************************************************/
 
-void                GCDump::DumpPtrsInFrame(PTR_CBYTE   infoBlock,
+void                GCDump::DumpPtrsInFrame(PTR_CBYTE   gcInfoBlock,
                                             PTR_CBYTE   codeBlock,
                                             unsigned    offs,
                                             bool        verifyGCTables)
 {
-    PTR_CBYTE       table = infoBlock;
+    PTR_CBYTE       table = gcInfoBlock;
 
     size_t          methodSize;
     size_t          stackSize;
@@ -963,7 +970,7 @@ void                GCDump::DumpPtrsInFrame(PTR_CBYTE   infoBlock,
     // Typically only uses one-byte to store everything.
     //
     InfoHdr header;
-    table = decodeHeader(table, &header);
+    table = decodeHeader(table, gcInfoVersion, &header);
     
     if (header.untrackedCnt == HAS_UNTRACKED)
     {
@@ -994,6 +1001,13 @@ void                GCDump::DumpPtrsInFrame(PTR_CBYTE   infoBlock,
         header.syncEndOffset = offset;
         _ASSERTE(offset != INVALID_SYNC_OFFSET);
     }
+    if (header.revPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET)
+    {
+        unsigned offset;
+        table += decodeUnsigned(table, &offset);
+        header.revPInvokeOffset = offset;
+        _ASSERTE(offset != INVALID_REV_PINVOKE_OFFSET);
+    }
 
     prologSize = header.prologSize;
     epilogSize = header.epilogSize;
index 6e183c5..502d181 100644 (file)
@@ -278,16 +278,16 @@ virtual void * GetGSCookieAddr(PREGDISPLAY     pContext,
   Returns true if the given IP is in the given method's prolog or an epilog.
 */
 virtual bool IsInPrologOrEpilog(DWORD  relPCOffset,
-                                PTR_VOID methodInfoPtr,
+                                GCInfoToken gcInfoToken,
                                 size_t* prologSize) = 0;
 
 /*
   Returns true if the given IP is in the synchronized region of the method (valid for synchronized methods only)
 */
 virtual bool IsInSynchronizedRegion(
-                DWORD           relOffset,
-                PTR_VOID        methodInfoPtr,
-                unsigned        flags) = 0;
+                DWORD       relOffset,
+                GCInfoToken gcInfoToken,
+                unsigned    flags) = 0;
 
 /*
   Returns the size of a given function as reported in the GC info (does
@@ -297,9 +297,15 @@ virtual bool IsInSynchronizedRegion(
 virtual size_t GetFunctionSize(GCInfoToken gcInfoToken) = 0;
 
 /*
+Returns the ReturnKind of a given function as reported in the GC info.
+*/
+
+virtual ReturnKind GetReturnKind(GCInfoToken gcInfotoken) = 0;
+
+/*
   Returns the size of the frame (barring localloc)
 */
-virtual unsigned int GetFrameSize(PTR_VOID methodInfoPtr) = 0;
+virtual unsigned int GetFrameSize(GCInfoToken gcInfoToken) = 0;
 
 #ifndef DACCESS_COMPILE
 
@@ -307,16 +313,16 @@ virtual unsigned int GetFrameSize(PTR_VOID methodInfoPtr) = 0;
 
 virtual const BYTE*     GetFinallyReturnAddr(PREGDISPLAY pReg)=0;
 
-virtual BOOL            IsInFilter(void *methodInfoPtr,
+virtual BOOL            IsInFilter(GCInfoToken gcInfoToken,
                                    unsigned offset,
                                    PCONTEXT pCtx,
                                    DWORD curNestLevel) = 0;
 
-virtual BOOL            LeaveFinally(void *methodInfoPtr,
+virtual BOOL            LeaveFinally(GCInfoToken gcInfoToken,
                                      unsigned offset,
                                      PCONTEXT pCtx) = 0;
 
-virtual void            LeaveCatch(void *methodInfoPtr,
+virtual void            LeaveCatch(GCInfoToken gcInfoToken,
                                    unsigned offset,
                                    PCONTEXT pCtx)=0;
 
@@ -535,18 +541,18 @@ void * GetGSCookieAddr(PREGDISPLAY     pContext,
 */
 virtual
 bool IsInPrologOrEpilog(
-                DWORD           relOffset,
-                PTR_VOID        methodInfoPtr,
-                size_t*         prologSize);
+                DWORD       relOffset,
+                GCInfoToken gcInfoToken,
+                size_t*     prologSize);
 
 /*
   Returns true if the given IP is in the synchronized region of the method (valid for synchronized functions only)
 */
 virtual
 bool IsInSynchronizedRegion(
-                DWORD           relOffset,
-                PTR_VOID        methodInfoPtr,
-                unsigned        flags);
+                DWORD       relOffset,
+                GCInfoToken gcInfoToken,
+                unsigned    flags);
 
 /*
   Returns the size of a given function.
@@ -555,23 +561,27 @@ virtual
 size_t GetFunctionSize(GCInfoToken gcInfoToken);
 
 /*
+Returns the ReturnKind of a given function.
+*/
+virtual ReturnKind GetReturnKind(GCInfoToken gcInfotoken);
+
+/*
   Returns the size of the frame (barring localloc)
 */
 virtual
-unsigned int GetFrameSize(
-                PTR_VOID        methodInfoPtr);
+unsigned int GetFrameSize(GCInfoToken gcInfoToken);
 
 #ifndef DACCESS_COMPILE
 
 virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg);
-virtual BOOL LeaveFinally(void *methodInfoPtr,
+virtual BOOL LeaveFinally(GCInfoToken gcInfoToken,
                           unsigned offset,
                           PCONTEXT pCtx);
-virtual BOOL IsInFilter(void *methodInfoPtr,
+virtual BOOL IsInFilter(GCInfoToken gcInfoToken,
                         unsigned offset,
                         PCONTEXT pCtx,
                           DWORD curNestLevel);
-virtual void LeaveCatch(void *methodInfoPtr,
+virtual void LeaveCatch(GCInfoToken gcInfoToken,
                          unsigned offset,
                          PCONTEXT pCtx);
 
@@ -646,8 +656,9 @@ struct hdrInfo
 {
     unsigned int        methodSize;     // native code bytes
     unsigned int        argSize;        // in bytes
-    unsigned int        stackSize;      /* including callee saved registers */
-    unsigned int        rawStkSize;     /* excluding callee saved registers */
+    unsigned int        stackSize;      // including callee saved registers
+    unsigned int        rawStkSize;     // excluding callee saved registers
+    ReturnKind          returnKind;     // The ReturnKind for this method.
 
     unsigned int        prologSize;
 
@@ -689,6 +700,7 @@ struct hdrInfo
     unsigned int        syncStartOffset; // start/end code offset of the protected region in synchronized methods.
     unsigned int        syncEndOffset;   // INVALID_SYNC_OFFSET if there not synchronized method
     unsigned int        syncEpilogStart; // The start of the epilog. Synchronized methods are guaranteed to have no more than one epilog.
+    unsigned int        revPInvokeOffset; // INVALID_REV_PINVOKE_OFFSET if there is no Reverse PInvoke frame
 
     enum { NOT_IN_PROLOG = -1, NOT_IN_EPILOG = -1 };
     
index d337fae..ae67236 100644 (file)
@@ -86,19 +86,20 @@ size_t FASTCALL decodeSigned(PTR_CBYTE src, int* val)
 #pragma optimize("tgy", on)
 #endif
 
-PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header)
+PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, UINT32 version, InfoHdr* header)
 {
     LIMITED_METHOD_DAC_CONTRACT;
 
-    BYTE byte = *table++;
-    BYTE encoding = byte & 0x7f;
-    
+    BYTE nextByte = *table++;
+    BYTE encoding = nextByte & 0x7f;
+    const BYTE maskHaveMoreBytesBit = MORE_BYTES_TO_FOLLOW - 1;
     GetInfoHdr(encoding, header);
-
-    while (byte & 0x80)
+    while (nextByte & MORE_BYTES_TO_FOLLOW)
     {
-        byte = *table++;
-        encoding = byte & 0x7f;
+        nextByte = *table++;
+        encoding = nextByte & maskHaveMoreBytesBit;
+        // encoding here always corresponds to codes in InfoHdrAdjust set
+
         if (encoding < NEXT_FOUR_START)
         {
             if (encoding < SET_ARGCOUNT)
@@ -126,6 +127,7 @@ PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header)
             else if (encoding < FIRST_FLIP)
             {
                 header->untrackedCnt = encoding - SET_UNTRACKED;
+                _ASSERTE(header->untrackedCnt != HAS_UNTRACKED);
             }
             else switch (encoding)
             {
@@ -145,22 +147,22 @@ PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header)
                 header->ebpSaved ^= 1;
                 break;
             case FLIP_EBP_FRAME:
-                header->ebpFrame  ^= 1;
+                header->ebpFrame ^= 1;
                 break;
             case FLIP_INTERRUPTIBLE:
-                header->interruptible  ^= 1;
+                header->interruptible ^= 1;
                 break;
             case FLIP_DOUBLE_ALIGN:
-                header->doubleAlign  ^= 1;
+                header->doubleAlign ^= 1;
                 break;
             case FLIP_SECURITY:
-                header->security  ^= 1;
+                header->security ^= 1;
                 break;
             case FLIP_HANDLERS:
-                header->handlers  ^= 1;
+                header->handlers ^= 1;
                 break;
             case FLIP_LOCALLOC:
-                header->localloc  ^= 1;
+                header->localloc ^= 1;
                 break;
             case FLIP_EDITnCONTINUE:
                 header->editNcontinue ^= 1;
@@ -172,10 +174,10 @@ PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header)
                 header->untrackedCnt = HAS_UNTRACKED;
                 break;
             case FLIP_VARARGS:
-                header->varargs  ^= 1;
+                header->varargs ^= 1;
                 break;
             case FLIP_PROF_CALLBACKS:
-                header->profCallbacks  ^= 1;
+                header->profCallbacks ^= 1;
                 break;
             case FLIP_HAS_GENERICS_CONTEXT:
                 header->genericsContext ^= 1;
@@ -189,6 +191,27 @@ PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header)
             case FLIP_SYNC:
                 header->syncStartOffset ^= HAS_SYNC_OFFSET;
                 break;
+            case FLIP_REV_PINVOKE_FRAME:
+                _ASSERTE(GCInfoEncodesRevPInvokeFrame(version));
+                header->revPInvokeOffset ^= HAS_REV_PINVOKE_FRAME_OFFSET;
+                break;
+
+            case NEXT_OPCODE:
+                _ASSERTE((nextByte & MORE_BYTES_TO_FOLLOW) && "Must have another code");
+                nextByte = *table++;
+                encoding = nextByte & maskHaveMoreBytesBit;
+                // encoding here always corresponds to codes in InfoHdrAdjust2 set
+
+                if (encoding < SET_RET_KIND_MAX)
+                {
+                    _ASSERTE(GCInfoEncodesReturnKind(version));
+                    header->returnKind = (ReturnKind)encoding;
+                }
+                else
+                {
+                    assert(!"Unexpected encoding");
+                }
+                break;
             }
         }
         else
@@ -202,14 +225,14 @@ PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header)
             case 5:
                 assert(NEXT_FOUR_FRAMESIZE == 0x50);
                 lowBits = encoding & 0xf;
-                header->frameSize  <<= 4;
-                header->frameSize   += lowBits;
+                header->frameSize <<= 4;
+                header->frameSize += lowBits;
                 break;
             case 6:
                 assert(NEXT_FOUR_ARGCOUNT == 0x60);
                 lowBits = encoding & 0xf;
-                header->argCount   <<= 4;
-                header->argCount    += lowBits;
+                header->argCount <<= 4;
+                header->argCount += lowBits;
                 break;
             case 7:
                 if ((encoding & 0x8) == 0)
@@ -217,14 +240,14 @@ PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header)
                     assert(NEXT_THREE_PROLOGSIZE == 0x70);
                     lowBits = encoding & 0x7;
                     header->prologSize <<= 3;
-                    header->prologSize  += lowBits;
+                    header->prologSize += lowBits;
                 }
                 else
                 {
                     assert(NEXT_THREE_EPILOGSIZE == 0x78);
                     lowBits = encoding & 0x7;
                     header->epilogSize <<= 3;
-                    header->epilogSize  += lowBits;
+                    header->epilogSize += lowBits;
                 }
                 break;
             }
@@ -293,154 +316,155 @@ const InfoHdrSmall infoHdrShortcut[128] = {
 //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
 //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  genericsContext
 //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   genericsContextIsMethodDesc
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   Arg count
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |                                 Counted occurances
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   Frame size                    |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |                             |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   untrackedCnt              |   Header encoding
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |                         |   |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |  varPtrTable            |   |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |   |                     |   |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |   |  gsCookieOffs       |   |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |   |   |                 |   |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |   |   | syncOffs        |   |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |   |   |  |  |           |   |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |   |   |  |  |           |   |
-//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |   |   |  |  |           |   |
-//        v   v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v   v   v   v   v   v   v  v  v           v   v
-       {  0,  1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    1139  00
-       {  0,  1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //  128738  01
-       {  0,  1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    3696  02
-       {  0,  1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     402  03
-       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //    4259  04
-       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  1,  0          },  //    3379  05
-       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  0,  0          },  //    2058  06
-       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  1,  0          },  //     728  07
-       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  2,  0          },  //     984  08
-       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  3,  0,  0,  0          },  //     606  09
-       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  4,  0,  0,  0          },  //    1110  0a
-       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  4,  0,  1,  0          },  //     414  0b
-       {  1,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //    1553  0c
-       {  1,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  1,  0, YES         },  //     584  0d
-       {  1,  2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //    2182  0e
-       {  1,  2, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    3445  0f
-       {  1,  2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //    1369  10
-       {  1,  2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     515  11
-       {  1,  2, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //   21127  12
-       {  1,  2, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    3517  13
-       {  1,  2, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     750  14
-       {  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //    1876  15
-       {  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  1,  0          },  //    1665  16
-       {  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  0,  0          },  //     729  17
-       {  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  2,  0          },  //     484  18
-       {  1,  4, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //     331  19
-       {  2,  3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //     361  1a
-       {  2,  3, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     964  1b
-       {  2,  3, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    3713  1c
-       {  2,  3, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     466  1d
-       {  2,  3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //    1325  1e
-       {  2,  3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //     712  1f
-       {  2,  3, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     588  20
-       {  2,  3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //   20542  21
-       {  2,  3, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    3802  22
-       {  2,  3, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     798  23
-       {  2,  5, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //    1900  24
-       {  2,  5, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  0,  0          },  //     385  25
-       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //    1617  26
-       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  1,  0          },  //    1743  27
-       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  0,  0          },  //     909  28
-       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  1,  0          },  //     602  29
-       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  2,  0          },  //     352  2a
-       {  2,  6, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //     657  2b
-       {  2,  7, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  0,  0, YES         },  //    1283  2c
-       {  2,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //    1286  2d
-       {  3,  4, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //    1495  2e
-       {  3,  4, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    1989  2f
-       {  3,  4, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //    1154  30
-       {  3,  4, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    9300  31
-       {  3,  4, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //     392  32
-       {  3,  4, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    1720  33
-       {  3,  6, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //    1246  34
-       {  3,  6, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  0,  0          },  //     800  35
-       {  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //    1179  36
-       {  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  1,  0          },  //    1368  37
-       {  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  0,  0          },  //     349  38
-       {  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  2,  0          },  //     505  39
-       {  3,  6, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //     629  3a
-       {  3,  8, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  9,  2, YES         },  //     365  3b
-       {  4,  5, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //     487  3c
-       {  4,  5, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    1752  3d
-       {  4,  5, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //    1959  3e
-       {  4,  5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    2436  3f
-       {  4,  5, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     861  40
-       {  4,  7, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //    1459  41
-       {  4,  7, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  0,  0          },  //     950  42
-       {  4,  7, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //    1491  43
-       {  4,  7, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  1,  0          },  //     879  44
-       {  4,  7, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  0,  0,  0          },  //     408  45
-       {  5,  4, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //    4870  46
-       {  5,  6, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //     359  47
-       {  5,  6, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  2,  0,  0          },  //     915  48
-       {  5,  6, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  4,  0,  0          },  //     412  49
-       {  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //    1288  4a
-       {  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //    1591  4b
-       {  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  1,  0, YES         },  //     361  4c
-       {  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  1,  0,  0          },  //     623  4d
-       {  5,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  1,  0,  0          },  //    1239  4e
-       {  6,  0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     457  4f
-       {  6,  0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     606  50
-       {  6,  4, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  2,  0, YES         },  //    1073  51
-       {  6,  4, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  2,  0, YES         },  //     508  52
-       {  6,  6, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //     330  53
-       {  6,  6, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //    1709  54
-       {  6,  7, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  2,  0,  0          },  //    1164  55
-       {  7,  4, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0          },  //     556  56
-       {  7,  5, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  3,  0, YES         },  //     529  57
-       {  7,  5, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  5,  0, YES         },  //    1423  58
-       {  7,  8, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  3,  0, YES         },  //    2455  59
-       {  7,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  2,  0,  0          },  //     956  5a
-       {  7,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  2,  0, YES         },  //    1399  5b
-       {  7,  8, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  3,  0, YES         },  //     587  5c
-       {  7, 10, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  6,  1, YES         },  //     743  5d
-       {  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  2,  0,  0          },  //    1004  5e
-       {  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  2,  1, YES         },  //     487  5f
-       {  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  2,  0,  0          },  //     337  60
-       {  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  3,  0, YES         },  //     361  61
-       {  8,  3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  1,  0          },  //     560  62
-       {  8,  6, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  2,  0,  0          },  //    1377  63
-       {  9,  4, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  1,  0          },  //     877  64
-       {  9,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  2,  0,  0          },  //    3041  65
-       {  9,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  0,  0, YES         },  //     349  66
-       { 10,  5, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  4,  1,  0          },  //    2061  67
-       { 10,  5, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  1,  0          },  //     577  68
-       { 11,  6, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  4,  1,  0          },  //    1195  69
-       { 12,  5, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0,  0          },  //     491  6a
-       { 13,  8, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  9,  0, YES         },  //     627  6b
-       { 13,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  2,  1,  0          },  //    1099  6c
-       { 13, 10, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  2,  6,  1, YES         },  //     488  6d
-       { 14,  7, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //     574  6e
-       { 16,  7, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  4,  0, YES         },  //    1281  6f
-       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  0,  0, YES         },  //    1881  70
-       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //     339  71
-       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  3,  0,  0          },  //    2594  72
-       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  4,  0,  0          },  //     339  73
-       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  4,  0, YES         },  //    2107  74
-       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  5,  0, YES         },  //    2372  75
-       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  6,  0, YES         },  //    1078  76
-       { 16,  7, 2, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  4,  0, YES         },  //     384  77
-       { 16,  9, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  1,  4,  1, YES         },  //    1541  78
-       { 16,  9, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  2,  4,  1, YES         },  //     975  79
-       { 19,  7, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  5,  0, YES         },  //     546  7a
-       { 24,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,  0,  0,  5,  0, YES         },  //     675  7b
-       { 45,  9, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  1,  0,  0,  0          },  //     902  7c
-       { 51,  7, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, 13,  0, YES         },  //     432  7d
-       { 51,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  1,  0, YES         },  //     361  7e
-       { 51,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, 11,  0,  0          },  //     703  7f
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  genericsContextIsMethodDesc
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  returnKind
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  Arg count
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |                                 Counted occurences
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   Frame size                    |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |                             |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   untrackedCnt              |   Header encoding
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |                         |   |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |  varPtrTable            |   |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |                     |   |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |  gsCookieOffs       |   |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |                 |   |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   | syncOffs        |   |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |  |  |           |   |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |  |  |           |   |
+//        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |  |  |           |   |
+//        v   v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v   v   v   v   v  v  v           v   v
+       {  0,  1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    1139  00
+       {  0,  1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //  128738  01
+       {  0,  1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    3696  02
+       {  0,  1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     402  03
+       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //    4259  04
+       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          },  //    3379  05
+       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          },  //    2058  06
+       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  1,  0          },  //     728  07
+       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  2,  0          },  //     984  08
+       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,  0,  0,  0          },  //     606  09
+       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,  0,  0,  0          },  //    1110  0a
+       {  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,  0,  1,  0          },  //     414  0b
+       {  1,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //    1553  0c
+       {  1,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  1,  0, YES         },  //     584  0d
+       {  1,  2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //    2182  0e
+       {  1,  2, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    3445  0f
+       {  1,  2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //    1369  10
+       {  1,  2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     515  11
+       {  1,  2, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //   21127  12
+       {  1,  2, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    3517  13
+       {  1,  2, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     750  14
+       {  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //    1876  15
+       {  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          },  //    1665  16
+       {  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          },  //     729  17
+       {  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  2,  0          },  //     484  18
+       {  1,  4, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //     331  19
+       {  2,  3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //     361  1a
+       {  2,  3, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     964  1b
+       {  2,  3, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    3713  1c
+       {  2,  3, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     466  1d
+       {  2,  3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //    1325  1e
+       {  2,  3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //     712  1f
+       {  2,  3, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     588  20
+       {  2,  3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //   20542  21
+       {  2,  3, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    3802  22
+       {  2,  3, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     798  23
+       {  2,  5, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //    1900  24
+       {  2,  5, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          },  //     385  25
+       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //    1617  26
+       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          },  //    1743  27
+       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          },  //     909  28
+       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  1,  0          },  //     602  29
+       {  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  2,  0          },  //     352  2a
+       {  2,  6, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //     657  2b
+       {  2,  7, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, YES         },  //    1283  2c
+       {  2,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //    1286  2d
+       {  3,  4, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //    1495  2e
+       {  3,  4, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    1989  2f
+       {  3,  4, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //    1154  30
+       {  3,  4, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    9300  31
+       {  3,  4, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //     392  32
+       {  3,  4, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    1720  33
+       {  3,  6, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //    1246  34
+       {  3,  6, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          },  //     800  35
+       {  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //    1179  36
+       {  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          },  //    1368  37
+       {  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          },  //     349  38
+       {  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  2,  0          },  //     505  39
+       {  3,  6, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //     629  3a
+       {  3,  8, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  9,  2, YES         },  //     365  3b
+       {  4,  5, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //     487  3c
+       {  4,  5, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    1752  3d
+       {  4,  5, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //    1959  3e
+       {  4,  5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    2436  3f
+       {  4,  5, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     861  40
+       {  4,  7, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //    1459  41
+       {  4,  7, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          },  //     950  42
+       {  4,  7, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //    1491  43
+       {  4,  7, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          },  //     879  44
+       {  4,  7, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          },  //     408  45
+       {  5,  4, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //    4870  46
+       {  5,  6, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //     359  47
+       {  5,  6, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          },  //     915  48
+       {  5,  6, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0,  0          },  //     412  49
+       {  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //    1288  4a
+       {  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //    1591  4b
+       {  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  1,  0, YES         },  //     361  4c
+       {  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  1,  0,  0          },  //     623  4d
+       {  5,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  1,  0,  0          },  //    1239  4e
+       {  6,  0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     457  4f
+       {  6,  0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     606  50
+       {  6,  4, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0, YES         },  //    1073  51
+       {  6,  4, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0, YES         },  //     508  52
+       {  6,  6, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //     330  53
+       {  6,  6, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //    1709  54
+       {  6,  7, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          },  //    1164  55
+       {  7,  4, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          },  //     556  56
+       {  7,  5, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  3,  0, YES         },  //     529  57
+       {  7,  5, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  5,  0, YES         },  //    1423  58
+       {  7,  8, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  3,  0, YES         },  //    2455  59
+       {  7,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          },  //     956  5a
+       {  7,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0, YES         },  //    1399  5b
+       {  7,  8, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  3,  0, YES         },  //     587  5c
+       {  7, 10, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  6,  1, YES         },  //     743  5d
+       {  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  2,  0,  0          },  //    1004  5e
+       {  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  2,  1, YES         },  //     487  5f
+       {  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  2,  0,  0          },  //     337  60
+       {  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  3,  0, YES         },  //     361  61
+       {  8,  3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  1,  0          },  //     560  62
+       {  8,  6, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          },  //    1377  63
+       {  9,  4, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  1,  0          },  //     877  64
+       {  9,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          },  //    3041  65
+       {  9,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, YES         },  //     349  66
+       { 10,  5, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  4,  1,  0          },  //    2061  67
+       { 10,  5, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  1,  0          },  //     577  68
+       { 11,  6, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  4,  1,  0          },  //    1195  69
+       { 12,  5, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          },  //     491  6a
+       { 13,  8, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  9,  0, YES         },  //     627  6b
+       { 13,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  1,  0          },  //    1099  6c
+       { 13, 10, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  6,  1, YES         },  //     488  6d
+       { 14,  7, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //     574  6e
+       { 16,  7, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0, YES         },  //    1281  6f
+       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, YES         },  //    1881  70
+       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //     339  71
+       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  3,  0,  0          },  //    2594  72
+       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0,  0          },  //     339  73
+       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0, YES         },  //    2107  74
+       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  5,  0, YES         },  //    2372  75
+       { 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  6,  0, YES         },  //    1078  76
+       { 16,  7, 2, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0, YES         },  //     384  77
+       { 16,  9, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,  4,  1, YES         },  //    1541  78
+       { 16,  9, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2,  4,  1, YES         },  //     975  79
+       { 19,  7, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  5,  0, YES         },  //     546  7a
+       { 24,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  5,  0, YES         },  //     675  7b
+       { 45,  9, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          },  //     902  7c
+       { 51,  7, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13,  0, YES         },  //     432  7d
+       { 51,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         },  //     361  7e
+       { 51,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11,  0,  0          },  //     703  7f
 };
 
-
 bool InfoHdrSmall::isHeaderMatch(const InfoHdr& target) const
 {
 #ifdef _ASSERTE
@@ -448,7 +472,8 @@ bool InfoHdrSmall::isHeaderMatch(const InfoHdr& target) const
     _ASSERTE(target.untrackedCnt != HAS_UNTRACKED &&
                 target.varPtrTableSize != HAS_VARPTR &&
                 target.gsCookieOffset != HAS_GS_COOKIE_OFFSET &&
-                target.syncStartOffset != HAS_SYNC_OFFSET);
+                target.syncStartOffset != HAS_SYNC_OFFSET && 
+                target.revPInvokeOffset != HAS_REV_PINVOKE_FRAME_OFFSET);
 #endif
 
     // compare two InfoHdr's up to but not including the untrackCnt field
@@ -470,7 +495,13 @@ bool InfoHdrSmall::isHeaderMatch(const InfoHdr& target) const
     if (target.gsCookieOffset != INVALID_GS_COOKIE_OFFSET)
         return false;
 
-    return target.syncStartOffset == INVALID_SYNC_OFFSET;
+    if (target.syncStartOffset != INVALID_SYNC_OFFSET)
+        return false;
+
+    if (target.revPInvokeOffset!= INVALID_REV_PINVOKE_OFFSET)
+        return false;
+
+    return true;
 }
 
 
@@ -503,7 +534,7 @@ const unsigned callCommonDelta[4] = { 6,8,10,12 };
  *   EDI = 0x1, ESI = 0x2, EBX = 0x4, EBP = 0x8
  *
  */
-const unsigned callPatternTable[80] = {               // # of occurances
+const unsigned callPatternTable[80] = {               // # of occurences
     0x0a000200, //   30109
     0x0c000200, //   22970
     0x0c000201, //   19005
index cd73940..3271ca1 100644 (file)
@@ -45,7 +45,7 @@ public:
      * Return value     : Size in bytes of the header encoding
      */
 
-    unsigned FASTCALL   DumpInfoHdr (PTR_CBYTE      gcInfoBlock,
+    unsigned FASTCALL   DumpInfoHdr (PTR_CBYTE   gcInfoBlock,
                                      InfoHdr    *   header,         /* OUT */
                                      unsigned   *   methodSize,     /* OUT */
                                      bool           verifyGCTables = false);
@@ -53,7 +53,7 @@ public:
 
     /*-------------------------------------------------------------------------
      * Dumps the GC tables to 'stdout'
-     * table            : The GCInfoToken
+     * gcInfoBlock      : Start of the GC info block
      * verifyGCTables   : If the JIT has been compiled with VERIFY_GC_TABLES
      * Return value     : Size in bytes of the GC table encodings
      */
@@ -70,10 +70,10 @@ public:
      * verifyGCTables   : If the JIT has been compiled with VERIFY_GC_TABLES
      */
 
-    void     FASTCALL   DumpPtrsInFrame(PTR_CBYTE   infoBlock,
-                                     PTR_CBYTE      codeBlock,
-                                     unsigned       offs,
-                                     bool           verifyGCTables = false);
+    void     FASTCALL   DumpPtrsInFrame(PTR_CBYTE   gcInfoBlock,
+                                        PTR_CBYTE   codeBlock,
+                                        unsigned    offs,
+                                        bool        verifyGCTables = false);
 
 
 public:
index 8d249a3..acfc072 100644 (file)
@@ -32,8 +32,8 @@ const unsigned   this_OFFSET_FLAG  = 0x2;  // the offset is "this"
 // The current GCInfo Version
 //-----------------------------------------------------------------------------
 
-#ifdef _TARGET_X86_
-// X86 GcInfo encoding is yet to be changed.
+#if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
+// X86 GcInfo encoding is yet to be changed for Desktop JIT32.         
 #define GCINFO_VERSION 1
 #else
 #define GCINFO_VERSION 2
@@ -41,6 +41,17 @@ const unsigned   this_OFFSET_FLAG  = 0x2;  // the offset is "this"
 
 #define MIN_GCINFO_VERSION_WITH_RETURN_KIND 2
 #define MIN_GCINFO_VERSION_WITH_REV_PINVOKE_FRAME 2
+
+inline BOOL GCInfoEncodesReturnKind(UINT32 version=GCINFO_VERSION)
+{
+    return version >= MIN_GCINFO_VERSION_WITH_RETURN_KIND;
+}
+
+inline BOOL GCInfoEncodesRevPInvokeFrame(UINT32 version=GCINFO_VERSION)
+{
+    return version >= MIN_GCINFO_VERSION_WITH_REV_PINVOKE_FRAME;
+}
+
 //-----------------------------------------------------------------------------
 // GCInfoToken: A wrapper that contains the GcInfo data and version number.
 //
@@ -62,11 +73,11 @@ struct GCInfoToken
 
     BOOL IsReturnKindAvailable() 
     {
-        return (Version >= MIN_GCINFO_VERSION_WITH_RETURN_KIND);
+        return GCInfoEncodesReturnKind(Version);
     }
     BOOL IsReversePInvokeFrameAvailable() 
     {
-        return (Version >= MIN_GCINFO_VERSION_WITH_REV_PINVOKE_FRAME);
+        return GCInfoEncodesRevPInvokeFrame(Version);
     }
 
     static UINT32 ReadyToRunVersionToGcInfoVersion(UINT32 readyToRunMajorVersion)
index cd19759..1edb5f3 100644 (file)
@@ -376,12 +376,15 @@ enum infoHdrAdjustConstants {
     SET_PROLOGSIZE_MAX = 16,
     SET_EPILOGSIZE_MAX = 10,  // Change to 6
     SET_EPILOGCNT_MAX = 4,
-    SET_UNTRACKED_MAX = 3
+    SET_UNTRACKED_MAX = 3,
+    SET_RET_KIND_MAX = 4,   // 2 bits for ReturnKind
+    MORE_BYTES_TO_FOLLOW = 0x80 // If the High-bit of a header or adjustment byte 
+                               // is set, then there are more adjustments to follow.
 };
 
 //
-// Enum to define the 128 codes that are used to incrementally adjust the InfoHdr structure
-//
+// Enum to define codes that are used to incrementally adjust the InfoHdr structure.
+// First set of opcodes
 enum infoHdrAdjust {
 
     SET_FRAMESIZE = 0,                                            // 0x00
@@ -412,18 +415,25 @@ enum infoHdrAdjust {
     FLIP_SYNC,                // 0x4B
     FLIP_HAS_GENERICS_CONTEXT,// 0x4C
     FLIP_GENERICS_CONTEXT_IS_METHODDESC,// 0x4D
+    FLIP_REV_PINVOKE_FRAME,   // 0x4E
+    NEXT_OPCODE,              // 0x4F -- see next Adjustment enumeration
+    NEXT_FOUR_START = 0x50,
+    NEXT_FOUR_FRAMESIZE = 0x50,
+    NEXT_FOUR_ARGCOUNT = 0x60,
+    NEXT_THREE_PROLOGSIZE = 0x70,
+    NEXT_THREE_EPILOGSIZE = 0x78
+};
 
-                                        // 0x4E .. 0x4f unused
-
-                                        NEXT_FOUR_START = 0x50,
-                                        NEXT_FOUR_FRAMESIZE = 0x50,
-                                        NEXT_FOUR_ARGCOUNT = 0x60,
-                                        NEXT_THREE_PROLOGSIZE = 0x70,
-                                        NEXT_THREE_EPILOGSIZE = 0x78
+// Second set of opcodes, when first code is 0x4F
+enum infoHdrAdjust2 {
+    SET_RETURNKIND = 0,  // 0x00-SET_RET_KIND_MAX Set ReturnKind to value
 };
 
 #define HAS_UNTRACKED               ((unsigned int) -1)
 #define HAS_VARPTR                  ((unsigned int) -1)
+
+#define INVALID_REV_PINVOKE_OFFSET   0
+#define HAS_REV_PINVOKE_FRAME_OFFSET ((unsigned int) -1)
 // 0 is not a valid offset for EBP-frames as all locals are at a negative offset
 // For ESP frames, the cookie is above (at a higher address than) the buffers, 
 // and so cannot be at offset 0.
@@ -463,6 +473,7 @@ struct InfoHdrSmall {
     unsigned char  profCallbacks : 1; // 4 [0]
     unsigned char  genericsContext : 1;//4 [1]      function reports a generics context parameter is present
     unsigned char  genericsContextIsMethodDesc : 1;//4[2]
+    unsigned char  returnKind : 2; // 4 [4]  Available GcInfo v2 onwards, previously undefined 
     unsigned short argCount;          // 5,6        in bytes
     unsigned int   frameSize;         // 7,8,9,10   in bytes
     unsigned int   untrackedCnt;      // 11,12,13,14
@@ -483,8 +494,8 @@ struct InfoHdr : public InfoHdrSmall {
     unsigned int   gsCookieOffset;    // 19,20,21,22
     unsigned int   syncStartOffset;   // 23,24,25,26
     unsigned int   syncEndOffset;     // 27,28,29,30
-
-                                      // 31 bytes total
+    unsigned int   revPInvokeOffset;  // 31,32,33,34 Available GcInfo v2 onwards, previously undefined 
+                                      // 35 bytes total
 
                                       // Checks whether "this" is compatible with "target".
                                       // It is not an exact bit match as "this" could have some 
@@ -498,7 +509,8 @@ struct InfoHdr : public InfoHdrSmall {
         _ASSERTE(target.untrackedCnt != HAS_UNTRACKED &&
             target.varPtrTableSize != HAS_VARPTR &&
             target.gsCookieOffset != HAS_GS_COOKIE_OFFSET &&
-            target.syncStartOffset != HAS_SYNC_OFFSET);
+            target.syncStartOffset != HAS_SYNC_OFFSET && 
+            target.revPInvokeOffset != HAS_REV_PINVOKE_FRAME_OFFSET);
 #endif
 
         // compare two InfoHdr's up to but not including the untrackCnt field
@@ -525,6 +537,10 @@ struct InfoHdr : public InfoHdrSmall {
             (target.syncStartOffset == INVALID_SYNC_OFFSET))
             return false;
 
+        if ((revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET) !=
+            (target.revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET))
+            return false;
+
         return true;
     }
 };
@@ -551,15 +567,16 @@ inline void GetInfoHdr(int index, InfoHdr * header)
 {
     *((InfoHdrSmall *)header) = infoHdrShortcut[index];
 
-    header->gsCookieOffset = 0;
-    header->syncStartOffset = 0;
-    header->syncEndOffset = 0;
+    header->gsCookieOffset = INVALID_GS_COOKIE_OFFSET;
+    header->syncStartOffset = INVALID_SYNC_OFFSET;
+    header->syncEndOffset = INVALID_SYNC_OFFSET;
+    header->revPInvokeOffset = INVALID_REV_PINVOKE_OFFSET;
 }
 
-PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header);
+PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, UINT32 version, InfoHdr* header);
 
 BYTE FASTCALL encodeHeaderFirst(const InfoHdr& header, InfoHdr* state, int* more, int *pCached);
-BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state);
+BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state, BYTE &codeSet);
 
 size_t FASTCALL decodeUnsigned(PTR_CBYTE src, unsigned* value);
 size_t FASTCALL decodeUDelta(PTR_CBYTE src, unsigned* value, unsigned lastValue);
index f20183b..f2627e0 100644 (file)
@@ -23,6 +23,89 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 
 #include "gcinfotypes.h"
 
+ReturnKind GCTypeToReturnKind(CorInfoGCType gcType)
+{
+    switch (gcType)
+    {
+    case TYPE_GC_NONE:
+        return RT_Scalar;
+    case TYPE_GC_REF:
+        return RT_Object;
+    case TYPE_GC_BYREF:
+        return RT_ByRef;
+    default:
+        _ASSERTE(!"TYP_GC_OTHER is unexpected");
+        return RT_Illegal;
+    }
+}
+
+ReturnKind GCInfo::getReturnKind()
+{
+    switch (compiler->info.compRetType)
+    {
+    case TYP_REF:
+    case TYP_ARRAY:
+        return RT_Object;
+    case TYP_BYREF:
+        return RT_ByRef;
+    case TYP_STRUCT:
+    {
+        CORINFO_CLASS_HANDLE structType = compiler->info.compMethodInfo->args.retTypeClass;
+        var_types retType = compiler->getReturnTypeForStruct(structType);
+
+        switch (retType)
+        {
+        case TYP_ARRAY:
+            _ASSERTE(false && "TYP_ARRAY unexpected from getReturnTypeForStruct()");
+            // fall through
+        case TYP_REF:
+            return RT_Object;
+
+        case TYP_BYREF:
+            return RT_ByRef;
+
+        case TYP_STRUCT:
+            if (compiler->IsHfa(structType))
+            {
+#ifdef _TARGET_X86_
+                _ASSERTE(false && "HFAs not expected for X86");
+#endif // _TARGET_X86_
+
+                return RT_Scalar;
+            }
+            else
+            {
+                // Multi-reg return
+                BYTE gcPtrs[2] = { TYPE_GC_NONE, TYPE_GC_NONE };
+                compiler->info.compCompHnd->getClassGClayout(structType, gcPtrs);
+
+                ReturnKind first = GCTypeToReturnKind((CorInfoGCType)gcPtrs[0]);
+                ReturnKind second = GCTypeToReturnKind((CorInfoGCType)gcPtrs[1]);
+
+                return GetStructReturnKind(first, second);
+            }
+
+#ifdef _TARGET_X86_
+        case TYP_FLOAT:
+        case TYP_DOUBLE:
+            return RT_Float;
+#endif // _TARGET_X86_
+        default:
+            return RT_Scalar;
+        }
+    }
+
+#ifdef _TARGET_X86_
+    case TYP_FLOAT:
+    case TYP_DOUBLE:
+        return RT_Float;
+#endif // _TARGET_X86_
+
+    default:
+        return RT_Scalar;
+    }
+}
+
 #ifdef JIT32_GCENCODER
 
 #include "emit.h"
@@ -104,18 +187,21 @@ static void regenLog(unsigned encoding, InfoHdr* header, InfoHdr* state)
 
     fprintf(logFile, "InfoHdr( %2d, %2d, %1d, %1d, %1d,"
                      " %1d, %1d, %1d, %1d, %1d,"
-                     " %1d, %1d, %1d, %1d, %1d,"
-                     " %1d, %2d, %2d, %2d, %2d,"
-                     " %2d, %2d), \n",
+                     " %1d, %1d, %1d, %1d, %1d, %1d,"
+                     " %1d, %1d, %1d,"
+                     " %1d, %2d, %2d,"
+                     " %2d, %2d, %2d, %2d, %2d, %2d), \n",
             state->prologSize, state->epilogSize, state->epilogCount, state->epilogAtEnd, state->ediSaved,
             state->esiSaved, state->ebxSaved, state->ebpSaved, state->ebpFrame, state->interruptible,
             state->doubleAlign, state->security, state->handlers, state->localloc, state->editNcontinue, state->varargs,
-            state->profCallbacks, state->argCount, state->frameSize,
+            state->profCallbacks, state->genericsContext, state->genericsContextIsMethodDesc, 
+            state->returnKind, state->argCount, state->frameSize,
             (state->untrackedCnt <= SET_UNTRACKED_MAX) ? state->untrackedCnt : HAS_UNTRACKED,
             (state->varPtrTableSize == 0) ? 0 : HAS_VARPTR,
             (state->gsCookieOffset == INVALID_GS_COOKIE_OFFSET) ? 0 : HAS_GS_COOKIE_OFFSET,
             (state->syncStartOffset == INVALID_SYNC_OFFSET) ? 0 : HAS_SYNC_OFFSET,
-            (state->syncStartOffset == INVALID_SYNC_OFFSET) ? 0 : HAS_SYNC_OFFSET);
+            (state->syncStartOffset == INVALID_SYNC_OFFSET) ? 0 : HAS_SYNC_OFFSET,
+            (state->revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET) ? 0 : HAS_REV_PINVOKE_FRAME_OFFSET);
 
     fflush(logFile);
 
@@ -265,9 +351,11 @@ static int bigEncoding4(unsigned cur, unsigned tgt, unsigned max)
     return cnt;
 }
 
-BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state)
+BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state, BYTE &codeSet)
 {
     BYTE encoding = 0xff;
+    codeSet = 1; // codeSet is 1 or 2, depending on whether the returned encoding 
+                 // corresponds to InfoHdrAdjust, or InfoHdrAdjust2 enumerations.
 
     if (state->argCount != header.argCount)
     {
@@ -547,6 +635,16 @@ BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state)
         goto DO_RETURN;
     }
 
+    if (state->returnKind != header.returnKind)
+    {
+        _ASSERTE(GCInfoEncodesReturnKind());
+        state->returnKind = header.returnKind;
+        codeSet = 2; // Two byte encoding
+        encoding = header.returnKind;
+        _ASSERTE(encoding < SET_RET_KIND_MAX);
+        goto DO_RETURN;
+    }
+
     if (state->gsCookieOffset != header.gsCookieOffset)
     {
         assert(state->gsCookieOffset == INVALID_GS_COOKIE_OFFSET || state->gsCookieOffset == HAS_GS_COOKIE_OFFSET);
@@ -587,10 +685,31 @@ BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state)
         }
     }
 
+    if (state->revPInvokeOffset != header.revPInvokeOffset)
+    {
+        _ASSERTE(GCInfoEncodesRevPInvokeFrame());
+        assert(state->revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET || state->revPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET);
+
+        if (state->revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET)
+        {
+            // header.revPInvokeOffset is non-zero. 
+            state->revPInvokeOffset = HAS_REV_PINVOKE_FRAME_OFFSET;
+            encoding = FLIP_REV_PINVOKE_FRAME;
+            goto DO_RETURN;
+        }
+        else if (header.revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET)
+        {
+            state->revPInvokeOffset = INVALID_REV_PINVOKE_OFFSET;
+            encoding = FLIP_REV_PINVOKE_FRAME;
+            goto DO_RETURN;
+        }
+    }
+
 DO_RETURN:
-    assert(encoding < 0x80);
+    _ASSERTE(encoding < MORE_BYTES_TO_FOLLOW);
     if (!state->isHeaderMatch(header))
-        encoding |= 0x80;
+        encoding |= MORE_BYTES_TO_FOLLOW;
+
     return encoding;
 }
 
@@ -806,6 +925,14 @@ static int measureDistance(const InfoHdr& header, const InfoHdrSmall* p, int clo
             return distance;
     }
 
+    if (p->returnKind != header.returnKind)
+    {
+        // Setting the ReturnKind requires two bytes of encoding.
+        distance += 2;
+        if (distance >= closeness)
+            return distance;
+    }
+
     if (header.gsCookieOffset != INVALID_GS_COOKIE_OFFSET)
     {
         distance += 1;
@@ -820,6 +947,13 @@ static int measureDistance(const InfoHdr& header, const InfoHdrSmall* p, int clo
             return distance;
     }
 
+    if (header.revPInvokeOffset != INVALID_REV_PINVOKE_OFFSET)
+    {
+        distance += 1;
+        if (distance >= closeness)
+            return distance;
+    }
+
     return distance;
 }
 
@@ -1165,6 +1299,12 @@ size_t GCInfo::gcInfoBlockHdrSave(
     header->genericsContextIsMethodDesc =
         header->genericsContext && (compiler->info.compMethodInfo->options & (CORINFO_GENERICS_CTXT_FROM_METHODDESC));
     header->gsCookieOffset = INVALID_GS_COOKIE_OFFSET;
+
+    ReturnKind returnKind = getReturnKind();
+    _ASSERTE(IsValidReturnKind(returnKind) && "Return Kind must be valid");
+    _ASSERTE(!IsStructReturnKind(returnKind) && "Struct Return Kinds Unexpected for JIT32");
+    header->returnKind = returnKind;
+
     if (compiler->getNeedsGSSecurityCookie())
     {
         assert(compiler->lvaGSSecurityCookie != BAD_VAR_NUM);
@@ -1189,6 +1329,7 @@ size_t GCInfo::gcInfoBlockHdrSave(
         // synchronized methods can't have more than 1 epilog
         assert(header->epilogCount <= 1);
     }
+    header->revPInvokeOffset = INVALID_REV_PINVOKE_OFFSET;
 
     assert((compiler->compArgSize & 0x3) == 0);
 
@@ -1224,12 +1365,22 @@ size_t GCInfo::gcInfoBlockHdrSave(
         *dest++ = headerEncoding;
 
         BYTE encoding = headerEncoding;
-        while (encoding & 0x80)
+        BYTE codeSet = 1;
+        while (encoding & MORE_BYTES_TO_FOLLOW)
         {
-            encoding = encodeHeaderNext(*header, &state);
+            encoding = encodeHeaderNext(*header, &state, codeSet);
+
 #if REGEN_SHORTCUTS
             regenLog(headerEncoding, header, &state);
 #endif
+            _ASSERTE(codeSet == 1 || codeSet == 2 && 
+                     "Encoding must correspond to InfoHdrAdjust or InfoHdrAdjust2");
+            if (codeSet == 2)
+            {
+                *dest++ = NEXT_OPCODE | MORE_BYTES_TO_FOLLOW;
+                ++size;
+            }
+
             *dest++ = encoding;
             ++size;
         }
@@ -3277,7 +3428,7 @@ void GCInfo::gcFindPtrsInFrame(const void* infoBlock, const void* codeBlock, uns
     GCDump gcDump(GCINFO_VERSION);
     gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
 
-    gcDump.DumpPtrsInFrame((const BYTE*)infoBlock, (const BYTE*)codeBlock, offs, verifyGCTables);
+    gcDump.DumpPtrsInFrame((PTR_CBYTE)infoBlock, (const BYTE*)codeBlock, offs, verifyGCTables);
 }
 
 #endif // DUMP_GC_TABLES
@@ -3504,23 +3655,6 @@ public:
 
 #endif // DEBUG
 
-ReturnKind GCTypeToReturnKind(CorInfoGCType gcType)
-{
-
-    switch (gcType)
-    {
-        case TYPE_GC_NONE:
-            return RT_Scalar;
-        case TYPE_GC_REF:
-            return RT_Object;
-        case TYPE_GC_BYREF:
-            return RT_ByRef;
-        default:
-            _ASSERTE(!"TYP_GC_OTHER is unexpected");
-            return RT_Illegal;
-    }
-}
-
 void GCInfo::gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSize, unsigned prologSize)
 {
 #ifdef DEBUG
@@ -3536,65 +3670,7 @@ void GCInfo::gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSiz
 
     gcInfoEncoderWithLog->SetCodeLength(methodSize);
 
-    ReturnKind returnKind = RT_Illegal;
-
-    switch (compiler->info.compRetType)
-    {
-        case TYP_REF:
-        case TYP_ARRAY:
-            returnKind = RT_Object;
-            break;
-        case TYP_BYREF:
-            returnKind = RT_ByRef;
-            break;
-        case TYP_STRUCT:
-        {
-            CORINFO_CLASS_HANDLE structType = compiler->info.compMethodInfo->args.retTypeClass;
-            var_types retType = compiler->getReturnTypeForStruct(structType);
-
-            switch (retType)
-            {
-            case TYP_ARRAY:
-                _ASSERTE(false && "TYP_ARRAY unexpected from getReturnTypeForStruct()");
-
-            case TYP_REF:
-                returnKind = RT_Object;
-                break;
-
-            case TYP_BYREF:
-                returnKind = RT_ByRef;
-                break;
-
-            case TYP_STRUCT:
-                if (compiler->IsHfa(structType))
-                {
-                    returnKind = RT_Scalar;
-                }
-                else
-                {
-                    // Multi-reg return
-                    BYTE gcPtrs[2] = { TYPE_GC_NONE, TYPE_GC_NONE };
-                    compiler->info.compCompHnd->getClassGClayout(structType, gcPtrs);
-
-                    ReturnKind first = GCTypeToReturnKind((CorInfoGCType)gcPtrs[0]);
-                    ReturnKind second = GCTypeToReturnKind((CorInfoGCType)gcPtrs[1]);
-
-                    returnKind = GetStructReturnKind(first, second);
-                }
-                break;
-
-            default:
-                returnKind = RT_Scalar;
-                break;
-            }
-            break;
-        }
-        default:
-            returnKind = RT_Scalar;
-    }
-
-    _ASSERTE(returnKind != RT_Illegal);
-    gcInfoEncoderWithLog->SetReturnKind(returnKind);
+    gcInfoEncoderWithLog->SetReturnKind(getReturnKind());
 
     if (compiler->isFramePointerUsed())
     {
index b93ac33..3f8d8af 100644 (file)
@@ -380,6 +380,9 @@ private:
 public:
     void gcUpdateForRegVarMove(regMaskTP srcMask, regMaskTP dstMask, LclVarDsc* varDsc);
 #endif // !LEGACY_BACKEND
+
+private:
+    ReturnKind getReturnKind();
 };
 
 inline unsigned char encodeUnsigned(BYTE* dest, unsigned value)
index f143dd6..3b383cf 100644 (file)
@@ -1801,7 +1801,7 @@ public:
     ULONG       GetFixedStackSize()
     {
         WRAPPER_NO_CONTRACT;
-        return GetCodeManager()->GetFrameSize(GetGCInfo());
+        return GetCodeManager()->GetFrameSize(GetGCInfoToken());
     }
 #endif // WIN64EXCEPTIONS
 
index df76945..9db0ce5 100644 (file)
@@ -1198,12 +1198,12 @@ void DumpGCInfo(MethodDesc* method)
     _ASSERTE(codeInfo.GetRelOffset() == 0);
 
     ICodeManager* codeMan = codeInfo.GetCodeManager();
-    GCInfoToken table = codeInfo.GetGCInfoToken();
+    GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
 
-    unsigned methodSize = (unsigned)codeMan->GetFunctionSize(table);
+    unsigned methodSize = (unsigned)codeMan->GetFunctionSize(gcInfoToken);
 
-    GCDump gcDump(table.Version);
-    PTR_CBYTE gcInfo = PTR_CBYTE(table.Info);
+    GCDump gcDump(gcInfoToken.Version);
+    PTR_CBYTE gcInfo = PTR_CBYTE(gcInfoToken.Info);
 
     gcDump.gcPrintf = printfToDbgOut;
 
index 93decc9..ff63d84 100644 (file)
@@ -501,9 +501,9 @@ BOOL EEDbgInterfaceImpl::IsInPrologOrEpilog(const BYTE *address,
 
     if (codeInfo.IsValid())
     {
-        LPVOID methodInfo = codeInfo.GetGCInfo();
+        GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
 
-        if (codeInfo.GetCodeManager()->IsInPrologOrEpilog(codeInfo.GetRelOffset(), methodInfo, prologSize))
+        if (codeInfo.GetCodeManager()->IsInPrologOrEpilog(codeInfo.GetRelOffset(), gcInfoToken, prologSize))
         {
             return TRUE;
         }
index 032bda7..2ce7b59 100644 (file)
@@ -142,13 +142,15 @@ __forceinline int decodeSigned(PTR_CBYTE& src)
 
 /*****************************************************************************
  *
- *  Decodes the methodInfoPtr and returns the decoded information
- *  in the hdrInfo struct.  The EIP parameter is the PC location
- *  within the active method.
+ *  Decodes the X86 GcInfo header and returns the decoded information
+ *  in the hdrInfo struct. 
+ *  curOffset is the code offset within the active method used in the 
+ *  computation of PrologOffs/EpilogOffs.
+ *  Returns the size of the header (number of bytes decoded).
  */
-static size_t   crackMethodInfoHdr(PTR_VOID    methodInfoPtr,
-                                   unsigned    curOffset,
-                                   hdrInfo   * infoPtr)
+static size_t   DecodeGCHdrInfo(GCInfoToken gcInfoToken,
+                                unsigned    curOffset,
+                                hdrInfo   * infoPtr)
 {
     CONTRACTL {
         NOTHROW;
@@ -157,7 +159,7 @@ static size_t   crackMethodInfoHdr(PTR_VOID    methodInfoPtr,
         SUPPORTS_DAC;
     } CONTRACTL_END;
 
-    PTR_CBYTE table = PTR_CBYTE(methodInfoPtr);
+    PTR_CBYTE table = (PTR_CBYTE) gcInfoToken.Info;
 #if VERIFY_GC_TABLES
     _ASSERTE(*castto(table, unsigned short *)++ == 0xFEEF);
 #endif
@@ -170,7 +172,7 @@ static size_t   crackMethodInfoHdr(PTR_VOID    methodInfoPtr,
     /* Decode the InfoHdr */
 
     InfoHdr header;
-    table = decodeHeader(table, &header);
+    table = decodeHeader(table, gcInfoToken.Version, &header);
 
     BOOL hasArgTabOffset = FALSE;
     if (header.untrackedCnt == HAS_UNTRACKED)
@@ -199,6 +201,10 @@ static size_t   crackMethodInfoHdr(PTR_VOID    methodInfoPtr,
         _ASSERTE(header.syncStartOffset < header.syncEndOffset);
     }
 
+    if (header.revPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET)
+    {
+        header.revPInvokeOffset = fastDecodeUnsigned(table);
+    }
 
     /* Some sanity checks on header */
 
@@ -220,6 +226,7 @@ static size_t   crackMethodInfoHdr(PTR_VOID    methodInfoPtr,
     infoPtr->argSize         = header.argCount * 4;
     infoPtr->ebpFrame        = header.ebpFrame;
     infoPtr->interruptible   = header.interruptible;
+    infoPtr->returnKind      = (ReturnKind) header.returnKind;
 
     infoPtr->prologSize      = header.prologSize;
     infoPtr->epilogSize      = header.epilogSize;
@@ -232,6 +239,7 @@ static size_t   crackMethodInfoHdr(PTR_VOID    methodInfoPtr,
 
     infoPtr->syncStartOffset = header.syncStartOffset;
     infoPtr->syncEndOffset   = header.syncEndOffset;
+    infoPtr->revPInvokeOffset = header.revPInvokeOffset;
 
     infoPtr->doubleAlign     = header.doubleAlign;
     infoPtr->securityCheck   = header.security;
@@ -352,7 +360,7 @@ static size_t   crackMethodInfoHdr(PTR_VOID    methodInfoPtr,
              (infoPtr->gsCookieOffset < infoPtr->stackSize) &&
              ((header.gsCookieOffset % sizeof(void*)) == 0));
     
-    return  table - PTR_CBYTE(methodInfoPtr);
+    return  table - PTR_CBYTE(gcInfoToken.Info);
 }
 
 /*****************************************************************************/
@@ -715,7 +723,7 @@ void EECodeManager::FixContext( ContextType     ctxType,
 
     /* Extract the necessary information from the info block header */
 
-    stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(pCodeInfo->GetGCInfo(),
+    stateBuf->hdrInfoSize = (DWORD)DecodeGCHdrInfo(pCodeInfo->GetGCInfoToken(),
                                        dwRelOffset,
                                        &stateBuf->hdrInfoBody);
     pState->dwIsSet = 1;
@@ -836,11 +844,11 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT         pCtx,
 
     hdrInfo  oldInfo, newInfo;
 
-    crackMethodInfoHdr(pOldCodeInfo->GetGCInfo(),
+    DecodeGCHdrInfo(pOldCodeInfo->GetGCInfoToken(),
                        pOldCodeInfo->GetRelOffset(),
                        &oldInfo);
 
-    crackMethodInfoHdr(pNewCodeInfo->GetGCInfo(),
+    DecodeGCHdrInfo(pNewCodeInfo->GetGCInfoToken(),
                        pNewCodeInfo->GetRelOffset(),
                        &newInfo);
 
@@ -1545,7 +1553,7 @@ bool EECodeManager::IsGcSafe( EECodeInfo     *pCodeInfo,
 
     /* Extract the necessary information from the info block header */
 
-    table = (BYTE *)crackMethodInfoHdr(pCodeInfo->GetGCInfo(),
+    table = (BYTE *)DecodeGCHdrInfo(pCodeInfo->GetGCInfoToken(),
                                        dwRelOffset,
                                        &info);
 
@@ -3905,8 +3913,9 @@ bool EECodeManager::UnwindStackFrame(PREGDISPLAY     pContext,
 
     PTR_CBYTE methodStart = PTR_CBYTE(pCodeInfo->GetSavedMethodCode());
 
-    PTR_VOID       methodInfoPtr = pCodeInfo->GetGCInfo();
-    DWORD          curOffs = pCodeInfo->GetRelOffset();
+    GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
+    PTR_VOID    methodInfoPtr = gcInfoToken.Info;
+    DWORD       curOffs = pCodeInfo->GetRelOffset();
 
     _ASSERTE(sizeof(CodeManStateBuf) <= sizeof(pState->stateBuf));
     CodeManStateBuf * stateBuf = (CodeManStateBuf*)pState->stateBuf;
@@ -3915,7 +3924,7 @@ bool EECodeManager::UnwindStackFrame(PREGDISPLAY     pContext,
     {
         /* Extract the necessary information from the info block header */
 
-        stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(methodInfoPtr,
+        stateBuf->hdrInfoSize = (DWORD)DecodeGCHdrInfo(gcInfoToken,
                                                           curOffs,
                                                           &stateBuf->hdrInfoBody);
     }
@@ -4097,7 +4106,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY     pContext,
         GC_NOTRIGGER;
     } CONTRACTL_END;
 
-    PTR_VOID  methodInfoPtr = pCodeInfo->GetGCInfo();
+    GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
     unsigned  curOffs = pCodeInfo->GetRelOffset();
 
     unsigned  EBP     = *pContext->pEbp;
@@ -4108,7 +4117,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY     pContext,
     unsigned  count;
 
     hdrInfo   info;
-    PTR_CBYTE table = PTR_CBYTE(methodInfoPtr);
+    PTR_CBYTE table = PTR_CBYTE(gcInfoToken.Info);
 #if 0
     printf("EECodeManager::EnumGcRefs - EIP = %08x ESP = %08x  offset = %x  GC Info is at %08x\n", *pContext->pPC, ESP, curOffs, table);
 #endif
@@ -4116,14 +4125,14 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY     pContext,
 
     /* Extract the necessary information from the info block header */
 
-    table += crackMethodInfoHdr(methodInfoPtr,
-                                curOffs,
-                                &info);
+    table += DecodeGCHdrInfo(gcInfoToken,
+                             curOffs,
+                             &info);
 
     _ASSERTE( curOffs <= info.methodSize);
 
 #ifdef  _DEBUG
-//    if ((methodInfoPtr == (void*)0x37760d0) && (curOffs == 0x264))
+//    if ((gcInfoToken.Info == (void*)0x37760d0) && (curOffs == 0x264))
 //        __asm int 3;
 
     if (trEnumGCRefs) {
@@ -4220,11 +4229,11 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY     pContext,
 
             /* Extract the necessary information from the info block header */
 
-            table = PTR_CBYTE(methodInfoPtr);
+            table = PTR_CBYTE(gcInfoToken.Info);
 
-            table += crackMethodInfoHdr(methodInfoPtr,
-                                        curOffs,
-                                        &info);
+            table += DecodeGCHdrInfo(gcInfoToken,
+                                     curOffs,
+                                     &info);
         }
     }
 
@@ -5030,9 +5039,9 @@ OBJECTREF* EECodeManager::GetAddrOfSecurityObject(CrawlFrame *pCF)
     CodeManStateBuf * stateBuf = (CodeManStateBuf*)pState->stateBuf;
 
     /* Extract the necessary information from the info block header */
-    stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(gcInfoToken.Info, // <TODO>truncation</TODO>
-                                                      relOffset,
-                                                      &stateBuf->hdrInfoBody);
+    stateBuf->hdrInfoSize = (DWORD)DecodeGCHdrInfo(gcInfoToken, // <TODO>truncation</TODO>
+                                                   relOffset,
+                                                   &stateBuf->hdrInfoBody);
 
     pState->dwIsSet = 1;
     if  (stateBuf->hdrInfoBody.securityCheck)
@@ -5109,10 +5118,10 @@ OBJECTREF EECodeManager::GetInstance( PREGDISPLAY    pContext,
     } CONTRACTL_END;
 
 #ifdef _TARGET_X86_
-    PTR_VOID       methodInfoPtr = pCodeInfo->GetGCInfo();
-    unsigned       relOffset = pCodeInfo->GetRelOffset();
+    GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
+    unsigned    relOffset = pCodeInfo->GetRelOffset();
 
-    PTR_CBYTE    table = PTR_CBYTE(methodInfoPtr);
+    PTR_CBYTE   table = PTR_CBYTE(gcInfoToken.Info);
     hdrInfo     info;
     unsigned    stackDepth;
     TADDR       taArgBase;
@@ -5120,9 +5129,9 @@ OBJECTREF EECodeManager::GetInstance( PREGDISPLAY    pContext,
 
     /* Extract the necessary information from the info block header */
 
-    table += crackMethodInfoHdr(methodInfoPtr,
-                                relOffset,
-                                &info);
+    table += DecodeGCHdrInfo(gcInfoToken,
+                             relOffset,
+                             &info);
 
     // We do not have accurate information in the prolog or the epilog
     if (info.prologOffs != hdrInfo::NOT_IN_PROLOG ||
@@ -5236,14 +5245,15 @@ GenericParamContextType EECodeManager::GetParamContextType(PREGDISPLAY     pCont
 
 #ifdef _TARGET_X86_
     /* Extract the necessary information from the info block header */
-    PTR_VOID       methodInfoPtr = pCodeInfo->GetGCInfo();
-    unsigned       relOffset = pCodeInfo->GetRelOffset();
+    GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
+    PTR_VOID    methodInfoPtr = pCodeInfo->GetGCInfo();
+    unsigned    relOffset = pCodeInfo->GetRelOffset();
 
     hdrInfo     info;
-    PTR_CBYTE    table = PTR_CBYTE(methodInfoPtr);
-    table += crackMethodInfoHdr(methodInfoPtr,
-                                relOffset,
-                                &info);
+    PTR_CBYTE   table = PTR_CBYTE(gcInfoToken.Info);
+    table += DecodeGCHdrInfo(gcInfoToken,
+                             relOffset,
+                             &info);
 
     if (!info.genericsContext || 
         info.prologOffs != hdrInfo::NOT_IN_PROLOG || 
@@ -5300,15 +5310,16 @@ PTR_VOID EECodeManager::GetParamTypeArg(PREGDISPLAY     pContext,
     LIMITED_METHOD_DAC_CONTRACT;
 
 #ifdef _TARGET_X86_
-    PTR_VOID       methodInfoPtr = pCodeInfo->GetGCInfo();
-    unsigned       relOffset = pCodeInfo->GetRelOffset();
+    GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
+    PTR_VOID    methodInfoPtr = pCodeInfo->GetGCInfo();
+    unsigned    relOffset = pCodeInfo->GetRelOffset();
 
     /* Extract the necessary information from the info block header */
     hdrInfo     info;
-    PTR_CBYTE    table = PTR_CBYTE(methodInfoPtr);
-    table += crackMethodInfoHdr(methodInfoPtr,
-                                relOffset,
-                                &info);
+    PTR_CBYTE   table = PTR_CBYTE(gcInfoToken.Info);
+    table += DecodeGCHdrInfo(gcInfoToken,
+                             relOffset,
+                             &info);
 
     if (!info.genericsContext || 
         info.prologOffs != hdrInfo::NOT_IN_PROLOG || 
@@ -5424,9 +5435,9 @@ void * EECodeManager::GetGSCookieAddr(PREGDISPLAY     pContext,
     
     /* Extract the necessary information from the info block header */
     hdrInfo * info = &stateBuf->hdrInfoBody;
-    stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(gcInfoToken.Info, // <TODO>truncation</TODO>
-                                                      relOffset,
-                                                      info);
+    stateBuf->hdrInfoSize = (DWORD)DecodeGCHdrInfo(gcInfoToken, // <TODO>truncation</TODO>
+                                                   relOffset,
+                                                   info);
 
     pState->dwIsSet = 1;
     
@@ -5482,9 +5493,9 @@ void * EECodeManager::GetGSCookieAddr(PREGDISPLAY     pContext,
  *
  *  Returns true if the given IP is in the given method's prolog or epilog.
  */
-bool EECodeManager::IsInPrologOrEpilog(DWORD        relPCoffset,
-                                       PTR_VOID     methodInfoPtr,
-                                       size_t*      prologSize)
+bool EECodeManager::IsInPrologOrEpilog(DWORD       relPCoffset,
+                                       GCInfoToken gcInfoToken,
+                                       size_t*     prologSize)
 {
     CONTRACTL {
         NOTHROW;
@@ -5494,7 +5505,7 @@ bool EECodeManager::IsInPrologOrEpilog(DWORD        relPCoffset,
 #ifndef USE_GC_INFO_DECODER
     hdrInfo info;
 
-    crackMethodInfoHdr(methodInfoPtr, relPCoffset, &info);
+    DecodeGCHdrInfo(gcInfoToken, relPCoffset, &info);
 
     if (prologSize)
         *prologSize = info.prologSize;
@@ -5511,10 +5522,9 @@ bool EECodeManager::IsInPrologOrEpilog(DWORD        relPCoffset,
  *
  *  Returns true if the given IP is in the synchronized region of the method (valid for synchronized functions only)
 */
-bool  EECodeManager::IsInSynchronizedRegion(
-                DWORD           relOffset,
-                PTR_VOID        methodInfoPtr,
-                unsigned        flags)
+bool  EECodeManager::IsInSynchronizedRegion(DWORD       relOffset,
+                                            GCInfoToken gcInfoToken,
+                                            unsigned    flags)
 {
     CONTRACTL {
         NOTHROW;
@@ -5524,7 +5534,7 @@ bool  EECodeManager::IsInSynchronizedRegion(
 #ifndef USE_GC_INFO_DECODER
     hdrInfo info;
 
-    crackMethodInfoHdr(methodInfoPtr, relOffset, &info);
+    DecodeGCHdrInfo(gcInfoToken, relOffset, &info);
 
     // We should be called only for synchronized methods
     _ASSERTE(info.syncStartOffset != INVALID_SYNC_OFFSET && info.syncEndOffset != INVALID_SYNC_OFFSET);
@@ -5558,9 +5568,8 @@ size_t EECodeManager::GetFunctionSize(GCInfoToken gcInfoToken)
 
 #if defined(_TARGET_X86_)
     hdrInfo info;
-    PTR_VOID  methodInfoPtr = gcInfoToken.Info;
 
-    crackMethodInfoHdr(methodInfoPtr, 0, &info);
+    DecodeGCHdrInfo(gcInfoToken, 0, &info);
 
     return info.methodSize;
 #elif defined(USE_GC_INFO_DECODER)
@@ -5578,15 +5587,47 @@ size_t EECodeManager::GetFunctionSize(GCInfoToken gcInfoToken)
     PORTABILITY_ASSERT("EECodeManager::GetFunctionSize is not implemented on this platform.");
     return 0;
 #endif
+}
 
+/*****************************************************************************
+*
+*  Returns the size of a given function.
+*/
+ReturnKind EECodeManager::GetReturnKind(GCInfoToken gcInfoToken)
+{
+    CONTRACTL{
+        NOTHROW;
+    GC_NOTRIGGER;
+    SUPPORTS_DAC;
+    } CONTRACTL_END;
 
+    if (!gcInfoToken.IsReturnKindAvailable())
+    {
+        return RT_Illegal;
+    }
+
+#if defined(_TARGET_X86_)
+    hdrInfo info;
+
+    DecodeGCHdrInfo(gcInfoToken, 0, &info);
+
+    return info.returnKind;
+#elif defined(USE_GC_INFO_DECODER)
+
+    GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_RETURN_KIND);
+    return gcInfoDecoder.GetReturnKind();
+
+#else // !_TARGET_X86_ && !USE_GC_INFO_DECODER
+    PORTABILITY_ASSERT("EECodeManager::GetReturnKind is not implemented on this platform.");
+    return 0;
+#endif
 }
 
 /*****************************************************************************
  *
  *  Returns the size of the frame of the given function.
  */
-unsigned int EECodeManager::GetFrameSize(PTR_VOID methodInfoPtr)
+unsigned int EECodeManager::GetFrameSize(GCInfoToken gcInfoToken)
 {
     CONTRACTL {
         NOTHROW;
@@ -5596,7 +5637,7 @@ unsigned int EECodeManager::GetFrameSize(PTR_VOID methodInfoPtr)
 #ifndef USE_GC_INFO_DECODER
     hdrInfo info;
 
-    crackMethodInfoHdr(methodInfoPtr, 0, &info);
+    DecodeGCHdrInfo(gcInfoToken, 0, &info);
 
     // currently only used by E&C callers need to know about doubleAlign
     // in all likelyhood
@@ -5624,10 +5665,10 @@ const BYTE* EECodeManager::GetFinallyReturnAddr(PREGDISPLAY pReg)
 #endif
 }
 
-BOOL EECodeManager::IsInFilter(void *methodInfoPtr,
-                              unsigned offset,
-                              PCONTEXT pCtx,
-                              DWORD curNestLevel)
+BOOL EECodeManager::IsInFilter(GCInfoToken gcInfoToken,
+                               unsigned offset,
+                               PCONTEXT pCtx,
+                               DWORD curNestLevel)
 {
     CONTRACTL {
         NOTHROW;
@@ -5640,9 +5681,9 @@ BOOL EECodeManager::IsInFilter(void *methodInfoPtr,
 
     hdrInfo     info;
 
-    crackMethodInfoHdr(methodInfoPtr,
-                       offset,
-                       &info);
+    DecodeGCHdrInfo(gcInfoToken,
+                    offset,
+                    &info);
 
     /* make sure that we have an ebp stack frame */
 
@@ -5668,7 +5709,7 @@ BOOL EECodeManager::IsInFilter(void *methodInfoPtr,
 }
 
 
-BOOL EECodeManager::LeaveFinally(void *methodInfoPtr,
+BOOL EECodeManager::LeaveFinally(GCInfoToken gcInfoToken,
                                 unsigned offset,
                                 PCONTEXT pCtx)
 {
@@ -5681,9 +5722,9 @@ BOOL EECodeManager::LeaveFinally(void *methodInfoPtr,
 
     hdrInfo info;
 
-    crackMethodInfoHdr(methodInfoPtr,
-                       offset,
-                       &info);
+    DecodeGCHdrInfo(gcInfoToken,
+                    offset,
+                    &info);
 
     DWORD       nestingLevel;
     GetHandlerFrameInfo(&info, pCtx->Ebp, pCtx->Esp, (DWORD) IGNORE_VAL, NULL, &nestingLevel);
@@ -5707,7 +5748,7 @@ BOOL EECodeManager::LeaveFinally(void *methodInfoPtr,
 #endif
 }
 
-void EECodeManager::LeaveCatch(void *methodInfoPtr,
+void EECodeManager::LeaveCatch(GCInfoToken gcInfoToken,
                                 unsigned offset,
                                 PCONTEXT pCtx)
 {
@@ -5724,7 +5765,7 @@ void EECodeManager::LeaveCatch(void *methodInfoPtr,
     bool        hasInnerFilter;
     hdrInfo     info;
 
-    crackMethodInfoHdr(methodInfoPtr, offset, &info);
+    DecodeGCHdrInfo(gcInfoToken, offset, &info);
     GetHandlerFrameInfo(&info, pCtx->Ebp, pCtx->Esp, (DWORD) IGNORE_VAL,
                         &baseSP, &nestingLevel, &hasInnerFilter);
 //    _ASSERTE(frameType == FR_HANDLER);
@@ -5774,17 +5815,17 @@ TADDR EECodeManager::GetAmbientSP(PREGDISPLAY     pContext,
     } CONTRACTL_END;
 
 #ifdef _TARGET_X86_
-    PTR_VOID  methodInfoPtr = pCodeInfo->GetGCInfo();
+    GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
 
     _ASSERTE(sizeof(CodeManStateBuf) <= sizeof(pState->stateBuf));
     CodeManStateBuf * stateBuf = (CodeManStateBuf*)pState->stateBuf;
-    PTR_CBYTE table = PTR_CBYTE(methodInfoPtr);
+    PTR_CBYTE table = PTR_CBYTE(gcInfoToken.Info);
 
     /* Extract the necessary information from the info block header */
 
-    stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(methodInfoPtr,
-                                       dwRelOffset,
-                                       &stateBuf->hdrInfoBody);
+    stateBuf->hdrInfoSize = (DWORD)DecodeGCHdrInfo(gcInfoToken,
+                                                   dwRelOffset,
+                                                   &stateBuf->hdrInfoBody);
     table += stateBuf->hdrInfoSize;
 
     pState->dwIsSet = 1;
@@ -5868,8 +5909,8 @@ ULONG32 EECodeManager::GetStackParameterSize(EECodeInfo * pCodeInfo)
     } CONTRACTL_END;
 
 #if defined(_TARGET_X86_)
-    PTR_VOID       methodInfoPtr = pCodeInfo->GetGCInfo();
-    unsigned       dwOffset = pCodeInfo->GetRelOffset();
+    GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
+    unsigned    dwOffset = pCodeInfo->GetRelOffset();
 
     CodeManState state;
     state.dwIsSet = 0;
@@ -5878,7 +5919,7 @@ ULONG32 EECodeManager::GetStackParameterSize(EECodeInfo * pCodeInfo)
     CodeManStateBuf * pStateBuf = reinterpret_cast<CodeManStateBuf *>(state.stateBuf);
 
     hdrInfo * pHdrInfo = &(pStateBuf->hdrInfoBody);
-    pStateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(methodInfoPtr, dwOffset, pHdrInfo);
+    pStateBuf->hdrInfoSize = (DWORD)DecodeGCHdrInfo(gcInfoToken, dwOffset, pHdrInfo);
 
     // We need to subtract 4 here because ESPIncrOnReturn() includes the stack slot containing the return
     // address.
index d26f2d6..4f72702 100644 (file)
@@ -1679,7 +1679,7 @@ bool FinallyIsUnwinding(EHRangeTreeNode *pNode,
 BOOL LeaveCatch(ICodeManager* pEECM,
                 Thread *pThread,
                 CONTEXT *pCtx,
-                void *methodInfoPtr,
+                GCInfoToken gcInfoToken,
                 unsigned offset)
 {
     CONTRACTL
@@ -1703,7 +1703,7 @@ BOOL LeaveCatch(ICodeManager* pEECM,
     PopNestedExceptionRecords(esp, pCtx, pThread->GetExceptionListPtr());
 
     // Do JIT-specific work
-    pEECM->LeaveCatch(methodInfoPtr, offset, pCtx);
+    pEECM->LeaveCatch(gcInfoToken, offset, pCtx);
 
     SetSP(pCtx, (UINT_PTR)esp);
     return TRUE;
@@ -1762,7 +1762,7 @@ HRESULT IsLegalTransition(Thread *pThread,
                           ICodeManager* pEECM,
                           PREGDISPLAY pReg,
                           SLOT addrStart,
-                          void *methodInfoPtr,
+                          GCInfoToken gcInfoToken,
                           PCONTEXT pCtx)
 {
     CONTRACTL
@@ -1875,7 +1875,7 @@ HRESULT IsLegalTransition(Thread *pThread,
                         if (!LeaveCatch(pEECM,
                                         pThread,
                                         pFilterCtx,
-                                        methodInfoPtr,
+                                        gcInfoToken,
                                         offFrom))
                             return E_FAIL;
                     }
@@ -1930,7 +1930,7 @@ HRESULT IsLegalTransition(Thread *pThread,
 
                         if (!fCanSetIPOnly)
                         {
-                            if (!pEECM->LeaveFinally(methodInfoPtr,
+                            if (!pEECM->LeaveFinally(gcInfoToken,
                                                      offFrom,
                                                      pFilterCtx))
                                 return E_FAIL;
@@ -2041,7 +2041,7 @@ HRESULT SetIPFromSrcToDst(Thread *pThread,
     EECodeInfo codeInfo((TADDR)(addrStart));
 
     ICodeManager * pEECM = codeInfo.GetCodeManager();
-    LPVOID methodInfoPtr = codeInfo.GetGCInfo();
+    GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
 
     // Do both checks here so compiler doesn't complain about skipping
     // initialization b/c of goto.
@@ -2097,7 +2097,7 @@ retryForCommit:
                                pEECM,
                                pReg,
                                addrStart,
-                               methodInfoPtr,
+                               gcInfoToken,
                                pCtx);
 
         if (FAILED(hr))
@@ -2120,7 +2120,7 @@ retryForCommit:
                                pEECM,
                                pReg,
                                addrStart,
-                               methodInfoPtr,
+                               gcInfoToken,
                                pCtx);
 
         if (FAILED(hr))
@@ -2143,7 +2143,7 @@ retryForCommit:
                                pEECM,
                                pReg,
                                addrStart,
-                               methodInfoPtr,
+                               gcInfoToken,
                                pCtx);
 
         if (FAILED(hr))
index 89f271c..24f9435 100644 (file)
@@ -80,7 +80,7 @@ void SetupAndSprinkleBreakpoints(
 
     gcCover->methodRegion      = methodRegionInfo;
     gcCover->codeMan           = pCodeInfo->GetCodeManager();
-    gcCover->gcInfoToken           = pCodeInfo->GetGCInfoToken();
+    gcCover->gcInfoToken       = pCodeInfo->GetGCInfoToken();
     gcCover->callerThread      = 0;
     gcCover->doingEpilogChecks = true;    
 
@@ -583,7 +583,7 @@ void GCCoverageInfo::SprinkleBreakpoints(
 #ifdef _TARGET_X86_
         // we will whack every instruction in the prolog and epilog to make certain
         // our unwinding logic works there.  
-        if (codeMan->IsInPrologOrEpilog((cur - codeStart) + (DWORD)regionOffsetAdj, gcInfoToken.Info, NULL)) {
+        if (codeMan->IsInPrologOrEpilog((cur - codeStart) + (DWORD)regionOffsetAdj, gcInfoToken, NULL)) {
             *cur = INTERRUPT_INSTR;
         }
 #endif
@@ -1527,7 +1527,7 @@ void DoGcStress (PCONTEXT regs, MethodDesc *pMD)
     /* are we in a prolog or epilog?  If so just test the unwind logic
        but don't actually do a GC since the prolog and epilog are not
        GC safe points */
-    if (gcCover->codeMan->IsInPrologOrEpilog(offset, gcCover->gcInfoToken.Info, NULL))
+    if (gcCover->codeMan->IsInPrologOrEpilog(offset, gcCover->gcInfoToken, NULL))
     {
         // We are not at a GC safe point so we can't Suspend EE (Suspend EE will yield to GC).
         // But we still have to update the GC Stress instruction. We do it directly without suspending
index 8dc1692..b294581 100644 (file)
@@ -125,7 +125,7 @@ inline bool SafeToReportGenericParamContext(CrawlFrame* pCF)
 #ifndef USE_GC_INFO_DECODER
 
     ICodeManager * pEECM = pCF->GetCodeManager();
-    if (pEECM != NULL && pEECM->IsInPrologOrEpilog(pCF->GetRelOffset(), pCF->GetGCInfo(), NULL))
+    if (pEECM != NULL && pEECM->IsInPrologOrEpilog(pCF->GetRelOffset(), pCF->GetGCInfoToken(), NULL))
     {
         return false;
     }
index fee883f..20dceed 100644 (file)
@@ -7081,12 +7081,13 @@ Loop:
 
             // GC info will assist us in determining whether this is a non-EBP frame and
             // info about pushed arguments.
-            PTR_VOID gcInfo = codeInfo.GetGCInfo();
+            GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
+            PTR_VOID gcInfo = gcInfoToken.Info;
             InfoHdr header;
             unsigned uiMethodSizeDummy;
             PTR_CBYTE table = PTR_CBYTE(gcInfo);
             table += decodeUnsigned(table, &uiMethodSizeDummy);
-            table = decodeHeader(table, &header);
+            table = decodeHeader(table, gcInfoToken.Version, &header);
 
             // Ok, GCInfo, can we do a simple EBP walk or what?
 
index 3b0b472..29b5617 100644 (file)
@@ -2416,7 +2416,7 @@ StackWalkAction StackFrameIterator::NextRaw(void)
                 OBJECTREF      orUnwind = NULL;
 
                 if (m_crawl.GetCodeManager()->IsInSynchronizedRegion(m_crawl.GetRelOffset(),
-                                                                    m_crawl.GetGCInfo(), 
+                                                                    m_crawl.GetGCInfoToken(), 
                                                                     m_crawl.GetCodeManagerFlags()))
                 {
                     if (pMD->IsStatic())
@@ -3158,7 +3158,7 @@ void StackFrameIterator::PreProcessingForManagedFrames(void)
          m_crawl.pFunc->IsSynchronized() && 
          !m_crawl.pFunc->IsStatic()      &&
          m_crawl.GetCodeManager()->IsInSynchronizedRegion(m_crawl.GetRelOffset(), 
-                                                         m_crawl.GetGCInfo(), 
+                                                         m_crawl.GetGCInfoToken(), 
                                                          m_crawl.GetCodeManagerFlags()))
     {
         BEGIN_GCX_ASSERT_COOP;
index 0458b7d..e5c5436 100644 (file)
@@ -7275,18 +7275,8 @@ ReturnKind GetReturnKindFromMethodTable(Thread *pThread, EECodeInfo *codeInfo)
 
 ReturnKind GetReturnKind(Thread *pThread, EECodeInfo *codeInfo)
 {
-    ReturnKind returnKind = RT_Illegal;
-
-#ifdef _TARGET_X86_  
-    // X86 GCInfo updates yet to be implemented.
-#else
     GCInfoToken gcInfoToken = codeInfo->GetGCInfoToken();
-    if (gcInfoToken.IsReturnKindAvailable()) 
-    {
-        GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_RETURN_KIND);
-        returnKind = gcInfoDecoder.GetReturnKind();
-    }
-#endif // _TARGET_X86_
+    ReturnKind returnKind = codeInfo->GetCodeManager()->GetReturnKind(gcInfoToken);
 
     if (!IsValidReturnKind(returnKind))
     {