File: CodeGen\VariableSlotAllocator.cs
Web Access
Project: src\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis)
// Licensed to the .NET Foundation under one or more agreements.
// 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.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection.Metadata;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Symbols;
 
namespace Microsoft.CodeAnalysis.CodeGen
{
    internal abstract class VariableSlotAllocator
    {
        public abstract void AddPreviousLocals(ArrayBuilder<Cci.ILocalDefinition> builder);
 
        public abstract LocalDefinition? GetPreviousLocal(
            Cci.ITypeReference type,
            ILocalSymbolInternal symbol,
            string? name,
            SynthesizedLocalKind kind,
            LocalDebugId id,
            LocalVariableAttributes pdbAttributes,
            LocalSlotConstraints constraints,
            ImmutableArray<bool> dynamicTransformFlags,
            ImmutableArray<string> tupleElementNames);
 
        public abstract string? PreviousStateMachineTypeName { get; }
 
        /// <summary>
        /// Returns an index of a slot that stores specified hoisted local variable in the previous generation.
        /// </summary>
        public abstract bool TryGetPreviousHoistedLocalSlotIndex(
            SyntaxNode currentDeclarator,
            Cci.ITypeReference currentType,
            SynthesizedLocalKind synthesizedKind,
            LocalDebugId currentId,
            DiagnosticBag diagnostics,
            out int slotIndex);
 
        /// <summary>
        /// Number of slots reserved for hoisted local variables.
        /// </summary>
        /// <remarks>
        /// Some of the slots might not be used anymore (a variable might have been deleted or its type changed).
        /// Still, new hoisted variables are assigned slots starting with <see cref="PreviousHoistedLocalSlotCount"/>.
        /// </remarks>
        public abstract int PreviousHoistedLocalSlotCount { get; }
 
        /// <summary>
        /// Returns true and an index of a slot that stores an awaiter of a specified type in the previous generation, if any. 
        /// </summary>
        public abstract bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, DiagnosticBag diagnostics, out int slotIndex);
 
        /// <summary>
        /// Number of slots reserved for awaiters.
        /// </summary>
        /// <remarks>
        /// Some of the slots might not be used anymore (the type of an awaiter might have changed).
        /// Still, new awaiters are assigned slots starting with <see cref="PreviousAwaiterSlotCount"/>.
        /// </remarks>
        public abstract int PreviousAwaiterSlotCount { get; }
 
        /// <summary>
        /// The id of the method, or null if the method wasn't assigned one.
        /// </summary>
        public abstract DebugId? MethodId { get; }
 
        /// <summary>
        /// Finds a closure in the previous generation that corresponds to the specified syntax.
        /// </summary>
        /// <param name="closureSyntax">Syntax of the closure scope.</param>
        /// <param name="parentClosureId">Id of the parent closure.</param>
        /// <param name="structCaptures">Names of variables hoisted into the closure, or default if the closure is a class.</param>
        /// <param name="closureId">Id of the closure assigned in the generation that defined the closure.</param>
        /// <param name="runtimeRudeEdit">
        /// Not-null if the previous closure is found, but is incompatible with the shape of the closure in the current source.
        /// The previous closure can't be reused (a new one needs to be emitted) and IL bodies of lambdas of the previous closure are updated to throw an exception.
        /// The exception message is specified in <see cref="RuntimeRudeEdit.Message"/>.
        /// </param>
        /// <remarks>
        /// See LambdaFrame.AssertIsLambdaScopeSyntax for kinds of syntax nodes that represent closures.
        /// </remarks>
        public abstract bool TryGetPreviousClosure(SyntaxNode closureSyntax, DebugId? parentClosureId, ImmutableArray<string> structCaptures, out DebugId closureId, out RuntimeRudeEdit? runtimeRudeEdit);
 
        /// <summary>
        /// Finds a lambda in the previous generation that corresponds to the specified syntax.
        /// </summary>
        /// <param name="lambdaOrLambdaBodySyntax">Syntax of the lambda or its body.</param>
        /// <param name="isLambdaBody">True if <paramref name="lambdaOrLambdaBodySyntax"/> is a lambda body syntax, false if it is a lambda syntax.</param>
        /// <param name="closureOrdinal">The ordinal of the closure the lambda is emitted to.</param>
        /// <param name="lambdaId">Id of the lambda assigned in the generation that defined the lambda.</param>
        /// <param name="runtimeRudeEdit">
        /// Not-null if the previous lambda is found, but is incompatible with the shape of the lambda in the current source.
        /// The previous lambda can't be reused (a new one needs to be emitted) and the previous lambda IL body is updated to throw an exception.
        /// The exception message is specified in <see cref="RuntimeRudeEdit.Message"/>.
        /// </param>
        public abstract bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, int closureOrdinal, ImmutableArray<DebugId> structClosureIds, out DebugId lambdaId, out RuntimeRudeEdit? runtimeRudeEdit);
 
        /// <summary>
        /// State number to be used for next state of the state machine,
        /// or <see langword="null"/> if none of the previous versions of the method was a state machine with an increasing state
        /// </summary>
        /// <param name="increasing">True if the state number increases with progress, false if it decreases (e.g. states for iterator try-finally blocks, or iterator states of async iterators).</param>
        public abstract StateMachineState? GetFirstUnusedStateMachineState(bool increasing);
 
        /// <summary>
        /// For a given node associated with entering a state of a state machine in the new compilation,
        /// returns the ordinal of the corresponding state in the previous version of the state machine.
        /// </summary>
        /// <param name="syntax">Await expression, await foreach statement, yield return statement, or try block syntax node.</param>
        /// <returns>
        /// True if there is a corresponding node in the previous code version that matches the given <paramref name="syntax"/>.
        /// </returns>
        public abstract bool TryGetPreviousStateMachineState(SyntaxNode syntax, AwaitDebugId awaitId, out StateMachineState state);
    }
}