예제 #1
0
 private BoundExpression RewriteLocal(BoundLocal node)
 {
     var local = node.LocalSymbol;
     var placeholder = local as PlaceholderLocalSymbol;
     if ((object)placeholder != null)
     {
         return placeholder.RewriteLocal(_compilation, _container, node.Syntax, _diagnostics);
     }
     if (_declaredLocals.Contains(local))
     {
         return ObjectIdLocalSymbol.RewriteLocal(_compilation, _container, node.Syntax, local);
     }
     return node;
 }
예제 #2
0
 public override BoundNode VisitLocal(BoundLocal node)
 {
     var local = node.LocalSymbol;
     if (!local.IsCompilerGenerated)
     {
         var variable = this.GetVariable(local.Name);
         if (variable != null)
         {
             var result = variable.ToBoundExpression(node.Syntax);
             Debug.Assert(node.Type == result.Type);
             return result;
         }
     }
     return node;
 }
예제 #3
0
        private void EmitLocalAddress(BoundLocal localAccess)
        {
            var local = localAccess.LocalSymbol;

            if (IsStackLocal(local))
            {
                if (local.RefKind != RefKind.None)
                {
                    // do nothing, ref should be on the stack
                }
                else
                {
                    // cannot get address of a stack value. 
                    // Something is wrong with optimizer
                    throw ExceptionUtilities.UnexpectedValue(local.RefKind);
                }
            }
            else
            {
                builder.EmitLocalAddress(GetLocal(localAccess));
            }
        }
예제 #4
0
        /// <summary>
        /// Generate a class containing methods that represent
        /// the set of arguments and locals at the current scope.
        /// </summary>
        internal CommonPEModuleBuilder CompileGetLocals(
            string typeName,
            ArrayBuilder<LocalAndMethod> localBuilder,
            bool argumentsOnly,
            ImmutableArray<Alias> aliases,
            Microsoft.CodeAnalysis.CodeGen.CompilationTestData testData,
            DiagnosticBag diagnostics)
        {
            var objectType = this.Compilation.GetSpecialType(SpecialType.System_Object);
            var allTypeParameters = _currentFrame.GetAllTypeParameters();
            var additionalTypes = ArrayBuilder<NamedTypeSymbol>.GetInstance();

            EENamedTypeSymbol typeVariablesType = null;
            if (!argumentsOnly && (allTypeParameters.Length > 0))
            {
                // Generate a generic type with matching type parameters.
                // A null instance of the type will be used to represent the
                // "Type variables" local.
                typeVariablesType = new EENamedTypeSymbol(
                    this.Compilation.SourceModule.GlobalNamespace,
                    objectType,
                    _syntax,
                    _currentFrame,
                    ExpressionCompilerConstants.TypeVariablesClassName,
                    (m, t) => ImmutableArray.Create<MethodSymbol>(new EEConstructorSymbol(t)),
                    allTypeParameters,
                    (t1, t2) => allTypeParameters.SelectAsArray((tp, i, t) => (TypeParameterSymbol)new SimpleTypeParameterSymbol(t, i, tp.Name), t2));
                additionalTypes.Add(typeVariablesType);
            }

            var synthesizedType = new EENamedTypeSymbol(
                Compilation.SourceModule.GlobalNamespace,
                objectType,
                _syntax,
                _currentFrame,
                typeName,
                (m, container) =>
                {
                    var methodBuilder = ArrayBuilder<MethodSymbol>.GetInstance();

                    if (!argumentsOnly)
                    {
                        // Pseudo-variables: $exception, $ReturnValue, etc.
                        if (aliases.Length > 0)
                        {
                            var sourceAssembly = Compilation.SourceAssembly;
                            var typeNameDecoder = new EETypeNameDecoder(Compilation, (PEModuleSymbol)_currentFrame.ContainingModule);
                            foreach (var alias in aliases)
                            {
                                if (alias.IsReturnValueWithoutIndex())
                                {
                                    Debug.Assert(aliases.Count(a => a.Kind == DkmClrAliasKind.ReturnValue) > 1);
                                    continue;
                                }

                                var local = PlaceholderLocalSymbol.Create(
                                    typeNameDecoder,
                                    _currentFrame,
                                    sourceAssembly,
                                    alias);
                                var methodName = GetNextMethodName(methodBuilder);
                                var syntax = SyntaxFactory.IdentifierName(SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken));
                                var aliasMethod = this.CreateMethod(container, methodName, syntax, (method, diags) =>
                                {
                                    var expression = new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type);
                                    return new BoundReturnStatement(syntax, expression) { WasCompilerGenerated = true };
                                });
                                var flags = local.IsWritable ? DkmClrCompilationResultFlags.None : DkmClrCompilationResultFlags.ReadOnlyResult;
                                localBuilder.Add(MakeLocalAndMethod(local, aliasMethod, flags));
                                methodBuilder.Add(aliasMethod);
                            }
                        }

                        // "this" for non-static methods that are not display class methods or
                        // display class methods where the display class contains "<>4__this".
                        if (!m.IsStatic && (!IsDisplayClassType(m.ContainingType) || _displayClassVariables.ContainsKey(GeneratedNames.ThisProxyFieldName())))
                        {
                            var methodName = GetNextMethodName(methodBuilder);
                            var method = this.GetThisMethod(container, methodName);
                            localBuilder.Add(new CSharpLocalAndMethod("this", "this", method, DkmClrCompilationResultFlags.None)); // Note: writable in dev11.
                            methodBuilder.Add(method);
                        }
                    }

                    // Hoisted method parameters (represented as locals in the EE).
                    if (!_hoistedParameterNames.IsEmpty)
                    {
                        int localIndex = 0;
                        foreach (var local in _localsForBinding)
                        {
                            // Since we are showing hoisted method parameters first, the parameters may appear out of order
                            // in the Locals window if only some of the parameters are hoisted.  This is consistent with the
                            // behavior of the old EE.
                            if (_hoistedParameterNames.Contains(local.Name))
                            {
                                AppendLocalAndMethod(localBuilder, methodBuilder, local, container, localIndex, GetLocalResultFlags(local));
                            }

                            localIndex++;
                        }
                    }

                    // Method parameters (except those that have been hoisted).
                    int parameterIndex = m.IsStatic ? 0 : 1;
                    foreach (var parameter in m.Parameters)
                    {
                        var parameterName = parameter.Name;
                        if (!_hoistedParameterNames.Contains(parameterName) && GeneratedNames.GetKind(parameterName) == GeneratedNameKind.None)
                        {
                            AppendParameterAndMethod(localBuilder, methodBuilder, parameter, container, parameterIndex);
                        }

                        parameterIndex++;
                    }

                    if (!argumentsOnly)
                    {
                        // Locals.
                        int localIndex = 0;
                        foreach (var local in _localsForBinding)
                        {
                            if (!_hoistedParameterNames.Contains(local.Name))
                            {
                                AppendLocalAndMethod(localBuilder, methodBuilder, local, container, localIndex, GetLocalResultFlags(local));
                            }

                            localIndex++;
                        }

                        // "Type variables".
                        if ((object)typeVariablesType != null)
                        {
                            var methodName = GetNextMethodName(methodBuilder);
                            var returnType = typeVariablesType.Construct(allTypeParameters.Cast<TypeParameterSymbol, TypeSymbol>());
                            var method = this.GetTypeVariablesMethod(container, methodName, returnType);
                            localBuilder.Add(new CSharpLocalAndMethod(
                                ExpressionCompilerConstants.TypeVariablesLocalName,
                                ExpressionCompilerConstants.TypeVariablesLocalName,
                                method,
                                DkmClrCompilationResultFlags.ReadOnlyResult));
                            methodBuilder.Add(method);
                        }
                    }

                    return methodBuilder.ToImmutableAndFree();
                });

            additionalTypes.Add(synthesizedType);

            var module = CreateModuleBuilder(
                this.Compilation,
                synthesizedType.Methods,
                additionalTypes: additionalTypes.ToImmutableAndFree(),
                synthesizedType: synthesizedType,
                testData: testData,
                diagnostics: diagnostics);

            Debug.Assert(module != null);

            this.Compilation.Compile(
                module,
                win32Resources: null,
                xmlDocStream: null,
                emittingPdb: false,
                diagnostics: diagnostics,
                filterOpt: null,
                cancellationToken: CancellationToken.None);

            return diagnostics.HasAnyErrors() ? null : module;
        }
예제 #5
0
            // private static T <Factory>(object[] submissionArray) 
            // {
            //     var submission = new Submission#N(submissionArray);
            //     return submission.<Initialize>();
            // }
            internal override BoundBlock CreateBody()
            {
                var syntax = this.GetSyntax();

                var ctor = _containingType.GetScriptConstructor();
                Debug.Assert(ctor.ParameterCount == 1);

                var initializer = _containingType.GetScriptInitializer();
                Debug.Assert(initializer.ParameterCount == 0);

                var submissionArrayParameter = new BoundParameter(syntax, _parameters[0]) { WasCompilerGenerated = true };
                var submissionLocal = new BoundLocal(
                    syntax,
                    new SynthesizedLocal(this, _containingType, SynthesizedLocalKind.LoweringTemp),
                    null,
                    _containingType)
                { WasCompilerGenerated = true };

                // var submission = new Submission#N(submissionArray);
                var submissionAssignment = new BoundExpressionStatement(
                    syntax,
                    new BoundAssignmentOperator(
                        syntax,
                        submissionLocal,
                        new BoundObjectCreationExpression(
                            syntax,
                            ctor,
                            ImmutableArray.Create<BoundExpression>(submissionArrayParameter),
                            default(ImmutableArray<string>),
                            default(ImmutableArray<RefKind>),
                            false,
                            default(ImmutableArray<int>),
                            null,
                            null,
                            _containingType)
                        { WasCompilerGenerated = true },
                        _containingType)
                    { WasCompilerGenerated = true })
                { WasCompilerGenerated = true };

                // return submission.<Initialize>();
                var initializeResult = CreateParameterlessCall(
                    syntax,
                    submissionLocal,
                    initializer);
                Debug.Assert(initializeResult.Type == _returnType);
                var returnStatement = new BoundReturnStatement(
                    syntax,
                    RefKind.None,
                    initializeResult)
                { WasCompilerGenerated = true };

                return new BoundBlock(syntax,
                    ImmutableArray.Create<LocalSymbol>(submissionLocal.LocalSymbol),
                    ImmutableArray<LocalFunctionSymbol>.Empty,
                    ImmutableArray.Create<BoundStatement>(submissionAssignment, returnStatement))
                { WasCompilerGenerated = true };
            }
예제 #6
0
        public override BoundNode VisitLocal(BoundLocal node)
        {
            CapturedSymbolReplacement proxy;
            if (proxies.TryGetValue(node.LocalSymbol, out proxy))
            {
                return proxy.Replacement(node.Syntax, frameType => FramePointer(node.Syntax, frameType));
            }

            Debug.Assert(!VariablesCaptured.Contains(node.LocalSymbol));
            LocalSymbol replacementLocal;
            if (this.localMap.TryGetValue(node.LocalSymbol, out replacementLocal))
            {
                return new BoundLocal(node.Syntax, replacementLocal, node.ConstantValueOpt, replacementLocal.Type, node.HasErrors);
            }

            return base.VisitLocal(node);
        }
        /// <summary>
        /// The rewrites are as follows:
        /// 
        /// x++
        ///     temp = x
        ///     x = temp + 1
        ///     return temp
        /// x--
        ///     temp = x
        ///     x = temp - 1
        ///     return temp
        /// ++x
        ///     temp = x + 1
        ///     x = temp
        ///     return temp
        /// --x
        ///     temp = x - 1
        ///     x = temp
        ///     return temp
        ///     
        /// In each case, the literal 1 is of the type required by the builtin addition/subtraction operator that
        /// will be used.  The temp is of the same type as x, but the sum/difference may be wider, in which case a
        /// conversion is required.
        /// </summary>
        /// <param name="node">The unary operator expression representing the increment/decrement.</param>
        /// <param name="isPrefix">True for prefix, false for postfix.</param>
        /// <param name="isIncrement">True for increment, false for decrement.</param>
        /// <returns>A bound sequence that uses a temp to acheive the correct side effects and return value.</returns>
        private BoundNode LowerOperator(BoundUnaryOperator node, bool isPrefix, bool isIncrement)
        {
            BoundExpression operand = node.Operand;
            TypeSymbol operandType = operand.Type; //type of the variable being incremented
            Debug.Assert(operandType == node.Type);

            ConstantValue constantOne;
            BinaryOperatorKind binaryOperatorKind;
            MakeConstantAndOperatorKind(node.OperatorKind.OperandTypes(), node, out constantOne, out binaryOperatorKind);
            binaryOperatorKind |= isIncrement ? BinaryOperatorKind.Addition : BinaryOperatorKind.Subtraction;

            Debug.Assert(constantOne != null);
            Debug.Assert(constantOne.SpecialType != SpecialType.None);
            Debug.Assert(binaryOperatorKind.OperandTypes() != 0);

            TypeSymbol constantType = compilation.GetSpecialType(constantOne.SpecialType);
            BoundExpression boundOne = new BoundLiteral(
                syntax: null,
                syntaxTree: null,
                constantValueOpt: constantOne,
                type: constantType);

            LocalSymbol tempSymbol = new TempLocalSymbol(operandType, RefKind.None, containingSymbol);
            BoundExpression boundTemp = new BoundLocal(
                syntax: null,
                syntaxTree: null,
                localSymbol: tempSymbol,
                constantValueOpt: null,
                type: operandType);

            // NOTE: the LHS may have a narrower type than the operator expects, but that
            // doesn't seem to cause any problems.  If a problem does arise, just add an
            // explicit BoundConversion.
            BoundExpression newValue = new BoundBinaryOperator(
                syntax: null,
                syntaxTree: null,
                operatorKind: binaryOperatorKind,
                left: isPrefix ? operand : boundTemp,
                right: boundOne,
                constantValueOpt: null,
                type: constantType);

            if (constantType != operandType)
            {
                newValue = new BoundConversion(
                    syntax: null,
                    syntaxTree: null,
                    operand: newValue,
                    conversionKind: operandType.IsEnumType() ? ConversionKind.ImplicitEnumeration : ConversionKind.ImplicitNumeric,
                    symbolOpt: null,
                    @checked: false,
                    explicitCastInCode: false,
                    constantValueOpt: null,
                    type: operandType);
            }

            ReadOnlyArray<BoundExpression> assignments = ReadOnlyArray<BoundExpression>.CreateFrom(
                new BoundAssignmentOperator(
                    syntax: null,
                    syntaxTree: null,
                    left: boundTemp,
                    right: isPrefix ? newValue : operand,
                    type: operandType),
                new BoundAssignmentOperator(
                    syntax: null,
                    syntaxTree: null,
                    left: operand,
                    right: isPrefix ? boundTemp : newValue,
                    type: operandType));

            return new BoundSequence(
                syntax: node.Syntax,
                syntaxTree: node.SyntaxTree,
                locals: ReadOnlyArray<LocalSymbol>.CreateFrom(tempSymbol),
                sideEffects: assignments,
                value: boundTemp,
                type: operandType);
        }
예제 #8
0
            public override BoundNode VisitLocal(BoundLocal node)
            {
                if (node.LocalSymbol == _local)
                {
                    _found = true;
                }

                return null;
            }
            internal override BoundBlock CreateBody(BindingDiagnosticBag diagnostics)
            {
                var syntax = DummySyntax();

                var ctor = _containingType.GetScriptConstructor();

                Debug.Assert(ctor.ParameterCount == 1);

                var initializer = _containingType.GetScriptInitializer();

                Debug.Assert(initializer.ParameterCount == 0);

                var submissionArrayParameter = new BoundParameter(syntax, _parameters[0])
                {
                    WasCompilerGenerated = true
                };
                var submissionLocal = new BoundLocal(
                    syntax,
                    new SynthesizedLocal(this, TypeWithAnnotations.Create(_containingType), SynthesizedLocalKind.LoweringTemp),
                    null,
                    _containingType)
                {
                    WasCompilerGenerated = true
                };

                // var submission = new Submission#N(submissionArray);
                var submissionAssignment = new BoundExpressionStatement(
                    syntax,
                    new BoundAssignmentOperator(
                        syntax,
                        submissionLocal,
                        new BoundObjectCreationExpression(
                            syntax,
                            ctor,
                            ImmutableArray.Create <BoundExpression>(submissionArrayParameter),
                            argumentNamesOpt: default(ImmutableArray <string>),
                            argumentRefKindsOpt: default(ImmutableArray <RefKind>),
                            expanded: false,
                            argsToParamsOpt: default(ImmutableArray <int>),
                            defaultArguments: default(BitVector),
                            constantValueOpt: null,
                            initializerExpressionOpt: null,
                            type: _containingType)
                {
                    WasCompilerGenerated = true
                },
                        _containingType)
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                };

                // return submission.<Initialize>();
                var initializeResult = CreateParameterlessCall(
                    syntax,
                    submissionLocal,
                    initializer);

                Debug.Assert(TypeSymbol.Equals(initializeResult.Type, _returnType.Type, TypeCompareKind.ConsiderEverything2));
                var returnStatement = new BoundReturnStatement(
                    syntax,
                    RefKind.None,
                    initializeResult,
                    @checked: false)
                {
                    WasCompilerGenerated = true
                };

                return(new BoundBlock(syntax,
                                      ImmutableArray.Create <LocalSymbol>(submissionLocal.LocalSymbol),
                                      ImmutableArray.Create <BoundStatement>(submissionAssignment, returnStatement))
                {
                    WasCompilerGenerated = true
                });
            }
            internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
            {
                AnonymousTypeManager      manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager;
                SyntheticBoundNodeFactory F       = this.CreateBoundNodeFactory(compilationState, diagnostics);

                //  Method body:
                //
                //  {
                //      $anonymous$ local = value as $anonymous$;
                //      return local != null
                //             && System.Collections.Generic.EqualityComparer<T_1>.Default.Equals(this.backingFld_1, local.backingFld_1)
                //             ...
                //             && System.Collections.Generic.EqualityComparer<T_N>.Default.Equals(this.backingFld_N, local.backingFld_N);
                //  }

                // Type and type expression
                AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType;

                //  local
                BoundAssignmentOperator assignmentToTemp;
                BoundLocal boundLocal = F.StoreToTemp(F.As(F.Parameter(_parameters[0]), anonymousType), out assignmentToTemp);

                //  Generate: statement <= 'local = value as $anonymous$'
                BoundStatement assignment = F.ExpressionStatement(assignmentToTemp);

                //  Generate expression for return statement
                //      retExpression <= 'local != null'
                BoundExpression retExpression = F.Binary(BinaryOperatorKind.ObjectNotEqual,
                                                         manager.System_Boolean,
                                                         F.Convert(manager.System_Object, boundLocal),
                                                         F.Null(manager.System_Object));

                //  prepare symbols
                MethodSymbol    equalityComparer_Equals      = manager.System_Collections_Generic_EqualityComparer_T__Equals;
                MethodSymbol    equalityComparer_get_Default = manager.System_Collections_Generic_EqualityComparer_T__get_Default;
                NamedTypeSymbol equalityComparerType         = equalityComparer_Equals.ContainingType;

                // Compare fields
                for (int index = 0; index < anonymousType.Properties.Length; index++)
                {
                    // Prepare constructed symbols
                    TypeParameterSymbol typeParameter = anonymousType.TypeParameters[index];
                    FieldSymbol         fieldSymbol   = anonymousType.Properties[index].BackingField;
                    NamedTypeSymbol     constructedEqualityComparer = equalityComparerType.Construct(typeParameter);

                    // Generate 'retExpression' = 'retExpression && System.Collections.Generic.EqualityComparer<T_index>.
                    //                                                  Default.Equals(this.backingFld_index, local.backingFld_index)'
                    retExpression = F.LogicalAnd(retExpression,
                                                 F.Call(F.StaticCall(constructedEqualityComparer,
                                                                     equalityComparer_get_Default.AsMember(constructedEqualityComparer)),
                                                        equalityComparer_Equals.AsMember(constructedEqualityComparer),
                                                        F.Field(F.This(), fieldSymbol),
                                                        F.Field(boundLocal, fieldSymbol)));
                }

                // Final return statement
                BoundStatement retStatement = F.Return(retExpression);

                // Create a bound block
                F.CloseMethod(F.Block(ImmutableArray.Create <LocalSymbol>(boundLocal.LocalSymbol), assignment, retStatement));
            }
 internal IVariableDeclaratorOperation CreateVariableDeclarator(BoundLocal boundLocal)
 {
     return(boundLocal == null ? null : new VariableDeclaratorOperation(boundLocal.LocalSymbol.GetPublicSymbol(), initializer: null, ignoredArguments: ImmutableArray <IOperation> .Empty, semanticModel: _semanticModel, syntax: boundLocal.Syntax, type: null, constantValue: null, isImplicit: false));
 }
 public override BoundNode VisitLocal(BoundLocal node)
 {
     AddIfCaptured(node.LocalSymbol, node.Syntax);
     return(base.VisitLocal(node));
 }
예제 #13
0
 static BoundStatement makeAppendString(SyntheticBoundNodeFactory F, BoundLocal builder, string value)
 {
     return(F.ExpressionStatement(F.Call(receiver: builder, F.WellKnownMethod(WellKnownMember.System_Text_StringBuilder__AppendString), F.StringLiteral(value))));
 }
        // Generates:
        //
        // private static T {Factory}(InteractiveSession session)
        // {
        //    T submissionResult;
        //    new {ThisScriptClass}(session, out submissionResult);
        //    return submissionResult;
        // }
        private BoundBlock CreateSubmissionFactoryBody()
        {
            Debug.Assert(_containingType.TypeKind == TypeKind.Submission);

            SyntaxTree       syntaxTree = CSharpSyntaxTree.Dummy;
            CSharpSyntaxNode syntax     = (CSharpSyntaxNode)syntaxTree.GetRoot();

            var interactiveSessionParam = new BoundParameter(syntax, _parameters[0])
            {
                WasCompilerGenerated = true
            };

            var ctor = _containingType.InstanceConstructors.Single();

            Debug.Assert(ctor is SynthesizedInstanceConstructor);
            Debug.Assert(ctor.ParameterCount == 2);

            var submissionResultType = ctor.Parameters[1].Type;

            var resultLocal    = new SynthesizedLocal(ctor, submissionResultType, SynthesizedLocalKind.LoweringTemp);
            var localReference = new BoundLocal(syntax, resultLocal, null, submissionResultType)
            {
                WasCompilerGenerated = true
            };

            BoundExpression submissionResult = localReference;

            if (submissionResultType.IsStructType() && _returnType.SpecialType == SpecialType.System_Object)
            {
                submissionResult = new BoundConversion(syntax, submissionResult, Conversion.Boxing, false, true, ConstantValue.NotAvailable, _returnType)
                {
                    WasCompilerGenerated = true
                };
            }

            return(new BoundBlock(syntax,
                                  // T submissionResult;
                                  ImmutableArray.Create <LocalSymbol>(resultLocal),
                                  ImmutableArray.Create <BoundStatement>(
                                      // new Submission(interactiveSession, out submissionResult);
                                      new BoundExpressionStatement(syntax,
                                                                   new BoundObjectCreationExpression(
                                                                       syntax,
                                                                       ctor,
                                                                       ImmutableArray.Create <BoundExpression>(interactiveSessionParam, localReference),
                                                                       ImmutableArray <string> .Empty,
                                                                       ImmutableArray.Create <RefKind>(RefKind.None, RefKind.Ref),
                                                                       false,
                                                                       default(ImmutableArray <int>),
                                                                       null,
                                                                       null,
                                                                       _containingType
                                                                       )
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            },
                                      // return submissionResult;
                                      new BoundReturnStatement(syntax, submissionResult)
            {
                WasCompilerGenerated = true
            }))
            {
                WasCompilerGenerated = true
            });
        }
예제 #15
0
        public sealed override BoundNode VisitLocal(BoundLocal node)
        {
            BoundNode replacement;
            if (TryReplaceWithProxy(node.LocalSymbol, node.Syntax, out replacement))
            {
                return replacement;
            }

            // if a local needs a proxy it should have been allocated by its declaration node.
            Debug.Assert(!NeedsProxy(node.LocalSymbol));

            return VisitUnhoistedLocal(node);
        }
예제 #16
0
 /// <summary>
 /// Gets already declared and initialized local.
 /// </summary>
 private LocalDefinition GetLocal(BoundLocal localExpression)
 {
     var symbol = localExpression.LocalSymbol;
     return GetLocal(symbol);
 }
예제 #17
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundExpression originalLeft = node.Left;

            if (originalLeft.Kind != BoundKind.Local)
            {
                return(base.VisitAssignmentOperator(node));
            }

            var leftLocal = (BoundLocal)originalLeft;

            BoundExpression originalRight = node.Right;

            if (leftLocal.LocalSymbol.RefKind != RefKind.None &&
                node.IsRef &&
                NeedsProxy(leftLocal.LocalSymbol))
            {
                Debug.Assert(!proxies.ContainsKey(leftLocal.LocalSymbol));
                Debug.Assert(originalRight.Kind != BoundKind.ConvertedStackAllocExpression);
                //spilling ref local variables
                throw ExceptionUtilities.Unreachable;
            }

            if (NeedsProxy(leftLocal.LocalSymbol) && !proxies.ContainsKey(leftLocal.LocalSymbol))
            {
                Debug.Assert(leftLocal.LocalSymbol.DeclarationKind == LocalDeclarationKind.None);
                // spilling temp variables
                throw ExceptionUtilities.Unreachable;
            }

            BoundExpression rewrittenLeft  = (BoundExpression)this.Visit(leftLocal);
            BoundExpression rewrittenRight = (BoundExpression)this.Visit(originalRight);
            TypeSymbol      rewrittenType  = VisitType(node.Type);

            // Check if we're assigning the result of stackalloc to a hoisted local.
            // If we are, we need to store the result in a temp local and then assign
            // the value of the local to the field corresponding to the hoisted local.
            // If the receiver of the field is on the stack when the stackalloc happens,
            // popping it will free the memory (?) or otherwise cause verification issues.
            // DevDiv Bugs 59454
            if (rewrittenLeft.Kind != BoundKind.Local && originalRight.Kind == BoundKind.ConvertedStackAllocExpression)
            {
                // From ILGENREC::genAssign:
                // DevDiv Bugs 59454: Handle hoisted local initialized with a stackalloc
                // NOTE: Need to check for cast of stackalloc on RHS.
                // If LHS isLocal, then genAddr is a noop so regular case works fine.

                SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(this.CurrentMethod, rewrittenLeft.Syntax, this.CompilationState, this.Diagnostics);
                BoundAssignmentOperator   tempAssignment;
                BoundLocal tempLocal = factory.StoreToTemp(rewrittenRight, out tempAssignment);

                Debug.Assert(!node.IsRef);
                BoundAssignmentOperator rewrittenAssignment = node.Update(rewrittenLeft, tempLocal, node.IsRef, rewrittenType);

                return(new BoundSequence(
                           node.Syntax,
                           ImmutableArray.Create <LocalSymbol>(tempLocal.LocalSymbol),
                           ImmutableArray.Create <BoundExpression>(tempAssignment),
                           rewrittenAssignment,
                           rewrittenType));
            }

            return(node.Update(rewrittenLeft, rewrittenRight, node.IsRef, rewrittenType));
        }
예제 #18
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            var sequence = node.Left as BoundSequence;
            if (sequence != null)
            {
                // assigning to a sequence is uncommon, but could happen in a
                // case if LHS was a declaration expression.
                // 
                // Just rewrite {se1, se2, se3, val} = something
                // into ==>     {se1, se2, se3, val = something}
                BoundExpression rewritten = sequence.Update(sequence.Locals,
                                        sequence.SideEffects,
                                        node.Update(sequence.Value, node.Right, node.RefKind, node.Type),
                                        sequence.Type);

                rewritten = (BoundExpression)Visit(rewritten);

                // do not count the assignment twice
                _counter--;

                return rewritten;
            }


            var isIndirectAssignment = IsIndirectAssignment(node);

            var left = VisitExpression(node.Left, isIndirectAssignment ?
                                                    ExprContext.Address :
                                                    ExprContext.AssignmentTarget);

            // must delay recording a write until after RHS is evaluated
            var assignmentLocal = _assignmentLocal;
            _assignmentLocal = null;

            Debug.Assert(_context != ExprContext.AssignmentTarget, "assignment expression cannot be a target of another assignment");

            ExprContext rhsContext;
            if (node.RefKind != RefKind.None ||
                _context == ExprContext.Address)
            {
                // we need the address of rhs one way or another so we cannot have it on the stack.
                rhsContext = ExprContext.Address;
            }
            else
            {
                Debug.Assert(_context == ExprContext.Value ||
                             _context == ExprContext.Box ||
                             _context == ExprContext.Sideeffects, "assignment expression cannot be a target of another assignment");
                // we only need a value of rhs, so if otherwise possible it can be a stack value.
                rhsContext = ExprContext.Value;
            }

            // if right is a struct ctor, it may be optimized into in-place call
            // Such call will push the receiver ref before the arguments
            // so we need to ensure that arguments cannot use stack temps
            BoundExpression right = node.Right;
            object rhsCookie = null;
            if (right.Kind == BoundKind.ObjectCreationExpression &&
                right.Type.IsVerifierValue() &&
                ((BoundObjectCreationExpression)right).Constructor.ParameterCount != 0)
            {
                rhsCookie = this.GetStackStateCookie();
            }

            right = VisitExpression(node.Right, rhsContext);

            // if assigning to a local, now it is the time to record the Write
            if (assignmentLocal != null)
            {
                // This assert will fire if code relies on implicit CLR coercions 
                // - i.e assigns int value to a short local.
                // in that case we should force lhs to be a real local.
                Debug.Assert(
                    node.Left.Type.Equals(node.Right.Type, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true),
                    @"type of the assignment value is not the same as the type of assignment target. 
                This is not expected by the optimizer and is typically a result of a bug somewhere else.");

                Debug.Assert(!isIndirectAssignment, "indirect assignment is a read, not a write");

                LocalSymbol localSymbol = assignmentLocal.LocalSymbol;

                // Special Case: If the RHS is a pointer conversion, then the assignment functions as
                // a conversion (because the RHS will actually be typed as a native u/int in IL), so
                // we should not optimize away the local (i.e. schedule it on the stack).
                if (CanScheduleToStack(localSymbol) &&
                    assignmentLocal.Type.IsPointerType() && right.Kind == BoundKind.Conversion &&
                    ((BoundConversion)right).ConversionKind.IsPointerConversion())
                {
                    ShouldNotSchedule(localSymbol);
                }

                RecordVarWrite(localSymbol);
                assignmentLocal = null;
            }

            if (rhsCookie != null)
            {
                // we currently have the rhs on stack, adjust for that.
                PopEvalStack();
                this.EnsureStackState(rhsCookie);
            }

            return node.Update(left, right, node.RefKind, node.Type);
        }
예제 #19
0
            // private static void <Main>()
            // {
            //     var script = new Script();
            //     script.<Initialize>().GetAwaiter().GetResult();
            // }
            internal override BoundBlock CreateBody()
            {
                // CreateBody should only be called if no errors.
                Debug.Assert((object)_getAwaiterMethod != null);
                Debug.Assert((object)_getResultMethod != null);

                var syntax = this.GetSyntax();

                var ctor = _containingType.GetScriptConstructor();

                Debug.Assert(ctor.ParameterCount == 0);

                var initializer = _containingType.GetScriptInitializer();

                Debug.Assert(initializer.ParameterCount == 0);

                var scriptLocal = new BoundLocal(
                    syntax,
                    new SynthesizedLocal(this, _containingType, SynthesizedLocalKind.LoweringTemp),
                    null,
                    _containingType)
                {
                    WasCompilerGenerated = true
                };

                return(new BoundBlock(syntax,
                                      ImmutableArray.Create <LocalSymbol>(scriptLocal.LocalSymbol),
                                      ImmutableArray <LocalFunctionSymbol> .Empty,
                                      ImmutableArray.Create <BoundStatement>(
                                          // var script = new Script();
                                          new BoundExpressionStatement(
                                              syntax,
                                              new BoundAssignmentOperator(
                                                  syntax,
                                                  scriptLocal,
                                                  new BoundObjectCreationExpression(
                                                      syntax,
                                                      ctor)
                {
                    WasCompilerGenerated = true
                },
                                                  _containingType)
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                },
                                          // script.<Initialize>().GetAwaiter().GetResult();
                                          new BoundExpressionStatement(
                                              syntax,
                                              CreateParameterlessCall(
                                                  syntax,
                                                  CreateParameterlessCall(
                                                      syntax,
                                                      CreateParameterlessCall(
                                                          syntax,
                                                          scriptLocal,
                                                          initializer),
                                                      _getAwaiterMethod),
                                                  _getResultMethod))
                {
                    WasCompilerGenerated = true
                },
                                          // return;
                                          new BoundReturnStatement(
                                              syntax,
                                              RefKind.None,
                                              null)
                {
                    WasCompilerGenerated = true
                }))
                {
                    WasCompilerGenerated = true
                });
            }
 // Used to increment integer index into an array or string.
 private static BoundExpressionStatement MakePositionIncrement(SyntaxNode syntax, BoundLocal boundPositionVar, TypeSymbol intType)
 {
     return new BoundExpressionStatement(syntax,
         expression: new BoundAssignmentOperator(syntax, 
             left: boundPositionVar,
             right: new BoundBinaryOperator(syntax,
                 operatorKind: BinaryOperatorKind.IntAddition, // unchecked, never overflows since array/string index can't be >= Int32.MaxValue
                 left: boundPositionVar,
                 right: new BoundLiteral(syntax, 
                     constantValueOpt: ConstantValue.ConstantValueOne.Int32,
                     type: intType),
                 constantValueOpt: null, 
                 methodOpt: null, 
                 resultKind: LookupResultKind.Viable, 
                 type: intType),
             type: intType));
 }
예제 #21
0
            // private static void <Main>()
            // {
            //     var script = new Script();
            //     script.<Initialize>().GetAwaiter().GetResult();
            // }
            internal override BoundBlock CreateBody(DiagnosticBag diagnostics)
            {
                var syntax      = DummySyntax();
                var compilation = _containingType.DeclaringCompilation;

                // Creates a new top-level binder that just contains the global imports for the compilation.
                // The imports are required if a consumer of the scripting API is using a Task implementation
                // that uses extension methods.
                var binder = new InContainerBinder(
                    container: null,
                    next: new BuckStopsHereBinder(compilation),
                    imports: compilation.GlobalImports);

                binder = new InContainerBinder(compilation.GlobalNamespace, binder);

                var ctor = _containingType.GetScriptConstructor();

                Debug.Assert(ctor.ParameterCount == 0);

                var initializer = _containingType.GetScriptInitializer();

                Debug.Assert(initializer.ParameterCount == 0);

                var scriptLocal = new BoundLocal(
                    syntax,
                    new SynthesizedLocal(this, _containingType, SynthesizedLocalKind.LoweringTemp),
                    null,
                    _containingType)
                {
                    WasCompilerGenerated = true
                };

                var             initializeCall = CreateParameterlessCall(syntax, scriptLocal, initializer);
                BoundExpression getAwaiterGetResultCall;

                if (!binder.GetAwaitableExpressionInfo(initializeCall, out _, out _, out _, out getAwaiterGetResultCall, syntax, diagnostics))
                {
                    return(new BoundBlock(
                               syntax: syntax,
                               locals: ImmutableArray <LocalSymbol> .Empty,
                               statements: ImmutableArray <BoundStatement> .Empty,
                               hasErrors: true));
                }

                return(new BoundBlock(syntax,
                                      ImmutableArray.Create <LocalSymbol>(scriptLocal.LocalSymbol),
                                      ImmutableArray.Create <BoundStatement>(
                                          // var script = new Script();
                                          new BoundExpressionStatement(
                                              syntax,
                                              new BoundAssignmentOperator(
                                                  syntax,
                                                  scriptLocal,
                                                  new BoundObjectCreationExpression(
                                                      syntax,
                                                      ctor,
                                                      null)
                {
                    WasCompilerGenerated = true
                },
                                                  _containingType)
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                },
                                          // script.<Initialize>().GetAwaiter().GetResult();
                                          new BoundExpressionStatement(syntax, getAwaiterGetResultCall)
                {
                    WasCompilerGenerated = true
                },
                                          // return;
                                          new BoundReturnStatement(
                                              syntax,
                                              RefKind.None,
                                              null)
                {
                    WasCompilerGenerated = true
                }))
                {
                    WasCompilerGenerated = true
                });
            }
예제 #22
0
 public override BoundNode VisitLocal(BoundLocal node)
 {
     var result = RewriteLocal(node);
     Debug.Assert(result.Type == node.Type);
     return result;
 }
예제 #23
0
            // private static T <Factory>(object[] submissionArray)
            // {
            //     var submission = new Submission#N(submissionArray);
            //     return submission.<Initialize>();
            // }
            internal override BoundBlock CreateBody(DiagnosticBag diagnostics)
            {
                var syntax = DummySyntax();

                var ctor = _containingType.GetScriptConstructor();

                Debug.Assert(ctor.ParameterCount == 1);

                var initializer = _containingType.GetScriptInitializer();

                Debug.Assert(initializer.ParameterCount == 0);

                var submissionArrayParameter = new BoundParameter(syntax, _parameters[0])
                {
                    WasCompilerGenerated = true
                };
                var submissionLocal = new BoundLocal(
                    syntax,
                    new SynthesizedLocal(this, _containingType, SynthesizedLocalKind.LoweringTemp),
                    null,
                    _containingType)
                {
                    WasCompilerGenerated = true
                };

                // var submission = new Submission#N(submissionArray);
                var submissionAssignment = new BoundExpressionStatement(
                    syntax,
                    new BoundAssignmentOperator(
                        syntax,
                        submissionLocal,
                        new BoundObjectCreationExpression(
                            syntax,
                            ctor,
                            ImmutableArray.Create <BoundExpression>(submissionArrayParameter),
                            default(ImmutableArray <string>),
                            default(ImmutableArray <RefKind>),
                            false,
                            default(ImmutableArray <int>),
                            null,
                            null,
                            null,
                            _containingType)
                {
                    WasCompilerGenerated = true
                },
                        _containingType)
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                };

                // return submission.<Initialize>();
                var initializeResult = CreateParameterlessCall(
                    syntax,
                    submissionLocal,
                    initializer);

                Debug.Assert(initializeResult.Type == _returnType);
                var returnStatement = new BoundReturnStatement(
                    syntax,
                    RefKind.None,
                    initializeResult)
                {
                    WasCompilerGenerated = true
                };

                return(new BoundBlock(syntax,
                                      ImmutableArray.Create <LocalSymbol>(submissionLocal.LocalSymbol),
                                      ImmutableArray.Create <BoundStatement>(submissionAssignment, returnStatement))
                {
                    WasCompilerGenerated = true
                });
            }
예제 #24
0
            // private static void <Main>()
            // {
            //     var script = new Script();
            //     script.<Initialize>().GetAwaiter().GetResult();
            // }
            internal override BoundBlock CreateBody()
            {
                // CreateBody should only be called if no errors.
                Debug.Assert((object)_getAwaiterMethod != null);
                Debug.Assert((object)_getResultMethod != null);

                var syntax = this.GetSyntax();

                var ctor = _containingType.GetScriptConstructor();
                Debug.Assert(ctor.ParameterCount == 0);

                var initializer = _containingType.GetScriptInitializer();
                Debug.Assert(initializer.ParameterCount == 0);

                var scriptLocal = new BoundLocal(
                    syntax,
                    new SynthesizedLocal(this, _containingType, SynthesizedLocalKind.LoweringTemp),
                    null,
                    _containingType)
                { WasCompilerGenerated = true };

                return new BoundBlock(syntax,
                    ImmutableArray.Create<LocalSymbol>(scriptLocal.LocalSymbol),
                    ImmutableArray<LocalFunctionSymbol>.Empty,
                    ImmutableArray.Create<BoundStatement>(
                        // var script = new Script();
                        new BoundExpressionStatement(
                            syntax,
                            new BoundAssignmentOperator(
                                syntax,
                                scriptLocal,
                                new BoundObjectCreationExpression(
                                    syntax,
                                    ctor)
                                { WasCompilerGenerated = true },
                                _containingType)
                            { WasCompilerGenerated = true })
                        { WasCompilerGenerated = true },
                        // script.<Initialize>().GetAwaiter().GetResult();
                        new BoundExpressionStatement(
                            syntax,
                            CreateParameterlessCall(
                                syntax,
                                CreateParameterlessCall(
                                    syntax,
                                    CreateParameterlessCall(
                                        syntax,
                                        scriptLocal,
                                        initializer),
                                    _getAwaiterMethod),
                                _getResultMethod))
                        { WasCompilerGenerated = true },
                        // return;
                        new BoundReturnStatement(
                            syntax,
                            RefKind.None,
                            null)
                        { WasCompilerGenerated = true }))
                { WasCompilerGenerated = true };
            }
        private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bool used)
        {
            // Avoid rewriting if node has errors since at least
            // one of the operands is invalid.
            if (node.HasErrors)
            {
                return node;
            }

            var propertyAccessor = node.Left as BoundPropertyAccess;
            if (propertyAccessor == null)
            {
                return (BoundExpression)base.VisitAssignmentOperator(node);
            }

            // Rewrite property assignment into call to setter.
            var property = propertyAccessor.PropertySymbol.GetBaseProperty();
            var setMethod = property.SetMethod;
            Debug.Assert(setMethod != null);
            Debug.Assert(setMethod.Parameters.Count == 1);
            Debug.Assert(!setMethod.IsOverride);

            var rewrittenReceiver = (BoundExpression)Visit(propertyAccessor.ReceiverOpt);
            var rewrittenArgument = (BoundExpression)Visit(node.Right);

            if (used)
            {
                // Save expression value to a temporary before calling the
                // setter, and restore the temporary after the setter, so the
                // assignment can be used as an embedded expression.
                var exprType = rewrittenArgument.Type;
                var tempSymbol = new TempLocalSymbol(exprType, RefKind.None, containingSymbol);
                var tempLocal = new BoundLocal(null, null, tempSymbol, null, exprType);
                var saveTemp = new BoundAssignmentOperator(
                    null,
                    null,
                    tempLocal,
                    rewrittenArgument,
                    exprType);
                var call = BoundCall.SynthesizedCall(
                    rewrittenReceiver,
                    setMethod,
                    saveTemp);
                return new BoundSequence(
                    node.Syntax,
                    node.SyntaxTree,
                    ReadOnlyArray<LocalSymbol>.CreateFrom(tempSymbol),
                    ReadOnlyArray<BoundExpression>.CreateFrom(call),
                    tempLocal,
                    exprType);
            }
            else
            {
                return BoundCall.SynthesizedCall(
                    rewrittenReceiver,
                    setMethod,
                    rewrittenArgument);
            }
        }
예제 #26
0
 private EEMethodSymbol GetPseudoVariableMethod(
     TypeNameDecoder<PEModuleSymbol, TypeSymbol> typeNameDecoder,
     EENamedTypeSymbol container,
     string methodName,
     Alias alias)
 {
     var syntax = SyntaxFactory.IdentifierName(SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken));
     return this.CreateMethod(container, methodName, syntax, (method, diagnostics) =>
     {
         var local = PlaceholderLocalBinder.CreatePlaceholderLocal(typeNameDecoder, method, alias);
         var expression = new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type);
         return new BoundReturnStatement(syntax, expression) { WasCompilerGenerated = true };
     });
 }
        // Generates:
        // 
        // private static T {Factory}(InteractiveSession session) 
        // {
        //    T submissionResult;
        //    new {ThisScriptClass}(session, out submissionResult);
        //    return submissionResult;
        // }
        private BoundBlock CreateSubmissionFactoryBody()
        {
            Debug.Assert(_containingType.TypeKind == TypeKind.Submission);

            SyntaxTree syntaxTree = CSharpSyntaxTree.Dummy;
            CSharpSyntaxNode syntax = (CSharpSyntaxNode)syntaxTree.GetRoot();

            var interactiveSessionParam = new BoundParameter(syntax, _parameters[0]) { WasCompilerGenerated = true };

            var ctor = _containingType.InstanceConstructors.Single();
            Debug.Assert(ctor is SynthesizedInstanceConstructor);
            Debug.Assert(ctor.ParameterCount == 2);

            var submissionResultType = ctor.Parameters[1].Type;

            var resultLocal = new SynthesizedLocal(ctor, submissionResultType, SynthesizedLocalKind.LoweringTemp);
            var localReference = new BoundLocal(syntax, resultLocal, null, submissionResultType) { WasCompilerGenerated = true };

            BoundExpression submissionResult = localReference;
            if (submissionResultType.IsStructType() && _returnType.SpecialType == SpecialType.System_Object)
            {
                submissionResult = new BoundConversion(syntax, submissionResult, Conversion.Boxing, false, true, ConstantValue.NotAvailable, _returnType)
                { WasCompilerGenerated = true };
            }

            return new BoundBlock(syntax,
                // T submissionResult;
                ImmutableArray.Create<LocalSymbol>(resultLocal),
                ImmutableArray.Create<BoundStatement>(
                    // new Submission(interactiveSession, out submissionResult);
                    new BoundExpressionStatement(syntax,
                        new BoundObjectCreationExpression(
                            syntax,
                            ctor,
                            ImmutableArray.Create<BoundExpression>(interactiveSessionParam, localReference),
                            ImmutableArray<string>.Empty,
                            ImmutableArray.Create<RefKind>(RefKind.None, RefKind.Ref),
                            false,
                            default(ImmutableArray<int>),
                            null,
                            null,
                            _containingType
                        )
                        { WasCompilerGenerated = true })
                    { WasCompilerGenerated = true },
                    // return submissionResult;
                    new BoundReturnStatement(syntax, submissionResult) { WasCompilerGenerated = true }))
            { WasCompilerGenerated = true };
        }
예제 #28
0
 private EEMethodSymbol GetLocalMethod(EENamedTypeSymbol container, string methodName, string localName, int localIndex)
 {
     var syntax = SyntaxFactory.IdentifierName(localName);
     return this.CreateMethod(container, methodName, syntax, (method, diagnostics) =>
     {
         var local = method.LocalsForBinding[localIndex];
         var expression = new BoundLocal(syntax, local, constantValueOpt: local.GetConstantValue(null, null, diagnostics), type: local.Type);
         return new BoundReturnStatement(syntax, expression) { WasCompilerGenerated = true };
     });
 }
        public override BoundNode VisitLocal(BoundLocal node)
        {
            if (node.ConstantValueOpt == null)
            {
                switch (this.context)
                {
                    case ExprContext.Address:
                        if (node.LocalSymbol.RefKind != RefKind.None)
                        {
                            RecordVarRead(node.LocalSymbol);
                        }
                        else
                        {
                            RecordVarRef(node.LocalSymbol);
                        }
                        break;

                    case ExprContext.AssignmentTarget:
                        Debug.Assert(assignmentLocal == null);

                        // actual assignment will happen later, after Right is evaluated
                        // just remember what we are assigning to.
                        assignmentLocal = node;

                        // whatever is available as lastExpression is still available 
                        // (adjust for visit of this node)
                        this.lastExpressionCnt++;

                        break;

                    case ExprContext.Sideeffects:
                        break;

                    case ExprContext.Value:
                    case ExprContext.Box:
                        RecordVarRead(node.LocalSymbol);
                        break;
                }
            }

            return base.VisitLocal(node);
        }
예제 #30
0
        public override BoundNode VisitCatchBlock(BoundCatchBlock node)
        {
            EnsureOnlyEvalStack();

            var exceptionSourceOpt = node.ExceptionSourceOpt;
            DeclareLocals(node.Locals, stack: 0);

            if (exceptionSourceOpt != null)
            {
                // runtime pushes the exception object
                PushEvalStack(null, ExprContext.None);
                _counter++;

                // We consume it by writing into the exception source.
                if (exceptionSourceOpt.Kind == BoundKind.Local)
                {
                    RecordVarWrite(((BoundLocal)exceptionSourceOpt).LocalSymbol);
                }
                else
                {
                    int prevStack = StackDepth();
                    exceptionSourceOpt = VisitExpression(exceptionSourceOpt, ExprContext.AssignmentTarget);
                    _assignmentLocal = null; // not using this for exceptionSource
                    SetStackDepth(prevStack);
                }

                PopEvalStack();
                _counter++;
            }

            BoundExpression boundFilter;
            if (node.ExceptionFilterOpt != null)
            {
                boundFilter = (BoundExpression)this.Visit(node.ExceptionFilterOpt);

                // the value of filter expression is consumed by the VM
                PopEvalStack();
                _counter++;

                // variables allocated on stack in a filter can't be used in the catch handler 
                EnsureOnlyEvalStack();
            }
            else
            {
                boundFilter = null;
            }

            var boundBlock = (BoundBlock)this.Visit(node.Body);
            var exceptionTypeOpt = this.VisitType(node.ExceptionTypeOpt);

            return node.Update(node.Locals, exceptionSourceOpt, exceptionTypeOpt, boundFilter, boundBlock, node.IsSynthesizedAsyncCatchAll);
        }
예제 #31
0
        // Generates:
        // 
        // private static T {Factory}(InteractiveSession session) 
        // {
        //    T submissionResult;
        //    new {ThisScriptClass}(session, out submissionResult);
        //    return submissionResult;
        // }
        private BoundBlock CreateSubmissionFactoryBody()
        {
            Debug.Assert(containingType.TypeKind == TypeKind.Submission);

            SyntaxTree syntaxTree = CSharpSyntaxTree.Dummy;
            CSharpSyntaxNode syntax = (CSharpSyntaxNode)syntaxTree.GetRoot();

            var interactiveSessionParam = new BoundParameter(syntax, parameters[0]) { WasCompilerGenerated = true };

            var ctor = containingType.InstanceConstructors.Single();
            Debug.Assert(ctor is SynthesizedInstanceConstructor);
            Debug.Assert(ctor.ParameterCount == 2);

            var submissionResultType = ctor.Parameters[1].Type;
            var submissionResult = new BoundLocal(syntax, new SynthesizedLocal(ctor, submissionResultType), null, submissionResultType) { WasCompilerGenerated = true };

            return new BoundBlock(syntax,
                // T submissionResult;
                ImmutableArray.Create<LocalSymbol>(submissionResult.LocalSymbol),
                ImmutableArray.Create<BoundStatement>(
                    // new Submission(interactiveSession, out submissionResult);
                    new BoundExpressionStatement(syntax,
                        new BoundObjectCreationExpression(
                            syntax,
                            ctor,
                            ImmutableArray.Create<BoundExpression>(interactiveSessionParam, submissionResult),
                            ImmutableArray<string>.Empty,
                            ImmutableArray.Create<RefKind>(RefKind.None, RefKind.Ref),
                            false,
                            default(ImmutableArray<int>),
                            null,
                            null,
                            containingType
                        )
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true },
                    // return submissionResult;
                    new BoundReturnStatement(syntax, submissionResult) { WasCompilerGenerated = true }))
            { WasCompilerGenerated = true };
        }
예제 #32
0
        private BoundNode VisitUnhoistedLocal(BoundLocal node)
        {
            LocalSymbol replacementLocal;
            if (this.localMap.TryGetValue(node.LocalSymbol, out replacementLocal))
            {
                return new BoundLocal(node.Syntax, replacementLocal, node.ConstantValueOpt, replacementLocal.Type, node.HasErrors);
            }

            return base.VisitLocal(node);
        }
            // private static void <Main>()
            // {
            //     var script = new Script();
            //     script.<Initialize>();
            // }
            internal override BoundBlock CreateBody()
            {
                var syntax = this.GetSyntax();

                var ctor = _containingType.GetScriptConstructor();
                Debug.Assert(ctor.ParameterCount == 0);

                var initializer = _containingType.GetScriptInitializer();
                Debug.Assert(initializer.ParameterCount == 0);

                var submissionLocal = new BoundLocal(
                    syntax,
                    new SynthesizedLocal(this, _containingType, SynthesizedLocalKind.LoweringTemp),
                    null,
                    _containingType)
                { WasCompilerGenerated = true };

                return new BoundBlock(syntax,
                    ImmutableArray.Create<LocalSymbol>(submissionLocal.LocalSymbol),
                    ImmutableArray.Create<BoundStatement>(
                        // var script = new Script();
                        new BoundExpressionStatement(
                            syntax,
                            new BoundAssignmentOperator(
                                syntax,
                                submissionLocal,
                                new BoundObjectCreationExpression(
                                    syntax,
                                    ctor)
                                { WasCompilerGenerated = true },
                                _containingType)
                            { WasCompilerGenerated = true })
                        { WasCompilerGenerated = true },
                        // script.<Initialize>();
                        new BoundExpressionStatement(
                            syntax,
                            new BoundCall(
                                syntax,
                                submissionLocal,
                                initializer,
                                ImmutableArray<BoundExpression>.Empty,
                                default(ImmutableArray<string>),
                                default(ImmutableArray<RefKind>),
                                isDelegateCall: false,
                                expanded: false,
                                invokedAsExtensionMethod: false,
                                argsToParamsOpt: default(ImmutableArray<int>),
                                resultKind: LookupResultKind.Viable,
                                type: initializer.ReturnType)
                            { WasCompilerGenerated = true })
                        { WasCompilerGenerated = true },
                        // return;
                        new BoundReturnStatement(
                            syntax,
                            null)
                        { WasCompilerGenerated = true }))
                { WasCompilerGenerated = true };
            }
예제 #34
0
        public override BoundNode VisitLocal(BoundLocal node)
        {
            LocalDefUseInfo locInfo;
            if (!_info.TryGetValue(node.LocalSymbol, out locInfo))
            {
                return base.VisitLocal(node);
            }

            // not the last access, emit Dup.
            if (!IsLastAccess(locInfo, _nodeCounter))
            {
                return new BoundDup(node.Syntax, node.LocalSymbol.RefKind, node.Type);
            }

            // last access - leave the node as is. Emit will do nothing expecting the node on the stack
            return base.VisitLocal(node);
        }
            // private static T <Factory>(object[] submissionArray) 
            // {
            //     var submission = new Submission#N(submissionArray);
            //     return submission.<Initialize>();
            // }
            internal override BoundBlock CreateBody()
            {
                var syntax = this.GetSyntax();

                var ctor = _containingType.GetScriptConstructor();
                Debug.Assert(ctor.ParameterCount == 1);

                var initializer = _containingType.GetScriptInitializer();
                Debug.Assert(initializer.ParameterCount == 0);

                var submissionArrayParameter = new BoundParameter(syntax, _parameters[0]) { WasCompilerGenerated = true };
                var submissionLocal = new BoundLocal(
                    syntax,
                    new SynthesizedLocal(this, _containingType, SynthesizedLocalKind.LoweringTemp),
                    null,
                    _containingType)
                { WasCompilerGenerated = true };

                // var submission = new Submission#N(submissionArray);
                var submissionAssignment = new BoundExpressionStatement(
                    syntax,
                    new BoundAssignmentOperator(
                        syntax,
                        submissionLocal,
                        new BoundObjectCreationExpression(
                            syntax,
                            ctor,
                            ImmutableArray.Create<BoundExpression>(submissionArrayParameter),
                            default(ImmutableArray<string>),
                            default(ImmutableArray<RefKind>),
                            false,
                            default(ImmutableArray<int>),
                            null,
                            null,
                            _containingType)
                        { WasCompilerGenerated = true },
                        _containingType)
                    { WasCompilerGenerated = true })
                { WasCompilerGenerated = true };

                // return submission.<Initialize>();
                BoundExpression initializeResult = new BoundCall(
                    syntax,
                    submissionLocal,
                    initializer,
                    ImmutableArray<BoundExpression>.Empty,
                    default(ImmutableArray<string>),
                    default(ImmutableArray<RefKind>),
                    isDelegateCall: false,
                    expanded: false,
                    invokedAsExtensionMethod: false,
                    argsToParamsOpt: default(ImmutableArray<int>),
                    resultKind: LookupResultKind.Viable,
                    type: initializer.ReturnType)
                { WasCompilerGenerated = true };
                if (initializeResult.Type.IsStructType() && (_returnType.SpecialType == SpecialType.System_Object))
                {
                    initializeResult = new BoundConversion(syntax, initializeResult, Conversion.Boxing, false, true, ConstantValue.NotAvailable, _returnType)
                    { WasCompilerGenerated = true };
                }
                var returnStatement = new BoundReturnStatement(
                    syntax,
                    initializeResult)
                { WasCompilerGenerated = true };

                return new BoundBlock(syntax,
                    ImmutableArray.Create<LocalSymbol>(submissionLocal.LocalSymbol),
                    ImmutableArray.Create<BoundStatement>(submissionAssignment, returnStatement))
                { WasCompilerGenerated = true };
            }
예제 #36
0
        public override BoundNode VisitLocal(BoundLocal node)
        {
            if (node.ConstantValueOpt == null)
            {
                switch (_context)
                {
                    case ExprContext.Address:
                        if (node.LocalSymbol.RefKind != RefKind.None)
                        {
                            RecordVarRead(node.LocalSymbol);
                        }
                        else
                        {
                            RecordVarRef(node.LocalSymbol);
                        }
                        break;

                    case ExprContext.AssignmentTarget:
                        Debug.Assert(_assignmentLocal == null);

                        // actual assignment will happen later, after Right is evaluated
                        // just remember what we are assigning to.
                        _assignmentLocal = node;

                        break;

                    case ExprContext.Sideeffects:
                        break;

                    case ExprContext.Value:
                    case ExprContext.Box:
                        RecordVarRead(node.LocalSymbol);
                        break;
                }
            }

            return base.VisitLocal(node);
        }
        private BoundStatement RewriteMultiDimensionalArrayForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            Debug.Assert(collectionExpression.Type.IsArray());

            ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type;

            int rank = arrayType.Rank;
            Debug.Assert(rank > 1);

            TypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32);
            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);

            BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
            BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body);

            // A[...] a
            LocalSymbol arrayVar = new TempLocalSymbol(arrayType, RefKind.None, containingMethod);

            // A[...] a = /*node.Expression*/;
            BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression);

            AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl);

            // Reference to a.
            BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType);

            // int p_0, p_1, ...
            LocalSymbol[] positionVar = new LocalSymbol[rank];
            BoundLocal[] boundPositionVar = new BoundLocal[rank];
            for (int dimension = 0; dimension < rank; dimension++)
            {
                positionVar[dimension] = new TempLocalSymbol(intType, RefKind.None, containingMethod);
                boundPositionVar[dimension] = MakeBoundLocal(forEachSyntax, positionVar[dimension], intType);
            }

            // V v
            LocalSymbol iterationVar = node.IterationVariable;
            TypeSymbol iterationVarType = iterationVar.Type;

            // (V)a[p_0, p_1, ...]
            BoundExpression iterationVarInitValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: new BoundArrayAccess(forEachSyntax, 
                    expression: boundArrayVar,
                    indices: ReadOnlyArray<BoundExpression>.CreateFrom((BoundExpression[])boundPositionVar),
                    type: arrayType.ElementType),
                conversion: node.ElementConversion,
                type: iterationVarType);

            // V v = (V)a[p_0, p_1, ...];
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // { V v = (V)a[p_0, p_1, ...]; /* node.Body */ }
            BoundStatement innermostLoopBody = new BoundBlock(forEachSyntax, 
                localsOpt: ReadOnlyArray<LocalSymbol>.CreateFrom(iterationVar),
                statements: ReadOnlyArray<BoundStatement>.CreateFrom(iterationVarDecl, rewrittenBody));

            // Values we'll use every iteration
            MethodSymbol getLowerBoundMethod = (MethodSymbol)this.compilation.GetSpecialTypeMember(SpecialMember.System_Array__GetLowerBound);
            MethodSymbol getUpperBoundMethod = (MethodSymbol)this.compilation.GetSpecialTypeMember(SpecialMember.System_Array__GetUpperBound);

            // work from most-nested to least-nested
            // for (A[...] a = /*node.Expression*/; int p_0 = a.GetLowerBound(0); p_0 <= a.GetUpperBound(0); p_0 = p_0 + 1)
            //     for (int p_1 = a.GetLowerBound(0); p_1 <= a.GetUpperBound(0); p_1 = p_1 + 1)
            //         ...
            //             { V v = (V)a[p_0, p_1, ...]; /* node.Body */ }
            BoundStatement forLoop = null;
            for (int dimension = rank - 1; dimension >= 0; dimension--)
            {
                ReadOnlyArray<BoundExpression> dimensionArgument = ReadOnlyArray<BoundExpression>.CreateFrom(
                    new BoundLiteral(forEachSyntax, 
                        constantValueOpt: ConstantValue.Create(dimension, ConstantValueTypeDiscriminator.Int32),
                        type: intType));

                // a.GetLowerBound(/*dimension*/)
                BoundExpression currentDimensionLowerBound = BoundCall.Synthesized(forEachSyntax, boundArrayVar, getLowerBoundMethod, dimensionArgument);
                // a.GetUpperBound(/*dimension*/) //CONSIDER: dev10 creates a temp for each dimension's upper bound
                BoundExpression currentDimensionUpperBound = BoundCall.Synthesized(forEachSyntax, boundArrayVar, getUpperBoundMethod, dimensionArgument);

                // int p_/*dimension*/ = a.GetLowerBound(/*dimension*/);
                BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar[dimension], currentDimensionLowerBound);

                ReadOnlyArray<LocalSymbol> locals;
                BoundStatement initializer;
                GeneratedLabelSymbol breakLabel;

                if (dimension == 0)
                {
                    // outermost for-loop
                    locals = ReadOnlyArray<LocalSymbol>.CreateFrom(arrayVar, positionVar[dimension]);
                    initializer = new BoundStatementList(forEachSyntax, 
                        statements: ReadOnlyArray<BoundStatement>.CreateFrom(arrayVarDecl, positionVarDecl));
                    breakLabel = node.BreakLabel; // i.e. the one that break statements will jump to
                }
                else
                {
                    locals = ReadOnlyArray<LocalSymbol>.CreateFrom(positionVar[dimension]);
                    initializer = positionVarDecl;
                    breakLabel = new GeneratedLabelSymbol("break"); // Should not affect emitted code since unused
                }

                // p_/*dimension*/ <= a.GetUpperBound(/*dimension*/)  //NB: OrEqual
                BoundExpression exitCondition = new BoundBinaryOperator(
                    syntax: forEachSyntax, 
                    operatorKind: BinaryOperatorKind.IntLessThanOrEqual,
                    left: boundPositionVar[dimension],
                    right: currentDimensionUpperBound,
                    constantValueOpt: null, 
                    methodOpt: null, 
                    resultKind: LookupResultKind.Viable, 
                    type: boolType);

                // p_/*dimension*/ = p_/*dimension*/ + 1;
                BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar[dimension], intType);

                BoundStatement body;
                GeneratedLabelSymbol continueLabel;

                if(forLoop == null)
                {
                    // innermost for-loop
                    body = innermostLoopBody;
                    continueLabel = node.ContinueLabel; //i.e. the one continue statements will actually jump to
                }
                else
                {
                    body = forLoop;
                    continueLabel = new GeneratedLabelSymbol("continue"); // Should not affect emitted code since unused
                }

                forLoop = RewriteForStatement(
                    node.Syntax,
                    locals,
                    initializer,
                    exitCondition,
                    forEachSyntax.InKeyword,
                    positionIncrement,
                    body,
                    breakLabel,
                    continueLabel,
                    node.HasErrors);
            }

            Debug.Assert(forLoop != null);

            AddForEachExpressionSequencePoint(forEachSyntax, ref forLoop);

            return forLoop;
        }
예제 #38
0
        private void EmitLocalLoad(BoundLocal local, bool used)
        {
            if (IsStackLocal(local.LocalSymbol))
            {
                // local must be already on the stack
                EmitPopIfUnused(used);
            }
            else
            {
                if (used)
                {
                    LocalDefinition definition = GetLocal(local);
                    _builder.EmitLocalLoad(definition);
                }
                else
                {
                    // do nothing. Unused local load has no side-effects.
                    return;
                }
            }

            if (used && local.LocalSymbol.RefKind != RefKind.None)
            {
                EmitLoadIndirect(local.LocalSymbol.Type, local.Syntax);
            }
        }
예제 #39
0
        /// <summary>
        /// The rewrites are as follows:
        ///
        /// x++
        ///     temp = x
        ///     x = temp + 1
        ///     return temp
        /// x--
        ///     temp = x
        ///     x = temp - 1
        ///     return temp
        /// ++x
        ///     temp = x + 1
        ///     x = temp
        ///     return temp
        /// --x
        ///     temp = x - 1
        ///     x = temp
        ///     return temp
        ///
        /// In each case, the literal 1 is of the type required by the builtin addition/subtraction operator that
        /// will be used.  The temp is of the same type as x, but the sum/difference may be wider, in which case a
        /// conversion is required.
        /// </summary>
        /// <param name="node">The unary operator expression representing the increment/decrement.</param>
        /// <param name="isPrefix">True for prefix, false for postfix.</param>
        /// <param name="isIncrement">True for increment, false for decrement.</param>
        /// <returns>A bound sequence that uses a temp to acheive the correct side effects and return value.</returns>
        private BoundNode LowerOperator(BoundUnaryOperator node, bool isPrefix, bool isIncrement)
        {
            BoundExpression operand     = node.Operand;
            TypeSymbol      operandType = operand.Type; //type of the variable being incremented

            Debug.Assert(operandType == node.Type);

            ConstantValue      constantOne;
            BinaryOperatorKind binaryOperatorKind;

            MakeConstantAndOperatorKind(node.OperatorKind.OperandTypes(), node, out constantOne, out binaryOperatorKind);
            binaryOperatorKind |= isIncrement ? BinaryOperatorKind.Addition : BinaryOperatorKind.Subtraction;

            Debug.Assert(constantOne != null);
            Debug.Assert(constantOne.SpecialType != SpecialType.None);
            Debug.Assert(binaryOperatorKind.OperandTypes() != 0);

            TypeSymbol      constantType = compilation.GetSpecialType(constantOne.SpecialType);
            BoundExpression boundOne     = new BoundLiteral(
                syntax: null,
                syntaxTree: null,
                constantValueOpt: constantOne,
                type: constantType);

            LocalSymbol     tempSymbol = new TempLocalSymbol(operandType, RefKind.None, containingSymbol);
            BoundExpression boundTemp  = new BoundLocal(
                syntax: null,
                syntaxTree: null,
                localSymbol: tempSymbol,
                constantValueOpt: null,
                type: operandType);

            // NOTE: the LHS may have a narrower type than the operator expects, but that
            // doesn't seem to cause any problems.  If a problem does arise, just add an
            // explicit BoundConversion.
            BoundExpression newValue = new BoundBinaryOperator(
                syntax: null,
                syntaxTree: null,
                operatorKind: binaryOperatorKind,
                left: isPrefix ? operand : boundTemp,
                right: boundOne,
                constantValueOpt: null,
                type: constantType);

            if (constantType != operandType)
            {
                newValue = new BoundConversion(
                    syntax: null,
                    syntaxTree: null,
                    operand: newValue,
                    conversionKind: operandType.IsEnumType() ? ConversionKind.ImplicitEnumeration : ConversionKind.ImplicitNumeric,
                    symbolOpt: null,
                    @checked: false,
                    explicitCastInCode: false,
                    constantValueOpt: null,
                    type: operandType);
            }

            ReadOnlyArray <BoundExpression> assignments = ReadOnlyArray <BoundExpression> .CreateFrom(
                new BoundAssignmentOperator(
                    syntax : null,
                    syntaxTree : null,
                    left : boundTemp,
                    right : isPrefix ? newValue : operand,
                    type : operandType),
                new BoundAssignmentOperator(
                    syntax : null,
                    syntaxTree : null,
                    left : operand,
                    right : isPrefix ? boundTemp : newValue,
                    type : operandType));

            return(new BoundSequence(
                       syntax: node.Syntax,
                       syntaxTree: node.SyntaxTree,
                       locals: ReadOnlyArray <LocalSymbol> .CreateFrom(tempSymbol),
                       sideEffects: assignments,
                       value: boundTemp,
                       type: operandType));
        }