[x86/Linux] Enable gcMarkFilterVarsPinned (WIN64EXCEPTIONS) (dotnet/coreclr#11281)
authorHanjoung Lee <waterets@gmail.com>
Fri, 16 Jun 2017 00:53:44 +0000 (09:53 +0900)
committerBruce Forstall <brucefo@microsoft.com>
Fri, 16 Jun 2017 00:53:44 +0000 (17:53 -0700)
* [x86/Linux] Enable gcMarkFilterVarsPinned

Do gcMarkFilterVarsPinned() for WIN64EXCEPTIONS

* [x86/Linux] GCInfo : Force this pointer untracked

`this` pointer is now always untracked so we can use pinned flag in tracked lifetimes.
This allows us to make the refs(inside filter) pinned to prevent from double-relocation.

* [x86/Linux] GCInfo : fix comment and formatting

* [x86/Linux] GCInfo : Update

- Force "this" pointer untracked only when "this" is generic context
- Style fixes

* [x86/Linux] GCInfo : remove this_OFFSET_FLAG

Commit migrated from https://github.com/dotnet/coreclr/commit/0c96db33ddb7d784cda9bd0368756046f436e8bc

src/coreclr/src/gcdump/i386/gcdumpx86.cpp
src/coreclr/src/inc/gcinfo.h
src/coreclr/src/jit/codegenxarch.cpp
src/coreclr/src/jit/emit.cpp
src/coreclr/src/jit/gcencode.cpp
src/coreclr/src/jit/gcinfo.cpp
src/coreclr/src/jit/jitgcinfo.h
src/coreclr/src/jit/lclvars.cpp
src/coreclr/src/vm/eetwain.cpp

index 9096085..a152feb 100644 (file)
@@ -323,7 +323,11 @@ size_t              GCDump::DumpGCTable(PTR_CBYTE      table,
 
         gcPrintf("%s%s pointer\n",
                     (lowBits & byref_OFFSET_FLAG) ? "byref " : "",
+#ifndef WIN64EXCEPTIONS
                     (lowBits & this_OFFSET_FLAG)  ? "this"   : ""
+#else
+                    (lowBits & pinned_OFFSET_FLAG)  ? "pinned"   : ""
+#endif
            );
 
         _ASSERTE(endOffs <= methodSize);
@@ -677,7 +681,9 @@ size_t              GCDump::DumpGCTable(PTR_CBYTE      table,
                 {
                     argTab += decodeUnsigned(argTab, &val);
 
+#ifndef WIN64EXCEPTIONS
                     assert((val & this_OFFSET_FLAG) == 0);
+#endif
                     unsigned  stkOffs = val & ~byref_OFFSET_FLAG;
                     unsigned  lowBit  = val &  byref_OFFSET_FLAG;
 
index e5537e0..901f2cf 100644 (file)
@@ -26,7 +26,9 @@ const unsigned        OFFSET_MASK  = 0x3;  // mask to access the low 2 bits
 //
 const unsigned  byref_OFFSET_FLAG  = 0x1;  // the offset is an interior ptr
 const unsigned pinned_OFFSET_FLAG  = 0x2;  // the offset is a pinned ptr
+#if !defined(_TARGET_X86_) || !defined(WIN64EXCEPTIONS)
 const unsigned   this_OFFSET_FLAG  = 0x2;  // the offset is "this"
+#endif
 
 //-----------------------------------------------------------------------------
 // The current GCInfo Version
index 4439e55..b7efccd 100644 (file)
@@ -8223,6 +8223,15 @@ void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize,
     InfoHdr header;
 
     int s_cached;
+
+#ifdef WIN64EXCEPTIONS
+    // We should do this before gcInfoBlockHdrSave since varPtrTableSize must be finalized before it
+    if (compiler->ehAnyFunclets())
+    {
+        gcInfo.gcMarkFilterVarsPinned();
+    }
+#endif
+
 #ifdef DEBUG
     size_t headerSize =
 #endif
index 4684230..bad0528 100644 (file)
@@ -4721,12 +4721,14 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
 // printf("Variable #%2u/%2u is at stack offset %d\n", num, indx, offs);
 
 #ifdef JIT32_GCENCODER
+#ifndef WIN64EXCEPTIONS
                 /* Remember the frame offset of the "this" argument for synchronized methods */
                 if (emitComp->lvaIsOriginalThisArg(num) && emitComp->lvaKeepAliveAndReportThis())
                 {
                     emitSyncThisObjOffs = offs;
                     offs |= this_OFFSET_FLAG;
                 }
+#endif
 #endif // JIT32_GCENCODER
 
                 if (dsc->TypeGet() == TYP_BYREF)
@@ -5512,12 +5514,14 @@ void emitter::emitGCvarLiveSet(int offs, GCtype gcType, BYTE* addr, ssize_t disp
 
     desc->vpdNext = nullptr;
 
+#if !defined(JIT32_GCENCODER) || !defined(WIN64EXCEPTIONS)
     /* the lower 2 bits encode props about the stk ptr */
 
     if (offs == emitSyncThisObjOffs)
     {
         desc->vpdVarNum |= this_OFFSET_FLAG;
     }
+#endif
 
     if (gcType == GCT_BYREF)
     {
@@ -5604,10 +5608,17 @@ void emitter::emitGCvarDeadSet(int offs, BYTE* addr, ssize_t disp)
     if (EMITVERBOSE)
     {
         GCtype gcType = (desc->vpdVarNum & byref_OFFSET_FLAG) ? GCT_BYREF : GCT_GCREF;
-        bool   isThis = (desc->vpdVarNum & this_OFFSET_FLAG) != 0;
+#if !defined(JIT32_GCENCODER) || !defined(WIN64EXCEPTIONS)
+        bool isThis = (desc->vpdVarNum & this_OFFSET_FLAG) != 0;
 
         printf("[%08X] %s%s var died at [%s", dspPtr(desc), GCtypeStr(gcType), isThis ? "this-ptr" : "",
                emitGetFrameReg());
+#else
+        bool isPinned = (desc->vpdVarNum & pinned_OFFSET_FLAG) != 0;
+
+        printf("[%08X] %s%s var died at [%s", dspPtr(desc), GCtypeStr(gcType), isPinned ? "pinned" : "",
+               emitGetFrameReg());
+#endif
 
         if (offs < 0)
         {
index 4c300ac..a29da24 100644 (file)
@@ -106,6 +106,299 @@ ReturnKind GCInfo::getReturnKind()
     }
 }
 
+#if !defined(JIT32_GCENCODER) || defined(WIN64EXCEPTIONS)
+
+// gcMarkFilterVarsPinned - Walk all lifetimes and make it so that anything
+//     live in a filter is marked as pinned (often by splitting the lifetime
+//     so that *only* the filter region is pinned).  This should only be
+//     called once (after generating all lifetimes, but before slot ids are
+//     finalized.
+//
+// DevDiv 376329 - The VM has to double report filters and their parent frame
+// because they occur during the 1st pass and the parent frame doesn't go dead
+// until we start unwinding in the 2nd pass.
+//
+// Untracked locals will only be reported in non-filter funclets and the
+// parent.
+// Registers can't be double reported by 2 frames since they're different.
+// That just leaves stack variables which might be double reported.
+//
+// Technically double reporting is only a problem when the GC has to relocate a
+// reference. So we avoid that problem by marking all live tracked stack
+// variables as pinned inside the filter.  Thus if they are double reported, it
+// won't be a problem since they won't be double relocated.
+//
+void GCInfo::gcMarkFilterVarsPinned()
+{
+    assert(compiler->ehAnyFunclets());
+    const EHblkDsc* endHBtab = &(compiler->compHndBBtab[compiler->compHndBBtabCount]);
+
+    for (EHblkDsc* HBtab = compiler->compHndBBtab; HBtab < endHBtab; HBtab++)
+    {
+        if (HBtab->HasFilter())
+        {
+            const UNATIVE_OFFSET filterBeg = compiler->ehCodeOffset(HBtab->ebdFilter);
+            const UNATIVE_OFFSET filterEnd = compiler->ehCodeOffset(HBtab->ebdHndBeg);
+
+            for (varPtrDsc* varTmp = gcVarPtrList; varTmp != nullptr; varTmp = varTmp->vpdNext)
+            {
+                // Get hold of the variable's flags.
+                const unsigned lowBits = varTmp->vpdVarNum & OFFSET_MASK;
+
+                // Compute the actual lifetime offsets.
+                const unsigned begOffs = varTmp->vpdBegOfs;
+                const unsigned endOffs = varTmp->vpdEndOfs;
+
+                // Special case: skip any 0-length lifetimes.
+                if (endOffs == begOffs)
+                {
+                    continue;
+                }
+
+                // Skip lifetimes with no overlap with the filter
+                if ((endOffs <= filterBeg) || (begOffs >= filterEnd))
+                {
+                    continue;
+                }
+
+#ifndef JIT32_GCENCODER
+                // Because there is no nesting within filters, nothing
+                // should be already pinned.
+                // For JIT32_GCENCODER, we should not do this check as gcVarPtrList are always sorted by vpdBegOfs
+                // which means that we could see some varPtrDsc that were already pinned by previous splitting.
+                assert((lowBits & pinned_OFFSET_FLAG) == 0);
+#endif // JIT32_GCENCODER
+
+                if (begOffs < filterBeg)
+                {
+                    if (endOffs > filterEnd)
+                    {
+                        // The variable lifetime is starts before AND ends after
+                        // the filter, so we need to create 2 new lifetimes:
+                        //     (1) a pinned one for the filter
+                        //     (2) a regular one for after the filter
+                        // and then adjust the original lifetime to end before
+                        // the filter.
+                        CLANG_FORMAT_COMMENT_ANCHOR;
+
+#ifdef DEBUG
+                        if (compiler->verbose)
+                        {
+                            printf("Splitting lifetime for filter: [%04X, %04X).\nOld: ", filterBeg, filterEnd);
+                            gcDumpVarPtrDsc(varTmp);
+                        }
+#endif // DEBUG
+
+                        varPtrDsc* desc1 = new (compiler, CMK_GC) varPtrDsc;
+                        desc1->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
+                        desc1->vpdBegOfs = filterBeg;
+                        desc1->vpdEndOfs = filterEnd;
+
+                        varPtrDsc* desc2 = new (compiler, CMK_GC) varPtrDsc;
+                        desc2->vpdVarNum = varTmp->vpdVarNum;
+                        desc2->vpdBegOfs = filterEnd;
+                        desc2->vpdEndOfs = endOffs;
+
+                        varTmp->vpdEndOfs = filterBeg;
+
+                        gcInsertVarPtrDscSplit(desc1, varTmp);
+                        gcInsertVarPtrDscSplit(desc2, varTmp);
+
+#ifdef DEBUG
+                        if (compiler->verbose)
+                        {
+                            printf("New (1 of 3): ");
+                            gcDumpVarPtrDsc(varTmp);
+                            printf("New (2 of 3): ");
+                            gcDumpVarPtrDsc(desc1);
+                            printf("New (3 of 3): ");
+                            gcDumpVarPtrDsc(desc2);
+                        }
+#endif // DEBUG
+                    }
+                    else
+                    {
+                        // The variable lifetime started before the filter and ends
+                        // somewhere inside it, so we only create 1 new lifetime,
+                        // and then adjust the original lifetime to end before
+                        // the filter.
+                        CLANG_FORMAT_COMMENT_ANCHOR;
+
+#ifdef DEBUG
+                        if (compiler->verbose)
+                        {
+                            printf("Splitting lifetime for filter.\nOld: ");
+                            gcDumpVarPtrDsc(varTmp);
+                        }
+#endif // DEBUG
+
+                        varPtrDsc* desc = new (compiler, CMK_GC) varPtrDsc;
+                        desc->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
+                        desc->vpdBegOfs = filterBeg;
+                        desc->vpdEndOfs = endOffs;
+
+                        varTmp->vpdEndOfs = filterBeg;
+
+                        gcInsertVarPtrDscSplit(desc, varTmp);
+
+#ifdef DEBUG
+                        if (compiler->verbose)
+                        {
+                            printf("New (1 of 2): ");
+                            gcDumpVarPtrDsc(varTmp);
+                            printf("New (2 of 2): ");
+                            gcDumpVarPtrDsc(desc);
+                        }
+#endif // DEBUG
+                    }
+                }
+                else
+                {
+                    if (endOffs > filterEnd)
+                    {
+                        // The variable lifetime starts inside the filter and
+                        // ends somewhere after it, so we create 1 new
+                        // lifetime for the part inside the filter and adjust
+                        // the start of the original lifetime to be the end
+                        // of the filter
+                        CLANG_FORMAT_COMMENT_ANCHOR;
+#ifdef DEBUG
+                        if (compiler->verbose)
+                        {
+                            printf("Splitting lifetime for filter.\nOld: ");
+                            gcDumpVarPtrDsc(varTmp);
+                        }
+#endif // DEBUG
+
+                        varPtrDsc* desc = new (compiler, CMK_GC) varPtrDsc;
+#ifndef JIT32_GCENCODER
+                        desc->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
+                        desc->vpdBegOfs = begOffs;
+                        desc->vpdEndOfs = filterEnd;
+
+                        varTmp->vpdBegOfs = filterEnd;
+#else
+                        // Mark varTmp as pinned and generated use varPtrDsc(desc) as non-pinned
+                        // since gcInsertVarPtrDscSplit requires that varTmp->vpdBegOfs must precede desc->vpdBegOfs
+                        desc->vpdVarNum = varTmp->vpdVarNum;
+                        desc->vpdBegOfs = filterEnd;
+                        desc->vpdEndOfs = endOffs;
+
+                        varTmp->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
+                        varTmp->vpdEndOfs = filterEnd;
+#endif
+
+                        gcInsertVarPtrDscSplit(desc, varTmp);
+
+#ifdef DEBUG
+                        if (compiler->verbose)
+                        {
+                            printf("New (1 of 2): ");
+                            gcDumpVarPtrDsc(desc);
+                            printf("New (2 of 2): ");
+                            gcDumpVarPtrDsc(varTmp);
+                        }
+#endif // DEBUG
+                    }
+                    else
+                    {
+                        // The variable lifetime is completely within the filter,
+                        // so just add the pinned flag.
+                        CLANG_FORMAT_COMMENT_ANCHOR;
+#ifdef DEBUG
+                        if (compiler->verbose)
+                        {
+                            printf("Pinning lifetime for filter.\nOld: ");
+                            gcDumpVarPtrDsc(varTmp);
+                        }
+#endif // DEBUG
+
+                        varTmp->vpdVarNum |= pinned_OFFSET_FLAG;
+#ifdef DEBUG
+                        if (compiler->verbose)
+                        {
+                            printf("New : ");
+                            gcDumpVarPtrDsc(varTmp);
+                        }
+#endif // DEBUG
+                    }
+                }
+            }
+        } // HasFilter
+    }     // Foreach EH
+}
+
+// gcInsertVarPtrDscSplit - Insert varPtrDsc that were created by splitting lifetimes
+//     From gcMarkFilterVarsPinned, we may have created one or two `varPtrDsc`s due to splitting lifetimes
+//     and these newly created `varPtrDsc`s should be inserted in gcVarPtrList.
+//     However the semantics of this call depend on the architecture.
+//
+//     x86-GCInfo requires gcVarPtrList to be sorted by vpdBegOfs.
+//     Every time inserting an entry we should keep the order of entries.
+//     So this function searches for a proper insertion point from "begin" then "desc" gets inserted.
+//
+//     For other architectures(ones that uses GCInfo{En|De}coder), we don't need any sort.
+//     So the argument "begin" is unused and "desc" will be inserted at the front of the list.
+
+void GCInfo::gcInsertVarPtrDscSplit(varPtrDsc* desc, varPtrDsc* begin)
+{
+#ifndef JIT32_GCENCODER
+    (void)begin;
+    desc->vpdNext = gcVarPtrList;
+    gcVarPtrList  = desc;
+#else  // JIT32_GCENCODER
+    // "desc" and "begin" must not be null
+    assert(desc != nullptr);
+    assert(begin != nullptr);
+
+    // The caller must guarantee that desc's BegOfs is equal or greater than begin's
+    // since we will search for insertion point from "begin"
+    assert(desc->vpdBegOfs >= begin->vpdBegOfs);
+
+    varPtrDsc* varTmp    = begin->vpdNext;
+    varPtrDsc* varInsert = begin;
+
+    while (varTmp != nullptr && varTmp->vpdBegOfs < desc->vpdBegOfs)
+    {
+        varInsert = varTmp;
+        varTmp    = varTmp->vpdNext;
+    }
+
+    // Insert point cannot be null
+    assert(varInsert != nullptr);
+
+    desc->vpdNext      = varInsert->vpdNext;
+    varInsert->vpdNext = desc;
+#endif // JIT32_GCENCODER
+}
+
+#ifdef DEBUG
+
+void GCInfo::gcDumpVarPtrDsc(varPtrDsc* desc)
+{
+    const int    offs   = (desc->vpdVarNum & ~OFFSET_MASK);
+    const GCtype gcType = (desc->vpdVarNum & byref_OFFSET_FLAG) ? GCT_BYREF : GCT_GCREF;
+    const bool   isPin  = (desc->vpdVarNum & pinned_OFFSET_FLAG) != 0;
+
+    printf("[%08X] %s%s var at [%s", dspPtr(desc), GCtypeStr(gcType), isPin ? "pinned-ptr" : "",
+           compiler->isFramePointerUsed() ? STR_FPBASE : STR_SPBASE);
+
+    if (offs < 0)
+    {
+        printf("-%02XH", -offs);
+    }
+    else if (offs > 0)
+    {
+        printf("+%02XH", +offs);
+    }
+
+    printf("] live from %04X to %04X\n", desc->vpdBegOfs, desc->vpdEndOfs);
+}
+
+#endif // DEBUG
+
+#endif // !defined(JIT32_GCENCODER) || defined(WIN64EXCEPTIONS)
+
 #ifdef JIT32_GCENCODER
 
 #include "emit.h"
@@ -1972,7 +2265,11 @@ size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, un
                     }
                 }
 
+#ifndef WIN64EXCEPTIONS
+                // For WIN64EXCEPTIONS, "this" must always be in untracked variables
+                // so we cannot have "this" in variable lifetimes
                 if (compiler->lvaIsOriginalThisArg(varNum) && compiler->lvaKeepAliveAndReportThis())
+
                 {
                     // Encoding of untracked variables does not support reporting
                     // "this". So report it as a tracked variable with a liveness
@@ -1981,6 +2278,7 @@ size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, un
                     thisKeptAliveIsInUntracked = true;
                     continue;
                 }
+#endif
 
                 if (pass == 0)
                     count++;
@@ -2140,6 +2438,7 @@ size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, un
     varPtrDsc* varTmp;
     count = 0;
 
+#ifndef WIN64EXCEPTIONS
     if (thisKeptAliveIsInUntracked)
     {
         count = 1;
@@ -2166,6 +2465,7 @@ size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, un
         dest += (sz & mask);
         totalSize += sz;
     }
+#endif
 
     for (pass = 0; pass < 2; pass++)
     {
@@ -3452,27 +3752,6 @@ template class SimplerHashTable<StackSlotIdKey, StackSlotIdKey, GcSlotId, JitSim
 
 #ifdef DEBUG
 
-void GCInfo::gcDumpVarPtrDsc(varPtrDsc* desc)
-{
-    const int    offs   = (desc->vpdVarNum & ~OFFSET_MASK);
-    const GCtype gcType = (desc->vpdVarNum & byref_OFFSET_FLAG) ? GCT_BYREF : GCT_GCREF;
-    const bool   isPin  = (desc->vpdVarNum & pinned_OFFSET_FLAG) != 0;
-
-    printf("[%08X] %s%s var at [%s", dspPtr(desc), GCtypeStr(gcType), isPin ? "pinned-ptr" : "",
-           compiler->isFramePointerUsed() ? STR_FPBASE : STR_SPBASE);
-
-    if (offs < 0)
-    {
-        printf("-%02XH", -offs);
-    }
-    else if (offs > 0)
-    {
-        printf("+%02XH", +offs);
-    }
-
-    printf("] live from %04X to %04X\n", desc->vpdBegOfs, desc->vpdEndOfs);
-}
-
 static const char* const GcSlotFlagsNames[] = {"",
                                                "(byref) ",
                                                "(pinned) ",
@@ -4560,210 +4839,6 @@ void GCInfo::gcMakeVarPtrTable(GcInfoEncoder* gcInfoEncoder, MakeRegPtrMode mode
     }
 }
 
-// gcMarkFilterVarsPinned - Walk all lifetimes and make it so that anything
-//     live in a filter is marked as pinned (often by splitting the lifetime
-//     so that *only* the filter region is pinned).  This should only be
-//     called once (after generating all lifetimes, but before slot ids are
-//     finalized.
-//
-// DevDiv 376329 - The VM has to double report filters and their parent frame
-// because they occur during the 1st pass and the parent frame doesn't go dead
-// until we start unwinding in the 2nd pass.
-//
-// Untracked locals will only be reported in non-filter funclets and the
-// parent.
-// Registers can't be double reported by 2 frames since they're different.
-// That just leaves stack variables which might be double reported.
-//
-// Technically double reporting is only a problem when the GC has to relocate a
-// reference. So we avoid that problem by marking all live tracked stack
-// variables as pinned inside the filter.  Thus if they are double reported, it
-// won't be a problem since they won't be double relocated.
-//
-void GCInfo::gcMarkFilterVarsPinned()
-{
-    assert(compiler->ehAnyFunclets());
-    const EHblkDsc* endHBtab = &(compiler->compHndBBtab[compiler->compHndBBtabCount]);
-
-    for (EHblkDsc* HBtab = compiler->compHndBBtab; HBtab < endHBtab; HBtab++)
-    {
-        if (HBtab->HasFilter())
-        {
-            const UNATIVE_OFFSET filterBeg = compiler->ehCodeOffset(HBtab->ebdFilter);
-            const UNATIVE_OFFSET filterEnd = compiler->ehCodeOffset(HBtab->ebdHndBeg);
-
-            for (varPtrDsc* varTmp = gcVarPtrList; varTmp != nullptr; varTmp = varTmp->vpdNext)
-            {
-                // Get hold of the variable's flags.
-                const unsigned lowBits = varTmp->vpdVarNum & OFFSET_MASK;
-
-                // Compute the actual lifetime offsets.
-                const unsigned begOffs = varTmp->vpdBegOfs;
-                const unsigned endOffs = varTmp->vpdEndOfs;
-
-                // Special case: skip any 0-length lifetimes.
-                if (endOffs == begOffs)
-                {
-                    continue;
-                }
-
-                // Skip lifetimes with no overlap with the filter
-                if ((endOffs <= filterBeg) || (begOffs >= filterEnd))
-                {
-                    continue;
-                }
-
-                // Because there is no nesting within filters, nothing
-                // should be already pinned.
-                assert((lowBits & pinned_OFFSET_FLAG) == 0);
-
-                if (begOffs < filterBeg)
-                {
-                    if (endOffs > filterEnd)
-                    {
-                        // The variable lifetime is starts before AND ends after
-                        // the filter, so we need to create 2 new lifetimes:
-                        //     (1) a pinned one for the filter
-                        //     (2) a regular one for after the filter
-                        // and then adjust the original lifetime to end before
-                        // the filter.
-                        CLANG_FORMAT_COMMENT_ANCHOR;
-
-#ifdef DEBUG
-                        if (compiler->verbose)
-                        {
-                            printf("Splitting lifetime for filter: [%04X, %04X).\nOld: ", filterBeg, filterEnd);
-                            gcDumpVarPtrDsc(varTmp);
-                        }
-#endif // DEBUG
-
-                        varPtrDsc* desc1 = new (compiler, CMK_GC) varPtrDsc;
-                        desc1->vpdNext   = gcVarPtrList;
-                        desc1->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
-                        desc1->vpdBegOfs = filterBeg;
-                        desc1->vpdEndOfs = filterEnd;
-
-                        varPtrDsc* desc2 = new (compiler, CMK_GC) varPtrDsc;
-                        desc2->vpdNext   = desc1;
-                        desc2->vpdVarNum = varTmp->vpdVarNum;
-                        desc2->vpdBegOfs = filterEnd;
-                        desc2->vpdEndOfs = endOffs;
-                        gcVarPtrList     = desc2;
-
-                        varTmp->vpdEndOfs = filterBeg;
-#ifdef DEBUG
-                        if (compiler->verbose)
-                        {
-                            printf("New (1 of 3): ");
-                            gcDumpVarPtrDsc(varTmp);
-                            printf("New (2 of 3): ");
-                            gcDumpVarPtrDsc(desc1);
-                            printf("New (3 of 3): ");
-                            gcDumpVarPtrDsc(desc2);
-                        }
-#endif // DEBUG
-                    }
-                    else
-                    {
-                        // The variable lifetime started before the filter and ends
-                        // somewhere inside it, so we only create 1 new lifetime,
-                        // and then adjust the original lifetime to end before
-                        // the filter.
-                        CLANG_FORMAT_COMMENT_ANCHOR;
-
-#ifdef DEBUG
-                        if (compiler->verbose)
-                        {
-                            printf("Splitting lifetime for filter.\nOld: ");
-                            gcDumpVarPtrDsc(varTmp);
-                        }
-#endif // DEBUG
-
-                        varPtrDsc* desc = new (compiler, CMK_GC) varPtrDsc;
-                        desc->vpdNext   = gcVarPtrList;
-                        desc->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
-                        desc->vpdBegOfs = filterBeg;
-                        desc->vpdEndOfs = endOffs;
-                        gcVarPtrList    = desc;
-
-                        varTmp->vpdEndOfs = filterBeg;
-
-#ifdef DEBUG
-                        if (compiler->verbose)
-                        {
-                            printf("New (1 of 2): ");
-                            gcDumpVarPtrDsc(varTmp);
-                            printf("New (2 of 2): ");
-                            gcDumpVarPtrDsc(desc);
-                        }
-#endif // DEBUG
-                    }
-                }
-                else
-                {
-                    if (endOffs > filterEnd)
-                    {
-                        // The variable lifetime starts inside the filter and
-                        // ends somewhere after it, so we create 1 new
-                        // lifetime for the part inside the filter and adjust
-                        // the start of the original lifetime to be the end
-                        // of the filter
-                        CLANG_FORMAT_COMMENT_ANCHOR;
-#ifdef DEBUG
-                        if (compiler->verbose)
-                        {
-                            printf("Splitting lifetime for filter.\nOld: ");
-                            gcDumpVarPtrDsc(varTmp);
-                        }
-#endif // DEBUG
-
-                        varPtrDsc* desc = new (compiler, CMK_GC) varPtrDsc;
-                        desc->vpdNext   = gcVarPtrList;
-                        desc->vpdVarNum = varTmp->vpdVarNum | pinned_OFFSET_FLAG;
-                        desc->vpdBegOfs = begOffs;
-                        desc->vpdEndOfs = filterEnd;
-                        gcVarPtrList    = desc;
-
-                        varTmp->vpdBegOfs = filterEnd;
-
-#ifdef DEBUG
-                        if (compiler->verbose)
-                        {
-                            printf("New (1 of 2): ");
-                            gcDumpVarPtrDsc(desc);
-                            printf("New (2 of 2): ");
-                            gcDumpVarPtrDsc(varTmp);
-                        }
-#endif // DEBUG
-                    }
-                    else
-                    {
-                        // The variable lifetime is completely within the filter,
-                        // so just add the pinned flag.
-                        CLANG_FORMAT_COMMENT_ANCHOR;
-#ifdef DEBUG
-                        if (compiler->verbose)
-                        {
-                            printf("Pinning lifetime for filter.\nOld: ");
-                            gcDumpVarPtrDsc(varTmp);
-                        }
-#endif // DEBUG
-
-                        varTmp->vpdVarNum |= pinned_OFFSET_FLAG;
-#ifdef DEBUG
-                        if (compiler->verbose)
-                        {
-                            printf("New : ");
-                            gcDumpVarPtrDsc(varTmp);
-                        }
-#endif // DEBUG
-                    }
-                }
-            }
-        } // HasFilter
-    }     // Foreach EH
-}
-
 void GCInfo::gcInfoRecordGCStackArgLive(GcInfoEncoder* gcInfoEncoder, MakeRegPtrMode mode, regPtrDsc* genStackPtr)
 {
     // On non-x86 platforms, don't have pointer argument push/pop/kill declarations.
index ece039e..293abd5 100644 (file)
@@ -476,6 +476,9 @@ void GCInfo::gcCountForHeader(UNALIGNED unsigned int* untrackedCount, UNALIGNED
                 }
             }
 
+#if !defined(JIT32_GCENCODER) || !defined(WIN64EXCEPTIONS)
+            // For x86/WIN64EXCEPTIONS, "this" must always be in untracked variables
+            // so we cannot have "this" in variable lifetimes
             if (compiler->lvaIsOriginalThisArg(varNum) && compiler->lvaKeepAliveAndReportThis())
             {
                 // Encoding of untracked variables does not support reporting
@@ -485,6 +488,7 @@ void GCInfo::gcCountForHeader(UNALIGNED unsigned int* untrackedCount, UNALIGNED
                 thisKeptAliveIsInUntracked = true;
                 continue;
             }
+#endif
 
 #ifdef DEBUG
             if (compiler->verbose)
index 7b17b84..b2a8eb0 100644 (file)
@@ -208,10 +208,6 @@ public:
     // In the "do work" mode, we use these slot ids to actually declare live ranges to the encoder.
     void gcMakeVarPtrTable(GcInfoEncoder* gcInfoEncoder, MakeRegPtrMode mode);
 
-    // This method expands the tracked stack variables lifetimes so that any lifetimes within filters
-    // are reported as pinned.
-    void gcMarkFilterVarsPinned();
-
     // At instruction offset "instrOffset," the set of registers indicated by "regMask" is becoming live or dead,
     // depending on whether "newState" is "GC_SLOT_DEAD" or "GC_SLOT_LIVE".  The subset of registers whose corresponding
     // bits are set in "byRefMask" contain by-refs rather than regular GC pointers. "*pPtrRegs" is the set of
@@ -359,11 +355,22 @@ private:
 #else // JIT32_GCENCODER
     void gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSize, unsigned prologSize);
 
+#endif // JIT32_GCENCODER
+
+#if !defined(JIT32_GCENCODER) || defined(WIN64EXCEPTIONS)
+
+    // This method expands the tracked stack variables lifetimes so that any lifetimes within filters
+    // are reported as pinned.
+    void gcMarkFilterVarsPinned();
+
+    // Insert a varPtrDsc to gcVarPtrList that was generated by splitting lifetimes
+    void gcInsertVarPtrDscSplit(varPtrDsc* desc, varPtrDsc* begin);
+
 #ifdef DEBUG
     void gcDumpVarPtrDsc(varPtrDsc* desc);
 #endif // DEBUG
 
-#endif // JIT32_GCENCODER
+#endif // !defined(JIT32_GCENCODER) || defined(WIN64EXCEPTIONS)
 
 #if DUMP_GC_TABLES
 
index 0d557de..eda815d 100644 (file)
@@ -3293,6 +3293,14 @@ void Compiler::lvaSortByRefCount()
         {
             varDsc->lvTracked = 0;
         }
+#if defined(JIT32_GCENCODER) && defined(WIN64EXCEPTIONS)
+        else if (lvaIsOriginalThisArg(lclNum) && (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0)
+        {
+            // For x86/Linux, we need to track "this".
+            // However we cannot have it in tracked variables, so we set "this" pointer always untracked
+            varDsc->lvTracked = 0;
+        }
+#endif
 
         //  Are we not optimizing and we have exception handlers?
         //   if so mark all args and locals "do not enregister".
index 99e9107..9fe9670 100644 (file)
@@ -4796,7 +4796,12 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY     pContext,
                 if (dspPtr) {
                     printf("    Frame %s%s local at [E",
                            (lowBits & byref_OFFSET_FLAG) ? "byref "   : "",
+#ifndef WIN64EXCEPTIONS
                            (lowBits & this_OFFSET_FLAG)  ? "this-ptr" : "");
+#else
+                           (lowBits & pinned_OFFSET_FLAG)  ? "pinned" : "");
+#endif
+
                     
                     int  dspOffs = ptrAddr;
                     char frameType;
@@ -4816,8 +4821,22 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY     pContext,
                         printf("%cP+%02XH]: ", frameType, +dspOffs);
                 }
 #endif
+
+                unsigned flags = CHECK_APP_DOMAIN;
+#ifndef WIN64EXCEPTIONS
+                // First  Bit : byref
+                // Second Bit : this
+                // The second bit means `this` not `pinned`. So we ignore it.
+                flags |= lowBits & byref_OFFSET_FLAG;
+#else
+                // First  Bit : byref
+                // Second Bit : pinned
+                // Both bits are valid
+                flags |= lowBits;
+#endif
+
                 _ASSERTE(byref_OFFSET_FLAG == GC_CALL_INTERIOR);
-                pCallBack(hCallBack, (OBJECTREF*)(size_t)ptrAddr, (lowBits & byref_OFFSET_FLAG) | CHECK_APP_DOMAIN
+                pCallBack(hCallBack, (OBJECTREF*)(size_t)ptrAddr, flags
                           DAC_ARG(DacSlotLocation(info.ebpFrame ? REGI_EBP : REGI_ESP,
                                           info.ebpFrame ? EBP - ptrAddr : ptrAddr - ESP,
                                           true)));
@@ -5310,6 +5329,7 @@ OBJECTREF EECodeManager::GetInstance( PREGDISPLAY    pContext,
     _ASSERTE(*castto(table, unsigned short *)++ == 0xBEEF);
 #endif
 
+#ifndef WIN64EXCEPTIONS
     /* Parse the untracked frame variable table */
 
     /* The 'this' pointer can never be located in the untracked table */
@@ -5356,6 +5376,19 @@ OBJECTREF EECodeManager::GetInstance( PREGDISPLAY    pContext,
     _ASSERTE(*castto(table, unsigned short *) == 0xBABE);
 #endif
 
+#else // WIN64EXCEPTIONS
+    if (pCodeInfo->GetMethodDesc()->AcquiresInstMethodTableFromThis()) // Generic Context is "this"
+    {
+        // Untracked table must have at least one entry - this pointer
+        _ASSERTE(info.untrackedCnt > 0);
+
+        // The first entry must be "this" pointer
+        int stkOffs = fastDecodeSigned(table);
+        taArgBase -= stkOffs & ~OFFSET_MASK;
+        return (OBJECTREF)(size_t)(*PTR_DWORD(taArgBase));
+    }
+#endif // WIN64EXCEPTIONS
+
     return NULL;
 #else // !USE_GC_INFO_DECODER
     PTR_VOID token = EECodeManager::GetExactGenericsToken(pContext, pCodeInfo);