private void CreateNodeCaches()
{
- _typeSymbols = new NodeCache<TypeDesc, IEETypeNode>(CreateNecessaryTypeNode);
+ _typeSymbols = new NecessaryTypeSymbolHashtable(this);
- _constructedTypeSymbols = new NodeCache<TypeDesc, IEETypeNode>(CreateConstructedTypeNode);
+ _constructedTypeSymbols = new ConstructedTypeSymbolHashtable(this);
_clonedTypeSymbols = new NodeCache<TypeDesc, IEETypeNode>((TypeDesc type) =>
{
return new PInvokeMethodFixupNode(methodData);
});
- _methodEntrypoints = new NodeCache<MethodDesc, IMethodNode>(CreateMethodEntrypointNode);
+ _methodEntrypoints = new MethodEntrypointHashtable(this);
_unboxingStubs = new NodeCache<MethodDesc, IMethodNode>(CreateUnboxingStubNode);
return new ObjectGetTypeFlowDependenciesNode(type);
});
- _shadowConcreteMethods = new NodeCache<MethodKey, IMethodNode>(methodKey =>
- {
- MethodDesc canonMethod = methodKey.Method.GetCanonMethodTarget(CanonicalFormKind.Specific);
-
- if (methodKey.IsUnboxingStub)
- {
- return new ShadowConcreteUnboxingThunkNode(methodKey.Method, MethodEntrypoint(canonMethod, true));
- }
- else
- {
- return new ShadowConcreteMethodNode(methodKey.Method, MethodEntrypoint(canonMethod));
- }
- });
+ _shadowConcreteMethods = new ShadowConcreteMethodHashtable(this);
- _virtMethods = new NodeCache<MethodDesc, VirtualMethodUseNode>((MethodDesc method) =>
+ _shadowConcreteUnboxingMethods = new NodeCache<MethodDesc, ShadowConcreteUnboxingThunkNode>(method =>
{
- // We don't need to track virtual method uses for types that have a vtable with a known layout.
- // It's a waste of CPU time and memory.
- Debug.Assert(!VTable(method.OwningType).HasFixedSlots);
-
- return new VirtualMethodUseNode(method);
+ MethodDesc canonMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
+ return new ShadowConcreteUnboxingThunkNode(method, MethodEntrypoint(canonMethod, true));
});
+ _virtMethods = new VirtualMethodUseHashtable(this);
+
_variantMethods = new NodeCache<MethodDesc, VariantInterfaceMethodUseNode>((MethodDesc method) =>
{
// We don't need to track virtual method uses for types that have a vtable with a known layout.
return new StructMarshallingDataNode(type);
});
- _vTableNodes = new NodeCache<TypeDesc, VTableSliceNode>((TypeDesc type ) =>
- {
- if (CompilationModuleGroup.ShouldProduceFullVTable(type))
- return new EagerlyBuiltVTableSliceNode(type);
- else
- return _vtableSliceProvider.GetSlice(type);
- });
+ _vTableNodes = new VTableSliceHashtable(this);
_methodGenericDictionaries = new NodeCache<MethodDesc, ISortableSymbolNode>(method =>
{
return new ReadyToRunGenericLookupFromTypeNode(this, helperKey.HelperId, helperKey.Target, helperKey.DictionaryOwner);
}
- protected virtual IEETypeNode CreateNecessaryTypeNode(TypeDesc type)
+ private IEETypeNode CreateNecessaryTypeNode(TypeDesc type)
{
Debug.Assert(!_compilationModuleGroup.ShouldReferenceThroughImportTable(type));
if (_compilationModuleGroup.ContainsType(type))
}
}
- protected virtual IEETypeNode CreateConstructedTypeNode(TypeDesc type)
+ private IEETypeNode CreateConstructedTypeNode(TypeDesc type)
{
// Canonical definition types are *not* constructed types (call NecessaryTypeSymbol to get them)
Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any));
return new ThreadStaticsNode(type, this);
}
- private NodeCache<TypeDesc, IEETypeNode> _typeSymbols;
+ private abstract class TypeSymbolHashtable : LockFreeReaderHashtable<TypeDesc, IEETypeNode>
+ {
+ protected readonly NodeFactory _factory;
+ public TypeSymbolHashtable(NodeFactory factory) => _factory = factory;
+ protected override bool CompareKeyToValue(TypeDesc key, IEETypeNode value) => key == value.Type;
+ protected override bool CompareValueToValue(IEETypeNode value1, IEETypeNode value2) => value1.Type == value2.Type;
+ protected override int GetKeyHashCode(TypeDesc key) => key.GetHashCode();
+ protected override int GetValueHashCode(IEETypeNode value) => value.Type.GetHashCode();
+ }
+
+ private sealed class NecessaryTypeSymbolHashtable : TypeSymbolHashtable
+ {
+ public NecessaryTypeSymbolHashtable(NodeFactory factory) : base(factory) { }
+ protected override IEETypeNode CreateValueFromKey(TypeDesc key) => _factory.CreateNecessaryTypeNode(key);
+ }
+
+ private NecessaryTypeSymbolHashtable _typeSymbols;
public IEETypeNode NecessaryTypeSymbol(TypeDesc type)
{
Debug.Assert(!TypeCannotHaveEEType(type));
- return _typeSymbols.GetOrAdd(type);
+ return _typeSymbols.GetOrCreateValue(type);
}
- private NodeCache<TypeDesc, IEETypeNode> _constructedTypeSymbols;
+ private sealed class ConstructedTypeSymbolHashtable : TypeSymbolHashtable
+ {
+ public ConstructedTypeSymbolHashtable(NodeFactory factory) : base(factory) { }
+ protected override IEETypeNode CreateValueFromKey(TypeDesc key) => _factory.CreateConstructedTypeNode(key);
+ }
+
+ private ConstructedTypeSymbolHashtable _constructedTypeSymbols;
public IEETypeNode ConstructedTypeSymbol(TypeDesc type)
{
Debug.Assert(!TypeCannotHaveEEType(type));
- return _constructedTypeSymbols.GetOrAdd(type);
+ return _constructedTypeSymbols.GetOrCreateValue(type);
}
private NodeCache<TypeDesc, IEETypeNode> _clonedTypeSymbols;
return _pInvokeMethodFixups.GetOrAdd(methodData);
}
- private NodeCache<TypeDesc, VTableSliceNode> _vTableNodes;
+ private sealed class VTableSliceHashtable : LockFreeReaderHashtable<TypeDesc, VTableSliceNode>
+ {
+ private readonly NodeFactory _factory;
+ public VTableSliceHashtable(NodeFactory factory) => _factory = factory;
+ protected override bool CompareKeyToValue(TypeDesc key, VTableSliceNode value) => key == value.Type;
+ protected override bool CompareValueToValue(VTableSliceNode value1, VTableSliceNode value2) => value1.Type == value2.Type;
+ protected override VTableSliceNode CreateValueFromKey(TypeDesc key)
+ {
+ if (_factory.CompilationModuleGroup.ShouldProduceFullVTable(key))
+ return new EagerlyBuiltVTableSliceNode(key);
+ else
+ return _factory._vtableSliceProvider.GetSlice(key);
+ }
+ protected override int GetKeyHashCode(TypeDesc key) => key.GetHashCode();
+ protected override int GetValueHashCode(VTableSliceNode value) => value.Type.GetHashCode();
+ }
+
+ private VTableSliceHashtable _vTableNodes;
public VTableSliceNode VTable(TypeDesc type)
{
- return _vTableNodes.GetOrAdd(type);
+ return _vTableNodes.GetOrCreateValue(type);
}
private NodeCache<MethodDesc, ISortableSymbolNode> _methodGenericDictionaries;
return _stringAllocators.GetOrAdd(stringConstructor);
}
- protected NodeCache<MethodDesc, IMethodNode> _methodEntrypoints;
+ private sealed class MethodEntrypointHashtable : LockFreeReaderHashtable<MethodDesc, IMethodNode>
+ {
+ private readonly NodeFactory _factory;
+ public MethodEntrypointHashtable(NodeFactory factory) => _factory = factory;
+ protected override bool CompareKeyToValue(MethodDesc key, IMethodNode value) => key == value.Method;
+ protected override bool CompareValueToValue(IMethodNode value1, IMethodNode value2) => value1.Method == value2.Method;
+ protected override IMethodNode CreateValueFromKey(MethodDesc key) => _factory.CreateMethodEntrypointNode(key);
+ protected override int GetKeyHashCode(MethodDesc key) => key.GetHashCode();
+ protected override int GetValueHashCode(IMethodNode value) => value.Method.GetHashCode();
+ }
+
+ private MethodEntrypointHashtable _methodEntrypoints;
private NodeCache<MethodDesc, IMethodNode> _unboxingStubs;
private NodeCache<IMethodNode, MethodAssociatedDataNode> _methodAssociatedData;
return _unboxingStubs.GetOrAdd(method);
}
- return _methodEntrypoints.GetOrAdd(method);
+ return _methodEntrypoints.GetOrCreateValue(method);
}
public MethodAssociatedDataNode MethodAssociatedData(IMethodNode methodNode)
return _objectGetTypeFlowDependencies.GetOrAdd(type);
}
- private NodeCache<MethodKey, IMethodNode> _shadowConcreteMethods;
+ private sealed class ShadowConcreteMethodHashtable : LockFreeReaderHashtable<MethodDesc, ShadowConcreteMethodNode>
+ {
+ private readonly NodeFactory _factory;
+ public ShadowConcreteMethodHashtable(NodeFactory factory) => _factory = factory;
+ protected override bool CompareKeyToValue(MethodDesc key, ShadowConcreteMethodNode value) => key == value.Method;
+ protected override bool CompareValueToValue(ShadowConcreteMethodNode value1, ShadowConcreteMethodNode value2) => value1.Method == value2.Method;
+ protected override ShadowConcreteMethodNode CreateValueFromKey(MethodDesc key) =>
+ new ShadowConcreteMethodNode(key, _factory.MethodEntrypoint(key.GetCanonMethodTarget(CanonicalFormKind.Specific)));
+ protected override int GetKeyHashCode(MethodDesc key) => key.GetHashCode();
+ protected override int GetValueHashCode(ShadowConcreteMethodNode value) => value.Method.GetHashCode();
+ }
+
+ private ShadowConcreteMethodHashtable _shadowConcreteMethods;
+ private NodeCache<MethodDesc, ShadowConcreteUnboxingThunkNode> _shadowConcreteUnboxingMethods;
public IMethodNode ShadowConcreteMethod(MethodDesc method, bool isUnboxingStub = false)
{
- return _shadowConcreteMethods.GetOrAdd(new MethodKey(method, isUnboxingStub));
+ if (isUnboxingStub)
+ return _shadowConcreteUnboxingMethods.GetOrAdd(method);
+ else
+ return _shadowConcreteMethods.GetOrCreateValue(method);
}
private static readonly string[][] s_helperEntrypointNames = new string[][] {
}
}
- private NodeCache<MethodDesc, VirtualMethodUseNode> _virtMethods;
+ private sealed class VirtualMethodUseHashtable : LockFreeReaderHashtable<MethodDesc, VirtualMethodUseNode>
+ {
+ private readonly NodeFactory _factory;
+ public VirtualMethodUseHashtable(NodeFactory factory) => _factory = factory;
+ protected override bool CompareKeyToValue(MethodDesc key, VirtualMethodUseNode value) => key == value.Method;
+ protected override bool CompareValueToValue(VirtualMethodUseNode value1, VirtualMethodUseNode value2) => value1.Method == value2.Method;
+ protected override VirtualMethodUseNode CreateValueFromKey(MethodDesc key)
+ {
+ // We don't need to track virtual method uses for types that have a vtable with a known layout.
+ // It's a waste of CPU time and memory.
+ Debug.Assert(!_factory.VTable(key.OwningType).HasFixedSlots);
+ return new VirtualMethodUseNode(key);
+ }
+ protected override int GetKeyHashCode(MethodDesc key) => key.GetHashCode();
+ protected override int GetValueHashCode(VirtualMethodUseNode value) => value.Method.GetHashCode();
+ }
+
+ private VirtualMethodUseHashtable _virtMethods;
public DependencyNodeCore<NodeFactory> VirtualMethodUse(MethodDesc decl)
{
- return _virtMethods.GetOrAdd(decl);
+ return _virtMethods.GetOrCreateValue(decl);
}
private NodeCache<MethodDesc, VariantInterfaceMethodUseNode> _variantMethods;