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;
        }
Ejemplo n.º 2
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);
 }
Ejemplo n.º 3
0
            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);
            }
Ejemplo n.º 4
0
        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);
 }
Ejemplo n.º 6
0
 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];
        }
Ejemplo n.º 8
0
        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;
        }
Ejemplo n.º 13
0
        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;
        }
Ejemplo n.º 14
0
        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);
        }
Ejemplo n.º 15
0
            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);
        }
Ejemplo n.º 17
0
        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));
        }
Ejemplo n.º 18
0
        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()));
        }
Ejemplo n.º 19
0
 private static ImmutableArray <LocalSymbol> SingletonOrPair(LocalSymbol first, LocalSymbol secondOpt)
 {
     return((secondOpt == null) ? ImmutableArray.Create(first) : ImmutableArray.Create(first, secondOpt));
 }
Ejemplo n.º 20
0
 internal static BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, SyntaxNode syntax, LocalSymbol local)
 {
     return(RewriteLocalInternal(compilation, container, syntax, local));
 }
Ejemplo n.º 21
0
        /// <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));
        }
Ejemplo n.º 22
0
        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);
        }
Ejemplo n.º 23
0
 private bool IsStackLocal(LocalSymbol local)
 {
     return(_stackLocals != null && _stackLocals.Contains(local));
 }
Ejemplo n.º 24
0
 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));
 }
Ejemplo n.º 26
0
            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);
            }
Ejemplo n.º 27
0
        /// <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&lt;DelegateType&gt;(ref _event, tmp2, tmp1);
        /// } while ((object)tmp0 != (object)tmp1);
        ///
        /// Note, if System.Threading.Interlocked.CompareExchange&lt;T&gt; 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
            });
        }
Ejemplo n.º 28
0
 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)
 {
 }
Ejemplo n.º 29
0
 /// <summary>
 /// Generate implementation-specific state machine initialization for the kickoff method body.
 /// </summary>
 protected abstract BoundStatement GenerateStateMachineCreation(LocalSymbol stateMachineVariable, NamedTypeSymbol frameType);
Ejemplo n.º 30
0
 /// <summary>
 /// Initialize the state machine class.
 /// </summary>
 protected abstract void InitializeStateMachine(ArrayBuilder <BoundStatement> bodyBuilder, NamedTypeSymbol frameType, LocalSymbol stateMachineLocal);
Ejemplo n.º 31
0
 internal static bool IsStackLocal(LocalSymbol local, HashSet <LocalSymbol> stackLocalsOpt)
 => stackLocalsOpt?.Contains(local) ?? false;
Ejemplo n.º 32
0
        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)));
        }
Ejemplo n.º 33
0
 private bool IsStackLocal(LocalSymbol local) => IsStackLocal(local, _stackLocals);
Ejemplo n.º 34
0
        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))));
        }
Ejemplo n.º 35
0
 public ByType(BoundExpression expression, TypeSymbol type, LocalSymbol temp) : base(expression, type, temp)
 {
 }
Ejemplo n.º 36
0
        /// <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);
        }
Ejemplo n.º 37
0
 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();
                 }
             }
         }
     }
 }
Ejemplo n.º 38
0
        /// <summary>
        /// fixed(int* ptr = arr){ ... }    == becomes ===>
        ///
        /// pinned int[] pinnedTemp = arr;         // pinning managed ref
        /// int* ptr = pinnedTemp != null &amp;&amp; pinnedTemp.Length != 0
        ///                (int*)&amp;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));
        }
Ejemplo n.º 39
0
 private static BoundExpression RewriteLocalInternal(CSharpCompilation compilation, EENamedTypeSymbol container, SyntaxNode syntax, LocalSymbol local)
 {
     return(new BoundPseudoVariable(
                syntax,
                local,
                new ObjectIdExpressions(compilation),
                local.Type.TypeSymbol));
 }
Ejemplo n.º 40
0
        // 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;
        }
Ejemplo n.º 41
0
 /// <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));
 }
Ejemplo n.º 42
0
 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));
        }
Ejemplo n.º 45
0
 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);
        }
Ejemplo n.º 47
0
 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))));
 }
Ejemplo n.º 49
0
 internal LocalUsedWalker(LocalSymbol local)
 {
     _local = local;
 }
Ejemplo n.º 50
0
 private bool IsStackLocal(LocalSymbol local)
 {
     return _stackLocals != null && _stackLocals.Contains(local);
 }
Ejemplo n.º 51
0
        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);
        }
Ejemplo n.º 53
0
 public virtual TResult VisitLocal(LocalSymbol symbol)
 {
     return(DefaultVisit(symbol));
 }
Ejemplo n.º 54
0
 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));
            }
        }
Ejemplo n.º 58
0
        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);
        }
Ejemplo n.º 60
0
        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));
        }