PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs

https://gitlab.com/sharadag/TestProject2
C# | 243 lines | 188 code | 31 blank | 24 comment | 12 complexity | e99bd16fd324b773ded18dbd62730420 MD5 | raw file
  1. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Collections.Immutable;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. using System.Reflection.Metadata;
  8. using Microsoft.CodeAnalysis.CodeGen;
  9. using Microsoft.CodeAnalysis.CSharp.Symbols;
  10. using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
  11. using Microsoft.CodeAnalysis.Emit;
  12. using Roslyn.Utilities;
  13. namespace Microsoft.CodeAnalysis.CSharp.Emit
  14. {
  15. internal sealed class PEDeltaAssemblyBuilder : PEAssemblyBuilderBase, IPEDeltaAssemblyBuilder
  16. {
  17. private readonly EmitBaseline _previousGeneration;
  18. private readonly CSharpDefinitionMap _previousDefinitions;
  19. private readonly SymbolChanges _changes;
  20. private readonly CSharpSymbolMatcher.DeepTranslator _deepTranslator;
  21. public PEDeltaAssemblyBuilder(
  22. SourceAssemblySymbol sourceAssembly,
  23. EmitOptions emitOptions,
  24. OutputKind outputKind,
  25. Cci.ModulePropertiesForSerialization serializationProperties,
  26. IEnumerable<ResourceDescription> manifestResources,
  27. EmitBaseline previousGeneration,
  28. IEnumerable<SemanticEdit> edits,
  29. Func<ISymbol, bool> isAddedSymbol)
  30. : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes: ImmutableArray<NamedTypeSymbol>.Empty)
  31. {
  32. var initialBaseline = previousGeneration.InitialBaseline;
  33. var context = new EmitContext(this, null, new DiagnosticBag());
  34. // Hydrate symbols from initial metadata. Once we do so it is important to reuse these symbols across all generations,
  35. // in order for the symbol matcher to be able to use reference equality once it maps symbols to initial metadata.
  36. var metadataSymbols = GetOrCreateMetadataSymbols(initialBaseline, sourceAssembly.DeclaringCompilation);
  37. var metadataDecoder = (MetadataDecoder)metadataSymbols.MetadataDecoder;
  38. var metadataAssembly = (PEAssemblySymbol)metadataDecoder.ModuleSymbol.ContainingAssembly;
  39. var matchToMetadata = new CSharpSymbolMatcher(metadataSymbols.AnonymousTypes, sourceAssembly, context, metadataAssembly);
  40. CSharpSymbolMatcher matchToPrevious = null;
  41. if (previousGeneration.Ordinal > 0)
  42. {
  43. var previousAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly;
  44. var previousContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag());
  45. matchToPrevious = new CSharpSymbolMatcher(
  46. previousGeneration.AnonymousTypeMap,
  47. sourceAssembly: sourceAssembly,
  48. sourceContext: context,
  49. otherAssembly: previousAssembly,
  50. otherContext: previousContext,
  51. otherSynthesizedMembersOpt: previousGeneration.SynthesizedMembers);
  52. }
  53. _previousDefinitions = new CSharpDefinitionMap(previousGeneration.OriginalMetadata.Module, edits, metadataDecoder, matchToMetadata, matchToPrevious);
  54. _previousGeneration = previousGeneration;
  55. _changes = new SymbolChanges(_previousDefinitions, edits, isAddedSymbol);
  56. // Workaround for https://github.com/dotnet/roslyn/issues/3192.
  57. // When compiling state machine we stash types of awaiters and state-machine hoisted variables,
  58. // so that next generation can look variables up and reuse their slots if possible.
  59. //
  60. // When we are about to allocate a slot for a lifted variable while compiling the next generation
  61. // we map its type to the previous generation and then check the slot types that we stashed earlier.
  62. // If the variable type matches we reuse it. In order to compare the previous variable type with the current one
  63. // both need to be completely lowered (translated). Standard translation only goes one level deep.
  64. // Generic arguments are not translated until they are needed by metadata writer.
  65. //
  66. // In order to get the fully lowered form we run the type symbols of stashed variables thru a deep translator
  67. // that translates the symbol recursively.
  68. _deepTranslator = new CSharpSymbolMatcher.DeepTranslator(sourceAssembly.GetSpecialType(SpecialType.System_Object));
  69. }
  70. public override int CurrentGenerationOrdinal => _previousGeneration.Ordinal + 1;
  71. internal override Cci.ITypeReference EncTranslateLocalVariableType(TypeSymbol type, DiagnosticBag diagnostics)
  72. {
  73. // Note: The translator is not aware of synthesized types. If type is a synthesized type it won't get mapped.
  74. // In such case use the type itself. This can only happen for variables storing lambda display classes.
  75. var visited = (TypeSymbol)_deepTranslator.Visit(type);
  76. Debug.Assert((object)visited != null);
  77. //Debug.Assert(visited != null || type is LambdaFrame || ((NamedTypeSymbol)type).ConstructedFrom is LambdaFrame);
  78. return Translate(visited ?? type, null, diagnostics);
  79. }
  80. private EmitBaseline.MetadataSymbols GetOrCreateMetadataSymbols(EmitBaseline initialBaseline, CSharpCompilation compilation)
  81. {
  82. if (initialBaseline.LazyMetadataSymbols != null)
  83. {
  84. return initialBaseline.LazyMetadataSymbols;
  85. }
  86. var originalMetadata = initialBaseline.OriginalMetadata;
  87. // The purpose of this compilation is to provide PE symbols for original metadata.
  88. // We need to transfer the references from the current source compilation but don't need its syntax trees.
  89. var metadataCompilation = compilation.RemoveAllSyntaxTrees();
  90. var metadataAssembly = metadataCompilation.GetBoundReferenceManager().CreatePEAssemblyForAssemblyMetadata(AssemblyMetadata.Create(originalMetadata), MetadataImportOptions.All);
  91. var metadataDecoder = new MetadataDecoder(metadataAssembly.PrimaryModule);
  92. var metadataAnonymousTypes = GetAnonymousTypeMapFromMetadata(originalMetadata.MetadataReader, metadataDecoder);
  93. var metadataSymbols = new EmitBaseline.MetadataSymbols(metadataAnonymousTypes, metadataDecoder);
  94. return InterlockedOperations.Initialize(ref initialBaseline.LazyMetadataSymbols, metadataSymbols);
  95. }
  96. // internal for testing
  97. internal static IReadOnlyDictionary<AnonymousTypeKey, AnonymousTypeValue> GetAnonymousTypeMapFromMetadata(MetadataReader reader, MetadataDecoder metadataDecoder)
  98. {
  99. var result = new Dictionary<AnonymousTypeKey, AnonymousTypeValue>();
  100. foreach (var handle in reader.TypeDefinitions)
  101. {
  102. var def = reader.GetTypeDefinition(handle);
  103. if (!def.Namespace.IsNil)
  104. {
  105. continue;
  106. }
  107. if (!reader.StringComparer.StartsWith(def.Name, GeneratedNames.AnonymousNamePrefix))
  108. {
  109. continue;
  110. }
  111. var metadataName = reader.GetString(def.Name);
  112. short arity;
  113. var name = MetadataHelpers.InferTypeArityAndUnmangleMetadataName(metadataName, out arity);
  114. int index;
  115. if (GeneratedNames.TryParseAnonymousTypeTemplateName(name, out index))
  116. {
  117. var builder = ArrayBuilder<AnonymousTypeKeyField>.GetInstance();
  118. if (TryGetAnonymousTypeKey(reader, def, builder))
  119. {
  120. var type = (NamedTypeSymbol)metadataDecoder.GetTypeOfToken(handle);
  121. var key = new AnonymousTypeKey(builder.ToImmutable());
  122. var value = new AnonymousTypeValue(name, index, type);
  123. result.Add(key, value);
  124. }
  125. builder.Free();
  126. }
  127. }
  128. return result;
  129. }
  130. private static bool TryGetAnonymousTypeKey(
  131. MetadataReader reader,
  132. TypeDefinition def,
  133. ArrayBuilder<AnonymousTypeKeyField> builder)
  134. {
  135. foreach (var typeParameterHandle in def.GetGenericParameters())
  136. {
  137. var typeParameter = reader.GetGenericParameter(typeParameterHandle);
  138. string fieldName;
  139. if (!GeneratedNames.TryParseAnonymousTypeParameterName(reader.GetString(typeParameter.Name), out fieldName))
  140. {
  141. return false;
  142. }
  143. builder.Add(new AnonymousTypeKeyField(fieldName, isKey: false, ignoreCase: false));
  144. }
  145. return true;
  146. }
  147. internal EmitBaseline PreviousGeneration
  148. {
  149. get { return _previousGeneration; }
  150. }
  151. internal CSharpDefinitionMap PreviousDefinitions
  152. {
  153. get { return _previousDefinitions; }
  154. }
  155. internal override bool SupportsPrivateImplClass
  156. {
  157. get
  158. {
  159. // Disable <PrivateImplementationDetails> in ENC since the
  160. // CLR does not support adding non-private members.
  161. return false;
  162. }
  163. }
  164. public IReadOnlyDictionary<AnonymousTypeKey, AnonymousTypeValue> GetAnonymousTypeMap()
  165. {
  166. var anonymousTypes = this.Compilation.AnonymousTypeManager.GetAnonymousTypeMap();
  167. // Should contain all entries in previous generation.
  168. Debug.Assert(_previousGeneration.AnonymousTypeMap.All(p => anonymousTypes.ContainsKey(p.Key)));
  169. return anonymousTypes;
  170. }
  171. internal override VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymbol method, MethodSymbol topLevelMethod)
  172. {
  173. return _previousDefinitions.TryCreateVariableSlotAllocator(_previousGeneration, method, topLevelMethod);
  174. }
  175. internal override ImmutableArray<AnonymousTypeKey> GetPreviousAnonymousTypes()
  176. {
  177. return ImmutableArray.CreateRange(_previousGeneration.AnonymousTypeMap.Keys);
  178. }
  179. internal override int GetNextAnonymousTypeIndex()
  180. {
  181. return _previousGeneration.GetNextAnonymousTypeIndex();
  182. }
  183. internal override bool TryGetAnonymousTypeName(NamedTypeSymbol template, out string name, out int index)
  184. {
  185. Debug.Assert(this.Compilation == template.DeclaringCompilation);
  186. return _previousDefinitions.TryGetAnonymousTypeName(template, out name, out index);
  187. }
  188. internal SymbolChanges Changes
  189. {
  190. get { return _changes; }
  191. }
  192. internal override IEnumerable<Cci.INamespaceTypeDefinition> GetTopLevelTypesCore(EmitContext context)
  193. {
  194. return _changes.GetTopLevelTypes(context);
  195. }
  196. public void OnCreatedIndices(DiagnosticBag diagnostics)
  197. {
  198. var embeddedTypesManager = this.EmbeddedTypesManagerOpt;
  199. if (embeddedTypesManager != null)
  200. {
  201. foreach (var embeddedType in embeddedTypesManager.EmbeddedTypesMap.Keys)
  202. {
  203. diagnostics.Add(new CSDiagnosticInfo(ErrorCode.ERR_EncNoPIAReference, embeddedType), Location.None);
  204. }
  205. }
  206. }
  207. internal override bool IsEncDelta
  208. {
  209. get { return true; }
  210. }
  211. }
  212. }