コード例 #1
0
 private int GetNextSlotId(byte[] image, bool fSimple, bool fSkipFirst, int slotId, ref int couldBeLiveCnt, ref int couldBeLiveOffset)
 {
     if (fSimple)
     {
         // Get the slotId by iterating through the couldBeLive bit array. The slotId is the index of the next set bit
         while (NativeReader.ReadBits(image, 1, ref couldBeLiveOffset) == 0)
         {
             slotId++;
         }
     }
     else if (couldBeLiveCnt > 0)
     {
         // We have more from the last run to report
         couldBeLiveCnt--;
     }
     // We need to find a new run
     else if (fSkipFirst)
     {
         int tmp = (int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.LIVESTATE_RLE_SKIP_ENCBASE, ref couldBeLiveOffset) + 1;
         slotId        += tmp;
         couldBeLiveCnt = (int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.LIVESTATE_RLE_RUN_ENCBASE, ref couldBeLiveOffset);
     }
     else
     {
         int tmp = (int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.LIVESTATE_RLE_RUN_ENCBASE, ref couldBeLiveOffset) + 1;
         slotId        += tmp;
         couldBeLiveCnt = (int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.LIVESTATE_RLE_SKIP_ENCBASE, ref couldBeLiveOffset);
     }
     return(slotId);
 }
コード例 #2
0
        /// <summary>
        /// based on <a href="https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/gcinfodecoder.cpp">GcInfoDecoder::GcInfoDecoder</a>
        /// </summary>
        private void ParseHeaderFlags(byte[] image, ref int bitOffset)
        {
            GcInfoHeaderFlags headerFlags;

            _slimHeader = (NativeReader.ReadBits(image, 1, ref bitOffset) == 0);
            if (_slimHeader)
            {
                headerFlags = NativeReader.ReadBits(image, 1, ref bitOffset) == 1 ? GcInfoHeaderFlags.GC_INFO_HAS_STACK_BASE_REGISTER : 0;
            }
            else
            {
                int numFlagBits = (int)((Version == 1) ? GcInfoHeaderFlags.GC_INFO_FLAGS_BIT_SIZE_VERSION_1 : GcInfoHeaderFlags.GC_INFO_FLAGS_BIT_SIZE);
                headerFlags = (GcInfoHeaderFlags)NativeReader.ReadBits(image, numFlagBits, ref bitOffset);
            }

            _hasSecurityObject      = (headerFlags & GcInfoHeaderFlags.GC_INFO_HAS_SECURITY_OBJECT) != 0;
            _hasGSCookie            = (headerFlags & GcInfoHeaderFlags.GC_INFO_HAS_GS_COOKIE) != 0;
            _hasPSPSym              = (headerFlags & GcInfoHeaderFlags.GC_INFO_HAS_PSP_SYM) != 0;
            _hasGenericsInstContext = (headerFlags & GcInfoHeaderFlags.GC_INFO_HAS_GENERICS_INST_CONTEXT_MASK) != GcInfoHeaderFlags.GC_INFO_HAS_GENERICS_INST_CONTEXT_NONE;
            _hasStackBaseRegister   = (headerFlags & GcInfoHeaderFlags.GC_INFO_HAS_STACK_BASE_REGISTER) != 0;
            _hasSizeOfEditAndContinuePreservedArea = (headerFlags & GcInfoHeaderFlags.GC_INFO_HAS_EDIT_AND_CONTINUE_PRESERVED_SLOTS) != 0;
            if (Version >= MIN_GCINFO_VERSION_WITH_REV_PINVOKE_FRAME) // IsReversePInvokeFrameAvailable
            {
                _hasReversePInvokeFrame = (headerFlags & GcInfoHeaderFlags.GC_INFO_REVERSE_PINVOKE_FRAME) != 0;
            }
            _wantsReportOnlyLeaf = ((headerFlags & GcInfoHeaderFlags.GC_INFO_WANTS_REPORT_ONLY_LEAF) != 0);
        }
コード例 #3
0
ファイル: GcSlotTable.cs プロジェクト: Fredo-Q/dotnet-coreclr
        /// <summary>
        /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/vm/gcinfodecoder.cpp">GcSlotDecoder::DecodeSlotTable</a>
        /// </summary>
        public GcSlotTable(byte[] image, Machine machine, GcInfoTypes gcInfoTypes, ref int bitOffset)
        {
            if (NativeReader.ReadBits(image, 1, ref bitOffset) != 0)
            {
                NumRegisters = NativeReader.DecodeVarLengthUnsigned(image, gcInfoTypes.NUM_REGISTERS_ENCBASE, ref bitOffset);
            }
            if (NativeReader.ReadBits(image, 1, ref bitOffset) != 0)
            {
                NumStackSlots = NativeReader.DecodeVarLengthUnsigned(image, gcInfoTypes.NUM_STACK_SLOTS_ENCBASE, ref bitOffset);
                NumUntracked  = NativeReader.DecodeVarLengthUnsigned(image, gcInfoTypes.NUM_UNTRACKED_SLOTS_ENCBASE, ref bitOffset);
            }
            NumSlots = NumRegisters + NumStackSlots + NumUntracked;

            GcSlots = new List <GcSlot>();
            if (NumRegisters > 0)
            {
                DecodeRegisters(image, gcInfoTypes, ref bitOffset);
            }
            if ((NumStackSlots > 0) && (GcSlots.Count < gcInfoTypes.MAX_PREDECODED_SLOTS))
            {
                DecodeStackSlots(image, machine, gcInfoTypes, NumStackSlots, false, ref bitOffset);
            }
            if ((NumUntracked > 0) && (GcSlots.Count < gcInfoTypes.MAX_PREDECODED_SLOTS))
            {
                DecodeStackSlots(image, machine, gcInfoTypes, NumUntracked, true, ref bitOffset);
            }
        }
コード例 #4
0
ファイル: GcSlotTable.cs プロジェクト: Fredo-Q/dotnet-coreclr
        private void DecodeStackSlots(byte[] image, Machine machine, GcInfoTypes gcInfoTypes, uint nSlots, bool isUntracked, ref int bitOffset)
        {
            // We have stack slots left and more room to predecode
            GcStackSlotBase spBase       = (GcStackSlotBase)NativeReader.ReadBits(image, 2, ref bitOffset);
            int             normSpOffset = NativeReader.DecodeVarLengthSigned(image, gcInfoTypes.STACK_SLOT_ENCBASE, ref bitOffset);
            int             spOffset     = gcInfoTypes.DenormalizeStackSlot(normSpOffset);
            GcSlotFlags     flags        = (GcSlotFlags)NativeReader.ReadBits(image, 2, ref bitOffset);

            GcSlots.Add(new GcSlot(GcSlots.Count, -1, new GcStackSlot(spOffset, spBase), flags, isUntracked));

            for (int i = 1; i < nSlots; i++)
            {
                spBase = (GcStackSlotBase)NativeReader.ReadBits(image, 2, ref bitOffset);
                if ((uint)flags != 0)
                {
                    normSpOffset = NativeReader.DecodeVarLengthSigned(image, gcInfoTypes.STACK_SLOT_ENCBASE, ref bitOffset);
                    spOffset     = gcInfoTypes.DenormalizeStackSlot(normSpOffset);
                    flags        = (GcSlotFlags)NativeReader.ReadBits(image, 2, ref bitOffset);
                }
                else
                {
                    int normSpOffsetDelta = NativeReader.DecodeVarLengthSigned(image, gcInfoTypes.STACK_SLOT_DELTA_ENCBASE, ref bitOffset);
                    normSpOffset += normSpOffsetDelta;
                    spOffset      = gcInfoTypes.DenormalizeStackSlot(normSpOffset);
                }
                GcSlots.Add(new GcSlot(GcSlots.Count, -1, new GcStackSlot(spOffset, spBase), flags, isUntracked));
            }
        }
コード例 #5
0
        private List <SafePointOffset> EnumerateSafePoints(byte[] image, ref int bitOffset)
        {
            List <SafePointOffset> safePoints = new List <SafePointOffset>();
            uint numBitsPerOffset             = GcInfoTypes.CeilOfLog2(CodeLength);

            for (int i = 0; i < NumSafePoints; i++)
            {
                uint normOffset = (uint)NativeReader.ReadBits(image, (int)numBitsPerOffset, ref bitOffset);
                safePoints.Add(new SafePointOffset(i, normOffset));
            }
            return(safePoints);
        }
コード例 #6
0
        private uint GetNumCouldBeLiveSlots(byte[] image, ref int bitOffset)
        {
            uint numCouldBeLiveSlots = 0;
            uint numTracked          = SlotTable.NumTracked;

            if (NativeReader.ReadBits(image, 1, ref bitOffset) != 0)
            {
                // RLE encoded
                bool fSkip     = (NativeReader.ReadBits(image, 1, ref bitOffset) == 0);
                bool fReport   = true;
                uint readSlots = NativeReader.DecodeVarLengthUnsigned(image, fSkip ? _gcInfoTypes.LIVESTATE_RLE_SKIP_ENCBASE : _gcInfoTypes.LIVESTATE_RLE_RUN_ENCBASE, ref bitOffset);
                fSkip = !fSkip;
                while (readSlots < numTracked)
                {
                    uint cnt = NativeReader.DecodeVarLengthUnsigned(image, fSkip ? _gcInfoTypes.LIVESTATE_RLE_SKIP_ENCBASE : _gcInfoTypes.LIVESTATE_RLE_RUN_ENCBASE, ref bitOffset) + 1;
                    if (fReport)
                    {
                        numCouldBeLiveSlots += cnt;
                    }
                    readSlots += cnt;
                    fSkip      = !fSkip;
                    fReport    = !fReport;
                }
            }
            else
            {
                // count the number of set bits in the couldBeLive bit array
                foreach (var slot in SlotTable.GcSlots)
                {
                    if ((slot.Flags & GcSlotFlags.GC_SLOT_UNTRACKED) != 0)
                    {
                        break;
                    }

                    if (NativeReader.ReadBits(image, 1, ref bitOffset) != 0)
                    {
                        numCouldBeLiveSlots++;
                    }
                }
            }
            return(numCouldBeLiveSlots);
        }
コード例 #7
0
ファイル: GcSlotTable.cs プロジェクト: Fredo-Q/dotnet-coreclr
        private void DecodeRegisters(byte[] image, GcInfoTypes gcInfoTypes, ref int bitOffset)
        {
            // We certainly predecode the first register
            uint        regNum = NativeReader.DecodeVarLengthUnsigned(image, gcInfoTypes.REGISTER_ENCBASE, ref bitOffset);
            GcSlotFlags flags  = (GcSlotFlags)NativeReader.ReadBits(image, 2, ref bitOffset);

            GcSlots.Add(new GcSlot(GcSlots.Count, (int)regNum, null, flags));

            for (int i = 1; i < NumRegisters; i++)
            {
                if ((uint)flags != 0)
                {
                    regNum = NativeReader.DecodeVarLengthUnsigned(image, gcInfoTypes.REGISTER_ENCBASE, ref bitOffset);
                    flags  = (GcSlotFlags)NativeReader.ReadBits(image, 2, ref bitOffset);
                }
                else
                {
                    uint regDelta = NativeReader.DecodeVarLengthUnsigned(image, gcInfoTypes.REGISTER_DELTA_ENCBASE, ref bitOffset) + 1;
                    regNum += regDelta;
                }
                GcSlots.Add(new GcSlot(GcSlots.Count, (int)regNum, null, flags));
            }
        }
コード例 #8
0
        /// <summary>
        /// based on end of <a href="https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/gcinfodecoder.cpp">GcInfoDecoder::EnumerateLiveSlots and GcInfoEncoder::Build</a>
        /// </summary>
        private Dictionary <int, List <BaseGcTransition> > GetTransitions(byte[] image, ref int bitOffset)
        {
            int totalInterruptibleLength = 0;

            if (NumInterruptibleRanges == 0)
            {
                totalInterruptibleLength = CodeLength;
            }
            else
            {
                foreach (InterruptibleRange range in InterruptibleRanges)
                {
                    totalInterruptibleLength += (int)(range.StopOffset - range.StartOffset);
                }
            }

            int numChunks         = (totalInterruptibleLength + _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK - 1) / _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK;
            int numBitsPerPointer = (int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.POINTER_SIZE_ENCBASE, ref bitOffset);

            if (numBitsPerPointer == 0)
            {
                return(new Dictionary <int, List <BaseGcTransition> >());
            }

            // get offsets of each chunk
            int[] chunkPointers = new int[numChunks];
            for (int i = 0; i < numChunks; i++)
            {
                chunkPointers[i] = NativeReader.ReadBits(image, numBitsPerPointer, ref bitOffset);
            }

            // Offset to m_Info2 containing all the info on register liveness, which starts at the next byte
            int info2Offset = (bitOffset + 7) & ~7;

            List <GcTransition> transitions = new List <GcTransition>();

            bool[] liveAtEnd = new bool[SlotTable.NumTracked]; // true if slot is live at the end of the chunk
            for (int currentChunk = 0; currentChunk < numChunks; currentChunk++)
            {
                if (chunkPointers[currentChunk] == 0)
                {
                    continue;
                }
                else
                {
                    bitOffset = info2Offset + chunkPointers[currentChunk] - 1;
                }

                int  couldBeLiveOffset = bitOffset; // points to the couldBeLive bit array (array of bits indicating the slot changed state in the chunk)
                int  slotId            = 0;
                bool fSimple           = (NativeReader.ReadBits(image, 1, ref couldBeLiveOffset) == 0);
                bool fSkipFirst        = false;
                int  couldBeLiveCnt    = 0;
                if (!fSimple)
                {
                    fSkipFirst = (NativeReader.ReadBits(image, 1, ref couldBeLiveOffset) == 0);
                    slotId     = -1;
                }

                uint numCouldBeLiveSlots = GetNumCouldBeLiveSlots(image, ref bitOffset);                   // count the number of set bits in the couldBeLive array

                int finalStateOffset = bitOffset;                                                          // points to the finalState bit array (array of bits indicating if the slot is live at the end of the chunk)
                bitOffset += (int)numCouldBeLiveSlots;                                                     // points to the array of code offsets

                int normChunkBaseCodeOffset = currentChunk * _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK; // the sum of the sizes of all preceding chunks
                for (int i = 0; i < numCouldBeLiveSlots; i++)
                {
                    // get the index of the next couldBeLive slot
                    slotId = GetNextSlotId(image, fSimple, fSkipFirst, slotId, ref couldBeLiveCnt, ref couldBeLiveOffset);

                    // set the liveAtEnd for the slot at slotId
                    bool isLive = !liveAtEnd[slotId];
                    liveAtEnd[slotId] = (NativeReader.ReadBits(image, 1, ref finalStateOffset) != 0);

                    // Read all the code offsets where the slot at slotId changed state
                    while (NativeReader.ReadBits(image, 1, ref bitOffset) != 0)
                    {
                        int transitionOffset = NativeReader.ReadBits(image, _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2, ref bitOffset) + normChunkBaseCodeOffset;
                        transitions.Add(new GcTransition(transitionOffset, slotId, isLive, currentChunk, SlotTable, _machine));
                        isLive = !isLive;
                    }
                    slotId++;
                }
            }

            // convert normCodeOffsetDelta to the actual CodeOffset
            transitions.Sort((s1, s2) => s1.CodeOffset.CompareTo(s2.CodeOffset));
            return(UpdateTransitionCodeOffset(transitions));
        }
コード例 #9
0
        private List <List <BaseGcSlot> > GetLiveSlotsAtSafepoints(byte[] image, ref int bitOffset)
        {
            // For each safe point, enumerates a list of GC slots that are alive at that point
            var result = new List <List <BaseGcSlot> >();

            uint numSlots = SlotTable.NumTracked;

            if (numSlots == 0)
            {
                return(null);
            }

            uint numBitsPerOffset = 0;

            // Duplicate the encoder's heuristic to determine if we have indirect live
            // slot table (similar to the chunk pointers)
            if (NativeReader.ReadBits(image, 1, ref bitOffset) != 0)
            {
                numBitsPerOffset = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.POINTER_SIZE_ENCBASE, ref bitOffset) + 1;
                Debug.Assert(numBitsPerOffset != 0);
            }

            uint offsetTablePos = (uint)bitOffset;

            for (uint safePointIndex = 0; safePointIndex < NumSafePoints; safePointIndex++)
            {
                bitOffset = (int)offsetTablePos;

                var liveSlots = new List <BaseGcSlot>();

                if (numBitsPerOffset != 0)
                {
                    bitOffset += (int)(numBitsPerOffset * safePointIndex);

                    uint liveStatesOffset = (uint)NativeReader.ReadBits(image, (int)numBitsPerOffset, ref bitOffset);
                    uint liveStatesStart  = (uint)((offsetTablePos + NumSafePoints * numBitsPerOffset + 7) & (~7));
                    bitOffset = (int)(liveStatesStart + liveStatesOffset);
                    if (NativeReader.ReadBits(image, 1, ref bitOffset) != 0)
                    {
                        // RLE encoded
                        bool skip      = NativeReader.ReadBits(image, 1, ref bitOffset) == 0;
                        bool report    = true;
                        uint readSlots = NativeReader.DecodeVarLengthUnsigned(image,
                                                                              skip ? _gcInfoTypes.LIVESTATE_RLE_SKIP_ENCBASE : _gcInfoTypes.LIVESTATE_RLE_RUN_ENCBASE, ref bitOffset);
                        skip = !skip;
                        while (readSlots < numSlots)
                        {
                            uint cnt = NativeReader.DecodeVarLengthUnsigned(image,
                                                                            skip ? _gcInfoTypes.LIVESTATE_RLE_SKIP_ENCBASE : _gcInfoTypes.LIVESTATE_RLE_RUN_ENCBASE, ref bitOffset) + 1;
                            if (report)
                            {
                                for (uint slotIndex = readSlots; slotIndex < readSlots + cnt; slotIndex++)
                                {
                                    int trackedSlotIndex = 0;
                                    foreach (var slot in SlotTable.GcSlots)
                                    {
                                        if (slot.Flags != GcSlotFlags.GC_SLOT_UNTRACKED)
                                        {
                                            if (slotIndex == trackedSlotIndex)
                                            {
                                                liveSlots.Add(slot);
                                                break;
                                            }
                                            trackedSlotIndex++;
                                        }
                                    }
                                }
                            }
                            readSlots += cnt;
                            skip       = !skip;
                            report     = !report;
                        }
                        Debug.Assert(readSlots == numSlots);
                        result.Add(liveSlots);
                        continue;
                    }
                    // Just a normal live state (1 bit per slot), so use the normal decoding loop
                }
                else
                {
                    bitOffset += (int)(safePointIndex * numSlots);
                }

                for (uint slotIndex = 0; slotIndex < numSlots; slotIndex++)
                {
                    bool isLive = NativeReader.ReadBits(image, 1, ref bitOffset) != 0;
                    if (isLive)
                    {
                        int trackedSlotIndex = 0;
                        foreach (var slot in SlotTable.GcSlots)
                        {
                            if (slot.Flags != GcSlotFlags.GC_SLOT_UNTRACKED)
                            {
                                if (slotIndex == trackedSlotIndex)
                                {
                                    liveSlots.Add(slot);
                                    break;
                                }
                                trackedSlotIndex++;
                            }
                        }
                    }
                }

                result.Add(liveSlots);
            }

            return(result);
        }
コード例 #10
0
        /// <summary>
        /// based on <a href="https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/gcinfodecoder.cpp">GcInfoDecoder::GcInfoDecoder</a>
        /// </summary>
        public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion)
        {
            Offset       = offset;
            _gcInfoTypes = new GcInfoTypes(machine);
            _machine     = machine;

            SecurityObjectStackSlot            = -1;
            GSCookieStackSlot                  = -1;
            PSPSymStackSlot                    = -1;
            SecurityObjectStackSlot            = -1;
            GenericsInstContextStackSlot       = -1;
            StackBaseRegister                  = 0xffffffff;
            SizeOfEditAndContinuePreservedArea = 0xffffffff;
            ReversePInvokeFrameStackSlot       = -1;

            Version = ReadyToRunVersionToGcInfoVersion(majorVersion);
            int bitOffset = offset * 8;

            ParseHeaderFlags(image, ref bitOffset);

            if (Version >= MIN_GCINFO_VERSION_WITH_RETURN_KIND) // IsReturnKindAvailable
            {
                int returnKindBits = (_slimHeader) ? _gcInfoTypes.SIZE_OF_RETURN_KIND_SLIM : _gcInfoTypes.SIZE_OF_RETURN_KIND_FAT;
                ReturnKind = (ReturnKinds)NativeReader.ReadBits(image, returnKindBits, ref bitOffset);
            }

            CodeLength = _gcInfoTypes.DenormalizeCodeLength((int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.CODE_LENGTH_ENCBASE, ref bitOffset));

            if (_hasGSCookie)
            {
                uint normPrologSize = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_PROLOG_SIZE_ENCBASE, ref bitOffset) + 1;
                uint normEpilogSize = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_EPILOG_SIZE_ENCBASE, ref bitOffset);

                ValidRangeStart = normPrologSize;
                ValidRangeEnd   = (uint)CodeLength - normEpilogSize;
            }
            else if (_hasSecurityObject || _hasGenericsInstContext)
            {
                ValidRangeStart = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_PROLOG_SIZE_ENCBASE, ref bitOffset) + 1;
                ValidRangeEnd   = ValidRangeStart + 1;
            }

            if (_hasSecurityObject)
            {
                SecurityObjectStackSlot = _gcInfoTypes.DenormalizeStackSlot(NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.SECURITY_OBJECT_STACK_SLOT_ENCBASE, ref bitOffset));
            }

            if (_hasGSCookie)
            {
                GSCookieStackSlot = _gcInfoTypes.DenormalizeStackSlot(NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.GS_COOKIE_STACK_SLOT_ENCBASE, ref bitOffset));
            }

            if (_hasPSPSym)
            {
                PSPSymStackSlot = _gcInfoTypes.DenormalizeStackSlot(NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.PSP_SYM_STACK_SLOT_ENCBASE, ref bitOffset));
            }

            if (_hasGenericsInstContext)
            {
                GenericsInstContextStackSlot = _gcInfoTypes.DenormalizeStackSlot(NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE, ref bitOffset));
            }

            if (_hasStackBaseRegister && !_slimHeader)
            {
                StackBaseRegister = _gcInfoTypes.DenormalizeStackBaseRegister(NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.STACK_BASE_REGISTER_ENCBASE, ref bitOffset));
            }

            if (_hasSizeOfEditAndContinuePreservedArea)
            {
                SizeOfEditAndContinuePreservedArea = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE, ref bitOffset);
            }

            if (_hasReversePInvokeFrame)
            {
                ReversePInvokeFrameStackSlot = NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.REVERSE_PINVOKE_FRAME_ENCBASE, ref bitOffset);
            }

            // FIXED_STACK_PARAMETER_SCRATCH_AREA (this macro is always defined in _gcInfoTypes.h)
            if (!_slimHeader)
            {
                SizeOfStackOutgoingAndScratchArea = _gcInfoTypes.DenormalizeSizeOfStackArea(NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.SIZE_OF_STACK_AREA_ENCBASE, ref bitOffset));
            }

            // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED (this macro is always defined in _gcInfoTypes.h)
            NumSafePoints = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NUM_SAFE_POINTS_ENCBASE, ref bitOffset);

            if (!_slimHeader)
            {
                NumInterruptibleRanges = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NUM_INTERRUPTIBLE_RANGES_ENCBASE, ref bitOffset);
            }

            // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED (this macro is always defined in _gcInfoTypes.h)
            SafePointOffsets = EnumerateSafePoints(image, ref bitOffset);

            InterruptibleRanges = EnumerateInterruptibleRanges(image, _gcInfoTypes.INTERRUPTIBLE_RANGE_DELTA1_ENCBASE, _gcInfoTypes.INTERRUPTIBLE_RANGE_DELTA2_ENCBASE, ref bitOffset);

            SlotTable = new GcSlotTable(image, machine, _gcInfoTypes, ref bitOffset);

            if (SlotTable.NumSlots > 0)
            {
                if (NumSafePoints > 0)
                {
                    // Partially interruptible code
                    LiveSlotsAtSafepoints = GetLiveSlotsAtSafepoints(image, ref bitOffset);
                }
                else
                {
                    // Fully interruptible code
                    Transitions = GetTransitions(image, ref bitOffset);
                }
            }

            int nextByteOffset = (bitOffset + 7) >> 3;

            Size = nextByteOffset - offset;
        }