| File: Linker.Dataflow\InterproceduralState.cs | Web Access |
| Project: src\runtime\src\tools\illink\src\linker\Mono.Linker.csproj (illink) |
// 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.Diagnostics; using ILLink.Shared; using ILLink.Shared.DataFlow; using Mono.Cecil; using Mono.Cecil.Cil; using HoistedLocalState = ILLink.Shared.DataFlow.DefaultValueDictionary< Mono.Linker.Dataflow.HoistedLocalKey, ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>>; using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>; namespace Mono.Linker.Dataflow { // Tracks the set of methods which get analyzer together during interprocedural analysis, // and the possible states of hoisted locals in state machine methods and lambdas/local functions. struct InterproceduralState : IEquatable<InterproceduralState> { public ValueSet<MethodIL> MethodBodies; public HoistedLocalState HoistedLocals; readonly InterproceduralStateLattice lattice; public InterproceduralState(ValueSet<MethodIL> methodBodies, HoistedLocalState hoistedLocals, InterproceduralStateLattice lattice) => (MethodBodies, HoistedLocals, this.lattice) = (methodBodies, hoistedLocals, lattice); public bool Equals(InterproceduralState other) => MethodBodies.Equals(other.MethodBodies) && HoistedLocals.Equals(other.HoistedLocals); public override bool Equals(object? obj) => obj is InterproceduralState state && Equals(state); public override int GetHashCode() => HashUtils.Combine(MethodBodies.GetHashCode(), HoistedLocals.GetHashCode()); public InterproceduralState Clone() => new(MethodBodies.DeepCopy(), HoistedLocals.Clone(), lattice); public void TrackMethod(MethodDefinition method) { if (method.Body is not MethodBody methodBody) return; TrackMethod(methodBody); } public void TrackMethod(MethodBody methodBody) { TrackMethod(lattice.Context.GetMethodIL(methodBody)); } public void TrackMethod(MethodIL methodIL) { // Work around the fact that ValueSet is readonly Debug.Assert(!MethodBodies.IsUnknown()); var methodsList = new List<MethodIL>(MethodBodies.GetKnownValues()); methodsList.Add(methodIL); // For state machine methods, also scan the state machine members. // Simplification: assume that all generated methods of the state machine type are // reached at the point where the state machine method is reached. if (CompilerGeneratedState.TryGetStateMachineType(methodIL.Method, out TypeDefinition? stateMachineType)) { foreach (var stateMachineMethod in stateMachineType.Methods) { Debug.Assert(!CompilerGeneratedNames.IsLambdaOrLocalFunction(stateMachineMethod.Name)); if (stateMachineMethod.Body is MethodBody stateMachineMethodBody) methodsList.Add(lattice.Context.GetMethodIL(stateMachineMethodBody)); } } MethodBodies = new ValueSet<MethodIL>(methodsList); } public void SetHoistedLocal(HoistedLocalKey key, MultiValue value) { // For hoisted locals, we track the entire set of assigned values seen // in the closure of a method, so setting a hoisted local value meets // it with any existing value. HoistedLocals.Set(key, lattice.HoistedLocalsLattice.ValueLattice.Meet( HoistedLocals.Get(key), value)); } public MultiValue GetHoistedLocal(HoistedLocalKey key) => HoistedLocals.Get(key); } readonly struct InterproceduralStateLattice : ILattice<InterproceduralState> { public readonly ValueSetLattice<MethodIL> MethodBodyLattice; public readonly DictionaryLattice<HoistedLocalKey, MultiValue, ValueSetLattice<SingleValue>> HoistedLocalsLattice; public readonly LinkContext Context; public InterproceduralStateLattice( ValueSetLattice<MethodIL> methodBodyLattice, DictionaryLattice<HoistedLocalKey, MultiValue, ValueSetLattice<SingleValue>> hoistedLocalsLattice, LinkContext context) => (MethodBodyLattice, HoistedLocalsLattice, Context) = (methodBodyLattice, hoistedLocalsLattice, context); public InterproceduralState Top => new InterproceduralState(MethodBodyLattice.Top, HoistedLocalsLattice.Top, this); public InterproceduralState Meet(InterproceduralState left, InterproceduralState right) => new( MethodBodyLattice.Meet(left.MethodBodies, right.MethodBodies), HoistedLocalsLattice.Meet(left.HoistedLocals, right.HoistedLocals), this); } }