public static StateMachineStatesDebugInfo Create(VariableSlotAllocator?variableSlotAllocator, ImmutableArray <StateMachineStateDebugInfo> stateInfos)
    {
        StateMachineState?firstUnusedIncreasingStateMachineState = null, firstUnusedDecreasingStateMachineState = null;

        if (variableSlotAllocator != null)
        {
            // We start with first unused state numbers from the previous generation and update them based on states generated in the current one.
            firstUnusedIncreasingStateMachineState = variableSlotAllocator.GetFirstUnusedStateMachineState(increasing: true);
            firstUnusedDecreasingStateMachineState = variableSlotAllocator.GetFirstUnusedStateMachineState(increasing: false);

            if (!stateInfos.IsDefaultOrEmpty)
            {
                // The current method is a state machine and has some resumable/finalization states.
                // Update the first unused states based on the highest resumable (positive numbers) and lowest finalization (negative numbers) of this method.

                var maxState = stateInfos.Max(info => info.StateNumber) + 1;
                var minState = stateInfos.Min(info => info.StateNumber) - 1;

                firstUnusedIncreasingStateMachineState = (firstUnusedIncreasingStateMachineState != null) ? (StateMachineState)Math.Max((int)firstUnusedIncreasingStateMachineState.Value, (int)maxState) : maxState;

                if (minState < 0)
                {
                    firstUnusedDecreasingStateMachineState = (firstUnusedDecreasingStateMachineState != null) ? (StateMachineState)Math.Min((int)firstUnusedDecreasingStateMachineState.Value, (int)minState) : minState;
                }
            }
        }

        return(new StateMachineStatesDebugInfo(
                   stateInfos,
                   firstUnusedIncreasingStateMachineState,
                   firstUnusedDecreasingStateMachineState));
    }
        public EncVariableSlotAllocator(
            SymbolMatcher symbolMap,
            Func <SyntaxNode, SyntaxNode?>?syntaxMap,
            IMethodSymbolInternal previousTopLevelMethod,
            DebugId methodId,
            ImmutableArray <EncLocalInfo> previousLocals,
            IReadOnlyDictionary <int, KeyValuePair <DebugId, int> >?lambdaMap,
            IReadOnlyDictionary <int, DebugId>?closureMap,
            string?stateMachineTypeName,
            int hoistedLocalSlotCount,
            IReadOnlyDictionary <EncHoistedLocalInfo, int>?hoistedLocalSlots,
            int awaiterCount,
            IReadOnlyDictionary <Cci.ITypeReference, int>?awaiterMap,
            IReadOnlyDictionary <int, StateMachineState>?stateMachineStateMap,
            StateMachineState?firstUnusedIncreasingStateMachineState,
            StateMachineState?firstUnusedDecreasingStateMachineState,
            LambdaSyntaxFacts lambdaSyntaxFacts)
        {
            Debug.Assert(!previousLocals.IsDefault);

            _symbolMap              = symbolMap;
            _syntaxMap              = syntaxMap;
            _previousLocals         = previousLocals;
            _previousTopLevelMethod = previousTopLevelMethod;
            _methodId              = methodId;
            _hoistedLocalSlots     = hoistedLocalSlots;
            _hoistedLocalSlotCount = hoistedLocalSlotCount;
            _stateMachineTypeName  = stateMachineTypeName;
            _awaiterCount          = awaiterCount;
            _awaiterMap            = awaiterMap;
            _stateMachineStateMap  = stateMachineStateMap;
            _lambdaMap             = lambdaMap;
            _closureMap            = closureMap;
            _lambdaSyntaxFacts     = lambdaSyntaxFacts;
            _firstUnusedIncreasingStateMachineState = firstUnusedIncreasingStateMachineState;
            _firstUnusedDecreasingStateMachineState = firstUnusedDecreasingStateMachineState;

            // Create a map from local info to slot.
            var previousLocalInfoToSlot = new Dictionary <EncLocalInfo, int>();

            for (int slot = 0; slot < previousLocals.Length; slot++)
            {
                var localInfo = previousLocals[slot];
                Debug.Assert(!localInfo.IsDefault);
                if (localInfo.IsUnused)
                {
                    // Unrecognized or deleted local.
                    continue;
                }

                previousLocalInfoToSlot.Add(localInfo, slot);
            }

            _previousLocalSlots = previousLocalInfoToSlot;
        }
Beispiel #3
0
 /// <summary>
 /// Get an existing StateMachine resource's state with the given name, ID, and optional extra
 /// properties used to qualify the lookup.
 /// </summary>
 ///
 /// <param name="name">The unique name of the resulting resource.</param>
 /// <param name="id">The unique provider ID of the resource to lookup.</param>
 /// <param name="state">Any extra arguments used during the lookup.</param>
 /// <param name="options">A bag of options that control this resource's behavior</param>
 public static StateMachine Get(string name, Input <string> id, StateMachineState?state = null, CustomResourceOptions?options = null)
 {
     return(new StateMachine(name, id, state, options));
 }
Beispiel #4
0
 private StateMachine(string name, Input <string> id, StateMachineState?state = null, CustomResourceOptions?options = null)
     : base("aws:sfn/stateMachine:StateMachine", name, state, MakeResourceOptions(options, id))
 {
 }
 private StateMachineStatesDebugInfo(ImmutableArray <StateMachineStateDebugInfo> states, StateMachineState?firstUnusedIncreasingStateMachineState, StateMachineState?firstUnusedDecreasingStateMachineState)
 {
     States = states;
     FirstUnusedIncreasingStateMachineState = firstUnusedIncreasingStateMachineState;
     FirstUnusedDecreasingStateMachineState = firstUnusedDecreasingStateMachineState;
 }
Beispiel #6
0
        internal VariableSlotAllocator?TryCreateVariableSlotAllocator(EmitBaseline baseline, Compilation compilation, IMethodSymbolInternal method, IMethodSymbolInternal topLevelMethod, DiagnosticBag diagnostics)
        {
            // Top-level methods are always included in the semantic edit list. Lambda methods are not.
            if (!mappedMethods.TryGetValue(topLevelMethod, out var mappedMethod))
            {
                return(null);
            }

            // TODO (bug https://github.com/dotnet/roslyn/issues/2504):
            // Handle cases when the previous method doesn't exist.

            if (!TryGetMethodHandle(baseline, (Cci.IMethodDefinition)method.GetCciAdapter(), out var previousHandle))
            {
                // Unrecognized method. Must have been added in the current compilation.
                return(null);
            }

            ImmutableArray <EncLocalInfo> previousLocals;
            IReadOnlyDictionary <EncHoistedLocalInfo, int>?         hoistedLocalMap = null;
            IReadOnlyDictionary <Cci.ITypeReference, int>?          awaiterMap      = null;
            IReadOnlyDictionary <int, KeyValuePair <DebugId, int> >?lambdaMap       = null;
            IReadOnlyDictionary <int, DebugId>?          closureMap           = null;
            IReadOnlyDictionary <int, StateMachineState>?stateMachineStateMap = null;
            StateMachineState?firstUnusedIncreasingStateMachineState          = null;
            StateMachineState?firstUnusedDecreasingStateMachineState          = null;

            int           hoistedLocalSlotCount = 0;
            int           awaiterSlotCount      = 0;
            string?       stateMachineTypeName  = null;
            SymbolMatcher symbolMap;

            int     methodIndex = MetadataTokens.GetRowNumber(previousHandle);
            DebugId methodId;

            // Check if method has changed previously. If so, we already have a map.
            if (baseline.AddedOrChangedMethods.TryGetValue(methodIndex, out var addedOrChangedMethod))
            {
                methodId = addedOrChangedMethod.MethodId;

                MakeLambdaAndClosureMaps(addedOrChangedMethod.LambdaDebugInfo, addedOrChangedMethod.ClosureDebugInfo, out lambdaMap, out closureMap);
                MakeStateMachineStateMap(addedOrChangedMethod.StateMachineStates.States, out stateMachineStateMap);

                firstUnusedIncreasingStateMachineState = addedOrChangedMethod.StateMachineStates.FirstUnusedIncreasingStateMachineState;
                firstUnusedDecreasingStateMachineState = addedOrChangedMethod.StateMachineStates.FirstUnusedDecreasingStateMachineState;

                if (addedOrChangedMethod.StateMachineTypeName != null)
                {
                    // method is async/iterator kickoff method
                    GetStateMachineFieldMapFromPreviousCompilation(
                        addedOrChangedMethod.StateMachineHoistedLocalSlotsOpt,
                        addedOrChangedMethod.StateMachineAwaiterSlotsOpt,
                        out hoistedLocalMap,
                        out awaiterMap);

                    hoistedLocalSlotCount = addedOrChangedMethod.StateMachineHoistedLocalSlotsOpt.Length;
                    awaiterSlotCount      = addedOrChangedMethod.StateMachineAwaiterSlotsOpt.Length;

                    // Kickoff method has no interesting locals on its own.
                    // We use the EnC method debug information for hoisted locals.
                    previousLocals = ImmutableArray <EncLocalInfo> .Empty;

                    stateMachineTypeName = addedOrChangedMethod.StateMachineTypeName;
                }
                else
                {
                    previousLocals = addedOrChangedMethod.Locals;
                }

                // All types that AddedOrChangedMethodInfo refers to have been mapped to the previous generation.
                // Therefore we don't need to fall back to metadata if we don't find the type reference, like we do in DefinitionMap.MapReference.
                symbolMap = MapToPreviousSymbolMatcher;
            }
            else
            {
                // Method has not changed since initial generation. Generate a map
                // using the local names provided with the initial metadata.
                EditAndContinueMethodDebugInformation debugInfo;
                StandaloneSignatureHandle             localSignature;
                try
                {
                    debugInfo      = baseline.DebugInformationProvider(previousHandle);
                    localSignature = baseline.LocalSignatureProvider(previousHandle);
                }
                catch (Exception e) when(e is InvalidDataException || e is IOException)
                {
                    diagnostics.Add(MessageProvider.CreateDiagnostic(
                                        MessageProvider.ERR_InvalidDebugInfo,
                                        method.Locations.First(),
                                        method,
                                        MetadataTokens.GetToken(previousHandle),
                                        method.ContainingAssembly
                                        ));

                    return(null);
                }

                methodId = new DebugId(debugInfo.MethodOrdinal, 0);

                if (!debugInfo.Lambdas.IsDefaultOrEmpty)
                {
                    MakeLambdaAndClosureMaps(debugInfo.Lambdas, debugInfo.Closures, out lambdaMap, out closureMap);
                }

                MakeStateMachineStateMap(debugInfo.StateMachineStates, out stateMachineStateMap);

                if (!debugInfo.StateMachineStates.IsDefaultOrEmpty)
                {
                    firstUnusedIncreasingStateMachineState = debugInfo.StateMachineStates.Max(s => s.StateNumber) + 1;
                    firstUnusedDecreasingStateMachineState = debugInfo.StateMachineStates.Min(s => s.StateNumber) - 1;
                }

                ITypeSymbolInternal?stateMachineType = TryGetStateMachineType(previousHandle);
                if (stateMachineType != null)
                {
                    // method is async/iterator kickoff method
                    var localSlotDebugInfo = debugInfo.LocalSlots.NullToEmpty();
                    GetStateMachineFieldMapFromMetadata(stateMachineType, localSlotDebugInfo, out hoistedLocalMap, out awaiterMap, out awaiterSlotCount);
                    hoistedLocalSlotCount = localSlotDebugInfo.Length;

                    // Kickoff method has no interesting locals on its own.
                    // We use the EnC method debug information for hoisted locals.
                    previousLocals = ImmutableArray <EncLocalInfo> .Empty;

                    stateMachineTypeName = stateMachineType.Name;
                }
                else
                {
                    // If the current method is async/iterator then either the previous method wasn't declared as async/iterator and it's updated to be one,
                    // or it was but is not marked by the corresponding state machine attribute because it was missing in the compilation.
                    // In the later case we need to report an error since we don't known how to map to the previous state machine.

                    // The IDE already checked that the attribute type is present in the base compilation, but didn't validate that it is well-formed.
                    // We don't have the base compilation to directly query for the attribute, only the source compilation.
                    // But since constructor signatures can't be updated during EnC we can just check the current compilation.

                    if (method.IsAsync)
                    {
                        if (compilation.CommonGetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor) == null)
                        {
                            ReportMissingStateMachineAttribute(diagnostics, method, AttributeDescription.AsyncStateMachineAttribute.FullName);
                            return(null);
                        }
                    }
                    else if (method.IsIterator)
                    {
                        if (compilation.CommonGetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor) == null)
                        {
                            ReportMissingStateMachineAttribute(diagnostics, method, AttributeDescription.IteratorStateMachineAttribute.FullName);
                            return(null);
                        }
                    }

                    try
                    {
                        previousLocals = localSignature.IsNil ? ImmutableArray <EncLocalInfo> .Empty :
                                         GetLocalSlotMapFromMetadata(localSignature, debugInfo);
                    }
                    catch (Exception e) when(e is UnsupportedSignatureContent || e is BadImageFormatException || e is IOException)
                    {
                        diagnostics.Add(MessageProvider.CreateDiagnostic(
                                            MessageProvider.ERR_InvalidDebugInfo,
                                            method.Locations.First(),
                                            method,
                                            MetadataTokens.GetToken(localSignature),
                                            method.ContainingAssembly
                                            ));

                        return(null);
                    }
                }

                symbolMap = MapToMetadataSymbolMatcher;
            }

            return(new EncVariableSlotAllocator(
                       symbolMap,
                       mappedMethod.SyntaxMap,
                       mappedMethod.PreviousMethod,
                       methodId,
                       previousLocals,
                       lambdaMap,
                       closureMap,
                       stateMachineTypeName,
                       hoistedLocalSlotCount,
                       hoistedLocalMap,
                       awaiterSlotCount,
                       awaiterMap,
                       stateMachineStateMap,
                       firstUnusedIncreasingStateMachineState,
                       firstUnusedDecreasingStateMachineState,
                       GetLambdaSyntaxFacts()));
        }