|
// 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 System.Text;
using ILLink.Shared.DataFlow;
using Mono.Cecil;
using Mono.Linker.Dataflow;
using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
namespace ILLink.Shared.TrimAnalysis
{
internal partial record ArrayValue
{
public static MultiValue Create (MultiValue size, TypeReference elementType)
{
MultiValue result = MultiValueLattice.Top;
foreach (var sizeValue in size.AsEnumerable ()) {
result = MultiValueLattice.Meet (result, new MultiValue (new ArrayValue (sizeValue, elementType)));
}
return result;
}
public static ArrayValue Create (int size, TypeReference elementType)
{
return new ArrayValue (new ConstIntValue (size), elementType);
}
/// <summary>
/// Constructs an array value of the given size
/// </summary>
ArrayValue (SingleValue size, TypeReference elementType)
{
Size = size;
ElementType = elementType;
IndexValues = new Dictionary<int, ValueBasicBlockPair> ();
}
public TypeReference ElementType { get; }
public Dictionary<int, ValueBasicBlockPair> IndexValues { get; }
public partial bool TryGetValueByIndex (int index, out MultiValue value)
{
if (IndexValues.TryGetValue (index, out var valuePair)) {
value = valuePair.Value;
return true;
}
value = default;
return false;
}
public override int GetHashCode ()
{
return HashCode.Combine (GetType ().GetHashCode (), Size);
}
public bool Equals (ArrayValue? otherArr)
{
if (otherArr == null)
return false;
bool equals = Size.Equals (otherArr.Size);
equals &= IndexValues.Count == otherArr.IndexValues.Count;
if (!equals)
return false;
// Here we rely on the assumption that we can't store mutable values in arrays. The only mutable value
// which we currently support are array values, but those are not allowed in an array (to avoid complexity).
// As such we can rely on the values to be immutable, and thus if the counts are equal
// then the arrays are equal if items from one can be directly found in the other.
foreach (var kvp in IndexValues)
if (!otherArr.IndexValues.TryGetValue (kvp.Key, out ValueBasicBlockPair value) || !kvp.Value.Equals (value))
return false;
return true;
}
public override SingleValue DeepCopy ()
{
var newValue = new ArrayValue (Size.DeepCopy (), ElementType);
foreach (var kvp in IndexValues) {
#if DEBUG
// Since it's possible to store a reference to array as one of its own elements
// simple deep copy could lead to endless recursion.
// So instead we simply disallow arrays as element values completely - and treat that case as "too complex to analyze".
foreach (SingleValue v in kvp.Value.Value.AsEnumerable ()) {
System.Diagnostics.Debug.Assert (v is not ArrayValue);
}
#endif
newValue.IndexValues.Add (kvp.Key, new ValueBasicBlockPair (kvp.Value.Value.DeepCopy (), kvp.Value.BasicBlockIndex));
}
return newValue;
}
public override string ToString ()
{
StringBuilder result = new ();
result.Append ("Array Size:");
result.Append (this.ValueToString (Size));
result.Append (", Values:(");
bool first = true;
foreach (var element in IndexValues) {
if (!first) {
result.Append (',');
first = false;
}
result.Append ('(');
result.Append (element.Key);
result.Append (",(");
bool firstValue = true;
foreach (var v in element.Value.Value.AsEnumerable ()) {
if (firstValue) {
result.Append (',');
firstValue = false;
}
result.Append (v.ToString ());
}
result.Append ("))");
}
result.Append (')');
return result.ToString ();
}
}
}
|