public byte[] SerializeMethodDebugInfo(EmitContext context, IMethodBody methodBody, MethodDefinitionHandle methodHandle, bool emitEncInfo, bool suppressNewCustomDebugInfo, out bool emitExternNamespaces) { emitExternNamespaces = false; // CONSIDER: this may not be the same "first" method as in Dev10, but // it shouldn't matter since all methods will still forward to a method // containing the appropriate information. if (_methodBodyWithModuleInfo == null) { // This module level information could go on every method (and does in // the edit-and-continue case), but - as an optimization - we'll just // put it on the first method we happen to encounter and then put a // reference to the first method's token in every other method (so they // can find the information). if (context.Module.GetAssemblyReferenceAliases(context).Any()) { _methodWithModuleInfo = methodHandle; _methodBodyWithModuleInfo = methodBody; emitExternNamespaces = true; } } var pooledBuilder = PooledBlobBuilder.GetInstance(); var encoder = new CustomDebugInfoEncoder(pooledBuilder); // NOTE: This is an attempt to match Dev10's apparent behavior. For iterator methods (i.e. the method // that appears in source, not the synthesized ones), Dev10 only emits the StateMachineTypeName // custom debug info (e.g. there will be no information about the usings that were in scope). // NOTE: There seems to be an unusual behavior in ISymUnmanagedWriter where, if all the methods in a type are // iterator methods, no custom debug info is emitted for any method. Adding a single non-iterator // method causes the custom debug info to be produced for all methods (including the iterator methods). // Since we are making the same ISymUnmanagedWriter calls as Dev10, we see the same behavior (i.e. this // is not a regression). if (methodBody.StateMachineTypeName != null) { encoder.AddStateMachineTypeName(methodBody.StateMachineTypeName); } else { SerializeNamespaceScopeMetadata(ref encoder, context, methodBody); encoder.AddStateMachineHoistedLocalScopes(methodBody.StateMachineHoistedLocalScopes); } if (!suppressNewCustomDebugInfo) { SerializeDynamicLocalInfo(ref encoder, methodBody); SerializeTupleElementNames(ref encoder, methodBody); if (emitEncInfo) { var encMethodInfo = MetadataWriter.GetEncMethodDebugInfo(methodBody); SerializeCustomDebugInformation(ref encoder, encMethodInfo); } } byte[] result = encoder.ToArray(); pooledBuilder.Free(); return(result); }
private static PooledBlobBuilder SerializeRecord( byte kind, EditAndContinueMethodDebugInformation debugInfo, Action <EditAndContinueMethodDebugInformation, BlobBuilder> recordSerializer) { var cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.WriteByte(0); // alignment size and length (will be patched) var alignmentSizeAndLengthWriter = new BlobWriter(cmw.ReserveBytes(sizeof(byte) + sizeof(uint))); recordSerializer(debugInfo, cmw); int length = cmw.Count; int alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); cmw.WriteBytes(0, alignmentSize); // fill in alignment size and length: alignmentSizeAndLengthWriter.WriteByte(alignmentSize); alignmentSizeAndLengthWriter.WriteUInt32((uint)alignedLength); return(cmw); }
private static void SerializeStateMachineLocalScopes(IMethodBody methodBody, ArrayBuilder <PooledBlobBuilder> customDebugInfo) { var scopes = methodBody.StateMachineHoistedLocalScopes; if (scopes.IsDefaultOrEmpty) { return; } uint numberOfScopes = (uint)scopes.Length; var cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindStateMachineHoistedLocalScopes); cmw.Align(4); cmw.WriteUInt32(12 + numberOfScopes * 8); cmw.WriteUInt32(numberOfScopes); foreach (var scope in scopes) { if (scope.IsDefault) { cmw.WriteUInt32(0); cmw.WriteUInt32(0); } else { // Dev12 C# emits end-inclusive range cmw.WriteUInt32((uint)scope.StartOffset); cmw.WriteUInt32((uint)scope.EndOffset - 1); } } customDebugInfo.Add(cmw); }
private static PooledBlobBuilder SerializeRecord <T>( CustomDebugInfoKind kind, T debugInfo, Action <T, BlobBuilder> recordSerializer) { PooledBlobBuilder cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CustomDebugInfoConstants.Version); cmw.WriteByte((byte)kind); cmw.WriteByte(0); // alignment size and length (will be patched) BlobWriter alignmentSizeAndLengthWriter = new BlobWriter(cmw.ReserveBytes(sizeof(byte) + sizeof(uint))); recordSerializer(debugInfo, cmw); int length = cmw.Count; int alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); cmw.WriteBytes(0, alignmentSize); // fill in alignment size and length: alignmentSizeAndLengthWriter.WriteByte(alignmentSize); alignmentSizeAndLengthWriter.WriteUInt32((uint)alignedLength); return(cmw); }
private static PooledBlobBuilder SerializeRecord(byte kind, Action <BlobBuilder> data) { var cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.WriteByte(0); // alignment size and length (will be patched) var alignmentSizeAndLengthWriter = cmw.ReserveBytes(sizeof(byte) + sizeof(uint)); data(cmw); int length = cmw.Position; int alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); cmw.WriteBytes(0, alignmentSize); // fill in alignment size and length: alignmentSizeAndLengthWriter.WriteByte(alignmentSize); alignmentSizeAndLengthWriter.WriteUInt32((uint)alignedLength); return(cmw); }
private void SerializeReferenceToPreviousMethodWithUsingInfo(ArrayBuilder <PooledBlobBuilder> customDebugInfo) { var cmw = PooledBlobBuilder.GetInstance(12); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindForwardInfo); cmw.Align(4); cmw.WriteUInt32(12); cmw.WriteUInt32((uint)_previousMethodTokenWithUsingInfo); customDebugInfo.Add(cmw); }
private void SerializeReferenceToMethodWithModuleInfo(ArrayBuilder <PooledBlobBuilder> customDebugInfo) { PooledBlobBuilder cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CustomDebugInfoConstants.Version); cmw.WriteByte((byte)CustomDebugInfoKind.ForwardToModuleInfo); cmw.Align(4); cmw.WriteUInt32(12); cmw.WriteUInt32((uint)_methodTokenWithModuleInfo); customDebugInfo.Add(cmw); }
public byte[] SerializeMethodDebugInfo(EmitContext context, IMethodBody methodBody, MethodDefinitionHandle methodHandle, bool emitEncInfo, bool suppressNewCustomDebugInfo, out bool emitExternNamespaces) { emitExternNamespaces = false; // CONSIDER: this may not be the same "first" method as in Dev10, but // it shouldn't matter since all methods will still forward to a method // containing the appropriate information. if (_methodBodyWithModuleInfo == null) { // This module level information could go on every method (and does in // the edit-and-continue case), but - as an optimization - we'll just // put it on the first method we happen to encounter and then put a // reference to the first method's token in every other method (so they // can find the information). if (context.Module.GetAssemblyReferenceAliases(context).Any()) { _methodWithModuleInfo = methodHandle; _methodBodyWithModuleInfo = methodBody; emitExternNamespaces = true; } } var pooledBuilder = PooledBlobBuilder.GetInstance(); var encoder = new CustomDebugInfoEncoder(pooledBuilder); if (methodBody.StateMachineTypeName != null) { encoder.AddStateMachineTypeName(methodBody.StateMachineTypeName); } else { SerializeNamespaceScopeMetadata(ref encoder, context, methodBody); encoder.AddStateMachineHoistedLocalScopes(methodBody.StateMachineHoistedLocalScopes); } if (!suppressNewCustomDebugInfo) { SerializeDynamicLocalInfo(ref encoder, methodBody); SerializeTupleElementNames(ref encoder, methodBody); if (emitEncInfo) { var encMethodInfo = MetadataWriter.GetEncMethodDebugInfo(methodBody); SerializeCustomDebugInformation(ref encoder, encMethodInfo); } } byte[] result = encoder.ToArray(); pooledBuilder.Free(); return(result); }
private void SerializeNamespaceScopeMetadata(EmitContext context, IMethodBody methodBody, ArrayBuilder <PooledBlobBuilder> customDebugInfo) { if (context.Module.GenerateVisualBasicStylePdb) { return; } if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody)) { Debug.Assert(!ReferenceEquals(_previousMethodBodyWithUsingInfo, methodBody)); SerializeReferenceToPreviousMethodWithUsingInfo(customDebugInfo); return; } List <ushort> usingCounts = new List <ushort>(); var cmw = PooledBlobBuilder.GetInstance(); for (IImportScope scope = methodBody.ImportScope; scope != null; scope = scope.Parent) { usingCounts.Add((ushort)scope.GetUsedNamespaces().Length); } // ACASEY: This originally wrote (uint)12, (ushort)1, (ushort)0 in the // case where usingCounts was empty, but I'm not sure why. if (usingCounts.Count > 0) { uint streamLength; cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindUsingInfo); cmw.Align(4); cmw.WriteUInt32(streamLength = BitArithmeticUtilities.Align((uint)usingCounts.Count * 2 + 10, 4)); cmw.WriteUInt16((ushort)usingCounts.Count); foreach (ushort uc in usingCounts) { cmw.WriteUInt16(uc); } cmw.Align(4); Debug.Assert(streamLength == cmw.Count); customDebugInfo.Add(cmw); } if (_methodBodyWithModuleInfo != null && !ReferenceEquals(_methodBodyWithModuleInfo, methodBody)) { SerializeReferenceToMethodWithModuleInfo(customDebugInfo); } }
public BlobIdx GetConstantBlobIndex(object value) { string str = value as string; if (str != null) { return(this.GetBlobIndex(str)); } var writer = PooledBlobBuilder.GetInstance(); writer.WriteConstant(value); var result = this.GetBlobIndex(writer); writer.Free(); return(result); }
private static void SerializeReferenceToIteratorClass(string iteratorClassName, ArrayBuilder <PooledBlobBuilder> customDebugInfo) { if (iteratorClassName == null) { return; } PooledBlobBuilder cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CustomDebugInfoConstants.Version); cmw.WriteByte((byte)CustomDebugInfoKind.ForwardIterator); cmw.Align(4); uint length = 10 + (uint)iteratorClassName.Length * 2; if ((length & 3) != 0) { length += 4 - (length & 3); } cmw.WriteUInt32(length); WriteUtf16String(cmw, iteratorClassName); cmw.Align(4); Debug.Assert(cmw.Count == length); customDebugInfo.Add(cmw); }
private static void SerializeReferenceToIteratorClass(string iteratorClassName, ArrayBuilder <PooledBlobBuilder> customDebugInfo) { if (iteratorClassName == null) { return; } var cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindForwardIterator); cmw.Align(4); uint length = 10 + (uint)iteratorClassName.Length * 2; if ((length & 3) != 0) { length += 4 - (length & 3); } cmw.WriteUInt32(length); cmw.WriteUTF16(iteratorClassName); cmw.WriteInt16(0); cmw.Align(4); Debug.Assert(cmw.Position == length); customDebugInfo.Add(cmw); }
private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder <PooledBlobBuilder> customDebugInfo) { if (!methodBody.HasDynamicLocalVariables) { return; //There are no dynamic locals } var dynamicLocals = ArrayBuilder <ILocalDefinition> .GetInstance(); foreach (ILocalDefinition local in methodBody.LocalVariables) { Debug.Assert(local.SlotIndex >= 0); if (local.IsDynamic) { dynamicLocals.Add(local); } } foreach (var currentScope in methodBody.LocalScopes) { foreach (var localConstant in currentScope.Constants) { Debug.Assert(localConstant.SlotIndex < 0); if (localConstant.IsDynamic) { dynamicLocals.Add(localConstant); } } } Debug.Assert(dynamicLocals.Any()); // There must be at least one dynamic local if this point is reached const int dynamicAttributeSize = 64; const int identifierSize = 64; const int blobSize = dynamicAttributeSize + 4 + 4 + identifierSize * 2;//DynamicAttribute: 64, DynamicAttributeLength: 4, SlotIndex: 4, IdentifierName: 128 var cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindDynamicLocals); cmw.Align(4); // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob)) cmw.WriteUInt32(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUInt32((uint)dynamicLocals.Count); foreach (ILocalDefinition local in dynamicLocals) { if (local.Name.Length >= identifierSize)//Ignore and push empty information { cmw.WriteBytes(0, blobSize); continue; } var dynamicTransformFlags = local.DynamicTransformFlags; if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= dynamicAttributeSize) { byte[] flag = new byte[dynamicAttributeSize]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if ((bool)dynamicTransformFlags[k].Value) { flag[k] = 1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUInt32((uint)dynamicTransformFlags.Length); //Written Length } else { cmw.WriteBytes(0, dynamicAttributeSize + 4); //Empty flag array and size. } var localIndex = local.SlotIndex; cmw.WriteUInt32((localIndex < 0) ? 0u : (uint)localIndex); char[] localName = new char[identifierSize]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteUTF16(localName); } dynamicLocals.Free(); customDebugInfo.Add(cmw); }
private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder <PooledBlobBuilder> customDebugInfo) { if (!methodBody.HasDynamicLocalVariables) { return; //There are no dynamic locals } const int dynamicAttributeSize = 64; const int identifierSize = 64; ArrayBuilder <ILocalDefinition> dynamicLocals = GetLocalInfoToSerialize( methodBody, local => { System.Collections.Immutable.ImmutableArray <TypedConstant> dynamicTransformFlags = local.DynamicTransformFlags; return(!dynamicTransformFlags.IsEmpty && dynamicTransformFlags.Length <= dynamicAttributeSize && local.Name.Length < identifierSize); }, (scope, local) => local); if (dynamicLocals == null) { return; } const int blobSize = dynamicAttributeSize + 4 + 4 + identifierSize * 2;//DynamicAttribute: 64, DynamicAttributeLength: 4, SlotIndex: 4, IdentifierName: 128 PooledBlobBuilder cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CustomDebugInfoConstants.Version); cmw.WriteByte((byte)CustomDebugInfoKind.DynamicLocals); cmw.Align(4); // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob)) cmw.WriteUInt32(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUInt32((uint)dynamicLocals.Count); foreach (ILocalDefinition local in dynamicLocals) { System.Collections.Immutable.ImmutableArray <TypedConstant> dynamicTransformFlags = local.DynamicTransformFlags; byte[] flag = new byte[dynamicAttributeSize]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if ((bool)dynamicTransformFlags[k].Value) { flag[k] = 1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUInt32((uint)dynamicTransformFlags.Length); //Written Length int localIndex = local.SlotIndex; cmw.WriteUInt32((localIndex < 0) ? 0u : (uint)localIndex); char[] localName = new char[identifierSize]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteUTF16(localName); } dynamicLocals.Free(); customDebugInfo.Add(cmw); }