internal AsyncMethodToStateMachineRewriter( MethodSymbol method, int methodOrdinal, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, SyntheticBoundNodeFactory F, FieldSymbol state, FieldSymbol builder, IReadOnlySet<Symbol> hoistedVariables, IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, DiagnosticBag diagnostics) : base(F, method, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics, useFinalizerBookkeeping: false) { _method = method; _asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection; _asyncMethodBuilderField = builder; _exprReturnLabel = F.GenerateLabel("exprReturn"); _exitLabel = F.GenerateLabel("exitLabel"); _exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; _dynamicFactory = new LoweredDynamicOperationFactory(F, methodOrdinal); _awaiterFields = new Dictionary<TypeSymbol, FieldSymbol>(TypeSymbol.EqualsIgnoringDynamicComparer); _nextAwaiterId = slotAllocatorOpt?.PreviousAwaiterSlotCount ?? 0; }
private static BoundExpression RewriteLocalInternal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax, LocalSymbol local) { var parameterType = compilation.GetSpecialType(SpecialType.System_String); var getValueMethod = container.GetOrAddSynthesizedMethod( ExpressionCompilerConstants.GetVariableValueMethodName, (c, n, s) => { var returnType = compilation.GetSpecialType(SpecialType.System_Object); return new PlaceholderMethodSymbol( c, s, n, returnType, m => ImmutableArray.Create<ParameterSymbol>(new SynthesizedParameterSymbol(m, parameterType, ordinal: 0, refKind: RefKind.None))); }); var getAddressMethod = container.GetOrAddSynthesizedMethod( ExpressionCompilerConstants.GetVariableAddressMethodName, (c, n, s) => { return new PlaceholderMethodSymbol( c, s, n, m => ImmutableArray.Create<TypeParameterSymbol>(new SimpleTypeParameterSymbol(m, 0, "<>T")), m => m.TypeParameters[0], // return type is <>T& m => ImmutableArray.Create<ParameterSymbol>(new SynthesizedParameterSymbol(m, parameterType, ordinal: 0, refKind: RefKind.None)), returnValueIsByRef: true); }); return new BoundPseudoVariable( syntax, local, new ObjectIdExpressions(compilation, getValueMethod, getAddressMethod), local.Type); }
internal AsyncMethodToClassRewriter( MethodSymbol method, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, SyntheticBoundNodeFactory F, FieldSymbol state, FieldSymbol builder, HashSet<Symbol> variablesCaptured, Dictionary<Symbol, CapturedSymbolReplacement> initialProxies, DiagnosticBag diagnostics, bool generateDebugInfo) : base(F, method, state, variablesCaptured, initialProxies, diagnostics, useFinalizerBookkeeping: false, generateDebugInfo: generateDebugInfo) { this.method = method; this.asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection; this.asyncMethodBuilderField = builder; this.exprReturnLabel = F.GenerateLabel("exprReturn"); this.exitLabel = F.GenerateLabel("exitLabel"); this.exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, GeneratedNames.AsyncExprRetValueFieldName()) : null; this.dynamicFactory = new LoweredDynamicOperationFactory(F); }
protected bool TryRewriteLocal(LocalSymbol local, out LocalSymbol newLocal) { if (NeedsProxy(local)) { // no longer a local symbol newLocal = null; return false; } if (localMap.TryGetValue(local, out newLocal)) { return true; } var newType = VisitType(local.Type); if (newType == local.Type) { newLocal = local; } else { newLocal = new TypeSubstitutedLocalSymbol(local, newType, CurrentMethod); localMap.Add(local, newLocal); } return true; }
private static BoundExpression RewriteLocalInternal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax, LocalSymbol local) { return new BoundPseudoVariable( syntax, local, new ObjectIdExpressions(compilation), local.Type); }
public DecisionTree(BoundExpression expression, TypeSymbol type, LocalSymbol temp) { this.Expression = expression; this.Type = type; this.Temp = temp; Debug.Assert(this.Expression != null); Debug.Assert(this.Type != null); }
internal int EnsureSlot(LocalSymbol local) { if (!slots.ContainsKey(local)) { slots[local] = slots.Count; } return slots[local]; }
internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, DiagnosticBag diagnostics) { if (diagnostics != null && _value.IsBad) { diagnostics.Add(ErrorCode.ERR_BadPdbData, Location.None, Name); } return _value; }
public TypeSubstitutedLocalSymbol(LocalSymbol originalVariable, TypeSymbol type, Symbol containingSymbol) { Debug.Assert(originalVariable != null); Debug.Assert(type != null); Debug.Assert(containingSymbol != null); _originalVariable = originalVariable; _type = type; _containingSymbol = containingSymbol; }
private BoundStatement AddLocalDeclarationSequencePointIfNecessary(CSharpSyntaxNode syntax, LocalSymbol localSymbol, BoundStatement rewrittenLocalDeclaration, bool wasCompilerGenerated = false) { // Add sequence points, if necessary. if (this.GenerateDebugInfo && !wasCompilerGenerated && !localSymbol.IsConst && syntax.Kind() == SyntaxKind.VariableDeclarator) { Debug.Assert(syntax.SyntaxTree != null); rewrittenLocalDeclaration = AddSequencePoint((VariableDeclaratorSyntax)syntax, rewrittenLocalDeclaration); } return rewrittenLocalDeclaration; }
private BoundStatement RewriteLocalDeclaration(BoundLocalDeclaration originalOpt, SyntaxNode syntax, LocalSymbol localSymbol, BoundExpression rewrittenInitializer, bool hasErrors = false) { // A declaration of a local variable without an initializer has no associated IL. // Simply remove the declaration from the bound tree. The local symbol will // remain in the bound block, so codegen will make a stack frame location for it. if (rewrittenInitializer == null) { return null; } // A declaration of a local constant also does nothing, even though there is // an assignment. The value will be emitted directly where it is used. The // local symbol remains in the bound block, but codegen will skip making a // stack frame location for it. (We still need a symbol for it to stay // around because we'll be generating debug info for it.) if (localSymbol.IsConst) { if (!localSymbol.Type.IsReferenceType && localSymbol.ConstantValue == null) { // This can occur in error scenarios (e.g. bad imported metadata) hasErrors = true; } else { return null; } } // lowered local declaration node is associated with declaration (not whole statement) // this is done to make sure that debugger stepping is same as before var localDeclaration = syntax as LocalDeclarationStatementSyntax; if (localDeclaration != null) { syntax = localDeclaration.Declaration.Variables[0]; } BoundStatement rewrittenLocalDeclaration = new BoundExpressionStatement( syntax, new BoundAssignmentOperator( syntax, new BoundLocal( syntax, localSymbol, null, localSymbol.Type ), rewrittenInitializer, localSymbol.Type, localSymbol.RefKind), hasErrors); return InstrumentLocalDeclarationIfNecessary(originalOpt, localSymbol, rewrittenLocalDeclaration); }
private BoundStatement InstrumentLocalDeclarationIfNecessary(BoundLocalDeclaration originalOpt, LocalSymbol localSymbol, BoundStatement rewrittenLocalDeclaration) { // Add sequence points, if necessary. if (this.Instrument && originalOpt?.WasCompilerGenerated == false && !localSymbol.IsConst && (originalOpt.Syntax.Kind() == SyntaxKind.VariableDeclarator || (originalOpt.Syntax.Kind() == SyntaxKind.LocalDeclarationStatement && ((LocalDeclarationStatementSyntax)originalOpt.Syntax).Declaration.Variables.Count == 1))) { rewrittenLocalDeclaration = _instrumenter.InstrumentLocalInitialization(originalOpt, rewrittenLocalDeclaration); } return rewrittenLocalDeclaration; }
public override BoundStatement CreateBlockPrologue(BoundBlock original, out LocalSymbol synthesizedLocal) { BoundStatement previousPrologue = base.CreateBlockPrologue(original, out synthesizedLocal); if (_methodBody == original) { _dynamicAnalysisSpans = _spansBuilder.ToImmutableAndFree(); // In the future there will be multiple analysis kinds. const int analysisKind = 0; ArrayTypeSymbol modulePayloadType = ArrayTypeSymbol.CreateCSharpArray(_methodBodyFactory.Compilation.Assembly, _payloadType); // Synthesize the initialization of the instrumentation payload array, using concurrency-safe code: // // var payload = PID.PayloadRootField[methodIndex]; // if (payload == null) // payload = Instrumentation.CreatePayload(mvid, methodIndex, fileIndex, ref PID.PayloadRootField[methodIndex], payloadLength); BoundStatement payloadInitialization = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload), _methodBodyFactory.ArrayAccess(_methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method)))); BoundExpression mvid = _methodBodyFactory.ModuleVersionId(); BoundExpression methodToken = _methodBodyFactory.MethodDefIndex(_method); BoundExpression fileIndex = _methodBodyFactory.SourceDocumentIndex(GetSourceDocument(_methodBody.Syntax)); BoundExpression payloadSlot = _methodBodyFactory.ArrayAccess(_methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method))); BoundStatement createPayloadCall = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Call(null, _createPayload, mvid, methodToken, fileIndex, payloadSlot, _methodBodyFactory.Literal(_dynamicAnalysisSpans.Length))); BoundExpression payloadNullTest = _methodBodyFactory.Binary(BinaryOperatorKind.ObjectEqual, _methodBodyFactory.SpecialType(SpecialType.System_Boolean), _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Null(_payloadType)); BoundStatement payloadIf = _methodBodyFactory.If(payloadNullTest, createPayloadCall); Debug.Assert(synthesizedLocal == null); synthesizedLocal = _methodPayload; ArrayBuilder<BoundStatement> prologueStatements = ArrayBuilder<BoundStatement>.GetInstance(previousPrologue == null ? 3 : 4); prologueStatements.Add(payloadInitialization); prologueStatements.Add(payloadIf); if (_methodEntryInstrumentation != null) { prologueStatements.Add(_methodEntryInstrumentation); } if (previousPrologue != null) { prologueStatements.Add(previousPrologue); } return _methodBodyFactory.StatementList(prologueStatements.ToImmutableAndFree()); } return previousPrologue; }
private DynamicAnalysisInjector(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, MethodSymbol createPayload, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous) : base(previous) { _createPayload = createPayload; _method = method; _methodBody = methodBody; _spansBuilder = ArrayBuilder<SourceSpan>.GetInstance(); TypeSymbol payloadElementType = methodBodyFactory.SpecialType(SpecialType.System_Boolean); _payloadType = ArrayTypeSymbol.CreateCSharpArray(methodBodyFactory.Compilation.Assembly, payloadElementType); _methodPayload = methodBodyFactory.SynthesizedLocal(_payloadType, kind: SynthesizedLocalKind.InstrumentationPayload, syntax: methodBody.Syntax); _diagnostics = diagnostics; _debugDocumentProvider = debugDocumentProvider; _methodHasExplicitBlock = MethodHasExplicitBlock(method); _methodBodyFactory = methodBodyFactory; // The first point indicates entry into the method and has the span of the method definition. _methodEntryInstrumentation = AddAnalysisPoint(MethodDeclarationIfAvailable(methodBody.Syntax), methodBodyFactory); }
internal AsyncMethodToClassRewriter( MethodSymbol method, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, SyntheticBoundNodeFactory factory, FieldSymbol state, FieldSymbol builder, Dictionary<Symbol, CapturedSymbol> localProxies, DiagnosticBag diagnostics) : base(factory, state, localProxies, diagnostics) { this.method = method; this.asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection; this.asyncMethodBuilderField = builder; this.exprReturnLabel = factory.GenerateLabel("exprReturn"); this.exprRetValue = method.IsGenericTaskReturningAsync() ? factory.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, GeneratedNames.AsyncExprRetValueFieldName()) : null; this.dynamicFactory = new LoweredDynamicOperationFactory(factory); }
internal AsyncMethodToStateMachineRewriter( MethodSymbol method, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, SyntheticBoundNodeFactory F, FieldSymbol state, FieldSymbol builder, IReadOnlySet<Symbol> variablesCaptured, IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, DiagnosticBag diagnostics) : base(F, method, state, variablesCaptured, nonReusableLocalProxies, diagnostics, useFinalizerBookkeeping: false) { this.method = method; this.asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection; this.asyncMethodBuilderField = builder; this.exprReturnLabel = F.GenerateLabel("exprReturn"); this.exitLabel = F.GenerateLabel("exitLabel"); this.exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; this.dynamicFactory = new LoweredDynamicOperationFactory(F); }
private static void CreateLocal(CSharpCompilation compilation, HashSet<LocalSymbol> declaredLocals, ArrayBuilder<BoundStatement> statements, LocalSymbol local, SyntaxNode syntax) { declaredLocals.Add(local); var typeType = compilation.GetWellKnownType(WellKnownType.System_Type); var stringType = compilation.GetSpecialType(SpecialType.System_String); var guidConstructor = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Guid__ctor); // CreateVariable(Type type, string name) var method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName); var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType); var name = new BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType); bool hasCustomTypeInfoPayload; var customTypeInfoPayload = GetCustomTypeInfoPayload(local, syntax, compilation, out hasCustomTypeInfoPayload); var customTypeInfoPayloadId = GetCustomTypeInfoPayloadId(syntax, guidConstructor, hasCustomTypeInfoPayload); var call = BoundCall.Synthesized( syntax, receiverOpt: null, method: method, arguments: ImmutableArray.Create(type, name, customTypeInfoPayloadId, customTypeInfoPayload)); statements.Add(new BoundExpressionStatement(syntax, call)); }
private BoundBlock GenerateAwaitForIncompleteTask(LocalSymbol awaiterTemp) { int stateNumber; GeneratedLabelSymbol resumeLabel; AddState(out stateNumber, out resumeLabel); TypeSymbol awaiterFieldType = awaiterTemp.Type.IsVerifierReference() ? F.SpecialType(SpecialType.System_Object) : awaiterTemp.Type; FieldSymbol awaiterField = GetAwaiterField(awaiterFieldType); var blockBuilder = ArrayBuilder <BoundStatement> .GetInstance(); blockBuilder.Add( // this.state = cachedState = stateForLabel F.Assignment(F.Field(F.This(), stateField), F.AssignmentExpression(F.Local(cachedState), F.Literal(stateNumber)))); blockBuilder.Add( // Emit await yield point to be injected into PDB F.NoOp(NoOpStatementFlavor.AwaitYieldPoint)); blockBuilder.Add( // this.<>t__awaiter = $awaiterTemp F.Assignment( F.Field(F.This(), awaiterField), (awaiterField.Type == awaiterTemp.Type) ? F.Local(awaiterTemp) : F.Convert(awaiterFieldType, F.Local(awaiterTemp)))); blockBuilder.Add(awaiterTemp.Type.IsDynamic() ? GenerateAwaitOnCompletedDynamic(awaiterTemp) : GenerateAwaitOnCompleted(awaiterTemp.Type, awaiterTemp)); blockBuilder.Add( GenerateReturn(false)); blockBuilder.Add( F.Label(resumeLabel)); blockBuilder.Add( // Emit await resume point to be injected into PDB F.NoOp(NoOpStatementFlavor.AwaitResumePoint)); blockBuilder.Add( // $awaiterTemp = this.<>t__awaiter or $awaiterTemp = (AwaiterType)this.<>t__awaiter // $this.<>t__awaiter = null; F.Assignment( F.Local(awaiterTemp), awaiterTemp.Type == awaiterField.Type ? F.Field(F.This(), awaiterField) : F.Convert(awaiterTemp.Type, F.Field(F.This(), awaiterField)))); blockBuilder.Add( F.Assignment(F.Field(F.This(), awaiterField), F.NullOrDefault(awaiterField.Type))); blockBuilder.Add( // this.state = cachedState = NotStartedStateMachine F.Assignment(F.Field(F.This(), stateField), F.AssignmentExpression(F.Local(cachedState), F.Literal(StateMachineStates.NotStartedStateMachine)))); return(F.Block(blockBuilder.ToImmutableAndFree())); }
private static ImmutableArray <LocalSymbol> SingletonOrPair(LocalSymbol first, LocalSymbol secondOpt) { return((secondOpt == null) ? ImmutableArray.Create(first) : ImmutableArray.Create(first, secondOpt)); }
internal static BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, SyntaxNode syntax, LocalSymbol local) { return(RewriteLocalInternal(compilation, container, syntax, local)); }
/// <summary> /// fixed(char* ptr = stringVar){ ... } == becomes ===> /// /// pinned string pinnedTemp = stringVar; // pinning managed ref /// char* ptr = (char*)pinnedTemp; // unsafe cast to unmanaged ptr /// if (pinnedTemp != null) ptr += OffsetToStringData(); /// . . . /// </summary> private BoundStatement InitializeFixedStatementStringLocal( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol pinnedTemp) { TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; // intervening parens may have been skipped by the binder; find the declarator VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclaratorSyntax>(); Debug.Assert(declarator != null); pinnedTemp = factory.SynthesizedLocal( initializerType, syntax: declarator, isPinned: true, kind: SynthesizedLocalKind.FixedReference); // NOTE: we pin the string, not the pointer. Debug.Assert(pinnedTemp.IsPinned); Debug.Assert(!localSymbol.IsPinned); BoundStatement stringTempInit = factory.Assignment(factory.Local(pinnedTemp), initializerExpr); // (char*)pinnedTemp; var addr = factory.Convert( fixedInitializer.ElementPointerType, factory.Local(pinnedTemp), Conversion.PinnedObjectToPointer); var convertedStringTemp = factory.Convert( localType, addr, fixedInitializer.ElementPointerTypeConversion); BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, factory.Assignment(factory.Local(localSymbol), convertedStringTemp)); BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, factory.Local(localSymbol), BinaryOperatorKind.NotEqual); BoundExpression helperCall; MethodSymbol offsetMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData, out offsetMethod)) { helperCall = factory.Call(receiver: null, method: offsetMethod); } else { helperCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray <BoundExpression> .Empty, ErrorTypeSymbol.UnknownResultType); } BoundExpression addition = factory.Binary(BinaryOperatorKind.PointerAndIntAddition, localType, factory.Local(localSymbol), helperCall); BoundStatement conditionalAdd = factory.If(notNullCheck, factory.Assignment(factory.Local(localSymbol), addition)); return(factory.Block(stringTempInit, localInit, conditionalAdd)); }
public override BoundStatement CreateBlockPrologue(BoundBlock original, out LocalSymbol synthesizedLocal) { BoundStatement previousPrologue = base.CreateBlockPrologue(original, out synthesizedLocal); if (_methodBody == original) { _dynamicAnalysisSpans = _spansBuilder.ToImmutableAndFree(); // In the future there will be multiple analysis kinds. const int analysisKind = 0; ArrayTypeSymbol modulePayloadType = ArrayTypeSymbol.CreateCSharpArray(_methodBodyFactory.Compilation.Assembly, TypeSymbolWithAnnotations.Create(_payloadType)); // Synthesize the initialization of the instrumentation payload array, using concurrency-safe code: // // var payload = PID.PayloadRootField[methodIndex]; // if (payload == null) // payload = Instrumentation.CreatePayload(mvid, methodIndex, fileIndexOrIndices, ref PID.PayloadRootField[methodIndex], payloadLength); BoundStatement payloadInitialization = _methodBodyFactory.Assignment( _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.ArrayAccess( _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method)))); BoundExpression mvid = _methodBodyFactory.ModuleVersionId(); BoundExpression methodToken = _methodBodyFactory.MethodDefIndex(_method); BoundExpression payloadSlot = _methodBodyFactory.ArrayAccess( _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method))); BoundStatement createPayloadCall = GetCreatePayloadStatement( _dynamicAnalysisSpans, _methodBody.Syntax, _methodPayload, _createPayloadForMethodsSpanningSingleFile, _createPayloadForMethodsSpanningMultipleFiles, mvid, methodToken, payloadSlot, _methodBodyFactory, _debugDocumentProvider); BoundExpression payloadNullTest = _methodBodyFactory.Binary( BinaryOperatorKind.ObjectEqual, _methodBodyFactory.SpecialType(SpecialType.System_Boolean), _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Null(_payloadType)); BoundStatement payloadIf = _methodBodyFactory.If(payloadNullTest, createPayloadCall); Debug.Assert(synthesizedLocal == null); synthesizedLocal = _methodPayload; ArrayBuilder <BoundStatement> prologueStatements = ArrayBuilder <BoundStatement> .GetInstance(previousPrologue == null? 3 : 4); prologueStatements.Add(payloadInitialization); prologueStatements.Add(payloadIf); if (_methodEntryInstrumentation != null) { prologueStatements.Add(_methodEntryInstrumentation); } if (previousPrologue != null) { prologueStatements.Add(previousPrologue); } return(_methodBodyFactory.StatementList(prologueStatements.ToImmutableAndFree())); } return(previousPrologue); }
private bool IsStackLocal(LocalSymbol local) { return(_stackLocals != null && _stackLocals.Contains(local)); }
public ImplicitlyTypedLocalBinder(Binder next, LocalSymbol symbol) : base(next) { _symbols = new ConsList <LocalSymbol>(symbol, next.ImplicitlyTypedLocalsBeingBound); }
public bool TryGetHoistedLocal(LocalSymbol originalLocal, out LocalSymbol hoistedLocal) { return(_hoistedLocals.TryGetValue(originalLocal, out hoistedLocal)); }
private BoundStatement MakeLoweredForm(BoundPatternSwitchStatement node) { var expression = _localRewriter.VisitExpression(node.Expression); var result = ArrayBuilder <BoundStatement> .GetInstance(); // if the expression is "too complex", we copy it to a temp. LocalSymbol initialTemp = null; if (expression.ConstantValue == null) { initialTemp = _factory.SynthesizedLocal(expression.Type, expression.Syntax); result.Add(_factory.Assignment(_factory.Local(initialTemp), expression)); expression = _factory.Local(initialTemp); } // EnC: We need to insert a hidden sequence point to handle function remapping in case // the containing method is edited while methods invoked in the expression are being executed. if (!node.WasCompilerGenerated && _localRewriter.Instrument) { expression = _localRewriter._instrumenter.InstrumentSwitchStatementExpression(node, expression, _factory); } // output the decision tree part LowerPatternSwitch(expression, node, result); // if the endpoint is reachable, we exit the switch if (!node.IsComplete) { result.Add(_factory.Goto(node.BreakLabel)); } // at this point the end of result is unreachable. // output the sections of code foreach (var section in node.SwitchSections) { // Start with the part of the decision tree that is in scope of the section variables. // Its endpoint is not reachable (it jumps back into the decision tree code). var sectionSyntax = (SyntaxNode)section.Syntax; var sectionBuilder = _switchSections[sectionSyntax]; // Add labels corresponding to the labels of the switch section. foreach (var label in section.SwitchLabels) { sectionBuilder.Add(_factory.Label(label.Label)); } // Add the translated body of the switch section sectionBuilder.AddRange(_localRewriter.VisitList(section.Statements)); sectionBuilder.Add(_factory.Goto(node.BreakLabel)); result.Add(_factory.Block(section.Locals, sectionBuilder.ToImmutableAndFree())); // at this point the end of result is unreachable. } result.Add(_factory.Label(node.BreakLabel)); _declaredTemps.AddOptional(initialTemp); _declaredTemps.AddRange(node.InnerLocals); BoundStatement translatedSwitch = _factory.Block(_declaredTemps.ToImmutableArray(), node.InnerLocalFunctions, result.ToImmutableAndFree()); // Only add instrumentation (such as a sequence point) if the node is not compiler-generated. if (!node.WasCompilerGenerated && _localRewriter.Instrument) { translatedSwitch = _localRewriter._instrumenter.InstrumentPatternSwitchStatement(node, translatedSwitch); } return(translatedSwitch); }
/// <summary> /// Generate a thread-safe accessor for a regular field-like event. /// /// DelegateType tmp0 = _event; //backing field /// DelegateType tmp1; /// DelegateType tmp2; /// do { /// tmp1 = tmp0; /// tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -= /// tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); /// } while ((object)tmp0 != (object)tmp1); /// /// Note, if System.Threading.Interlocked.CompareExchange<T> is not available, /// we emit the following code and mark the method Synchronized (unless it is a struct). /// /// _event = (DelegateType)Delegate.Combine(_event, value); //Remove for -= /// /// </summary> internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics) { CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode; TypeSymbol delegateType = eventSymbol.Type; MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod; ParameterSymbol thisParameter = accessor.ThisParameter; TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); SpecialMember updateMethodId = isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove; MethodSymbol updateMethod = (MethodSymbol)compilation.GetSpecialTypeMember(updateMethodId); BoundStatement @return = new BoundReturnStatement(syntax, refKind: RefKind.None, expressionOpt: null) { WasCompilerGenerated = true }; if (updateMethod == null) { MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(updateMethodId); diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember, memberDescriptor.DeclaringTypeMetadataName, memberDescriptor.Name), syntax.Location)); return(BoundBlock.SynthesizedNoLocals(syntax, @return)); } Binder.ReportUseSiteDiagnostics(updateMethod, diagnostics, syntax); BoundThisReference fieldReceiver = eventSymbol.IsStatic ? null : new BoundThisReference(syntax, thisParameter.Type) { WasCompilerGenerated = true }; BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax, receiver: fieldReceiver, fieldSymbol: eventSymbol.AssociatedField, constantValueOpt: null) { WasCompilerGenerated = true }; BoundParameter boundParameter = new BoundParameter(syntax, parameterSymbol: accessor.Parameters[0]) { WasCompilerGenerated = true }; BoundExpression delegateUpdate; MethodSymbol compareExchangeMethod = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T); if ((object)compareExchangeMethod == null) { // (DelegateType)Delegate.Combine(_event, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundParameter)), conversion: Conversion.ExplicitReference, type: delegateType); // _event = (DelegateType)Delegate.Combine(_event, value); BoundStatement eventUpdate = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundBackingField, right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; return(BoundBlock.SynthesizedNoLocals(syntax, statements: ImmutableArray.Create <BoundStatement>( eventUpdate, @return))); } compareExchangeMethod = compareExchangeMethod.Construct(ImmutableArray.Create <TypeSymbol>(delegateType)); Binder.ReportUseSiteDiagnostics(compareExchangeMethod, diagnostics, syntax); GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop"); const int numTemps = 3; LocalSymbol[] tmps = new LocalSymbol[numTemps]; BoundLocal[] boundTmps = new BoundLocal[numTemps]; for (int i = 0; i < numTemps; i++) { tmps[i] = new SynthesizedLocal(accessor, delegateType, SynthesizedLocalKind.LoweringTemp); boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType); } // tmp0 = _event; BoundStatement tmp0Init = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: boundBackingField, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // LOOP: BoundStatement loopStart = new BoundLabelStatement(syntax, label: loopLabel) { WasCompilerGenerated = true }; // tmp1 = tmp0; BoundStatement tmp1Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[1], right: boundTmps[0], type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // (DelegateType)Delegate.Combine(tmp1, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundTmps[1], boundParameter)), conversion: Conversion.ExplicitReference, type: delegateType); // tmp2 = (DelegateType)Delegate.Combine(tmp1, value); BoundStatement tmp2Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[2], right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1) BoundExpression compareExchange = BoundCall.Synthesized(syntax, receiverOpt: null, method: compareExchangeMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1])); // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); BoundStatement tmp0Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: compareExchange, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise BoundExpression loopExitCondition = new BoundBinaryOperator(syntax, operatorKind: BinaryOperatorKind.ObjectEqual, left: boundTmps[0], right: boundTmps[1], constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType) { WasCompilerGenerated = true }; // branchfalse (tmp0 == tmp1) LOOP BoundStatement loopEnd = new BoundConditionalGoto(syntax, condition: loopExitCondition, jumpIfTrue: false, label: loopLabel) { WasCompilerGenerated = true }; return(new BoundBlock(syntax, locals: tmps.AsImmutable(), statements: ImmutableArray.Create <BoundStatement>( tmp0Init, loopStart, tmp1Update, tmp2Update, tmp0Update, loopEnd, @return)) { WasCompilerGenerated = true }); }
public BoundDeclarationPattern(SyntaxNode syntax, LocalSymbol localSymbol, BoundTypeExpression declaredType, bool isVar, bool hasErrors = false) : this(syntax, localSymbol, localSymbol == null ? new BoundDiscardExpression(syntax, declaredType.Type) : (BoundExpression) new BoundLocal(syntax, localSymbol, null, declaredType.Type), declaredType, isVar, hasErrors) { }
/// <summary> /// Generate implementation-specific state machine initialization for the kickoff method body. /// </summary> protected abstract BoundStatement GenerateStateMachineCreation(LocalSymbol stateMachineVariable, NamedTypeSymbol frameType);
/// <summary> /// Initialize the state machine class. /// </summary> protected abstract void InitializeStateMachine(ArrayBuilder <BoundStatement> bodyBuilder, NamedTypeSymbol frameType, LocalSymbol stateMachineLocal);
internal static bool IsStackLocal(LocalSymbol local, HashSet <LocalSymbol> stackLocalsOpt) => stackLocalsOpt?.Contains(local) ?? false;
private StateMachineFieldSymbol GetOrAllocateReusableHoistedField(TypeSymbol type, out bool reused, LocalSymbol local = null) { ArrayBuilder <StateMachineFieldSymbol> fields; if (_lazyAvailableReusableHoistedFields != null && _lazyAvailableReusableHoistedFields.TryGetValue(type, out fields) && fields.Count > 0) { var field = fields.Last(); fields.RemoveLast(); reused = true; return(field); } reused = false; var slotIndex = _nextHoistedFieldId++; if (local?.SynthesizedKind == SynthesizedLocalKind.UserDefined) { string fieldName = GeneratedNames.MakeHoistedLocalFieldName(SynthesizedLocalKind.UserDefined, slotIndex, local.Name); return(F.StateMachineField(type, fieldName, SynthesizedLocalKind.UserDefined, slotIndex)); } return(F.StateMachineField(type, GeneratedNames.ReusableHoistedLocalFieldName(slotIndex))); }
private bool IsStackLocal(LocalSymbol local) => IsStackLocal(local, _stackLocals);
private static BoundExpressionStatement GetCreatePayloadStatement( ImmutableArray <SourceSpan> dynamicAnalysisSpans, SyntaxNode methodBodySyntax, LocalSymbol methodPayload, MethodSymbol createPayloadForMethodsSpanningSingleFile, MethodSymbol createPayloadForMethodsSpanningMultipleFiles, BoundExpression mvid, BoundExpression methodToken, BoundExpression payloadSlot, SyntheticBoundNodeFactory methodBodyFactory, DebugDocumentProvider debugDocumentProvider) { MethodSymbol createPayloadOverload; BoundExpression fileIndexOrIndicesArgument; if (dynamicAnalysisSpans.IsEmpty) { createPayloadOverload = createPayloadForMethodsSpanningSingleFile; // For a compiler generated method that has no 'real' spans, we emit the index for // the document corresponding to the syntax node that is associated with its bound node. var document = GetSourceDocument(debugDocumentProvider, methodBodySyntax); fileIndexOrIndicesArgument = methodBodyFactory.SourceDocumentIndex(document); } else { var documents = PooledHashSet <DebugSourceDocument> .GetInstance(); var fileIndices = ArrayBuilder <BoundExpression> .GetInstance(); foreach (var span in dynamicAnalysisSpans) { var document = span.Document; if (documents.Add(document)) { fileIndices.Add(methodBodyFactory.SourceDocumentIndex(document)); } } documents.Free(); // At this point, we should have at least one document since we have already // handled the case where method has no 'real' spans (and therefore no documents) above. if (fileIndices.Count == 1) { createPayloadOverload = createPayloadForMethodsSpanningSingleFile; fileIndexOrIndicesArgument = fileIndices.Single(); } else { createPayloadOverload = createPayloadForMethodsSpanningMultipleFiles; // Order of elements in fileIndices should be deterministic because these // elements were added based on order of spans in dynamicAnalysisSpans above. fileIndexOrIndicesArgument = methodBodyFactory.Array( methodBodyFactory.SpecialType(SpecialType.System_Int32), fileIndices.ToImmutable()); } fileIndices.Free(); } return(methodBodyFactory.Assignment( methodBodyFactory.Local(methodPayload), methodBodyFactory.Call( null, createPayloadOverload, mvid, methodToken, fileIndexOrIndicesArgument, payloadSlot, methodBodyFactory.Literal(dynamicAnalysisSpans.Length)))); }
public ByType(BoundExpression expression, TypeSymbol type, LocalSymbol temp) : base(expression, type, temp) { }
/// <summary> /// <![CDATA[ /// fixed(int* ptr = &v){ ... } == becomes ===> /// /// pinned ref int pinnedTemp = ref v; // pinning managed ref /// int* ptr = (int*)&pinnedTemp; // unsafe cast to unmanaged ptr /// . . . /// ]]> /// </summary> private BoundStatement InitializeFixedStatementGetPinnable( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol pinnedTemp) { TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); var initializerType = initializerExpr.Type; var initializerSyntax = initializerExpr.Syntax; var getPinnableMethod = fixedInitializer.GetPinnableOpt; // intervening parens may have been skipped by the binder; find the declarator VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclaratorSyntax>(); Debug.Assert(declarator != null); // pinned ref int pinnedTemp pinnedTemp = factory.SynthesizedLocal( getPinnableMethod.ReturnType, syntax: declarator, isPinned: true, //NOTE: different from the array and string cases // RefReadOnly to allow referring to readonly variables. (technically we only "read" through the temp anyways) refKind: RefKind.RefReadOnly, kind: SynthesizedLocalKind.FixedReference); BoundExpression callReceiver; int currentConditionalAccessID = 0; bool needNullCheck = !initializerType.IsValueType; if (needNullCheck) { currentConditionalAccessID = ++_currentConditionalAccessID; callReceiver = new BoundConditionalReceiver( initializerSyntax, currentConditionalAccessID, initializerType); } else { callReceiver = initializerExpr; } // .GetPinnable() var getPinnableCall = getPinnableMethod.IsStatic ? factory.Call(null, getPinnableMethod, callReceiver) : factory.Call(callReceiver, getPinnableMethod); // temp =ref .GetPinnable() var tempAssignment = factory.AssignmentExpression( factory.Local(pinnedTemp), getPinnableCall, isRef: true); // &pinnedTemp var addr = new BoundAddressOfOperator( factory.Syntax, factory.Local(pinnedTemp), type: fixedInitializer.ElementPointerType); // (int*)&pinnedTemp var pointerValue = factory.Convert( localType, addr, fixedInitializer.ElementPointerTypeConversion); // {pinnedTemp =ref .GetPinnable(), (int*)&pinnedTemp} BoundExpression pinAndGetPtr = factory.Sequence( locals: ImmutableArray <LocalSymbol> .Empty, sideEffects: ImmutableArray.Create <BoundExpression>(tempAssignment), result: pointerValue); if (needNullCheck) { // initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default; pinAndGetPtr = new BoundLoweredConditionalAccess( initializerSyntax, initializerExpr, hasValueMethodOpt: null, whenNotNull: pinAndGetPtr, whenNullOpt: null, // just return default(T*) currentConditionalAccessID, localType); } // ptr = initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default; BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, factory.Assignment(factory.Local(localSymbol), pinAndGetPtr)); return(localInit); }
private void DeclareLocal(LocalSymbol local, int stack) { if ((object)local != null) { if (CanScheduleToStack(local)) { LocalDefUseInfo info; if (!_locals.TryGetValue(local, out info)) { _locals.Add(local, new LocalDefUseInfo(stack)); } else { Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.LoweringTemp, "only lowering temps may be sometimes reused"); if (info.stackAtDeclaration != stack) { info.ShouldNotSchedule(); } } } } }
/// <summary> /// fixed(int* ptr = arr){ ... } == becomes ===> /// /// pinned int[] pinnedTemp = arr; // pinning managed ref /// int* ptr = pinnedTemp != null && pinnedTemp.Length != 0 /// (int*)&pinnedTemp[0]: // unsafe cast to unmanaged ptr /// 0; /// . . . /// </summary> private BoundStatement InitializeFixedStatementArrayLocal( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol pinnedTemp) { TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; pinnedTemp = factory.SynthesizedLocal(initializerType, isPinned: true); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)pinnedTemp.Type; TypeSymbol arrayElementType = arrayType.ElementType; // NOTE: we pin the array, not the pointer. Debug.Assert(pinnedTemp.IsPinned); Debug.Assert(!localSymbol.IsPinned); //(pinnedTemp = array) BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(pinnedTemp), initializerExpr); //(pinnedTemp = array) != null BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual); BoundExpression lengthCall; if (arrayType.IsSZArray) { lengthCall = factory.ArrayLength(factory.Local(pinnedTemp)); } else { MethodSymbol lengthMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod)) { lengthCall = factory.Call(factory.Local(pinnedTemp), lengthMethod); } else { lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(factory.Local(pinnedTemp)), ErrorTypeSymbol.UnknownResultType); } } // NOTE: dev10 comment says ">", but code actually checks "!=" //temp.Length != 0 BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0)); //((temp = array) != null && temp.Length != 0) BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck); //temp[0] BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(pinnedTemp)); // NOTE: this is a fixed statement address-of in that it's the initial value of the pointer. //&temp[0] BoundExpression firstElementAddress = new BoundAddressOfOperator(factory.Syntax, firstElement, type: new PointerTypeSymbol(arrayElementType)); BoundExpression convertedFirstElementAddress = factory.Convert( localType, firstElementAddress, fixedInitializer.ElementPointerTypeConversion); //loc = &temp[0] BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress); //loc = null BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType)); //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null) BoundStatement localInit = factory.ExpressionStatement( new BoundConditionalOperator(factory.Syntax, false, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType)); return(InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, localInit)); }
private static BoundExpression RewriteLocalInternal(CSharpCompilation compilation, EENamedTypeSymbol container, SyntaxNode syntax, LocalSymbol local) { return(new BoundPseudoVariable( syntax, local, new ObjectIdExpressions(compilation), local.Type.TypeSymbol)); }
// detect a pattern used in compound operators // where a temp is declared in the outer sequence // only because it must be returned, otherwise all uses are // confined to the nested sequence that is assigned indirectly of to an instance field (and therefore has +1 stack) // in such case the desired stack for this local is +1 private static bool IsNestedLocalOfCompoundOperator(LocalSymbol local, BoundSequence node) { var value = node.Value; // local must be used as the value of the sequence. if (value != null && value.Kind == BoundKind.Local && ((BoundLocal)value).LocalSymbol == local) { var sideeffects = node.SideEffects; var lastSideeffect = sideeffects.LastOrDefault(); if (lastSideeffect != null) { // last side-effect must be an indirect assignment of a sequence. if (lastSideeffect.Kind == BoundKind.AssignmentOperator) { var assignment = (BoundAssignmentOperator)lastSideeffect; if (IsIndirectOrInstanceFieldAssignment(assignment) && assignment.Right.Kind == BoundKind.Sequence) { // and no other side-effects should use the variable var localUsedWalker = new LocalUsedWalker(local); for (int i = 0; i < sideeffects.Length - 1; i++) { if (localUsedWalker.IsLocalUsedIn(sideeffects[i])) { return false; } } // and local is not used on the left of the assignment // (extra check, but better be safe) if (localUsedWalker.IsLocalUsedIn(assignment.Left)) { return false; } // it should be used somewhere Debug.Assert(localUsedWalker.IsLocalUsedIn(assignment.Right), "who assigns the temp?"); return true; } } } } return false; }
/// <summary> /// Called when visiting a <see cref="LocalSymbol" />; Override this with specific /// implementation; Calling default <see cref="DefaultVisit" /> if it's not overridden /// </summary> /// <param name="symbol">The visited symbol</param> /// <param name="argument">Additional argument</param> /// <returns></returns> public virtual TResult VisitLocal(LocalSymbol symbol, TArgument argument) { return(DefaultVisit(symbol, argument)); }
public void Add(LocalSymbol local) { if (locals == null) locals = ArrayBuilder<LocalSymbol>.GetInstance(); locals.Add(local); }
internal static BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax, LocalSymbol local) { return RewriteLocalInternal(compilation, container, syntax, local); }
private BoundStatement InitializeFixedStatementArrayLocal( LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol arrayTemp) { // From ExpressionBinder::BindPtrToArray: // (((temp = array) != null && temp.Length > 0) ? loc = &temp[0] : loc = null) // NOTE: The assignment needs to be inside the EK_QUESTIONMARK. See Whidbey bug #397859. // We can't do loc = (... ? ... : ...) since the CLR type of &temp[0] is a managed // pointer and null is a UIntPtr - which confuses the JIT. We can't just convert // &temp[0] to UIntPtr with a conv.u instruction because then if a GC occurs between // the time of the cast and the assignment to the local, we're toast. TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; arrayTemp = factory.SynthesizedLocal(initializerType, name: null); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)arrayTemp.Type; TypeSymbol arrayElementType = arrayType.ElementType; int arrayRank = arrayType.Rank; // NOTE: we pin the pointer, not the array. Debug.Assert(!arrayTemp.IsPinned); Debug.Assert(localSymbol.IsPinned); //(temp = array) BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(arrayTemp), initializerExpr); //(temp = array) != null BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual); BoundExpression lengthCall; if (arrayRank == 1) { lengthCall = factory.ArrayLength(factory.Local(arrayTemp)); } else { MethodSymbol lengthMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod)) { lengthCall = factory.Call(factory.Local(arrayTemp), lengthMethod); } else { lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(factory.Local(arrayTemp)), ErrorTypeSymbol.UnknownResultType); } } // NOTE: dev10 comment says ">", but code actually checks "!=" //temp.Length != 0 BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0)); //((temp = array) != null && temp.Length != 0) BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck); //temp[0] BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(arrayTemp)); // NOTE: this is a fixed statement address-of in that it's the initial value of pinned local. //&temp[0] BoundExpression firstElementAddress = new BoundAddressOfOperator(factory.Syntax, firstElement, isFixedStatementAddressOf: true, type: new PointerTypeSymbol(arrayElementType)); BoundExpression convertedFirstElementAddress = factory.Convert( localType, firstElementAddress, fixedInitializer.ElementPointerTypeConversion); //loc = &temp[0] BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress); //loc = null BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType)); //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null) BoundStatement localInit = factory.ExpressionStatement( new BoundConditionalOperator(factory.Syntax, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType)); return(AddLocalDeclarationSequencePointIfNecessary(fixedInitializer.Syntax.Parent.Parent, localSymbol, localInit)); }
protected override void InitializeStateMachine(ArrayBuilder <BoundStatement> bodyBuilder, NamedTypeSymbol frameType, LocalSymbol stateMachineLocal) { if (frameType.TypeKind == TypeKind.Class) { // local = new {state machine type}(); bodyBuilder.Add( F.Assignment( F.Local(stateMachineLocal), F.New(frameType.InstanceConstructors[0]))); } }
public override BoundNode VisitTryStatement(BoundTryStatement node) { var tryStatementSyntax = node.Syntax; // If you add a syntax kind to the assertion below, please also ensure // that the scenario has been tested with Edit-and-Continue. Debug.Assert( tryStatementSyntax.IsKind(SyntaxKind.TryStatement) || tryStatementSyntax.IsKind(SyntaxKind.UsingStatement) || tryStatementSyntax.IsKind(SyntaxKind.ForEachStatement) || tryStatementSyntax.IsKind(SyntaxKind.ForEachVariableStatement) || tryStatementSyntax.IsKind(SyntaxKind.LocalDeclarationStatement) || tryStatementSyntax.IsKind(SyntaxKind.LockStatement)); BoundStatement finalizedRegion; BoundBlock rewrittenFinally; var finallyContainsAwaits = _analysis.FinallyContainsAwaits(node); if (!finallyContainsAwaits) { finalizedRegion = RewriteFinalizedRegion(node); rewrittenFinally = (BoundBlock)this.Visit(node.FinallyBlockOpt); if (rewrittenFinally == null) { return(finalizedRegion); } var asTry = finalizedRegion as BoundTryStatement; if (asTry != null) { // since finalized region is a try we can just attach finally to it Debug.Assert(asTry.FinallyBlockOpt == null); return(asTry.Update(asTry.TryBlock, asTry.CatchBlocks, rewrittenFinally, asTry.FinallyLabelOpt, asTry.PreferFaultHandler)); } else { // wrap finalizedRegion into a Try with a finally. return(_F.Try((BoundBlock)finalizedRegion, ImmutableArray <BoundCatchBlock> .Empty, rewrittenFinally)); } } // rewrite finalized region (try and catches) in the current frame var frame = PushFrame(node); finalizedRegion = RewriteFinalizedRegion(node); rewrittenFinally = (BoundBlock)this.VisitBlock(node.FinallyBlockOpt); PopFrame(); var exceptionType = _F.SpecialType(SpecialType.System_Object); var pendingExceptionLocal = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(exceptionType), SynthesizedLocalKind.TryAwaitPendingException, tryStatementSyntax); var finallyLabel = _F.GenerateLabel("finallyLabel"); var pendingBranchVar = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(_F.SpecialType(SpecialType.System_Int32)), SynthesizedLocalKind.TryAwaitPendingBranch, tryStatementSyntax); var catchAll = _F.Catch(_F.Local(pendingExceptionLocal), _F.Block()); var catchAndPendException = _F.Try( _F.Block( finalizedRegion, _F.HiddenSequencePoint(), _F.Goto(finallyLabel), PendBranches(frame, pendingBranchVar, finallyLabel)), ImmutableArray.Create(catchAll), finallyLabel: finallyLabel); BoundBlock syntheticFinallyBlock = _F.Block( _F.HiddenSequencePoint(), _F.Label(finallyLabel), rewrittenFinally, _F.HiddenSequencePoint(), UnpendException(pendingExceptionLocal), UnpendBranches( frame, pendingBranchVar, pendingExceptionLocal)); BoundStatement syntheticFinally = syntheticFinallyBlock; if (_F.CurrentFunction.IsAsync && _F.CurrentFunction.IsIterator) { // We wrap this block so that it can be processed as a finally block by async-iterator rewriting syntheticFinally = _F.ExtractedFinallyBlock(syntheticFinallyBlock); } var locals = ArrayBuilder <LocalSymbol> .GetInstance(); var statements = ArrayBuilder <BoundStatement> .GetInstance(); statements.Add(_F.HiddenSequencePoint()); locals.Add(pendingExceptionLocal); statements.Add(_F.Assignment(_F.Local(pendingExceptionLocal), _F.Default(pendingExceptionLocal.Type))); locals.Add(pendingBranchVar); statements.Add(_F.Assignment(_F.Local(pendingBranchVar), _F.Default(pendingBranchVar.Type))); LocalSymbol returnLocal = frame.returnValue; if (returnLocal != null) { locals.Add(returnLocal); } statements.Add(catchAndPendException); statements.Add(syntheticFinally); var completeTry = _F.Block( locals.ToImmutableAndFree(), statements.ToImmutableAndFree()); return(completeTry); }
internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, DiagnosticBag diagnostics) { throw new NotImplementedException(); }
protected override void InitializeStateMachine(ArrayBuilder<BoundStatement> bodyBuilder, NamedTypeSymbol frameType, LocalSymbol stateMachineLocal) { // var stateMachineLocal = new IteratorImplementationClass(N) // where N is either 0 (if we're producing an enumerator) or -2 (if we're producing an enumerable) int initialState = _isEnumerable ? StateMachineStates.FinishedStateMachine : StateMachineStates.FirstUnusedState; bodyBuilder.Add( F.Assignment( F.Local(stateMachineLocal), F.New(stateMachineType.Constructor.AsMember(frameType), F.Literal(initialState)))); }
internal LocalUsedWalker(LocalSymbol local) { _local = local; }
private bool IsStackLocal(LocalSymbol local) { return _stackLocals != null && _stackLocals.Contains(local); }
private void FreeLocals(BoundSequence sequence, LocalSymbol doNotRelease) { if (sequence.Locals.IsEmpty) { return; } _builder.CloseLocalScope(); foreach (var local in sequence.Locals) { if ((object)local != doNotRelease) { FreeLocal(local); } } }
private BoundStatement InitializeFixedStatementStringLocal( LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol stringTemp, out LocalSymbol localToClear) { TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; // intervening parens may have been skipped by the binder; find the declarator VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf<VariableDeclaratorSyntax>(); Debug.Assert(declarator != null); stringTemp = factory.SynthesizedLocal(initializerType, syntax: declarator, isPinned: true, kind: SynthesizedLocalKind.FixedString); // NOTE: we pin the string, not the pointer. Debug.Assert(stringTemp.IsPinned); Debug.Assert(!localSymbol.IsPinned); BoundStatement stringTempInit = factory.Assignment(factory.Local(stringTemp), initializerExpr); var convertedStringTemp = factory.Convert( localType, factory.Local(stringTemp), fixedInitializer.ElementPointerTypeConversion); BoundStatement localInit = AddLocalDeclarationSequencePointIfNecessary(declarator, localSymbol, factory.Assignment(factory.Local(localSymbol), convertedStringTemp)); BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, factory.Local(stringTemp), BinaryOperatorKind.NotEqual); BoundExpression helperCall; MethodSymbol offsetMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData, out offsetMethod)) { helperCall = factory.Call(receiver: null, method: offsetMethod); } else { helperCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray<Symbol>.Empty, ImmutableArray<BoundNode>.Empty, ErrorTypeSymbol.UnknownResultType); } BoundExpression addition = factory.Binary(BinaryOperatorKind.PointerAndIntAddition, localType, factory.Local(localSymbol), helperCall); BoundStatement conditionalAdd = factory.If(notNullCheck, factory.Assignment(factory.Local(localSymbol), addition)); localToClear = stringTemp; return factory.Block(stringTempInit, localInit, conditionalAdd); }
public virtual TResult VisitLocal(LocalSymbol symbol) { return(DefaultVisit(symbol)); }
public virtual void VisitLocal(LocalSymbol symbol) { DefaultVisit(symbol); }
protected override BoundStatement GenerateStateMachineCreation(LocalSymbol stateMachineVariable, NamedTypeSymbol frameType) { return F.Return(F.Local(stateMachineVariable)); }
internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, DiagnosticBag diagnostics = null) { return(null); }
private BoundStatement InitializeFixedStatementLocal( BoundLocalDeclaration localDecl, SyntheticBoundNodeFactory factory, out LocalSymbol temp, out LocalSymbol localToClear) { BoundExpression initializer = localDecl.InitializerOpt; Debug.Assert(!ReferenceEquals(initializer, null)); LocalSymbol localSymbol = localDecl.LocalSymbol; if (initializer.Kind == BoundKind.FixedLocalCollectionInitializer) { var fixedInitializer = (BoundFixedLocalCollectionInitializer)initializer; if (fixedInitializer.Expression.Type.SpecialType == SpecialType.System_String) { return InitializeFixedStatementStringLocal(localSymbol, fixedInitializer, factory, out temp, out localToClear); } else { Debug.Assert(fixedInitializer.Expression.Type.IsArray()); localToClear = localSymbol; return InitializeFixedStatementArrayLocal(localSymbol, fixedInitializer, factory, out temp); } } else { temp = null; localToClear = localSymbol; return RewriteLocalDeclaration(localDecl.Syntax, localSymbol, VisitExpression(initializer)); } }
private BoundStatement GenerateAwaitOnCompletedDynamic(LocalSymbol awaiterTemp) { // temp $criticalNotifyCompletedTemp = $awaiterTemp as ICriticalNotifyCompletion // if ($criticalNotifyCompletedTemp != null) // { // this.builder.AwaitUnsafeOnCompleted<ICriticalNotifyCompletion,TSM>( // ref $criticalNotifyCompletedTemp, // ref this) // } // else // { // temp $notifyCompletionTemp = (INotifyCompletion)$awaiterTemp // this.builder.AwaitOnCompleted<INotifyCompletion,TSM>(ref $notifyCompletionTemp, ref this) // free $notifyCompletionTemp // } // free $criticalNotifyCompletedTemp var criticalNotifyCompletedTemp = F.SynthesizedLocal( F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_ICriticalNotifyCompletion), null); var notifyCompletionTemp = F.SynthesizedLocal( F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_INotifyCompletion), null); LocalSymbol thisTemp = (F.CurrentType.TypeKind == TypeKind.Class) ? F.SynthesizedLocal(F.CurrentType) : null; var blockBuilder = ArrayBuilder <BoundStatement> .GetInstance(); blockBuilder.Add( F.Assignment( F.Local(criticalNotifyCompletedTemp), // Use reference conversion rather than dynamic conversion: F.As(F.Local(awaiterTemp), criticalNotifyCompletedTemp.Type))); if (thisTemp != null) { blockBuilder.Add(F.Assignment(F.Local(thisTemp), F.This())); } blockBuilder.Add( F.If( condition: F.ObjectEqual(F.Local(criticalNotifyCompletedTemp), F.Null(criticalNotifyCompletedTemp.Type)), thenClause: F.Block( ImmutableArray.Create(notifyCompletionTemp), F.Assignment( F.Local(notifyCompletionTemp), // Use reference conversion rather than dynamic conversion: F.Convert(notifyCompletionTemp.Type, F.Local(awaiterTemp), Conversion.ExplicitReference)), F.ExpressionStatement( F.Call( F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.AwaitOnCompleted.Construct( notifyCompletionTemp.Type, F.This().Type), F.Local(notifyCompletionTemp), F.This(thisTemp))), F.Assignment( F.Local(notifyCompletionTemp), F.NullOrDefault(notifyCompletionTemp.Type))), elseClauseOpt: F.Block( F.ExpressionStatement( F.Call( F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.AwaitUnsafeOnCompleted.Construct( criticalNotifyCompletedTemp.Type, F.This().Type), F.Local(criticalNotifyCompletedTemp), F.This(thisTemp)))))); blockBuilder.Add( F.Assignment( F.Local(criticalNotifyCompletedTemp), F.NullOrDefault(criticalNotifyCompletedTemp.Type))); return(F.Block( SingletonOrPair(criticalNotifyCompletedTemp, thisTemp), blockBuilder.ToImmutableAndFree())); }
private BoundStatement InitializeFixedStatementArrayLocal( LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol arrayTemp) { // From ExpressionBinder::BindPtrToArray: // (((temp = array) != null && temp.Length > 0) ? loc = &temp[0] : loc = null) // NOTE: The assignment needs to be inside the EK_QUESTIONMARK. See Whidbey bug #397859. // We can't do loc = (... ? ... : ...) since the CLR type of &temp[0] is a managed // pointer and null is a UIntPtr - which confuses the JIT. We can't just convert // &temp[0] to UIntPtr with a conv.u instruction because then if a GC occurs between // the time of the cast and the assignment to the local, we're toast. TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; arrayTemp = factory.SynthesizedLocal(initializerType); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)arrayTemp.Type; TypeSymbol arrayElementType = arrayType.ElementType; int arrayRank = arrayType.Rank; // NOTE: we pin the pointer, not the array. Debug.Assert(!arrayTemp.IsPinned); Debug.Assert(localSymbol.IsPinned); //(temp = array) BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(arrayTemp), initializerExpr); //(temp = array) != null BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual); BoundExpression lengthCall; if (arrayRank == 1) { lengthCall = factory.ArrayLength(factory.Local(arrayTemp)); } else { MethodSymbol lengthMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod)) { lengthCall = factory.Call(factory.Local(arrayTemp), lengthMethod); } else { lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(factory.Local(arrayTemp)), ErrorTypeSymbol.UnknownResultType); } } // NOTE: dev10 comment says ">", but code actually checks "!=" //temp.Length != 0 BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0)); //((temp = array) != null && temp.Length != 0) BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck); //temp[0] BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(arrayTemp)); // NOTE: this is a fixed statement address-of in that it's the initial value of pinned local. //&temp[0] BoundExpression firstElementAddress = new BoundAddressOfOperator(factory.Syntax, firstElement, isFixedStatementAddressOf: true, type: new PointerTypeSymbol(arrayElementType)); BoundExpression convertedFirstElementAddress = factory.Convert( localType, firstElementAddress, fixedInitializer.ElementPointerTypeConversion); //loc = &temp[0] BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress); //loc = null BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType)); //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null) BoundStatement localInit = factory.ExpressionStatement( new BoundConditionalOperator(factory.Syntax, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType)); return AddLocalDeclarationSequencePointIfNecessary(fixedInitializer.Syntax.Parent.Parent, localSymbol, localInit); }
private BoundStatement GenerateAwaitOnCompleted(TypeSymbol loweredAwaiterType, LocalSymbol awaiterTemp) { // this.builder.AwaitOnCompleted<TAwaiter,TSM>(ref $awaiterTemp, ref this) // or // this.builder.AwaitOnCompleted<TAwaiter,TSM>(ref $awaiterArrayTemp[0], ref this) LocalSymbol thisTemp = (F.CurrentType.TypeKind == TypeKind.Class) ? F.SynthesizedLocal(F.CurrentType) : null; HashSet <DiagnosticInfo> useSiteDiagnostics = null; var useUnsafeOnCompleted = F.Compilation.Conversions.ClassifyImplicitConversionFromType( loweredAwaiterType, F.Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ICriticalNotifyCompletion), ref useSiteDiagnostics).IsImplicit; var onCompleted = (useUnsafeOnCompleted ? _asyncMethodBuilderMemberCollection.AwaitUnsafeOnCompleted : _asyncMethodBuilderMemberCollection.AwaitOnCompleted).Construct(loweredAwaiterType, F.This().Type); if (_asyncMethodBuilderMemberCollection.CheckGenericMethodConstraints) { onCompleted.CheckConstraints(F.Compilation.Conversions, F.Syntax, F.Compilation, this.Diagnostics); } BoundExpression result = F.Call( F.Field(F.This(), _asyncMethodBuilderField), onCompleted, F.Local(awaiterTemp), F.This(thisTemp)); if (thisTemp != null) { result = F.Sequence( ImmutableArray.Create(thisTemp), ImmutableArray.Create <BoundExpression>(F.AssignmentExpression(F.Local(thisTemp), F.This())), result); } return(F.ExpressionStatement(result)); }