| File: DataFlow\LocalStateLattice.cs | Web Access |
| Project: src\runtime\src\tools\illink\src\ILLink.RoslynAnalyzer\ILLink.RoslynAnalyzer.csproj (ILLink.RoslynAnalyzer) |
// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; using ILLink.Shared.DataFlow; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.FlowAnalysis; namespace ILLink.RoslynAnalyzer.DataFlow { public readonly struct LocalKey : IEquatable<LocalKey> { private readonly ILocalSymbol? Local; private readonly CaptureId? CaptureId; public LocalKey(ILocalSymbol symbol) => (Local, CaptureId) = (symbol, null); public LocalKey(CaptureId captureId) => (Local, CaptureId) = (null, captureId); public bool Equals(LocalKey other) => SymbolEqualityComparer.Default.Equals(Local, other.Local) && (CaptureId?.Equals(other.CaptureId) ?? other.CaptureId == null); public override bool Equals(object obj) => obj is LocalKey inst && Equals(inst); public override int GetHashCode() => CaptureId is null ? SymbolEqualityComparer.Default.GetHashCode(Local) : CaptureId.GetHashCode(); public override string ToString() { if (Local != null) return Local.ToString(); return $"capture {CaptureId.GetHashCode()}"; } } public readonly struct CapturedTargetKey : IEquatable<CapturedTargetKey> { private readonly IOperation Operation; public CapturedTargetKey(IOperation operation) => Operation = operation; public bool Equals(CapturedTargetKey other) => Operation == other.Operation; public override bool Equals(object obj) => obj is CapturedTargetKey inst && Equals(inst); public override int GetHashCode() => Operation.GetHashCode(); } public readonly struct CapturedTargetValue<TValue> : IEquatable<CapturedTargetValue<TValue>>, IDeepCopyValue<CapturedTargetValue<TValue>> where TValue : IEquatable<TValue> { public readonly bool HasValue; public readonly TValue Value; public CapturedTargetValue(TValue value) => (HasValue, Value) = (true, value); public bool Equals(CapturedTargetValue<TValue> other) => HasValue == other.HasValue && (!HasValue || EqualityComparer<TValue>.Default.Equals(Value, other.Value)); public override bool Equals(object obj) => obj is CapturedTargetValue<TValue> inst && Equals(inst); public override int GetHashCode() => HasValue ? EqualityComparer<TValue>.Default.GetHashCode(Value) : 0; public CapturedTargetValue<TValue> DeepCopy() => HasValue ? new CapturedTargetValue<TValue>( Value is IDeepCopyValue<TValue> copyValue ? copyValue.DeepCopy() : Value) : default; } public readonly struct CapturedTargetValueLattice<TValue, TValueLattice> : ILattice<CapturedTargetValue<TValue>> where TValue : IEquatable<TValue> where TValueLattice : ILattice<TValue> { private readonly TValueLattice _valueLattice; public CapturedTargetValueLattice(TValueLattice valueLattice) => _valueLattice = valueLattice; public CapturedTargetValue<TValue> Top => default; public CapturedTargetValue<TValue> Meet(CapturedTargetValue<TValue> left, CapturedTargetValue<TValue> right) { if (!left.HasValue) return right.DeepCopy(); if (!right.HasValue) return left.DeepCopy(); return new CapturedTargetValue<TValue>(_valueLattice.Meet(left.Value, right.Value)); } } public struct LocalState<TValue> : IEquatable<LocalState<TValue>> where TValue : IEquatable<TValue> { public DefaultValueDictionary<LocalKey, TValue> Dictionary; // Stores any operations which are captured by reference in a FlowCaptureOperation. // Only stores captures which are assigned through. Captures of the values of operations // are tracked as part of the dictionary of values, keyed by LocalKey. public DefaultValueDictionary<CaptureId, ValueSet<CapturedReferenceValue>> CapturedReferences; // Stores target receiver and index values evaluated by deconstruction l-value captures. public DefaultValueDictionary<CapturedTargetKey, CapturedTargetValue<TValue>> CapturedTargetValues; public LocalState( DefaultValueDictionary<LocalKey, TValue> dictionary, DefaultValueDictionary<CaptureId, ValueSet<CapturedReferenceValue>> capturedReferences, DefaultValueDictionary<CapturedTargetKey, CapturedTargetValue<TValue>> capturedTargetValues) { Dictionary = dictionary; CapturedReferences = capturedReferences; CapturedTargetValues = capturedTargetValues; } public LocalState(DefaultValueDictionary<LocalKey, TValue> dictionary) : this( dictionary, new DefaultValueDictionary<CaptureId, ValueSet<CapturedReferenceValue>>(default(ValueSet<CapturedReferenceValue>)), new DefaultValueDictionary<CapturedTargetKey, CapturedTargetValue<TValue>>(default(CapturedTargetValue<TValue>))) { } public bool Equals(LocalState<TValue> other) => Dictionary.Equals(other.Dictionary) && CapturedReferences.Equals(other.CapturedReferences) && CapturedTargetValues.Equals(other.CapturedTargetValues); public override bool Equals(object obj) => obj is LocalState<TValue> inst && Equals(inst); public TValue Get(LocalKey key) => Dictionary.Get(key); // Local dataflow states are mutable and should never be used as dictionary keys. public override int GetHashCode() => throw new NotImplementedException(); public void Set(LocalKey key, TValue value) => Dictionary.Set(key, value); public override string ToString() => Dictionary.ToString(); } // Wrapper struct exists purely to substitute a concrete LocalKey for TKey of DictionaryLattice public readonly struct LocalStateLattice<TValue, TValueLattice> : ILattice<LocalState<TValue>> where TValue : struct, IEquatable<TValue> where TValueLattice : ILattice<TValue> { public readonly DictionaryLattice<LocalKey, TValue, TValueLattice> Lattice; public readonly DictionaryLattice<CaptureId, ValueSet<CapturedReferenceValue>, ValueSetLattice<CapturedReferenceValue>> CapturedReferenceLattice; public readonly DictionaryLattice<CapturedTargetKey, CapturedTargetValue<TValue>, CapturedTargetValueLattice<TValue, TValueLattice>> CapturedTargetValueLattice; public LocalStateLattice(TValueLattice valueLattice) { Lattice = new DictionaryLattice<LocalKey, TValue, TValueLattice>(valueLattice); CapturedReferenceLattice = new DictionaryLattice<CaptureId, ValueSet<CapturedReferenceValue>, ValueSetLattice<CapturedReferenceValue>>(default(ValueSetLattice<CapturedReferenceValue>)); CapturedTargetValueLattice = new DictionaryLattice<CapturedTargetKey, CapturedTargetValue<TValue>, CapturedTargetValueLattice<TValue, TValueLattice>>( new CapturedTargetValueLattice<TValue, TValueLattice>(valueLattice)); Top = new(Lattice.Top); } public LocalState<TValue> Top { get; } public LocalState<TValue> Meet(LocalState<TValue> left, LocalState<TValue> right) { var dictionary = Lattice.Meet(left.Dictionary, right.Dictionary); var capturedProperties = CapturedReferenceLattice.Meet(left.CapturedReferences, right.CapturedReferences); var capturedTargetValues = CapturedTargetValueLattice.Meet(left.CapturedTargetValues, right.CapturedTargetValues); return new LocalState<TValue>(dictionary, capturedProperties, capturedTargetValues); } } }