public AddedOrChangedMethodInfo( DebugId methodId, ImmutableArray<EncLocalInfo> locals, ImmutableArray<LambdaDebugInfo> lambdaDebugInfo, ImmutableArray<ClosureDebugInfo> closureDebugInfo, string stateMachineTypeNameOpt, ImmutableArray<EncHoistedLocalInfo> stateMachineHoistedLocalSlotsOpt, ImmutableArray<Cci.ITypeReference> stateMachineAwaiterSlotsOpt) { // An updated method will carry its id over, // an added method id has generation set to the current generation ordinal. Debug.Assert(methodId.Generation >= 0); // each state machine has to have awaiters: Debug.Assert(stateMachineAwaiterSlotsOpt.IsDefault == (stateMachineTypeNameOpt == null)); // a state machine might not have hoisted variables: Debug.Assert(stateMachineHoistedLocalSlotsOpt.IsDefault || (stateMachineTypeNameOpt != null)); this.MethodId = methodId; this.Locals = locals; this.LambdaDebugInfo = lambdaDebugInfo; this.ClosureDebugInfo = closureDebugInfo; this.StateMachineTypeNameOpt = stateMachineTypeNameOpt; this.StateMachineHoistedLocalSlotsOpt = stateMachineHoistedLocalSlotsOpt; this.StateMachineAwaiterSlotsOpt = stateMachineAwaiterSlotsOpt; }
internal SynthesizedClosureEnvironment( MethodSymbol topLevelMethod, MethodSymbol containingMethod, bool isStruct, SyntaxNode scopeSyntaxOpt, DebugId methodId, DebugId closureId) : base(MakeName(scopeSyntaxOpt, methodId, closureId), containingMethod) { TypeKind = isStruct ? TypeKind.Struct : TypeKind.Class; _topLevelMethod = topLevelMethod; OriginalContainingMethodOpt = containingMethod; Constructor = isStruct ? null : new SynthesizedClosureEnvironmentConstructor(this); this.ClosureOrdinal = closureId.Ordinal; // static lambdas technically have the class scope so the scope syntax is null if (scopeSyntaxOpt == null) { StaticConstructor = new SynthesizedStaticConstructor(this); var cacheVariableName = GeneratedNames.MakeCachedFrameInstanceFieldName(); SingletonCache = new SynthesizedLambdaCacheFieldSymbol(this, this, cacheVariableName, topLevelMethod, isReadOnly: true, isStatic: true); } AssertIsClosureScopeSyntax(scopeSyntaxOpt); this.ScopeSyntaxOpt = scopeSyntaxOpt; }
public AddedOrChangedMethodInfo( DebugId methodId, ImmutableArray <EncLocalInfo> locals, ImmutableArray <LambdaDebugInfo> lambdaDebugInfo, ImmutableArray <ClosureDebugInfo> closureDebugInfo, string stateMachineTypeNameOpt, ImmutableArray <EncHoistedLocalInfo> stateMachineHoistedLocalSlotsOpt, ImmutableArray <Cci.ITypeReference> stateMachineAwaiterSlotsOpt) { // An updated method will carry its id over, // an added method id has generation set to the current generation ordinal. Debug.Assert(methodId.Generation >= 0); // each state machine has to have awaiters: Debug.Assert(stateMachineAwaiterSlotsOpt.IsDefault == (stateMachineTypeNameOpt == null)); // a state machine might not have hoisted variables: Debug.Assert(stateMachineHoistedLocalSlotsOpt.IsDefault || (stateMachineTypeNameOpt != null)); this.MethodId = methodId; this.Locals = locals; this.LambdaDebugInfo = lambdaDebugInfo; this.ClosureDebugInfo = closureDebugInfo; this.StateMachineTypeNameOpt = stateMachineTypeNameOpt; this.StateMachineHoistedLocalSlotsOpt = stateMachineHoistedLocalSlotsOpt; this.StateMachineAwaiterSlotsOpt = stateMachineAwaiterSlotsOpt; }
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, int>?stateMachineStateMap, int?firstUnusedIncreasingStateMachineState, int?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; }
private static string MakeName(SyntaxNode scopeSyntaxOpt, DebugId methodId, DebugId closureId) { if (scopeSyntaxOpt == null) { // Display class is shared among static non-generic lambdas across generations, method ordinal is -1 in that case. // A new display class of a static generic lambda is created for each method and each generation. return GeneratedNames.MakeStaticLambdaDisplayClassName(methodId.Ordinal, methodId.Generation); } Debug.Assert(methodId.Ordinal >= 0); return GeneratedNames.MakeLambdaDisplayClassName(methodId.Ordinal, methodId.Generation, closureId.Ordinal, closureId.Generation); }
private static string MakeName(string topLevelMethodName, DebugId topLevelMethodId, ClosureKind closureKind, DebugId lambdaId) { // Lambda method name must contain the declaring method ordinal to be unique unless the method is emitted into a closure class exclusive to the declaring method. // Lambdas that only close over "this" are emitted directly into the top-level method containing type. // Lambdas that don't close over anything (static) are emitted into a shared closure singleton. return GeneratedNames.MakeLambdaMethodName( topLevelMethodName, (closureKind == ClosureKind.General) ? -1 : topLevelMethodId.Ordinal, topLevelMethodId.Generation, lambdaId.Ordinal, lambdaId.Generation); }
public override bool TryGetPreviousClosure(SyntaxNode scopeSyntax, out DebugId closureId) { if (_closureMap != null && TryGetPreviousSyntaxOffset(scopeSyntax, out int syntaxOffset) && _closureMap.TryGetValue(syntaxOffset, out closureId)) { return(true); } closureId = default; return(false); }
private static string MakeName(string topLevelMethodName, DebugId topLevelMethodId, ClosureKind closureKind, DebugId lambdaId) { // Lambda method name must contain the declaring method ordinal to be unique unless the method is emitted into a closure class exclusive to the declaring method. // Lambdas that only close over "this" are emitted directly into the top-level method containing type. // Lambdas that don't close over anything (static) are emitted into a shared closure singleton. return(GeneratedNames.MakeLambdaMethodName( topLevelMethodName, (closureKind == ClosureKind.General) ? -1 : topLevelMethodId.Ordinal, topLevelMethodId.Generation, lambdaId.Ordinal, lambdaId.Generation)); }
private static string MakeName(SyntaxNode scopeSyntaxOpt, DebugId methodId, DebugId closureId) { if (scopeSyntaxOpt == null) { // Display class is shared among static non-generic lambdas across generations, method ordinal is -1 in that case. // A new display class of a static generic lambda is created for each method and each generation. return(GeneratedNames.MakeStaticLambdaDisplayClassName(methodId.Ordinal, methodId.Generation)); } Debug.Assert(methodId.Ordinal >= 0); return(GeneratedNames.MakeLambdaDisplayClassName(methodId.Ordinal, methodId.Generation, closureId.Ordinal, closureId.Generation)); }
private readonly IReadOnlyDictionary <int, DebugId> _closureMapOpt; // SyntaxOffset -> Id public EncVariableSlotAllocator( CommonMessageProvider messageProvider, SymbolMatcher symbolMap, Func <SyntaxNode, SyntaxNode> syntaxMapOpt, IMethodSymbolInternal previousTopLevelMethod, DebugId methodId, ImmutableArray <EncLocalInfo> previousLocals, IReadOnlyDictionary <int, KeyValuePair <DebugId, int> > lambdaMapOpt, IReadOnlyDictionary <int, DebugId> closureMapOpt, string stateMachineTypeNameOpt, int hoistedLocalSlotCount, IReadOnlyDictionary <EncHoistedLocalInfo, int> hoistedLocalSlotsOpt, int awaiterCount, IReadOnlyDictionary <Cci.ITypeReference, int> awaiterMapOpt) { Debug.Assert(messageProvider != null); Debug.Assert(symbolMap != null); Debug.Assert(previousTopLevelMethod != null); Debug.Assert(!previousLocals.IsDefault); _messageProvider = messageProvider; _symbolMap = symbolMap; _syntaxMapOpt = syntaxMapOpt; _previousLocals = previousLocals; _previousTopLevelMethod = previousTopLevelMethod; _methodId = methodId; _hoistedLocalSlotsOpt = hoistedLocalSlotsOpt; _hoistedLocalSlotCount = hoistedLocalSlotCount; _stateMachineTypeNameOpt = stateMachineTypeNameOpt; _awaiterCount = awaiterCount; _awaiterMapOpt = awaiterMapOpt; _lambdaMapOpt = lambdaMapOpt; _closureMapOpt = closureMapOpt; // 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; }
public EncVariableSlotAllocator( CommonMessageProvider messageProvider, SymbolMatcher symbolMap, Func<SyntaxNode, SyntaxNode> syntaxMapOpt, IMethodSymbolInternal previousTopLevelMethod, DebugId methodId, ImmutableArray<EncLocalInfo> previousLocals, IReadOnlyDictionary<int, KeyValuePair<DebugId, int>> lambdaMapOpt, IReadOnlyDictionary<int, DebugId> closureMapOpt, string stateMachineTypeNameOpt, int hoistedLocalSlotCount, IReadOnlyDictionary<EncHoistedLocalInfo, int> hoistedLocalSlotsOpt, int awaiterCount, IReadOnlyDictionary<Cci.ITypeReference, int> awaiterMapOpt) { Debug.Assert(messageProvider != null); Debug.Assert(symbolMap != null); Debug.Assert(previousTopLevelMethod != null); Debug.Assert(!previousLocals.IsDefault); _messageProvider = messageProvider; _symbolMap = symbolMap; _syntaxMapOpt = syntaxMapOpt; _previousLocals = previousLocals; _previousTopLevelMethod = previousTopLevelMethod; _methodId = methodId; _hoistedLocalSlotsOpt = hoistedLocalSlotsOpt; _hoistedLocalSlotCount = hoistedLocalSlotCount; _stateMachineTypeNameOpt = stateMachineTypeNameOpt; _awaiterCount = awaiterCount; _awaiterMapOpt = awaiterMapOpt; _lambdaMapOpt = lambdaMapOpt; _closureMapOpt = closureMapOpt; // 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; }
private static string MakeName( string topLevelMethodName, string localFunctionName, DebugId topLevelMethodId, ClosureKind closureKind, DebugId lambdaId ) { return(GeneratedNames.MakeLocalFunctionName( topLevelMethodName, localFunctionName, (closureKind == ClosureKind.General) ? -1 : topLevelMethodId.Ordinal, topLevelMethodId.Generation, lambdaId.Ordinal, lambdaId.Generation )); }
public MethodBody( ImmutableArray<byte> ilBits, ushort maxStack, Cci.IMethodDefinition parent, DebugId methodId, ImmutableArray<Cci.ILocalDefinition> locals, SequencePointList sequencePoints, DebugDocumentProvider debugDocumentProvider, ImmutableArray<Cci.ExceptionHandlerRegion> exceptionHandlers, ImmutableArray<Cci.LocalScope> localScopes, bool hasDynamicLocalVariables, Cci.IImportScope importScopeOpt, ImmutableArray<LambdaDebugInfo> lambdaDebugInfo, ImmutableArray<ClosureDebugInfo> closureDebugInfo, string stateMachineTypeNameOpt, ImmutableArray<Cci.StateMachineHoistedLocalScope> stateMachineHoistedLocalScopes, ImmutableArray<EncHoistedLocalInfo> stateMachineHoistedLocalSlots, ImmutableArray<Cci.ITypeReference> stateMachineAwaiterSlots, Cci.AsyncMethodBodyDebugInfo asyncMethodDebugInfo, DynamicAnalysisMethodBodyData dynamicAnalysisDataOpt) { Debug.Assert(!locals.IsDefault); Debug.Assert(!exceptionHandlers.IsDefault); Debug.Assert(!localScopes.IsDefault); _ilBits = ilBits; _asyncMethodDebugInfo = asyncMethodDebugInfo; _maxStack = maxStack; _parent = parent; _methodId = methodId; _locals = locals; _sequencePoints = sequencePoints; _debugDocumentProvider = debugDocumentProvider; _exceptionHandlers = exceptionHandlers; _localScopes = localScopes; _hasDynamicLocalVariables = hasDynamicLocalVariables; _importScopeOpt = importScopeOpt; _lambdaDebugInfo = lambdaDebugInfo; _closureDebugInfo = closureDebugInfo; _stateMachineTypeNameOpt = stateMachineTypeNameOpt; _stateMachineHoistedLocalScopes = stateMachineHoistedLocalScopes; _stateMachineHoistedLocalSlots = stateMachineHoistedLocalSlots; _stateMachineAwaiterSlots = stateMachineAwaiterSlots; _dynamicAnalysisDataOpt = dynamicAnalysisDataOpt; }
internal LambdaFrame(MethodSymbol topLevelMethod, CSharpSyntaxNode scopeSyntaxOpt, DebugId methodId, DebugId closureId) : base(MakeName(scopeSyntaxOpt, methodId, closureId), topLevelMethod) { _topLevelMethod = topLevelMethod; _constructor = new LambdaFrameConstructor(this); this.ClosureOrdinal = closureId.Ordinal; // static lambdas technically have the class scope so the scope syntax is null if (scopeSyntaxOpt == null) { _staticConstructor = new SynthesizedStaticConstructor(this); var cacheVariableName = GeneratedNames.MakeCachedFrameInstanceFieldName(); _singletonCache = new SynthesizedLambdaCacheFieldSymbol(this, this, cacheVariableName, topLevelMethod, isReadOnly: true, isStatic: true); } AssertIsClosureScopeSyntax(scopeSyntaxOpt); this.ScopeSyntaxOpt = scopeSyntaxOpt; }
internal SynthesizedLambdaMethod( NamedTypeSymbol containingType, ClosureKind closureKind, MethodSymbol topLevelMethod, DebugId topLevelMethodId, BoundLambda lambdaNode, DebugId lambdaId) : base(containingType, lambdaNode.Symbol, null, lambdaNode.SyntaxTree.GetReference(lambdaNode.Body.Syntax), lambdaNode.Syntax.GetLocation(), MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaId), (closureKind == ClosureKind.ThisOnly ? DeclarationModifiers.Private : DeclarationModifiers.Internal) | (lambdaNode.Symbol.IsAsync ? DeclarationModifiers.Async : 0)) { _topLevelMethod = topLevelMethod; TypeMap typeMap; ImmutableArray<TypeParameterSymbol> typeParameters; LambdaFrame lambdaFrame; if (!topLevelMethod.IsGenericMethod) { typeMap = TypeMap.Empty; typeParameters = ImmutableArray<TypeParameterSymbol>.Empty; } else if ((object)(lambdaFrame = this.ContainingType as LambdaFrame) != null) { typeMap = lambdaFrame.TypeMap; typeParameters = ImmutableArray<TypeParameterSymbol>.Empty; } else { typeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out typeParameters); } AssignTypeMapAndTypeParameters(typeMap, typeParameters); }
internal DebugId GetClosureId(SyntaxNode syntax, ArrayBuilder <ClosureDebugInfo> closureDebugInfo) { Debug.Assert(syntax != null); DebugId closureId; DebugId previousClosureId; if (_slotAllocatorOpt != null && _slotAllocatorOpt.TryGetPreviousClosure(syntax, out previousClosureId)) { closureId = previousClosureId; } else { closureId = new DebugId(closureDebugInfo.Count, _compilationState.ModuleBuilderOpt.CurrentGenerationOrdinal); } int syntaxOffset = _topLevelMethod.CalculateLocalSyntaxOffset(syntax.SpanStart, syntax.SyntaxTree); closureDebugInfo.Add(new ClosureDebugInfo(syntaxOffset, closureId)); return(closureId); }
internal SynthesizedLambdaMethod( NamedTypeSymbol containingType, ClosureKind closureKind, MethodSymbol topLevelMethod, DebugId topLevelMethodId, BoundLambda lambdaNode, DebugId lambdaId) : base(containingType, lambdaNode.Symbol, null, lambdaNode.SyntaxTree.GetReference(lambdaNode.Body.Syntax), lambdaNode.Syntax.GetLocation(), MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaId), (closureKind == ClosureKind.ThisOnly ? DeclarationModifiers.Private : DeclarationModifiers.Internal) | (lambdaNode.Symbol.IsAsync ? DeclarationModifiers.Async : 0)) { _topLevelMethod = topLevelMethod; TypeMap typeMap; ImmutableArray <TypeParameterSymbol> typeParameters; LambdaFrame lambdaFrame; if (!topLevelMethod.IsGenericMethod) { typeMap = TypeMap.Empty; typeParameters = ImmutableArray <TypeParameterSymbol> .Empty; } else if ((object)(lambdaFrame = this.ContainingType as LambdaFrame) != null) { typeMap = lambdaFrame.TypeMap; typeParameters = ImmutableArray <TypeParameterSymbol> .Empty; } else { typeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out typeParameters); } AssignTypeMapAndTypeParameters(typeMap, typeParameters); }
public override bool TryGetPreviousLambda( SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, out DebugId lambdaId ) { if ( _lambdaMap != null && TryGetPreviousLambdaSyntaxOffset( lambdaOrLambdaBodySyntax, isLambdaBody, out int syntaxOffset ) && _lambdaMap.TryGetValue(syntaxOffset, out var idAndClosureOrdinal) ) { lambdaId = idAndClosureOrdinal.Key; return(true); } lambdaId = default; return(false); }
public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, out DebugId lambdaId) { lambdaId = default(DebugId); return false; }
public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, out DebugId lambdaId) { KeyValuePair<DebugId, int> idAndClosureOrdinal; int syntaxOffset; if (_lambdaMapOpt != null && TryGetPreviousLambdaSyntaxOffset(lambdaOrLambdaBodySyntax, isLambdaBody, out syntaxOffset) && _lambdaMapOpt.TryGetValue(syntaxOffset, out idAndClosureOrdinal)) { lambdaId = idAndClosureOrdinal.Key; return true; } lambdaId = default(DebugId); return false; }
public override bool TryGetPreviousClosure(SyntaxNode scopeSyntax, out DebugId closureId) { int syntaxOffset; if (_closureMapOpt != null && TryGetPreviousSyntaxOffset(scopeSyntax, out syntaxOffset) && _closureMapOpt.TryGetValue(syntaxOffset, out closureId)) { return true; } closureId = default(DebugId); return false; }
internal SynthesizedLambdaMethod( NamedTypeSymbol containingType, ImmutableArray <TypeSymbol> structClosures, ClosureKind closureKind, MethodSymbol topLevelMethod, DebugId topLevelMethodId, IBoundLambdaOrFunction lambdaNode, DebugId lambdaId) : base(containingType, lambdaNode.Symbol, null, lambdaNode.Syntax.SyntaxTree.GetReference(lambdaNode.Body.Syntax), lambdaNode.Syntax.GetLocation(), lambdaNode is BoundLocalFunctionStatement ? MakeName(topLevelMethod.Name, lambdaNode.Symbol.Name, topLevelMethodId, closureKind, lambdaId) : MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaId), (closureKind == ClosureKind.ThisOnly ? DeclarationModifiers.Private : DeclarationModifiers.Internal) | (closureKind == ClosureKind.Static ? DeclarationModifiers.Static : 0) | (lambdaNode.Symbol.IsAsync ? DeclarationModifiers.Async : 0)) { _topLevelMethod = topLevelMethod; ClosureKind = closureKind; TypeMap typeMap; ImmutableArray <TypeParameterSymbol> typeParameters; ImmutableArray <TypeParameterSymbol> constructedFromTypeParameters; LambdaFrame lambdaFrame; lambdaFrame = this.ContainingType as LambdaFrame; switch (closureKind) { case ClosureKind.Singleton: // all type parameters on method (except the top level method's) case ClosureKind.General: // only lambda's type parameters on method (rest on class) Debug.Assert(lambdaFrame != null); typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, out constructedFromTypeParameters, lambdaFrame.ContainingMethod); break; case ClosureKind.ThisOnly: // all type parameters on method case ClosureKind.Static: Debug.Assert(lambdaFrame == null); typeMap = TypeMap.Empty.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, out constructedFromTypeParameters, null); break; default: throw ExceptionUtilities.Unreachable; } if (!structClosures.IsDefaultOrEmpty && typeParameters.Length != 0) { var constructedStructClosures = ArrayBuilder <TypeSymbol> .GetInstance(); foreach (var closure in structClosures) { var frame = (LambdaFrame)closure; NamedTypeSymbol constructed; if (frame.Arity == 0) { constructed = frame; } else { var originals = frame.ConstructedFromTypeParameters; var newArgs = typeMap.SubstituteTypeParameters(originals); constructed = frame.Construct(newArgs); } constructedStructClosures.Add(constructed); } structClosures = constructedStructClosures.ToImmutableAndFree(); } _structClosures = structClosures; AssignTypeMapAndTypeParameters(typeMap, typeParameters); }
private unsafe static void UncompressLambdaMap( ImmutableArray <byte> compressedLambdaMap, out int methodOrdinal, out ImmutableArray <ClosureDebugInfo> closures, out ImmutableArray <LambdaDebugInfo> lambdas) { methodOrdinal = DebugId.UndefinedOrdinal; closures = default(ImmutableArray <ClosureDebugInfo>); lambdas = default(ImmutableArray <LambdaDebugInfo>); if (compressedLambdaMap.IsDefaultOrEmpty) { return; } var closuresBuilder = ArrayBuilder <ClosureDebugInfo> .GetInstance(); var lambdasBuilder = ArrayBuilder <LambdaDebugInfo> .GetInstance(); fixed(byte *blobPtr = &compressedLambdaMap.ToArray()[0]) { var blobReader = new BlobReader(blobPtr, compressedLambdaMap.Length); try { // Note: integer operations below can't overflow since compressed integers are in range [0, 0x20000000) // [-1, inf) methodOrdinal = blobReader.ReadCompressedInteger() - 1; int syntaxOffsetBaseline = -blobReader.ReadCompressedInteger(); int closureCount = blobReader.ReadCompressedInteger(); for (int i = 0; i < closureCount; i++) { int syntaxOffset = blobReader.ReadCompressedInteger(); var closureId = new DebugId(closuresBuilder.Count, generation: 0); closuresBuilder.Add(new ClosureDebugInfo(syntaxOffset + syntaxOffsetBaseline, closureId)); } while (blobReader.RemainingBytes > 0) { int syntaxOffset = blobReader.ReadCompressedInteger(); int closureOrdinal = blobReader.ReadCompressedInteger() + LambdaDebugInfo.MinClosureOrdinal; if (closureOrdinal >= closureCount) { throw CreateInvalidDataException(compressedLambdaMap, blobReader.Offset); } var lambdaId = new DebugId(lambdasBuilder.Count, generation: 0); lambdasBuilder.Add(new LambdaDebugInfo(syntaxOffset + syntaxOffsetBaseline, lambdaId, closureOrdinal)); } } catch (BadImageFormatException) { throw CreateInvalidDataException(compressedLambdaMap, blobReader.Offset); } } closures = closuresBuilder.ToImmutableAndFree(); lambdas = lambdasBuilder.ToImmutableAndFree(); }
/// <summary> /// Finds a lambda in the previous generation that corresponds to the specified syntax. /// The <paramref name="lambdaOrLambdaBodySyntax"/> is either a lambda syntax (<paramref name="isLambdaBody"/> is false), /// or lambda body syntax (<paramref name="isLambdaBody"/> is true). /// </summary> public abstract bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, out DebugId lambdaId);
/// <summary> /// Finds a closure in the previous generation that corresponds to the specified syntax. /// </summary> /// <remarks> /// See LambdaFrame.AssertIsLambdaScopeSyntax for kinds of syntax nodes that represent closures. /// </remarks> public abstract bool TryGetPreviousClosure(SyntaxNode closureSyntax, out DebugId closureId);
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, int>? stateMachineStateMap = null; int?firstUnusedIncreasingStateMachineState = null; int?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())); }
public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, out DebugId lambdaId) { KeyValuePair <DebugId, int> idAndClosureOrdinal; int syntaxOffset; if (_lambdaMapOpt != null && TryGetPreviousLambdaSyntaxOffset(lambdaOrLambdaBodySyntax, isLambdaBody, out syntaxOffset) && _lambdaMapOpt.TryGetValue(syntaxOffset, out idAndClosureOrdinal)) { lambdaId = idAndClosureOrdinal.Key; return(true); } lambdaId = default(DebugId); return(false); }
internal SynthesizedLambdaMethod( NamedTypeSymbol containingType, ImmutableArray<TypeSymbol> structClosures, ClosureKind closureKind, MethodSymbol topLevelMethod, DebugId topLevelMethodId, IBoundLambdaOrFunction lambdaNode, DebugId lambdaId) : base(containingType, lambdaNode.Symbol, null, lambdaNode.Syntax.SyntaxTree.GetReference(lambdaNode.Body.Syntax), lambdaNode.Syntax.GetLocation(), lambdaNode is BoundLocalFunctionStatement ? MakeName(topLevelMethod.Name, lambdaNode.Symbol.Name, topLevelMethodId, closureKind, lambdaId) : MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaId), (closureKind == ClosureKind.ThisOnly ? DeclarationModifiers.Private : DeclarationModifiers.Internal) | (closureKind == ClosureKind.Static ? DeclarationModifiers.Static : 0) | (lambdaNode.Symbol.IsAsync ? DeclarationModifiers.Async : 0)) { _topLevelMethod = topLevelMethod; TypeMap typeMap; ImmutableArray<TypeParameterSymbol> typeParameters; ImmutableArray<TypeParameterSymbol> constructedFromTypeParameters; LambdaFrame lambdaFrame; lambdaFrame = this.ContainingType as LambdaFrame; switch (closureKind) { case ClosureKind.Singleton: // all type parameters on method (except the top level method's) case ClosureKind.General: // only lambda's type parameters on method (rest on class) Debug.Assert(lambdaFrame != null); typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, out constructedFromTypeParameters, lambdaFrame.ContainingMethod); break; case ClosureKind.ThisOnly: // all type parameters on method case ClosureKind.Static: Debug.Assert(lambdaFrame == null); typeMap = TypeMap.Empty.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, out constructedFromTypeParameters, null); break; default: throw ExceptionUtilities.Unreachable; } if (!structClosures.IsDefaultOrEmpty && typeParameters.Length != 0) { var constructedStructClosures = ArrayBuilder<TypeSymbol>.GetInstance(); foreach (var closure in structClosures) { var frame = (LambdaFrame)closure; NamedTypeSymbol constructed; if (frame.Arity == 0) { constructed = frame; } else { var originals = frame.ConstructedFromTypeParameters; var newArgs = typeMap.SubstituteTypeParameters(originals); constructed = frame.Construct(newArgs); } constructedStructClosures.Add(constructed); } structClosures = constructedStructClosures.ToImmutableAndFree(); } _structClosures = structClosures; AssignTypeMapAndTypeParameters(typeMap, typeParameters); }
public override bool TryGetPreviousClosure(SyntaxNode closureSyntax, out DebugId closureId) { closureId = default(DebugId); return false; }
internal SynthesizedClosureMethod( NamedTypeSymbol containingType, ImmutableArray <SynthesizedClosureEnvironment> structEnvironments, ClosureKind closureKind, MethodSymbol topLevelMethod, DebugId topLevelMethodId, MethodSymbol originalMethod, SyntaxReference blockSyntax, DebugId lambdaId) : base(containingType, originalMethod, null, blockSyntax, originalMethod.DeclaringSyntaxReferences[0].GetLocation(), originalMethod is LocalFunctionSymbol ? MakeName(topLevelMethod.Name, originalMethod.Name, topLevelMethodId, closureKind, lambdaId) : MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaId), MakeDeclarationModifiers(closureKind, originalMethod)) { _topLevelMethod = topLevelMethod; ClosureKind = closureKind; LambdaId = lambdaId; TypeMap typeMap; ImmutableArray <TypeParameterSymbol> typeParameters; ImmutableArray <TypeParameterSymbol> constructedFromTypeParameters; var lambdaFrame = ContainingType as SynthesizedClosureEnvironment; switch (closureKind) { case ClosureKind.Singleton: // all type parameters on method (except the top level method's) case ClosureKind.General: // only lambda's type parameters on method (rest on class) Debug.Assert(lambdaFrame != null); typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename( originalMethod, this, out typeParameters, out constructedFromTypeParameters, lambdaFrame.OriginalContainingMethodOpt); break; case ClosureKind.ThisOnly: // all type parameters on method case ClosureKind.Static: Debug.Assert(lambdaFrame == null); typeMap = TypeMap.Empty.WithConcatAlphaRename( originalMethod, this, out typeParameters, out constructedFromTypeParameters, stopAt: null); break; default: throw ExceptionUtilities.UnexpectedValue(closureKind); } if (!structEnvironments.IsDefaultOrEmpty && typeParameters.Length != 0) { var constructedStructClosures = ArrayBuilder <NamedTypeSymbol> .GetInstance(); foreach (var env in structEnvironments) { NamedTypeSymbol constructed; if (env.Arity == 0) { constructed = env; } else { var originals = env.ConstructedFromTypeParameters; var newArgs = typeMap.SubstituteTypeParameters(originals); constructed = env.Construct(newArgs); } constructedStructClosures.Add(constructed); } _structEnvironments = constructedStructClosures.ToImmutableAndFree(); } else { _structEnvironments = ImmutableArray <NamedTypeSymbol> .CastUp(structEnvironments); } AssignTypeMapAndTypeParameters(typeMap, typeParameters); }
public override bool TryGetPreviousClosure(SyntaxNode closureSyntax, out DebugId closureId) { closureId = default(DebugId); return(false); }
public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, out DebugId lambdaId) { lambdaId = default(DebugId); return(false); }
private unsafe static void UncompressLambdaMap( ImmutableArray<byte> compressedLambdaMap, out int methodOrdinal, out ImmutableArray<ClosureDebugInfo> closures, out ImmutableArray<LambdaDebugInfo> lambdas) { methodOrdinal = DebugId.UndefinedOrdinal; closures = default(ImmutableArray<ClosureDebugInfo>); lambdas = default(ImmutableArray<LambdaDebugInfo>); if (compressedLambdaMap.IsDefaultOrEmpty) { return; } var closuresBuilder = ArrayBuilder<ClosureDebugInfo>.GetInstance(); var lambdasBuilder = ArrayBuilder<LambdaDebugInfo>.GetInstance(); fixed (byte* blobPtr = &compressedLambdaMap.ToArray()[0]) { var blobReader = new BlobReader(blobPtr, compressedLambdaMap.Length); try { // Note: integer operations below can't overflow since compressed integers are in range [0, 0x20000000) // [-1, inf) methodOrdinal = blobReader.ReadCompressedInteger() - 1; int syntaxOffsetBaseline = -blobReader.ReadCompressedInteger(); int closureCount = blobReader.ReadCompressedInteger(); for (int i = 0; i < closureCount; i++) { int syntaxOffset = blobReader.ReadCompressedInteger(); var closureId = new DebugId(closuresBuilder.Count, generation: 0); closuresBuilder.Add(new ClosureDebugInfo(syntaxOffset + syntaxOffsetBaseline, closureId)); } while (blobReader.RemainingBytes > 0) { int syntaxOffset = blobReader.ReadCompressedInteger(); int closureOrdinal = blobReader.ReadCompressedInteger() + LambdaDebugInfo.MinClosureOrdinal; if (closureOrdinal >= closureCount) { throw CreateInvalidDataException(compressedLambdaMap, blobReader.Offset); } var lambdaId = new DebugId(lambdasBuilder.Count, generation: 0); lambdasBuilder.Add(new LambdaDebugInfo(syntaxOffset + syntaxOffsetBaseline, lambdaId, closureOrdinal)); } } catch (BadImageFormatException) { throw CreateInvalidDataException(compressedLambdaMap, blobReader.Offset); } } closures = closuresBuilder.ToImmutableAndFree(); lambdas = lambdasBuilder.ToImmutableAndFree(); }
private static string MakeName(string topLevelMethodName, string localFunctionName, DebugId topLevelMethodId, ClosureKind closureKind, DebugId lambdaId) { return GeneratedNames.MakeLocalFunctionName( topLevelMethodName, localFunctionName, (closureKind == ClosureKind.General) ? -1 : topLevelMethodId.Ordinal, topLevelMethodId.Generation, lambdaId.Ordinal, lambdaId.Generation); }
private void MakeAndAssignEnvironments(ArrayBuilder <ClosureDebugInfo> closureDebugInfo) { VisitScopeTree(ScopeTree, scope => { if (scope.DeclaredVariables.Count > 0) { // First walk the nested scopes to find all closures which // capture variables from this scope. They all need to capture // this environment. This includes closures which captured local // functions that capture those variables, so multiple passes may // be needed. This will also decide if the environment is a struct // or a class. bool isStruct = true; var closures = new SetWithInsertionOrder <Closure>(); bool addedItem; do { addedItem = false; VisitClosures(scope, (closureScope, closure) => { if (!closures.Contains(closure) && (closure.CapturedVariables.Overlaps(scope.DeclaredVariables) || closure.CapturedVariables.Overlaps(closures.Select(c => c.OriginalMethodSymbol)))) { closures.Add(closure); addedItem = true; isStruct &= CanTakeRefParameters(closure.OriginalMethodSymbol); } }); } while (addedItem == true); // Next create the environment and add it to the declaration scope // Currently all variables declared in the same scope are added // to the same closure environment var env = MakeEnvironment(scope, scope.DeclaredVariables, isStruct); scope.DeclaredEnvironments.Add(env); foreach (var closure in closures) { closure.CapturedEnvironments.Add(env); } } }); ClosureEnvironment MakeEnvironment(Scope scope, IEnumerable <Symbol> capturedVariables, bool isStruct) { var scopeBoundNode = scope.BoundNode; var syntax = scopeBoundNode.Syntax; Debug.Assert(syntax != null); DebugId methodId = GetTopLevelMethodId(); DebugId closureId = GetClosureId(syntax, closureDebugInfo); var containingMethod = scope.ContainingClosureOpt?.OriginalMethodSymbol ?? _topLevelMethod; if ((object)_substitutedSourceMethod != null && containingMethod == _topLevelMethod) { containingMethod = _substitutedSourceMethod; } return(new ClosureEnvironment( capturedVariables, _topLevelMethod, containingMethod, isStruct, syntax, methodId, closureId)); } }