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); }
private int GetNextSlotId(byte[] image, bool fSimple, bool fSkipFirst, int slotId, ref int couldBeLiveCnt, ref int couldBeLiveOffset) { if (fSimple) { 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); }
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); } }
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(-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(-1, new GcStackSlot(spOffset, spBase), flags, isUntracked)); } }
private IEnumerable <uint> EnumerateSafePoints(byte[] image, ref int bitOffset) { List <uint> safePoints = new List <uint>(); uint numBitsPerOffset = GcInfoTypes.CeilOfLog2(CodeLength); for (int i = 0; i < NumSafePoints; i++) { uint normOffset = (uint)NativeReader.ReadBits(image, (int)numBitsPerOffset, ref bitOffset); safePoints.Add(normOffset); } return(safePoints); }
private uint GetNumCouldBeLiveSlots(byte[] image, ref int bitOffset) { uint numCouldBeLiveSlots = 0; int numTracked = SlotTable.GcSlots.Count - (int)SlotTable.NumUntracked; 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 { foreach (var slot in SlotTable.GcSlots) { if (slot.Flags == GcSlotFlags.GC_SLOT_UNTRACKED) { break; } if (NativeReader.ReadBits(image, 1, ref bitOffset) != 0) { numCouldBeLiveSlots++; } } } return(numCouldBeLiveSlots); }
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((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((int)regNum, null, flags)); } }
public IList <GcTransition> GetTranstions(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; //=2 int numBitsPerPointer = (int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.POINTER_SIZE_ENCBASE, ref bitOffset); if (numBitsPerPointer == 0) { return(new List <GcTransition>()); } int[] chunkPointers = new int[numChunks]; for (int i = 0; i < numChunks; i++) { chunkPointers[i] = NativeReader.ReadBits(image, numBitsPerPointer, ref bitOffset); } int info2Offset = (int)Math.Ceiling(bitOffset / 8.0) * 8; List <GcTransition> transitions = new List <GcTransition>(); bool[] liveAtEnd = new bool[SlotTable.GcSlots.Count - SlotTable.NumUntracked]; for (int currentChunk = 0; currentChunk < numChunks; currentChunk++) { if (chunkPointers[currentChunk] == 0) { continue; } else { bitOffset = info2Offset + chunkPointers[currentChunk] - 1; } int couldBeLiveOffset = bitOffset; 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); int finalStateOffset = bitOffset; bitOffset += (int)numCouldBeLiveSlots; int normChunkBaseCodeOffset = currentChunk * _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK; for (int i = 0; i < numCouldBeLiveSlots; i++) { slotId = GetNextSlotId(image, fSimple, fSkipFirst, slotId, ref couldBeLiveCnt, ref couldBeLiveOffset); bool isLive = !liveAtEnd[slotId]; liveAtEnd[slotId] = (NativeReader.ReadBits(image, 1, ref finalStateOffset) != 0); // Read transitions 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)); isLive = !isLive; } slotId++; } } transitions.Sort((s1, s2) => s1.CodeOffset.CompareTo(s2.CodeOffset)); UpdateTransitionCodeOffset(transitions); return(transitions); }
public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion) { Offset = offset; _gcInfoTypes = new GcInfoTypes(machine); SecurityObjectStackSlot = -1; GSCookieStackSlot = -1; PSPSymStackSlot = -1; SecurityObjectStackSlot = -1; GenericsInstContextStackSlot = -1; StackBaseRegister = 0xffffffff; SizeOfEditAndContinuePreservedArea = 0xffffffff; ReversePInvokeFrameStackSlot = -1; Version = ReadyToRunVersionToGcInfoVersion(majorVersion); int bitOffset = offset * 8; int startBitOffset = bitOffset; 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_PROLOG_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); uint numBitsPerOffset = GcInfoTypes.CeilOfLog2(CodeLength); bitOffset += (int)(NumSafePoints * numBitsPerOffset); InterruptibleRanges = EnumerateInterruptibleRanges(image, _gcInfoTypes.INTERRUPTIBLE_RANGE_DELTA1_ENCBASE, _gcInfoTypes.INTERRUPTIBLE_RANGE_DELTA2_ENCBASE, ref bitOffset); SlotTable = new GcSlotTable(image, machine, _gcInfoTypes, ref bitOffset); Transitions = GetTranstions(image, ref bitOffset); Size = bitOffset - startBitOffset; _machine = machine; }