private static void WriteFakeILWithBranches(BlobBuilder builder, ControlFlowBuilder branchBuilder, int size) { Assert.Equal(0, builder.Count); const byte filling = 0x01; int ilOffset = 0; foreach (var branch in branchBuilder.Branches) { builder.WriteBytes(filling, branch.ILOffset - ilOffset); Assert.Equal(branch.ILOffset, builder.Count); builder.WriteByte((byte)branch.OpCode); int operandSize = branch.OpCode.GetBranchOperandSize(); if (operandSize == 1) { builder.WriteSByte(-1); } else { builder.WriteInt32(-1); } ilOffset = branch.ILOffset + sizeof(byte) + operandSize; } builder.WriteBytes(filling, size - ilOffset); Assert.Equal(size, builder.Count); }
public void Serialize(BlobBuilder writer) { switch (this.Discriminator) { case ConstantValueTypeDiscriminator.Boolean: writer.WriteBoolean(this.BooleanValue); break; case ConstantValueTypeDiscriminator.SByte: writer.WriteSByte(this.SByteValue); break; case ConstantValueTypeDiscriminator.Byte: writer.WriteByte(this.ByteValue); break; case ConstantValueTypeDiscriminator.Char: case ConstantValueTypeDiscriminator.Int16: writer.WriteInt16(this.Int16Value); break; case ConstantValueTypeDiscriminator.UInt16: writer.WriteUInt16(this.UInt16Value); break; case ConstantValueTypeDiscriminator.Single: writer.WriteSingle(this.SingleValue); break; case ConstantValueTypeDiscriminator.Int32: writer.WriteInt32(this.Int32Value); break; case ConstantValueTypeDiscriminator.UInt32: writer.WriteUInt32(this.UInt32Value); break; case ConstantValueTypeDiscriminator.Double: writer.WriteDouble(this.DoubleValue); break; case ConstantValueTypeDiscriminator.Int64: writer.WriteInt64(this.Int64Value); break; case ConstantValueTypeDiscriminator.UInt64: writer.WriteUInt64(this.UInt64Value); break; default: throw ExceptionUtilities.UnexpectedValue(this.Discriminator); } }
public void WritePrimitive() { var writer = new BlobBuilder(17); writer.WriteUInt32(0x11223344); writer.WriteUInt16(0x5566); writer.WriteByte(0x77); writer.WriteUInt64(0x8899aabbccddeeff); writer.WriteInt32(-1); writer.WriteInt16(-2); writer.WriteSByte(-3); writer.WriteBoolean(true); writer.WriteBoolean(false); writer.WriteInt64(unchecked ((long)0xfedcba0987654321)); writer.WriteDateTime(new DateTime(0x1112223334445556)); writer.WriteDecimal(102030405060.70m); writer.WriteDouble(double.NaN); writer.WriteSingle(float.NegativeInfinity); var guid = new Guid("01020304-0506-0708-090A-0B0C0D0E0F10"); writer.WriteBytes(guid.ToByteArray()); writer.WriteGuid(guid); AssertEx.Equal(new byte[] { 0x44, 0x33, 0x22, 0x11, 0x66, 0x55, 0x77, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfd, 0x01, 0x00, 0x21, 0x43, 0x65, 0x87, 0x09, 0xBA, 0xDC, 0xFE, 0x56, 0x55, 0x44, 0x34, 0x33, 0x22, 0x12, 0x11, 0x02, 0xD6, 0xE0, 0x9A, 0x94, 0x47, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x80, 0xFF, 0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }, writer.ToArray()); }
internal void FixupBranches(BlobBuilder srcBuilder, BlobBuilder dstBuilder) { int srcOffset = 0; var branch = _branches[0]; int branchIndex = 0; int blobOffset = 0; foreach (Blob blob in srcBuilder.GetBlobs()) { Debug.Assert(blobOffset == 0 || blobOffset == 1 && blob.Buffer[blobOffset - 1] == 0xff); while (true) { // copy bytes preceding the next branch, or till the end of the blob: int chunkSize = Math.Min(branch.ILOffset - srcOffset, blob.Length - blobOffset); dstBuilder.WriteBytes(blob.Buffer, blobOffset, chunkSize); srcOffset += chunkSize; blobOffset += chunkSize; // there is no branch left in the blob: if (blobOffset == blob.Length) { blobOffset = 0; break; } Debug.Assert(blob.Buffer[blobOffset] == branch.ShortOpCode && (blobOffset + 1 == blob.Length || blob.Buffer[blobOffset + 1] == 0xff)); srcOffset += sizeof(byte) + sizeof(sbyte); // write actual branch instruction: int branchDistance; if (branch.IsShortBranchDistance(_labels, out branchDistance)) { dstBuilder.WriteByte(branch.ShortOpCode); dstBuilder.WriteSByte((sbyte)branchDistance); } else { dstBuilder.WriteByte((byte)((ILOpCode)branch.ShortOpCode).GetLongBranch()); dstBuilder.WriteInt32(branchDistance); } // next branch: branchIndex++; if (branchIndex == _branches.Count) { branch = new BranchInfo(int.MaxValue, default(LabelHandle), 0); } else { branch = _branches[branchIndex]; } // the branch starts at the very end and its operand is in the next blob: if (blobOffset == blob.Length - 1) { blobOffset = 1; break; } // skip fake branch instruction: blobOffset += sizeof(byte) + sizeof(sbyte); } } }
/// <exception cref="InvalidOperationException" /> internal void CopyCodeAndFixupBranches(BlobBuilder srcBuilder, BlobBuilder dstBuilder) { var branch = _branches[0]; int branchIndex = 0; // offset within the source builder int srcOffset = 0; // current offset within the current source blob int srcBlobOffset = 0; foreach (Blob srcBlob in srcBuilder.GetBlobs()) { Debug.Assert( srcBlobOffset == 0 || srcBlobOffset == 1 && srcBlob.Buffer[0] == 0xff || srcBlobOffset == 4 && srcBlob.Buffer[0] == 0xff && srcBlob.Buffer[1] == 0xff && srcBlob.Buffer[2] == 0xff && srcBlob.Buffer[3] == 0xff); while (true) { // copy bytes preceding the next branch, or till the end of the blob: int chunkSize = Math.Min(branch.ILOffset - srcOffset, srcBlob.Length - srcBlobOffset); dstBuilder.WriteBytes(srcBlob.Buffer, srcBlobOffset, chunkSize); srcOffset += chunkSize; srcBlobOffset += chunkSize; // there is no branch left in the blob: if (srcBlobOffset == srcBlob.Length) { srcBlobOffset = 0; break; } Debug.Assert(srcBlob.Buffer[srcBlobOffset] == (byte)branch.OpCode); int operandSize = branch.OpCode.GetBranchOperandSize(); bool isShortInstruction = operandSize == 1; // Note: the 4B operand is contiguous since we wrote it via BlobBuilder.WriteInt32() Debug.Assert( srcBlobOffset + 1 == srcBlob.Length || (isShortInstruction ? srcBlob.Buffer[srcBlobOffset + 1] == 0xff : BitConverter.ToUInt32(srcBlob.Buffer, srcBlobOffset + 1) == 0xffffffff)); // write branch opcode: dstBuilder.WriteByte(srcBlob.Buffer[srcBlobOffset]); // write branch operand: int branchDistance; bool isShortDistance = branch.IsShortBranchDistance(_labels, out branchDistance); if (isShortInstruction && !isShortDistance) { // We could potentially implement algortihm that automatically fixes up the branch instructions as well to accomodate bigger distances, // however an optimal algorithm would be rather complex (something like: calculate topological ordering of crossing branch instructions // and then use fixed point to eliminate cycles). If the caller doesn't care about optimal IL size they can use long branches whenever the // distance is unknown upfront. If they do they probably already implement more sophisticad algorithm for IL layout optimization already. throw new InvalidOperationException(SR.Format(SR.DistanceBetweenInstructionAndLabelTooBig, branch.OpCode, srcOffset, branchDistance)); } if (isShortInstruction) { dstBuilder.WriteSByte((sbyte)branchDistance); } else { dstBuilder.WriteInt32(branchDistance); } srcOffset += sizeof(byte) + operandSize; // next branch: branchIndex++; if (branchIndex == _branches.Count) { branch = new BranchInfo(int.MaxValue, default(LabelHandle), 0); } else { branch = _branches[branchIndex]; } // the branch starts at the very end and its operand is in the next blob: if (srcBlobOffset == srcBlob.Length - 1) { srcBlobOffset = operandSize; break; } // skip fake branch instruction: srcBlobOffset += sizeof(byte) + operandSize; } } }
/// <exception cref="InvalidOperationException" /> internal void CopyCodeAndFixupBranches(BlobBuilder srcBuilder, BlobBuilder dstBuilder) { var branch = _branches[0]; int branchIndex = 0; // offset within the source builder int srcOffset = 0; // current offset within the current source blob int srcBlobOffset = 0; foreach (Blob srcBlob in srcBuilder.GetBlobs()) { Debug.Assert( srcBlobOffset == 0 || srcBlobOffset == 1 && srcBlob.Buffer[0] == 0xff || srcBlobOffset == 4 && srcBlob.Buffer[0] == 0xff && srcBlob.Buffer[1] == 0xff && srcBlob.Buffer[2] == 0xff && srcBlob.Buffer[3] == 0xff); while (true) { // copy bytes preceding the next branch, or till the end of the blob: int chunkSize = Math.Min(branch.ILOffset - srcOffset, srcBlob.Length - srcBlobOffset); dstBuilder.WriteBytes(srcBlob.Buffer, srcBlobOffset, chunkSize); srcOffset += chunkSize; srcBlobOffset += chunkSize; // there is no branch left in the blob: if (srcBlobOffset == srcBlob.Length) { srcBlobOffset = 0; break; } Debug.Assert(srcBlob.Buffer[srcBlobOffset] == (byte)branch.OpCode); int operandSize = branch.OpCode.GetBranchOperandSize(); bool isShortInstruction = operandSize == 1; // Note: the 4B operand is contiguous since we wrote it via BlobBuilder.WriteInt32() Debug.Assert( srcBlobOffset + 1 == srcBlob.Length || (isShortInstruction ? srcBlob.Buffer[srcBlobOffset + 1] == 0xff : BitConverter.ToUInt32(srcBlob.Buffer, srcBlobOffset + 1) == 0xffffffff)); // write branch opcode: dstBuilder.WriteByte(srcBlob.Buffer[srcBlobOffset]); int branchDistance = branch.GetBranchDistance(_labels, branch.OpCode, srcOffset, isShortInstruction); // write branch operand: if (isShortInstruction) { dstBuilder.WriteSByte((sbyte)branchDistance); } else { dstBuilder.WriteInt32(branchDistance); } srcOffset += sizeof(byte) + operandSize; // next branch: branchIndex++; if (branchIndex == _branches.Count) { branch = new BranchInfo(int.MaxValue, label: default, opCode: default);
public void WritePrimitive() { var writer = new BlobBuilder(17); writer.WriteUInt32(0x11223344); writer.WriteUInt16(0x5566); writer.WriteByte(0x77); writer.WriteUInt64(0x8899aabbccddeeff); writer.WriteInt32(-1); writer.WriteInt16(-2); writer.WriteSByte(-3); writer.WriteBoolean(true); writer.WriteBoolean(false); writer.WriteInt64(unchecked((long)0xfedcba0987654321)); writer.WriteDateTime(new DateTime(0x1112223334445556)); writer.WriteDecimal(102030405060.70m); writer.WriteDouble(double.NaN); writer.WriteSingle(float.NegativeInfinity); var guid = new Guid("01020304-0506-0708-090A-0B0C0D0E0F10"); writer.WriteBytes(guid.ToByteArray()); writer.WriteGuid(guid); AssertEx.Equal(new byte[] { 0x44, 0x33, 0x22, 0x11, 0x66, 0x55, 0x77, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfd, 0x01, 0x00, 0x21, 0x43, 0x65, 0x87, 0x09, 0xBA, 0xDC, 0xFE, 0x56, 0x55, 0x44, 0x34, 0x33, 0x22, 0x12, 0x11, 0x02, 0xD6, 0xE0, 0x9A, 0x94, 0x47, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x80, 0xFF, 0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }, writer.ToArray()); }
internal static void WriteConstant(BlobBuilder writer, object value) { if (value == null) { // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 32-bit. writer.WriteUInt32(0); return; } var type = value.GetType(); if (type.GetTypeInfo().IsEnum) { type = Enum.GetUnderlyingType(type); } if (type == typeof(bool)) { writer.WriteBoolean((bool)value); } else if (type == typeof(int)) { writer.WriteInt32((int)value); } else if (type == typeof(string)) { writer.WriteUTF16((string)value); } else if (type == typeof(byte)) { writer.WriteByte((byte)value); } else if (type == typeof(char)) { writer.WriteUInt16((char)value); } else if (type == typeof(double)) { writer.WriteDouble((double)value); } else if (type == typeof(short)) { writer.WriteInt16((short)value); } else if (type == typeof(long)) { writer.WriteInt64((long)value); } else if (type == typeof(sbyte)) { writer.WriteSByte((sbyte)value); } else if (type == typeof(float)) { writer.WriteSingle((float)value); } else if (type == typeof(ushort)) { writer.WriteUInt16((ushort)value); } else if (type == typeof(uint)) { writer.WriteUInt32((uint)value); } else if (type == typeof(ulong)) { writer.WriteUInt64((ulong)value); } else { // TODO: message throw new ArgumentException(); } }
public static void Write( BlobBuilder writer, IReadOnlyList <Instruction> il, Func <string, StringHandle> getString, IReadOnlyDictionary <Guid, EntityHandle> typeHandles, IReadOnlyDictionary <ConstructorInfo, MemberReferenceHandle> ctorRefHandles, IReadOnlyDictionary <FieldInfo, FieldDefinitionHandle> fieldHandles, IReadOnlyDictionary <MethodInfo, MethodDefinitionHandle> methodHandles) { var targetOffsets = new ArrayMapper <int>(); //var offsetIndex = new Dictionary<int, int>(); for (var i = 0; i < il.Count; i++) { //offsetIndex.Add(il[i].Offset, i); var opCode = il[i].OpCode; opCode.WriteOpCode(writer.WriteByte); switch (opCode.OperandType) { case OperandType.InlineNone: break; case OperandType.InlineSwitch: var branches = (int[])il[i].Operand; writer.WriteInt32(branches.Length); for (var k = 0; k < branches.Length; k++) { var branchOffset = branches[k]; writer.WriteInt32(targetOffsets.Add( branchOffset + il[i].Offset + opCode.Size + 4 * (branches.Length + 1))); } break; case OperandType.ShortInlineBrTarget: var offset8 = (sbyte)il[i].Operand; // offset convention in IL: zero is at next instruction writer.WriteSByte((sbyte)targetOffsets.Add(offset8 + il[i].Offset + opCode.Size + 1)); break; case OperandType.InlineBrTarget: var offset32 = (int)il[i].Operand; // offset convention in IL: zero is at next instruction writer.WriteInt32(targetOffsets.Add(offset32 + il[i].Offset + opCode.Size + 4)); break; case OperandType.ShortInlineI: if (opCode == OpCodes.Ldc_I4_S) { writer.WriteSByte((sbyte)il[i].Operand); } else { writer.WriteByte((byte)il[i].Operand); } break; case OperandType.InlineI: writer.WriteInt32((int)il[i].Operand); break; case OperandType.ShortInlineR: writer.WriteSingle((float)il[i].Operand); break; case OperandType.InlineR: writer.WriteDouble((double)il[i].Operand); break; case OperandType.InlineI8: writer.WriteInt64((long)il[i].Operand); break; case OperandType.InlineSig: writer.WriteBytes((byte[])il[i].Operand); break; case OperandType.InlineString: writer.WriteInt32(MetadataTokens.GetToken(getString((string)il[i].Operand))); break; case OperandType.InlineType: case OperandType.InlineTok: case OperandType.InlineMethod: case OperandType.InlineField: switch (il[i].Operand) { case Type type: writer.WriteInt32(MetadataTokens.GetToken(typeHandles[type.GUID])); break; case ConstructorInfo constructorInfo: writer.WriteInt32(MetadataTokens.GetToken(ctorRefHandles[constructorInfo])); break; case FieldInfo fieldInfo: writer.WriteInt32(MetadataTokens.GetToken(fieldHandles[fieldInfo])); break; case MethodInfo methodInfo: writer.WriteInt32(MetadataTokens.GetToken(methodHandles[methodInfo])); break; default: throw new NotSupportedException(); } break; case OperandType.ShortInlineVar: var bLocalVariableInfo = il[i].Operand as LocalVariableInfo; var bParameterInfo = il[i].Operand as ParameterInfo; if (bLocalVariableInfo != null) { writer.WriteByte((byte)bLocalVariableInfo.LocalIndex); } else if (bParameterInfo != null) { writer.WriteByte((byte)bParameterInfo.Position); } else { throw new NotSupportedException(); } break; case OperandType.InlineVar: var sLocalVariableInfo = il[i].Operand as LocalVariableInfo; var sParameterInfo = il[i].Operand as ParameterInfo; if (sLocalVariableInfo != null) { writer.WriteUInt16((ushort)sLocalVariableInfo.LocalIndex); } else if (sParameterInfo != null) { writer.WriteUInt16((ushort)sParameterInfo.Position); } else { throw new NotSupportedException(); } break; default: throw new NotSupportedException(); } } }