From 494f7a0dc268b5a2132838219ad388052621f3dc Mon Sep 17 00:00:00 2001 From: Anubhav Srivastava Date: Mon, 7 Oct 2019 11:50:53 -0700 Subject: [PATCH 1/2] Preparation to introduce parallelism into CrossGen2 - Change dictionaries in ReadyToRunCodegenNodeFactory and ReadyToRunSymbolNodeFactory to NodeCaches (i.e. ConcurrentDictionary, at the moment) - Add structs to act as keys for the above NodeCaches (MethodFixupKey, DynamicHelperKey, ReadyToRunHelperKey) - Synchronize logger - Update some Dictionaries to ConcurrentDictionary --- src/tools/crossgen2/Common/Compiler/Logger.cs | 2 +- .../ReadyToRun/MethodWithGCInfo.cs | 3 +- .../ReadyToRun/ModuleTokenResolver.cs | 7 +- .../ReadyToRunCodegenNodeFactory.cs | 475 +++++++++-------- .../ReadyToRunSymbolNodeFactory.cs | 483 +++++++++++------- .../DependencyAnalysis/TypeAndMethod.cs | 10 +- .../Compiler/ReadyToRunCodegenCompilation.cs | 31 +- .../ReadyToRunMetadataFieldLayoutAlgorithm.cs | 56 +- ...RunSingleAssemblyCompilationModuleGroup.cs | 13 +- .../Compiler/ReadyToRunTableManager.cs | 2 - .../JitInterface/CorInfoImpl.ReadyToRun.cs | 2 +- 11 files changed, 623 insertions(+), 461 deletions(-) diff --git a/src/tools/crossgen2/Common/Compiler/Logger.cs b/src/tools/crossgen2/Common/Compiler/Logger.cs index f50ca450d431..5fa09a1c420d 100644 --- a/src/tools/crossgen2/Common/Compiler/Logger.cs +++ b/src/tools/crossgen2/Common/Compiler/Logger.cs @@ -18,7 +18,7 @@ public class Logger public Logger(TextWriter writer, bool isVerbose) { - Writer = writer; + Writer = TextWriter.Synchronized(writer); IsVerbose = isVerbose; } } diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs index eea229388d96..f31648e6474d 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs @@ -5,8 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; - -using ILCompiler.DependencyAnalysis; +using System.Threading; using Internal.JitInterface; using Internal.Text; diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleTokenResolver.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleTokenResolver.cs index 02061e5b255e..cab398c9c9fd 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleTokenResolver.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleTokenResolver.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; +using System.Collections.Concurrent; using System.Collections.Immutable; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -25,9 +25,9 @@ public class ModuleTokenResolver /// Reverse lookup table mapping external types to reference tokens in the input modules. The table /// gets lazily initialized as various tokens are resolved in CorInfoImpl. /// - private readonly Dictionary _typeToRefTokens = new Dictionary(); + private readonly ConcurrentDictionary _typeToRefTokens = new ConcurrentDictionary(); - private readonly Dictionary _fieldToRefTokens = new Dictionary(); + private readonly ConcurrentDictionary _fieldToRefTokens = new ConcurrentDictionary(); private readonly CompilationModuleGroup _compilationModuleGroup; @@ -163,6 +163,7 @@ public void AddModuleTokenForField(FieldDesc field, ModuleToken token) } _fieldToRefTokens[canonField] = token; + switch (token.TokenType) { case CorTokenType.mdtMemberRef: diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index f0c048ce7287..52e1b2df7eb0 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -6,16 +6,15 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; + using ILCompiler.DependencyAnalysis.ReadyToRun; using ILCompiler.DependencyAnalysisFramework; +using ILCompiler.Win32Resources; using Internal.JitInterface; using Internal.TypeSystem; using Internal.Text; using Internal.TypeSystem.Ecma; -using ILCompiler.Win32Resources; namespace ILCompiler.DependencyAnalysis { @@ -25,6 +24,29 @@ public interface IEETypeNode TypeDesc Type { get; } } + public struct NodeCache + { + private Func _creator; + private ConcurrentDictionary _cache; + + public NodeCache(Func creator, IEqualityComparer comparer) + { + _creator = creator; + _cache = new ConcurrentDictionary(comparer); + } + + public NodeCache(Func creator) + { + _creator = creator; + _cache = new ConcurrentDictionary(); + } + + public TValue GetOrAdd(TKey key) + { + return _cache.GetOrAdd(key, _creator); + } + } + // TODO-REFACTOR: merge with the ReadyToRunCodegen factory public abstract class NodeFactory { @@ -130,34 +152,6 @@ public BlobNode ReadOnlyDataBlob(Utf8String name, byte[] blobData, int alignment return _readOnlyDataBlobs.GetOrAdd(new ReadOnlyDataBlobKey(name, blobData, alignment)); } - protected struct NodeCache - { - private Func _creator; - private ConcurrentDictionary _cache; - - public NodeCache(Func creator, IEqualityComparer comparer) - { - _creator = creator; - _cache = new ConcurrentDictionary(comparer); - } - - public NodeCache(Func creator) - { - _creator = creator; - _cache = new ConcurrentDictionary(); - } - - public TValue GetOrAdd(TKey key) - { - return _cache.GetOrAdd(key, _creator); - } - - public TValue GetOrAdd(TKey key, Func creator) - { - return _cache.GetOrAdd(key, creator); - } - } - protected struct ReadyToRunGenericHelperKey : IEquatable { public readonly object Target; @@ -207,8 +201,6 @@ public ReadOnlyDataBlobKey(Utf8String name, byte[] data, int alignment) public sealed class ReadyToRunCodegenNodeFactory : NodeFactory { - private Dictionary _importMethods; - public ReadyToRunCodegenNodeFactory( CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, @@ -222,13 +214,97 @@ public ReadyToRunCodegenNodeFactory( nameMangler, new ReadyToRunTableManager(context)) { - _importMethods = new Dictionary(); Resolver = moduleTokenResolver; InputModuleContext = signatureContext; CopiedCorHeaderNode = corHeaderNode; if (!win32Resources.IsEmpty) Win32ResourcesNode = new Win32ResourcesNode(win32Resources); + + CreateCodegenNodeCaches(); + } + + private void CreateCodegenNodeCaches() + { + + // Create node caches + _constructedHelpers = new NodeCache(CreateReadyToRunHelperCell); + + _importMethods = new NodeCache(CreateMethodEntrypoint); + + _localMethodCache = new NodeCache(key => + { + return new MethodWithGCInfo(key.Method.Method, key.SignatureContext); + }); + + _methodSignatures = new NodeCache(key => + { + return new MethodFixupSignature( + key.FixupKind, + key.TypeAndMethod.Method, + key.TypeAndMethod.SignatureContext, + key.TypeAndMethod.IsUnboxingStub, + key.TypeAndMethod.IsInstantiatingStub + ); + }); + + _typeSignatures = new NodeCache(key => + { + return new TypeFixupSignature(key.FixupKind, key.TypeDesc, InputModuleContext); + }); + + _dynamicHelperCellCache = new NodeCache(key => + { + return new DelayLoadHelperMethodImport( + this, + DispatchImports, + ILCompiler.ReadyToRunHelper.DelayLoad_Helper_Obj, + key.Method, + useVirtualCall: false, + useInstantiatingStub: true, + MethodSignature( + ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, + key.Method, + signatureContext: key.SignatureContext, + isUnboxingStub: key.IsUnboxingStub, + isInstantiatingStub: key.IsInstantiatingStub), + key.SignatureContext); + }); + + _copiedCorHeaders = new NodeCache(module => + { + return new CopiedCorHeaderNode(module); + }); + + _copiedMetadataBlobs = new NodeCache(module => + { + return new CopiedMetadataBlobNode(module); + }); + + _copiedMethodIL = new NodeCache(method => + { + return new CopiedMethodILNode((EcmaMethod)method); + }); + + _copiedFieldRvas = new NodeCache(ecmaField => + { + return new CopiedFieldRvaNode(ecmaField); + }); + + _copiedStrongNameSignatures = new NodeCache(module => + { + return new CopiedStrongNameSignatureNode(module); + }); + + _copiedManagedResources = new NodeCache(module => + { + return new CopiedManagedResourcesNode(module); + }); + + _profileDataCountsNodes = new NodeCache(method => + { + return new ProfileDataNode(method, Target); + }); } public SignatureContext InputModuleContext; @@ -277,16 +353,11 @@ public ReadyToRunCodegenNodeFactory( public ImportSectionNode PrecodeImports; - private readonly Dictionary _constructedHelpers = new Dictionary(); + private NodeCache _constructedHelpers; public ISymbolNode GetReadyToRunHelperCell(ReadyToRunHelper helperId) { - if (!_constructedHelpers.TryGetValue(helperId, out ISymbolNode helperCell)) - { - helperCell = CreateReadyToRunHelperCell(helperId); - _constructedHelpers.Add(helperId, helperCell); - } - return helperCell; + return _constructedHelpers.GetOrAdd(helperId); } private ISymbolNode CreateReadyToRunHelperCell(ReadyToRunHelper helperId) @@ -294,62 +365,68 @@ private ISymbolNode CreateReadyToRunHelperCell(ReadyToRunHelper helperId) return new Import(EagerImports, new ReadyToRunHelperSignature(helperId)); } - public IMethodNode MethodEntrypoint( - MethodWithToken method, - bool isUnboxingStub, - bool isInstantiatingStub, - bool isPrecodeImportRequired, - SignatureContext signatureContext) + + private NodeCache _importMethods; + + private IMethodNode CreateMethodEntrypoint(TypeAndMethod key) { - IMethodNode methodImport; - TypeAndMethod key = new TypeAndMethod(method.ConstrainedType, method, isUnboxingStub, isInstantiatingStub, isPrecodeImportRequired); - if (!_importMethods.TryGetValue(key, out methodImport)) + MethodWithToken method = key.Method; + bool isUnboxingStub = key.IsUnboxingStub; + bool isInstantiatingStub = key.IsInstantiatingStub; + bool isPrecodeImportRequired = key.IsPrecodeImportRequired; + SignatureContext signatureContext = key.SignatureContext; + if (CompilationModuleGroup.ContainsMethodBody(method.Method, false)) { - if (CompilationModuleGroup.ContainsMethodBody(method.Method, false)) + if (isPrecodeImportRequired) { - if (isPrecodeImportRequired) - { - methodImport = new PrecodeMethodImport( - this, - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, - method, - CreateMethodEntrypointNode(method, isUnboxingStub, isInstantiatingStub, signatureContext), - isUnboxingStub, - isInstantiatingStub, - signatureContext); - } - else - { - methodImport = new LocalMethodImport( - this, - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, - method, - CreateMethodEntrypointNode(method, isUnboxingStub, isInstantiatingStub, signatureContext), - isUnboxingStub, - isInstantiatingStub, - signatureContext); - } + return new PrecodeMethodImport( + this, + ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, + method, + CreateMethodEntrypointNodeHelper(method, isUnboxingStub, isInstantiatingStub, signatureContext), + isUnboxingStub, + isInstantiatingStub, + signatureContext); } else { - // First time we see a given external method - emit indirection cell and the import entry - methodImport = new ExternalMethodImport( + return new LocalMethodImport( this, ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, method, + CreateMethodEntrypointNodeHelper(method, isUnboxingStub, isInstantiatingStub, signatureContext), isUnboxingStub, isInstantiatingStub, signatureContext); } - _importMethods.Add(key, methodImport); } + else + { + // First time we see a given external method - emit indirection cell and the import entry + return new ExternalMethodImport( + this, + ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, + method, + isUnboxingStub, + isInstantiatingStub, + signatureContext); + } + } - return methodImport; + public IMethodNode MethodEntrypoint( + MethodWithToken method, + bool isUnboxingStub, + bool isInstantiatingStub, + bool isPrecodeImportRequired, + SignatureContext signatureContext) + { + TypeAndMethod key = new TypeAndMethod(method.ConstrainedType, method, isUnboxingStub, isInstantiatingStub, isPrecodeImportRequired, signatureContext); + return _importMethods.GetOrAdd(key); } - private readonly Dictionary _localMethodCache = new Dictionary(); + private NodeCache _localMethodCache = new NodeCache(); - private MethodWithGCInfo CreateMethodEntrypointNode(MethodWithToken targetMethod, bool isUnboxingStub, bool isInstantiatingStub, SignatureContext signatureContext) + private MethodWithGCInfo CreateMethodEntrypointNodeHelper(MethodWithToken targetMethod, bool isUnboxingStub, bool isInstantiatingStub, SignatureContext signatureContext) { Debug.Assert(CompilationModuleGroup.ContainsMethodBody(targetMethod.Method, false)); @@ -357,15 +434,11 @@ private MethodWithGCInfo CreateMethodEntrypointNode(MethodWithToken targetMethod TypeAndMethod localMethodKey = new TypeAndMethod(localMethod.OwningType, new MethodWithToken(localMethod, default(ModuleToken), constrainedType: null), - isUnboxingStub: false, isInstantiatingStub: false, isPrecodeImportRequired: false); - MethodWithGCInfo localMethodNode; - if (!_localMethodCache.TryGetValue(localMethodKey, out localMethodNode)) - { - localMethodNode = new MethodWithGCInfo(localMethod, signatureContext); - _localMethodCache.Add(localMethodKey, localMethodNode); - } - - return localMethodNode; + isUnboxingStub: false, + isInstantiatingStub: false, + isPrecodeImportRequired: false, + signatureContext); + return _localMethodCache.GetOrAdd(localMethodKey); } public IEnumerable EnumerateCompiledMethods() @@ -390,8 +463,35 @@ public IEnumerable EnumerateCompiledMethods() } } - private readonly Dictionary> _methodSignatures = - new Dictionary>(); + private struct MethodFixupKey : IEquatable + { + public readonly ReadyToRunFixupKind FixupKind; + public readonly TypeAndMethod TypeAndMethod; + + public MethodFixupKey(ReadyToRunFixupKind fixupKind, TypeAndMethod typeAndMethod) + { + FixupKind = fixupKind; + TypeAndMethod = typeAndMethod; + } + + public bool Equals(MethodFixupKey other) + { + return FixupKind == other.FixupKind && TypeAndMethod.Equals(other.TypeAndMethod); + } + + public override bool Equals(object obj) + { + return obj is MethodFixupKey other && Equals(other); + } + + public override int GetHashCode() + { + return FixupKind.GetHashCode() ^ TypeAndMethod.GetHashCode(); + } + + } + + private NodeCache _methodSignatures; public MethodFixupSignature MethodSignature( ReadyToRunFixupKind fixupKind, @@ -400,42 +500,48 @@ public MethodFixupSignature MethodSignature( bool isInstantiatingStub, SignatureContext signatureContext) { - Dictionary perFixupKindMap; - if (!_methodSignatures.TryGetValue(fixupKind, out perFixupKindMap)) + TypeAndMethod key = new TypeAndMethod(method.ConstrainedType, method, isUnboxingStub, isInstantiatingStub, false, signatureContext); + return _methodSignatures.GetOrAdd(new MethodFixupKey(fixupKind, key)); + } + + private struct TypeFixupKey : IEquatable + { + public readonly ReadyToRunFixupKind FixupKind; + public readonly TypeDesc TypeDesc; + public readonly SignatureContext SignatureContext; + public TypeFixupKey(ReadyToRunFixupKind fixupKind, TypeDesc typeDesc, SignatureContext signatureContext) { - perFixupKindMap = new Dictionary(); - _methodSignatures.Add(fixupKind, perFixupKindMap); + FixupKind = fixupKind; + TypeDesc = typeDesc; + SignatureContext = signatureContext; } - TypeAndMethod key = new TypeAndMethod(method.ConstrainedType, method, isUnboxingStub, isInstantiatingStub, false); - MethodFixupSignature signature; - if (!perFixupKindMap.TryGetValue(key, out signature)) + public bool Equals(TypeFixupKey other) { - signature = new MethodFixupSignature(fixupKind, method, signatureContext, isUnboxingStub, isInstantiatingStub); - perFixupKindMap.Add(key, signature); + return FixupKind == other.FixupKind + && TypeDesc == other.TypeDesc + && SignatureContext.Equals(other.SignatureContext); } - return signature; - } - private readonly Dictionary> _typeSignatures = - new Dictionary>(); - - public TypeFixupSignature TypeSignature(ReadyToRunFixupKind fixupKind, TypeDesc typeDesc, SignatureContext signatureContext) - { - Dictionary perFixupKindMap; - if (!_typeSignatures.TryGetValue(fixupKind, out perFixupKindMap)) + public override bool Equals(object obj) { - perFixupKindMap = new Dictionary(); - _typeSignatures.Add(fixupKind, perFixupKindMap); + return obj is TypeFixupKey other && Equals(other); } - TypeFixupSignature signature; - if (!perFixupKindMap.TryGetValue(typeDesc, out signature)) + public override int GetHashCode() { - signature = new TypeFixupSignature(fixupKind, typeDesc, signatureContext); - perFixupKindMap.Add(typeDesc, signature); + return FixupKind.GetHashCode() + ^ (31 * TypeDesc.GetHashCode()) + ^ (23 * SignatureContext.GetHashCode()); } - return signature; + } + + private NodeCache _typeSignatures; + + public TypeFixupSignature TypeSignature(ReadyToRunFixupKind fixupKind, TypeDesc typeDesc, SignatureContext signatureContext) + { + TypeFixupKey fixupKey = new TypeFixupKey(fixupKind, typeDesc, signatureContext); + return _typeSignatures.GetOrAdd(fixupKey); } public override void AttachToDependencyGraph(DependencyAnalyzerBase graph) @@ -660,75 +766,73 @@ protected override ISymbolNode CreateGenericLookupFromTypeNode(ReadyToRunGeneric InputModuleContext)); } - private Dictionary _dynamicHelperCellCache = new Dictionary(); - - public ISymbolNode DynamicHelperCell(MethodWithToken methodWithToken, bool isInstantiatingStub, SignatureContext signatureContext) + struct DynamicHelperCellKey : IEquatable { - ISymbolNode result; - if (!_dynamicHelperCellCache.TryGetValue(methodWithToken, out result)) + public readonly MethodWithToken Method; + public readonly bool IsUnboxingStub; + public readonly bool IsInstantiatingStub; + public readonly SignatureContext SignatureContext; + + public DynamicHelperCellKey(MethodWithToken method, bool isUnboxingStub, bool isInstantiatingStub, SignatureContext signatureContext) { - result = new DelayLoadHelperMethodImport( - this, - DispatchImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper_Obj, - methodWithToken, - useVirtualCall: false, - useInstantiatingStub: true, - MethodSignature( - ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, - methodWithToken, - signatureContext: signatureContext, - isUnboxingStub: false, - isInstantiatingStub: isInstantiatingStub), - signatureContext); - _dynamicHelperCellCache.Add(methodWithToken, result); + Method = method; + IsUnboxingStub = isUnboxingStub; + IsInstantiatingStub = isInstantiatingStub; + SignatureContext = signatureContext; } - return result; - } - private Dictionary _copiedCorHeaders = new Dictionary(); + public bool Equals(DynamicHelperCellKey other) + { + return Method.Equals(other.Method) + && IsUnboxingStub == other.IsUnboxingStub + && IsInstantiatingStub == other.IsInstantiatingStub + && SignatureContext.Equals(other.SignatureContext); + } - public CopiedCorHeaderNode CopiedCorHeader(EcmaModule module) - { - CopiedCorHeaderNode result; - if (!_copiedCorHeaders.TryGetValue(module, out result)) + public override bool Equals(object obj) { - result = new CopiedCorHeaderNode(module); - _copiedCorHeaders.Add(module, result); + return obj is DynamicHelperCellKey other && Equals(other); } - return result; + public override int GetHashCode() + { + return Method.GetHashCode() + ^ (IsUnboxingStub ? -0x80000000 : 0) + ^ (IsInstantiatingStub ? -0x40000000 : 0) + ^ (31 * SignatureContext.GetHashCode()); + } } - private Dictionary _copiedMetadataBlobs = new Dictionary(); + private NodeCache _dynamicHelperCellCache; - public CopiedMetadataBlobNode CopiedMetadataBlob(EcmaModule module) + public ISymbolNode DynamicHelperCell(MethodWithToken methodWithToken, bool isInstantiatingStub, SignatureContext signatureContext) { - CopiedMetadataBlobNode result; - if (!_copiedMetadataBlobs.TryGetValue(module, out result)) - { - result = new CopiedMetadataBlobNode(module); - _copiedMetadataBlobs.Add(module, result); - } + DynamicHelperCellKey key = new DynamicHelperCellKey(methodWithToken, isUnboxingStub: false, isInstantiatingStub, signatureContext); + return _dynamicHelperCellCache.GetOrAdd(key); + } + + private NodeCache _copiedCorHeaders; - return result; + public CopiedCorHeaderNode CopiedCorHeader(EcmaModule module) + { + return _copiedCorHeaders.GetOrAdd(module); } - private Dictionary _copiedMethodIL = new Dictionary(); + private NodeCache _copiedMetadataBlobs; - public CopiedMethodILNode CopiedMethodIL(EcmaMethod method) + public CopiedMetadataBlobNode CopiedMetadataBlob(EcmaModule module) { - CopiedMethodILNode result; - if (!_copiedMethodIL.TryGetValue(method, out result)) - { - result = new CopiedMethodILNode(method); - _copiedMethodIL.Add(method, result); - } + return _copiedMetadataBlobs.GetOrAdd(module); + } - return result; + private NodeCache _copiedMethodIL; + + public CopiedMethodILNode CopiedMethodIL(EcmaMethod method) + { + return _copiedMethodIL.GetOrAdd(method); } - private Dictionary _copiedFieldRvas = new Dictionary(); + private NodeCache _copiedFieldRvas; public CopiedFieldRvaNode CopiedFieldRva(FieldDesc field) { @@ -746,55 +850,28 @@ public CopiedFieldRvaNode CopiedFieldRva(FieldDesc field) throw new NotSupportedException($"{ecmaField} ... {string.Join("; ", TypeSystemContext.InputFilePaths.Keys)}"); } - CopiedFieldRvaNode result; - if (!_copiedFieldRvas.TryGetValue(ecmaField, out result)) - { - result = new CopiedFieldRvaNode(ecmaField); - _copiedFieldRvas.Add(ecmaField, result); - } - - return result; + return _copiedFieldRvas.GetOrAdd(ecmaField); } - private Dictionary _copiedStrongNameSignatures = new Dictionary(); + private NodeCache _copiedStrongNameSignatures; public CopiedStrongNameSignatureNode CopiedStrongNameSignature(EcmaModule module) { - CopiedStrongNameSignatureNode result; - if (!_copiedStrongNameSignatures.TryGetValue(module, out result)) - { - result = new CopiedStrongNameSignatureNode(module); - _copiedStrongNameSignatures.Add(module, result); - } - - return result; + return _copiedStrongNameSignatures.GetOrAdd(module); } - private Dictionary _copiedManagedResources = new Dictionary(); + private NodeCache _copiedManagedResources; public CopiedManagedResourcesNode CopiedManagedResources(EcmaModule module) { - CopiedManagedResourcesNode result; - if (!_copiedManagedResources.TryGetValue(module, out result)) - { - result = new CopiedManagedResourcesNode(module); - _copiedManagedResources.Add(module, result); - } - - return result; + return _copiedManagedResources.GetOrAdd(module); } - private readonly Dictionary _profileDataCountsNodes = new Dictionary(); + private NodeCache _profileDataCountsNodes; - public ProfileDataNode ProfileDataNode(MethodWithGCInfo method) + public ProfileDataNode ProfileData(MethodWithGCInfo method) { - ProfileDataNode node; - if (!_profileDataCountsNodes.TryGetValue(method, out node)) - { - node = new ProfileDataNode(method, Target); - _profileDataCountsNodes.Add(method, node); - } - return node; + return _profileDataCountsNodes.GetOrAdd(method); } } } diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs index 7183fd2dcf29..28720b61334a 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs @@ -3,14 +3,10 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection.PortableExecutable; using ILCompiler.DependencyAnalysis.ReadyToRun; using Internal.JitInterface; using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; namespace ILCompiler.DependencyAnalysis { @@ -45,99 +41,228 @@ public sealed class ReadyToRunSymbolNodeFactory public ReadyToRunSymbolNodeFactory(ReadyToRunCodegenNodeFactory codegenNodeFactory) { _codegenNodeFactory = codegenNodeFactory; + CreateSymbolNodeCaches(); } - private readonly Dictionary _importStrings = new Dictionary(); + private void CreateSymbolNodeCaches() + { + _importStrings = new NodeCache(key => + { + return new StringImport(_codegenNodeFactory.StringImports, key.ModuleToken, key.SignatureContext); + }); + + _r2rHelpers = new NodeCache(CreateReadyToRunHelper); + + _fieldAddressCache = new NodeCache(key => + { + return new DelayLoadHelperImport( + _codegenNodeFactory, + _codegenNodeFactory.HelperImports, + ILCompiler.ReadyToRunHelper.DelayLoad_Helper, + new FieldFixupSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldAddress, key.Field, key.SignatureContext) + ); + }); + + _fieldOffsetCache = new NodeCache(key => + { + return new PrecodeHelperImport( + _codegenNodeFactory, + new FieldFixupSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldOffset, key.Field, key.SignatureContext) + ); + }); + + _fieldBaseOffsetCache = new NodeCache(key => + { + return new PrecodeHelperImport( + _codegenNodeFactory, + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldBaseOffset, key.Type, key.SignatureContext) + ); + }); + + _interfaceDispatchCells = new NodeCache(cellKey => + { + return new DelayLoadHelperMethodImport( + _codegenNodeFactory, + _codegenNodeFactory.DispatchImports, + ILCompiler.ReadyToRunHelper.DelayLoad_MethodCall, + cellKey.Method, + useVirtualCall: true, + useInstantiatingStub: false, + _codegenNodeFactory.MethodSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, + cellKey.Method, + cellKey.IsUnboxingStub, isInstantiatingStub: false, cellKey.SignatureContext), + cellKey.SignatureContext, + cellKey.CallSite); + }); + + _delegateCtors = new NodeCache(ctorKey => + { + SignatureContext signatureContext = ctorKey.SignatureContext; + IMethodNode targetMethodNode = _codegenNodeFactory.MethodEntrypoint( + ctorKey.Method, + isUnboxingStub: false, + isInstantiatingStub: false, + isPrecodeImportRequired: false, + signatureContext: signatureContext); + + return new DelayLoadHelperImport( + _codegenNodeFactory, + _codegenNodeFactory.HelperImports, + ILCompiler.ReadyToRunHelper.DelayLoad_Helper, + new DelegateCtorSignature(ctorKey.Type, targetMethodNode, ctorKey.Method.Token, signatureContext)); + }); + + _genericLookupHelpers = new NodeCache(key => + { + return new DelayLoadHelperImport( + _codegenNodeFactory, + _codegenNodeFactory.HelperImports, + ILCompiler.ReadyToRunHelper.DelayLoad_Helper, + new GenericLookupSignature( + key.LookupKind, + key.FixupKind, + key.TypeArgument, + key.MethodArgument, + key.FieldArgument, + key.MethodContext, + key.SignatureContext)); + }); + + _indirectPInvokeTargetNodes = new NodeCache(key => + { + return new PrecodeHelperImport( + _codegenNodeFactory, + _codegenNodeFactory.MethodSignature( + ReadyToRunFixupKind.READYTORUN_FIXUP_IndirectPInvokeTarget, + key.MethodWithToken, + signatureContext: key.SignatureContext, + isUnboxingStub: false, + isInstantiatingStub: false)); + }); + } - public ISymbolNode StringLiteral(ModuleToken token, SignatureContext signatureContext) + private struct ModuleTokenAndSignatureContext : IEquatable { - if (!_importStrings.TryGetValue(token, out ISymbolNode stringNode)) + public readonly ModuleToken ModuleToken; + public readonly SignatureContext SignatureContext; + + public ModuleTokenAndSignatureContext(ModuleToken moduleToken, SignatureContext signatureContext) + { + ModuleToken = moduleToken; + SignatureContext = signatureContext; + } + + public bool Equals(ModuleTokenAndSignatureContext other) + { + return ModuleToken.Equals(other.ModuleToken) + && SignatureContext.Equals(other.SignatureContext); + } + + public override bool Equals(object obj) + { + return obj is ModuleTokenAndSignatureContext other && Equals(other); + } + + public override int GetHashCode() { - stringNode = new StringImport(_codegenNodeFactory.StringImports, token, signatureContext); - _importStrings.Add(token, stringNode); + return ModuleToken.GetHashCode() ^ (SignatureContext.GetHashCode() * 31); } - return stringNode; } - private readonly Dictionary> _r2rHelpers = new Dictionary>(); + private NodeCache _importStrings; - public ISymbolNode ReadyToRunHelper(ReadyToRunHelperId id, object target, SignatureContext signatureContext) + public ISymbolNode StringLiteral(ModuleToken moduleToken, SignatureContext signatureContext) + { + return _importStrings.GetOrAdd(new ModuleTokenAndSignatureContext(moduleToken, signatureContext)); + } + + private struct ReadyToRunHelperKey { - if (!_r2rHelpers.TryGetValue(id, out Dictionary helperNodeMap)) + public readonly ReadyToRunHelperId Id; + public readonly object Target; + public readonly SignatureContext SignatureContext; + + public ReadyToRunHelperKey(ReadyToRunHelperId id, object target, SignatureContext signatureContext) + { + Id = id; + Target = target; + SignatureContext = signatureContext; + } + + public bool Equals(ReadyToRunHelperKey other) + { + return Id == other.Id + && Target.Equals(other.Target) + && SignatureContext.Equals(other.SignatureContext); + } + + public override bool Equals(object obj) { - helperNodeMap = new Dictionary(); - _r2rHelpers.Add(id, helperNodeMap); + return obj is ReadyToRunHelperKey other && Equals(other); } - if (helperNodeMap.TryGetValue(target, out ISymbolNode helperNode)) + public override int GetHashCode() { - return helperNode; + return Id.GetHashCode() ^ (SignatureContext.GetHashCode() * 31); } + } + + private NodeCache _r2rHelpers; - switch (id) + private ISymbolNode CreateReadyToRunHelper(ReadyToRunHelperKey key) + { + switch (key.Id) { case ReadyToRunHelperId.NewHelper: - helperNode = CreateNewHelper((TypeDesc)target, signatureContext); - break; + return CreateNewHelper((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.NewArr1: - helperNode = CreateNewArrayHelper((ArrayType)target, signatureContext); - break; + return CreateNewArrayHelper((ArrayType)key.Target, key.SignatureContext); case ReadyToRunHelperId.GetGCStaticBase: - helperNode = CreateGCStaticBaseHelper((TypeDesc)target, signatureContext); - break; + return CreateGCStaticBaseHelper((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.GetNonGCStaticBase: - helperNode = CreateNonGCStaticBaseHelper((TypeDesc)target, signatureContext); - break; + return CreateNonGCStaticBaseHelper((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.GetThreadStaticBase: - helperNode = CreateThreadGcStaticBaseHelper((TypeDesc)target, signatureContext); - break; + return CreateThreadGcStaticBaseHelper((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.GetThreadNonGcStaticBase: - helperNode = CreateThreadNonGcStaticBaseHelper((TypeDesc)target, signatureContext); - break; + return CreateThreadNonGcStaticBaseHelper((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.IsInstanceOf: - helperNode = CreateIsInstanceOfHelper((TypeDesc)target, signatureContext); - break; + return CreateIsInstanceOfHelper((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.CastClass: - helperNode = CreateCastClassHelper((TypeDesc)target, signatureContext); - break; + return CreateCastClassHelper((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.TypeHandle: - helperNode = CreateTypeHandleHelper((TypeDesc)target, signatureContext); - break; + return CreateTypeHandleHelper((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.MethodHandle: - helperNode = CreateMethodHandleHelper((MethodWithToken)target, signatureContext); - break; + return CreateMethodHandleHelper((MethodWithToken)key.Target, key.SignatureContext); case ReadyToRunHelperId.FieldHandle: - helperNode = CreateFieldHandleHelper((FieldDesc)target, signatureContext); - break; + return CreateFieldHandleHelper((FieldDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.CctorTrigger: - helperNode = CreateCctorTrigger((TypeDesc)target, signatureContext); - break; + return CreateCctorTrigger((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.TypeDictionary: - helperNode = CreateTypeDictionary((TypeDesc)target, signatureContext); - break; + return CreateTypeDictionary((TypeDesc)key.Target, key.SignatureContext); case ReadyToRunHelperId.MethodDictionary: - helperNode = CreateMethodDictionary((MethodWithToken)target, signatureContext); - break; + return CreateMethodDictionary((MethodWithToken)key.Target, key.SignatureContext); default: - throw new NotImplementedException(id.ToString()); + throw new NotImplementedException(key.Id.ToString()); } + } - helperNodeMap.Add(target, helperNode); - return helperNode; + public ISymbolNode ReadyToRunHelper(ReadyToRunHelperId id, object target, SignatureContext signatureContext) + { + return _r2rHelpers.GetOrAdd(new ReadyToRunHelperKey(id, target, signatureContext)); } private ISymbolNode CreateNewHelper(TypeDesc type, SignatureContext signatureContext) @@ -253,10 +378,8 @@ private ISymbolNode CreateTypeDictionary(TypeDesc type, SignatureContext signatu { return new PrecodeHelperImport( _codegenNodeFactory, - _codegenNodeFactory.TypeSignature( - ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionary, - type, - signatureContext)); + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionary, type, signatureContext) + ); } private ISymbolNode CreateMethodDictionary(MethodWithToken method, SignatureContext signatureContext) @@ -271,116 +394,126 @@ private ISymbolNode CreateMethodDictionary(MethodWithToken method, SignatureCont signatureContext)); } - private readonly Dictionary _fieldAddressCache = new Dictionary(); - - public ISymbolNode FieldAddress(FieldDesc fieldDesc, SignatureContext signatureContext) + private struct FieldAndSignatureContext : IEquatable { - ISymbolNode result; - if (!_fieldAddressCache.TryGetValue(fieldDesc, out result)) + public readonly FieldDesc Field; + public readonly SignatureContext SignatureContext; + + public FieldAndSignatureContext(FieldDesc fieldDesc, SignatureContext signatureContext) { - result = new DelayLoadHelperImport( - _codegenNodeFactory, - _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - new FieldFixupSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldAddress, fieldDesc, signatureContext)); - _fieldAddressCache.Add(fieldDesc, result); + Field = fieldDesc; + SignatureContext = signatureContext; + } + + public bool Equals(FieldAndSignatureContext other) + { + return Field.Equals(other.Field) && + SignatureContext.Equals(other.SignatureContext); + } + + public override bool Equals(object obj) + { + return obj is FieldAndSignatureContext other && Equals(other); + } + + public override int GetHashCode() + { + return Field.GetHashCode() ^ (SignatureContext.GetHashCode() * 31); } - return result; } - private readonly Dictionary _fieldOffsetCache = new Dictionary(); + private NodeCache _fieldAddressCache; + + public ISymbolNode FieldAddress(FieldDesc fieldDesc, SignatureContext signatureContext) + { + return _fieldAddressCache.GetOrAdd(new FieldAndSignatureContext(fieldDesc, signatureContext)); + } + + private NodeCache _fieldOffsetCache; public ISymbolNode FieldOffset(FieldDesc fieldDesc, SignatureContext signatureContext) { - ISymbolNode result; - if (!_fieldOffsetCache.TryGetValue(fieldDesc, out result)) + return _fieldOffsetCache.GetOrAdd(new FieldAndSignatureContext(fieldDesc, signatureContext)); + } + + private struct TypeAndSignatureContext : IEquatable + { + public readonly TypeDesc Type; + public readonly SignatureContext SignatureContext; + + public TypeAndSignatureContext(TypeDesc typeDesc, SignatureContext signatureContext) { - result = new PrecodeHelperImport( - _codegenNodeFactory, - new FieldFixupSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldOffset, fieldDesc, signatureContext)); - _fieldOffsetCache.Add(fieldDesc, result); + Type = typeDesc; + SignatureContext = signatureContext; + } + + public bool Equals(TypeAndSignatureContext other) + { + return Type.Equals(other.Type) && + SignatureContext.Equals(other.SignatureContext); + } + + public override bool Equals(object obj) + { + return obj is FieldAndSignatureContext other && Equals(other); + } + + public override int GetHashCode() + { + return Type.GetHashCode() ^ (SignatureContext.GetHashCode() * 31); } - return result; } - private readonly Dictionary _fieldBaseOffsetCache = new Dictionary(); + private NodeCache _fieldBaseOffsetCache; public ISymbolNode FieldBaseOffset(TypeDesc typeDesc, SignatureContext signatureContext) { - ISymbolNode result; - if (!_fieldBaseOffsetCache.TryGetValue(typeDesc, out result)) - { - result = new PrecodeHelperImport( - _codegenNodeFactory, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldBaseOffset, typeDesc, signatureContext)); - _fieldBaseOffsetCache.Add(typeDesc, result); - } - return result; + return _fieldBaseOffsetCache.GetOrAdd(new TypeAndSignatureContext(typeDesc, signatureContext)); } - private readonly Dictionary _interfaceDispatchCells = new Dictionary(); + private NodeCache _interfaceDispatchCells = new NodeCache(); public ISymbolNode InterfaceDispatchCell(MethodWithToken method, SignatureContext signatureContext, bool isUnboxingStub, string callSite) { - MethodAndCallSite cellKey = new MethodAndCallSite(method, callSite); - if (!_interfaceDispatchCells.TryGetValue(cellKey, out ISymbolNode dispatchCell)) - { - dispatchCell = new DelayLoadHelperMethodImport( - _codegenNodeFactory, - _codegenNodeFactory.DispatchImports, - ILCompiler.ReadyToRunHelper.DelayLoad_MethodCall, - method, - useVirtualCall: true, - useInstantiatingStub: false, - _codegenNodeFactory.MethodSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, - method, - isUnboxingStub, isInstantiatingStub: false, signatureContext), - signatureContext, - callSite); - - _interfaceDispatchCells.Add(cellKey, dispatchCell); - } - return dispatchCell; + MethodAndCallSite cellKey = new MethodAndCallSite(method, isUnboxingStub, callSite, signatureContext); + return _interfaceDispatchCells.GetOrAdd(cellKey); } - private readonly Dictionary _delegateCtors = new Dictionary(); + private NodeCache _delegateCtors = new NodeCache(); public ISymbolNode DelegateCtor(TypeDesc delegateType, MethodWithToken method, SignatureContext signatureContext) { - TypeAndMethod ctorKey = new TypeAndMethod(delegateType, method, isUnboxingStub: false, isInstantiatingStub: false, isPrecodeImportRequired: false); - if (!_delegateCtors.TryGetValue(ctorKey, out ISymbolNode ctorNode)) - { - IMethodNode targetMethodNode = _codegenNodeFactory.MethodEntrypoint( - method, - isUnboxingStub: false, - isInstantiatingStub: false, - isPrecodeImportRequired: false, - signatureContext: signatureContext); - - ctorNode = new DelayLoadHelperImport( - _codegenNodeFactory, - _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - new DelegateCtorSignature(delegateType, targetMethodNode, method.Token, signatureContext)); - _delegateCtors.Add(ctorKey, ctorNode); - } - return ctorNode; + TypeAndMethod ctorKey = new TypeAndMethod( + delegateType, + method, + isUnboxingStub: false, + isInstantiatingStub: false, + isPrecodeImportRequired: false, + signatureContext); + return _delegateCtors.GetOrAdd(ctorKey); } struct MethodAndCallSite : IEquatable { public readonly MethodWithToken Method; + public readonly bool IsUnboxingStub; public readonly string CallSite; + public readonly SignatureContext SignatureContext; - public MethodAndCallSite(MethodWithToken method, string callSite) + public MethodAndCallSite(MethodWithToken method, bool isUnboxingStub, string callSite, SignatureContext signatureContext) { CallSite = callSite; + IsUnboxingStub = isUnboxingStub; Method = method; + SignatureContext = signatureContext; } public bool Equals(MethodAndCallSite other) { - return CallSite == other.CallSite && Method.Equals(other.Method); + return CallSite == other.CallSite + && Method.Equals(other.Method) + && IsUnboxingStub == other.IsUnboxingStub + && SignatureContext.Equals(other.SignatureContext); } public override bool Equals(object obj) @@ -390,11 +523,14 @@ public override bool Equals(object obj) public override int GetHashCode() { - return (CallSite != null ? CallSite.GetHashCode() : 0) + unchecked(31 * Method.GetHashCode()); + return (CallSite != null ? CallSite.GetHashCode() : 0) + ^ unchecked(31 * Method.GetHashCode()) + ^ (IsUnboxingStub ? -0x80000000 : 0) + ^ (23 * SignatureContext.GetHashCode()); } } - private class GenericLookupKey : IEquatable + private struct GenericLookupKey : IEquatable { public readonly CORINFO_RUNTIME_LOOKUP_KIND LookupKind; public readonly ReadyToRunFixupKind FixupKind; @@ -402,6 +538,7 @@ private class GenericLookupKey : IEquatable public readonly MethodWithToken MethodArgument; public readonly FieldDesc FieldArgument; public readonly GenericContext MethodContext; + public readonly SignatureContext SignatureContext; public GenericLookupKey( CORINFO_RUNTIME_LOOKUP_KIND lookupKind, @@ -409,7 +546,8 @@ public GenericLookupKey( TypeDesc typeArgument, MethodWithToken methodArgument, FieldDesc fieldArgument, - GenericContext methodContext) + GenericContext methodContext, + SignatureContext signatureContext) { LookupKind = lookupKind; FixupKind = fixupKind; @@ -417,6 +555,7 @@ public GenericLookupKey( MethodArgument = methodArgument; FieldArgument = fieldArgument; MethodContext = methodContext; + SignatureContext = signatureContext; } public bool Equals(GenericLookupKey other) @@ -445,7 +584,7 @@ public override int GetHashCode() } } - private Dictionary _genericLookupHelpers = new Dictionary(); + private NodeCache _genericLookupHelpers; public ISymbolNode GenericLookupHelper( CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind, @@ -538,18 +677,8 @@ private ISymbolNode GenericLookupTypeHelper( typeArgument = (TypeDesc)helperArgument; } - GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, fieldArgument: null, methodContext); - ISymbolNode node; - if (!_genericLookupHelpers.TryGetValue(key, out node)) - { - node = new DelayLoadHelperImport( - _codegenNodeFactory, - _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, fieldArgument: null, methodContext, signatureContext)); - _genericLookupHelpers.Add(key, node); - } - return node; + GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, fieldArgument: null, methodContext, signatureContext); + return _genericLookupHelpers.GetOrAdd(key); } private ISymbolNode GenericLookupFieldHelper( @@ -559,18 +688,8 @@ private ISymbolNode GenericLookupFieldHelper( GenericContext methodContext, SignatureContext signatureContext) { - GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument: null, fieldArgument: fieldArgument, methodContext); - ISymbolNode node; - if (!_genericLookupHelpers.TryGetValue(key, out node)) - { - node = new DelayLoadHelperImport( - _codegenNodeFactory, - _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument: null, fieldArgument: fieldArgument, methodContext, signatureContext)); - _genericLookupHelpers.Add(key, node); - } - return node; + GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument: null, fieldArgument: fieldArgument, methodContext, signatureContext); + return _genericLookupHelpers.GetOrAdd(key); } private ISymbolNode GenericLookupMethodHelper( @@ -580,45 +699,43 @@ private ISymbolNode GenericLookupMethodHelper( GenericContext methodContext, SignatureContext signatureContext) { - GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, fieldArgument: null, methodContext); - ISymbolNode node; - if (!_genericLookupHelpers.TryGetValue(key, out node)) - { - node = new DelayLoadHelperMethodImport( - _codegenNodeFactory, - _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - methodArgument, - useVirtualCall: false, - useInstantiatingStub: false, - new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, fieldArgument: null, methodContext, signatureContext), - signatureContext); - _genericLookupHelpers.Add(key, node); - } - return node; + GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, fieldArgument: null, methodContext, signatureContext); + return _genericLookupHelpers.GetOrAdd(key); } - private Dictionary _indirectPInvokeTargetNodes = new Dictionary(); - - public ISymbolNode GetIndirectPInvokeTargetNode(MethodWithToken methodWithToken, SignatureContext signatureContext) + private struct IndirectPInvokeTargetKey : IEquatable { - ISymbolNode result; + public readonly MethodWithToken MethodWithToken; + public readonly SignatureContext SignatureContext; - if (!_indirectPInvokeTargetNodes.TryGetValue(methodWithToken, out result)) + public IndirectPInvokeTargetKey(MethodWithToken methodWithToken, SignatureContext signatureContext) { - result = new PrecodeHelperImport( - _codegenNodeFactory, - _codegenNodeFactory.MethodSignature( - ReadyToRunFixupKind.READYTORUN_FIXUP_IndirectPInvokeTarget, - methodWithToken, - signatureContext: signatureContext, - isUnboxingStub: false, - isInstantiatingStub: false)); + MethodWithToken = methodWithToken; + SignatureContext = signatureContext; + } + + public bool Equals(IndirectPInvokeTargetKey other) + { + return MethodWithToken.Equals(other.MethodWithToken) + && SignatureContext.Equals(other.SignatureContext); + } - _indirectPInvokeTargetNodes.Add(methodWithToken, result); + public override bool Equals(object obj) + { + return obj is IndirectPInvokeTargetKey other && Equals(other); } - return result; + public override int GetHashCode() + { + return MethodWithToken.GetHashCode() ^ (SignatureContext.GetHashCode() * 31); + } + } + + private NodeCache _indirectPInvokeTargetNodes = new NodeCache(); + + public ISymbolNode GetIndirectPInvokeTargetNode(MethodWithToken methodWithToken, SignatureContext signatureContext) + { + return _indirectPInvokeTargetNodes.GetOrAdd(new IndirectPInvokeTargetKey(methodWithToken, signatureContext)); } } } diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/TypeAndMethod.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/TypeAndMethod.cs index cbd89bf506b4..b03c7d547773 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/TypeAndMethod.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/TypeAndMethod.cs @@ -18,14 +18,16 @@ internal struct TypeAndMethod : IEquatable public readonly bool IsUnboxingStub; public readonly bool IsInstantiatingStub; public readonly bool IsPrecodeImportRequired; + public readonly SignatureContext SignatureContext; - public TypeAndMethod(TypeDesc type, MethodWithToken method, bool isUnboxingStub, bool isInstantiatingStub, bool isPrecodeImportRequired) + public TypeAndMethod(TypeDesc type, MethodWithToken method, bool isUnboxingStub, bool isInstantiatingStub, bool isPrecodeImportRequired, SignatureContext signatureContext) { Type = type; Method = method; IsUnboxingStub = isUnboxingStub; IsInstantiatingStub = isInstantiatingStub; IsPrecodeImportRequired = isPrecodeImportRequired; + SignatureContext = signatureContext; } public bool Equals(TypeAndMethod other) @@ -34,7 +36,8 @@ public bool Equals(TypeAndMethod other) Method.Equals(other.Method) && IsUnboxingStub == other.IsUnboxingStub && IsInstantiatingStub == other.IsInstantiatingStub && - IsPrecodeImportRequired == other.IsPrecodeImportRequired; + IsPrecodeImportRequired == other.IsPrecodeImportRequired && + SignatureContext.Equals(other.SignatureContext); } public override bool Equals(object obj) @@ -48,7 +51,8 @@ public override int GetHashCode() unchecked(Method.GetHashCode() * 31) ^ (IsUnboxingStub ? -0x80000000 : 0) ^ (IsInstantiatingStub ? 0x40000000 : 0) ^ - (IsPrecodeImportRequired ? 0x20000000 : 0); + (IsPrecodeImportRequired ? 0x20000000 : 0) ^ + (SignatureContext.GetHashCode() * 23); } } } diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index eb5e6b39488d..5d3488ffd472 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using System.IO; using System.Reflection.PortableExecutable; +using System.Runtime.CompilerServices; +using System.Threading; using Internal.IL; using Internal.JitInterface; @@ -176,11 +178,6 @@ public sealed class ReadyToRunCodegenCompilation : Compilation /// private readonly string _inputFilePath; - /// - /// JIT interface implementation. - /// - private readonly CorInfoImpl _corInfo; - private bool _resilient; public new ReadyToRunCodegenNodeFactory NodeFactory { get; } @@ -206,7 +203,6 @@ internal ReadyToRunCodegenCompilation( _jitConfigProvider = configProvider; _inputFilePath = inputFilePath; - _corInfo = new CorInfoImpl(this, _jitConfigProvider); } public override void Compile(string outputFile) @@ -241,27 +237,11 @@ protected override void ComputeDependencyNodeDependencies(List cwt = new ConditionalWeakTable(); foreach (DependencyNodeCore dependency in obj) { - var methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; - if (methodCodeNodeNeedingCode == null) - { - // To compute dependencies of the shadow method that tracks dictionary - // dependencies we need to ensure there is code for the canonical method body. - var dependencyMethod = (ShadowConcreteMethodNode)dependency; - methodCodeNodeNeedingCode = (MethodWithGCInfo)dependencyMethod.CanonicalMethodNode; - } - - // We might have already compiled this method. - if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed) - continue; - + MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; MethodDesc method = methodCodeNodeNeedingCode.Method; - if (!NodeFactory.CompilationModuleGroup.ContainsMethodBody(method, unboxingStub: false)) - { - // Don't drill into methods defined outside of this version bubble - continue; - } if (Logger.IsVerbose) { @@ -273,7 +253,8 @@ protected override void ComputeDependencyNodeDependencies(List new CorInfoImpl(this, _jitConfigProvider)); + corInfoImpl.CompileMethod(methodCodeNodeNeedingCode); } } catch (TypeSystemException ex) diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index 58588c513f52..4ef0ca76e068 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -14,6 +14,7 @@ using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Internal.TypeSystem.Interop; +using System.Collections.Concurrent; namespace ILCompiler { @@ -373,33 +374,29 @@ private void GetElementTypeInfo( public FieldAndOffset[] GetOrAddDynamicLayout(DefType defType, ModuleFieldLayout moduleFieldLayout) { - FieldAndOffset[] fieldsForType; - if (!moduleFieldLayout.TryGetDynamicLayout(defType, out fieldsForType)) + int nonGcOffset; + switch (moduleFieldLayout.Module.Context.Target.Architecture) { - int nonGcOffset; - switch (moduleFieldLayout.Module.Context.Target.Architecture) - { - case TargetArchitecture.X86: - nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobX86; - break; + case TargetArchitecture.X86: + nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobX86; + break; - case TargetArchitecture.X64: - nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobAmd64; - break; + case TargetArchitecture.X64: + nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobAmd64; + break; - default: - throw new NotImplementedException(); - } - OffsetsForType offsetsForType = new OffsetsForType( - nonGcOffset: new LayoutInt(nonGcOffset), - tlsNonGcOffset: new LayoutInt(nonGcOffset), - gcOffset: LayoutInt.Zero, - tlsGcOffset: LayoutInt.Zero); - - fieldsForType = CalculateTypeLayout(defType, moduleFieldLayout.Module, offsetsForType); - moduleFieldLayout.AddDynamicLayout(defType, fieldsForType); + default: + throw new NotImplementedException(); } - return fieldsForType; + OffsetsForType offsetsForType = new OffsetsForType( + nonGcOffset: new LayoutInt(nonGcOffset), + tlsNonGcOffset: new LayoutInt(nonGcOffset), + gcOffset: LayoutInt.Zero, + tlsGcOffset: LayoutInt.Zero); + + FieldAndOffset[] fieldsForType; + fieldsForType = CalculateTypeLayout(defType, moduleFieldLayout.Module, offsetsForType); + return moduleFieldLayout.GetOrAddDynamicLayout(defType, fieldsForType); } public FieldAndOffset[] CalculateTypeLayout(DefType defType, EcmaModule module, in OffsetsForType offsetsForType) @@ -728,7 +725,7 @@ private class ModuleFieldLayout public IReadOnlyDictionary TypeOffsets { get; } - private Dictionary _genericTypeToFieldMap; + private ConcurrentDictionary _genericTypeToFieldMap; public ModuleFieldLayout( EcmaModule module, @@ -745,17 +742,12 @@ public ModuleFieldLayout( ThreadNonGcStatics = threadNonGcStatics; TypeOffsets = typeOffsets; - _genericTypeToFieldMap = new Dictionary(); - } - - public bool TryGetDynamicLayout(DefType instantiatedType, out FieldAndOffset[] fieldMap) - { - return _genericTypeToFieldMap.TryGetValue(instantiatedType, out fieldMap); + _genericTypeToFieldMap = new ConcurrentDictionary(); } - public void AddDynamicLayout(DefType instantiatedType, FieldAndOffset[] fieldMap) + public FieldAndOffset[] GetOrAddDynamicLayout(DefType instantiatedType, FieldAndOffset[] fieldMap) { - _genericTypeToFieldMap.Add(instantiatedType, fieldMap); + return _genericTypeToFieldMap.GetOrAdd(instantiatedType, fieldMap); } } diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunSingleAssemblyCompilationModuleGroup.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunSingleAssemblyCompilationModuleGroup.cs index a871b4f7d947..b70c31285ad7 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunSingleAssemblyCompilationModuleGroup.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunSingleAssemblyCompilationModuleGroup.cs @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; +using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; @@ -102,20 +101,14 @@ private bool CompileVersionBubbleGenericsIntoCurrentModule(MethodDesc method) return VersionsWithType(method.OwningType); } - Dictionary _containsTypeLayoutCache = new Dictionary(); + private ConcurrentDictionary _containsTypeLayoutCache = new ConcurrentDictionary(); /// /// If true, the type is fully contained in the current compilation group. /// public override bool ContainsTypeLayout(TypeDesc type) { - if (!_containsTypeLayoutCache.TryGetValue(type, out bool containsTypeLayout)) - { - containsTypeLayout = ContainsTypeLayoutUncached(type); - _containsTypeLayoutCache[type] = containsTypeLayout; - } - - return containsTypeLayout; + return _containsTypeLayoutCache.GetOrAdd(type, ContainsTypeLayoutUncached); } private bool ContainsTypeLayoutUncached(TypeDesc type) diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs index c04efc6e2f1e..54225facc0d8 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs @@ -50,8 +50,6 @@ protected virtual void Graph_NewMarkedNode(DependencyNodeCore obj) { IMethodBodyNode methodBodyNode = obj as IMethodBodyNode; var methodNode = methodBodyNode as IMethodNode; - if (methodNode == null) - methodNode = obj as ShadowConcreteMethodNode; if (methodNode != null) { diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index b05add234491..87b4c4023910 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -1876,7 +1876,7 @@ private HRESULT allocMethodBlockCounts(uint count, ref BlockCounts* pBlockCounts pBlockCounts = (BlockCounts*)GetPin(_bbCounts = new byte[count * sizeof(BlockCounts)]); if (_profileDataNode == null) { - _profileDataNode = _compilation.NodeFactory.ProfileDataNode((MethodWithGCInfo)_methodCodeNode); + _profileDataNode = _compilation.NodeFactory.ProfileData((MethodWithGCInfo)_methodCodeNode); } return 0; } From 7c48df66ca61eb6cc45bdd9881d290c6f8f34cd5 Mon Sep 17 00:00:00 2001 From: Anubhav Srivastava Date: Mon, 7 Oct 2019 17:25:39 -0700 Subject: [PATCH 2/2] Fix nits and add .Equals and GetHashCode to SignatureContext. --- .../ReadyToRun/SignatureContext.cs | 17 +++++++++++++++++ .../ReadyToRunCodegenNodeFactory.cs | 6 ++---- .../ReadyToRunSymbolNodeFactory.cs | 8 +++++--- .../ReadyToRunMetadataFieldLayoutAlgorithm.cs | 2 +- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureContext.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureContext.cs index cd1b1ce8eccd..657f435a8585 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureContext.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureContext.cs @@ -83,5 +83,22 @@ public ModuleToken GetModuleTokenForField(FieldDesc field, bool throwIfNotFound { return Resolver.GetModuleTokenForField(field, throwIfNotFound); } + + public bool Equals(SignatureContext other) + { + return GlobalContext == other.GlobalContext + && LocalContext == other.LocalContext; + } + + public override bool Equals(object obj) + { + return obj is SignatureContext other && Equals(other); + } + + public override int GetHashCode() + { + return GlobalContext.GetHashCode() + ^ (LocalContext.GetHashCode() * 31); + } } } diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 52e1b2df7eb0..f6d7e0ac3828 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -221,12 +221,11 @@ public ReadyToRunCodegenNodeFactory( if (!win32Resources.IsEmpty) Win32ResourcesNode = new Win32ResourcesNode(win32Resources); - CreateCodegenNodeCaches(); + CreateNodeCaches(); } - private void CreateCodegenNodeCaches() + private void CreateNodeCaches() { - // Create node caches _constructedHelpers = new NodeCache(CreateReadyToRunHelperCell); @@ -488,7 +487,6 @@ public override int GetHashCode() { return FixupKind.GetHashCode() ^ TypeAndMethod.GetHashCode(); } - } private NodeCache _methodSignatures; diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs index 28720b61334a..ef404fca29f4 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs @@ -41,10 +41,10 @@ public sealed class ReadyToRunSymbolNodeFactory public ReadyToRunSymbolNodeFactory(ReadyToRunCodegenNodeFactory codegenNodeFactory) { _codegenNodeFactory = codegenNodeFactory; - CreateSymbolNodeCaches(); + CreateNodeCaches(); } - private void CreateSymbolNodeCaches() + private void CreateNodeCaches() { _importStrings = new NodeCache(key => { @@ -203,7 +203,9 @@ public override bool Equals(object obj) public override int GetHashCode() { - return Id.GetHashCode() ^ (SignatureContext.GetHashCode() * 31); + return Id.GetHashCode() + ^ (Target.GetHashCode() * 23) + ^ (SignatureContext.GetHashCode() * 31); } } diff --git a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index 4ef0ca76e068..ded0b7c53d8b 100644 --- a/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -14,7 +15,6 @@ using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Internal.TypeSystem.Interop; -using System.Collections.Concurrent; namespace ILCompiler {