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; }
/// <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)); }
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; }
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())); }