public MetadataBuilder( int userStringHeapStartOffset = 0, int stringHeapStartOffset = 0, int blobHeapStartOffset = 0, int guidHeapStartOffset = 0) { // -1 for the 0 we always write at the beginning of the heap: if (userStringHeapStartOffset >= UserStringHeapSizeLimit - 1) { throw ImageFormatLimitationException.HeapSizeLimitExceeded(HeapIndex.UserString); } // Add zero-th entry to all heaps, even in EnC delta. // We don't want generation-relative handles to ever be IsNil. // In both full and delta metadata all nil heap handles should have zero value. // There should be no blob handle that references the 0 byte added at the // beginning of the delta blob. _userStringBuilder.WriteByte(0); _blobs.Add(ImmutableArray <byte> .Empty, default(BlobHandle)); _blobHeapSize = 1; // When EnC delta is applied #US, #String and #Blob heaps are appended. // Thus indices of strings and blobs added to this generation are offset // by the sum of respective heap sizes of all previous generations. _userStringHeapStartOffset = userStringHeapStartOffset; _stringHeapStartOffset = stringHeapStartOffset; _blobHeapStartOffset = blobHeapStartOffset; // Unlike other heaps, #Guid heap in EnC delta is zero-padded. _guidBuilder.WriteBytes(0, guidHeapStartOffset); }
private int GetNewUserStringHeapOffset(int stringLength) { int startPosition = _userStringWriter.Position; int offset = startPosition + _userStringHeapStartOffset; // Native metadata emitter allows strings to exceed the heap size limit as long // as the index is within the limits (see https://github.com/dotnet/roslyn/issues/9852) if (offset > UserStringHeapSizeLimit) { ImageFormatLimitationException.ThrowHeapSizeLimitExceeded(HeapIndex.UserString); } return(offset); }
/// <exception cref="ImageFormatLimitationException">The remaining space on the heap is too small to fit the string.</exception> public UserStringHandle GetOrAddUserString(string str) { int index; if (!_userStrings.TryGetValue(str, out index)) { Debug.Assert(!_streamsAreComplete); int startPosition = _userStringBuilder.Count; int encodedLength = str.Length * 2 + 1; index = startPosition + _userStringHeapStartOffset; // Native metadata emitter allows strings to exceed the heap size limit as long // as the index is within the limits (see https://github.com/dotnet/roslyn/issues/9852) if (index >= UserStringHeapSizeLimit) { throw ImageFormatLimitationException.HeapSizeLimitExceeded(HeapIndex.UserString); } _userStrings.Add(str, index); _userStringBuilder.WriteCompressedInteger(encodedLength); _userStringBuilder.WriteUTF16(str); // Write out a trailing byte indicating if the string is really quite simple byte stringKind = 0; foreach (char ch in str) { if (ch >= 0x7F) { stringKind = 1; } else { switch ((int)ch) { case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: case 0x8: case 0xE: case 0xF: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: case 0x27: case 0x2D: stringKind = 1; break; default: continue; } } break; } _userStringBuilder.WriteByte(stringKind); } return(MetadataTokens.UserStringHandle(index)); }