Ejemplo n.º 1
0
            private static BoundExpression InvokeGetMethod(MethodSymbol method, SyntaxNode syntax, string name)
            {
                var argument = new BoundLiteral(
                    syntax,
                    Microsoft.CodeAnalysis.ConstantValue.Create(name),
                    method.Parameters[0].Type);

                return(BoundCall.Synthesized(
                           syntax,
                           receiverOpt: null,
                           method: method,
                           arguments: ImmutableArray.Create <BoundExpression>(argument)));
            }
Ejemplo n.º 2
0
        private BoundNode RewriteDelegateOperation(BoundBinaryOperator node, SpecialMember member)
        {
            Debug.Assert(node != null);
            var method = (MethodSymbol)this.compilation.Assembly.GetSpecialTypeMember(member);

            // UNDONE: Handle the bizarre error case where we don't have the expected methods.
            Debug.Assert(method != null);
            BoundExpression call   = BoundCall.SynthesizedCall(null, method, node.Left, node.Right);
            BoundExpression result = method.ReturnType.SpecialType == SpecialType.System_Delegate ?
                                     BoundConversion.SynthesizedConversion(call, ConversionKind.ExplicitReference, node.Type) :
                                     call;

            return(Visit(result));
        }
Ejemplo n.º 3
0
        private static void RewriteLocalDeclaration(
            CSharpCompilation compilation,
            EENamedTypeSymbol container,
            HashSet <LocalSymbol> declaredLocals,
            ArrayBuilder <BoundStatement> statements,
            BoundLocalDeclaration node)
        {
            Debug.Assert(node.ArgumentsOpt.IsDefault);

            var local  = node.LocalSymbol;
            var syntax = node.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));

            var initializer = node.InitializerOpt;

            if (initializer != null)
            {
                // Generate assignment to local. The assignment will
                // be rewritten in PlaceholderLocalRewriter.
                var assignment = new BoundAssignmentOperator(
                    syntax,
                    new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type),
                    initializer,
                    RefKind.None,
                    local.Type);
                statements.Add(new BoundExpressionStatement(syntax, assignment));
            }
        }
Ejemplo n.º 4
0
        internal override BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax, DiagnosticBag diagnostics)
        {
            var method   = GetIntrinsicMethod(compilation, ExpressionCompilerConstants.GetReturnValueMethodName);
            var argument = new BoundLiteral(
                syntax,
                Microsoft.CodeAnalysis.ConstantValue.Create(_index),
                method.Parameters[0].Type);
            var call = BoundCall.Synthesized(
                syntax,
                receiverOpt: null,
                method: method,
                arguments: ImmutableArray.Create <BoundExpression>(argument));

            return(ConvertToLocalType(compilation, call, this.Type, diagnostics));
        }
        internal override BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, SyntaxNode syntax, DiagnosticBag diagnostics)
        {
            var method   = GetIntrinsicMethod(compilation, ExpressionCompilerConstants.GetObjectAtAddressMethodName);
            var argument = new BoundLiteral(
                syntax,
                Microsoft.CodeAnalysis.ConstantValue.Create(_address),
                method.Parameters[0].Type.TypeSymbol);
            var call = BoundCall.Synthesized(
                syntax,
                receiverOpt: null,
                method: method,
                arguments: ImmutableArray.Create <BoundExpression>(argument));

            Debug.Assert(call.Type == this.Type.TypeSymbol);
            return(call);
        }
Ejemplo n.º 6
0
        private BoundNode RewriteStringEquality(BoundBinaryOperator node, SpecialMember member)
        {
            Debug.Assert(node != null);
            Debug.Assert(node.ConstantValueOpt == null);

            if (node.Left.ConstantValue == ConstantValue.Null || node.Right.ConstantValue == ConstantValue.Null)
            {
                return(base.VisitBinaryOperator(node));
            }

            var method = (MethodSymbol)this.compilation.Assembly.GetSpecialTypeMember(member);

            Debug.Assert(method != null);

            return(Visit(BoundCall.SynthesizedCall(null, method, node.Left, node.Right)));
        }
Ejemplo n.º 7
0
        private BoundNode RewriteNumericToDecimalConversion(SyntaxNode syntaxNode, BoundExpression operand, TypeSymbol typeFrom)
        {
            SpecialMember member;

            switch (typeFrom.SpecialType)
            {
            case SpecialType.System_Char: member = SpecialMember.System_Decimal__op_Implicit_FromChar; break;

            case SpecialType.System_SByte: member = SpecialMember.System_Decimal__op_Implicit_FromSByte; break;

            case SpecialType.System_Byte: member = SpecialMember.System_Decimal__op_Implicit_FromByte; break;

            case SpecialType.System_Int16: member = SpecialMember.System_Decimal__op_Implicit_FromInt16; break;

            case SpecialType.System_UInt16: member = SpecialMember.System_Decimal__op_Implicit_FromUInt16; break;

            case SpecialType.System_Int32: member = SpecialMember.System_Decimal__op_Implicit_FromInt32; break;

            case SpecialType.System_UInt32: member = SpecialMember.System_Decimal__op_Implicit_FromUInt32; break;

            case SpecialType.System_Int64: member = SpecialMember.System_Decimal__op_Implicit_FromInt64; break;

            case SpecialType.System_UInt64: member = SpecialMember.System_Decimal__op_Implicit_FromUInt64; break;

            case SpecialType.System_Single: member = SpecialMember.System_Decimal__op_Explicit_FromSingle; break;

            case SpecialType.System_Double: member = SpecialMember.System_Decimal__op_Explicit_FromDouble; break;

            default:
                Debug.Assert(false);     // Cannot reach here
                return(null);
            }

            // call the method
            var method = (MethodSymbol)this.compilation.Assembly.GetSpecialTypeMember(member);

            Debug.Assert(method != null); // Should have been checked during Warnings pass

            return(BoundCall.Synthesized(
                       syntaxNode,
                       null,
                       method,
                       operand));
        }
            internal AsyncForwardEntryPoint(CSharpCompilation compilation, NamedTypeSymbol containingType, MethodSymbol userMain) :
                base(containingType)
            {
                // There should be no way for a userMain to be passed in unless it already passed the
                // parameter checks for determining entrypoint validity.
                Debug.Assert(userMain.ParameterCount == 0 || userMain.ParameterCount == 1);

                UserMain = userMain;
                _userMainReturnTypeSyntax = userMain.ExtractReturnTypeSyntax();
                var binder = compilation.GetBinder(_userMainReturnTypeSyntax);

                _parameters = SynthesizedParameterSymbol.DeriveParameters(userMain, this);

                var arguments = Parameters.SelectAsArray((p, s) => (BoundExpression) new BoundParameter(s, p, p.Type), _userMainReturnTypeSyntax);

                // Main(args) or Main()
                BoundCall userMainInvocation = new BoundCall(
                    syntax: _userMainReturnTypeSyntax,
                    receiverOpt: null,
                    method: userMain,
                    arguments: arguments,
                    argumentNamesOpt: default(ImmutableArray <string>),
                    argumentRefKindsOpt: default(ImmutableArray <RefKind>),
                    isDelegateCall: false,
                    expanded: false,
                    invokedAsExtensionMethod: false,
                    argsToParamsOpt: default(ImmutableArray <int>),
                    resultKind: LookupResultKind.Viable,
                    binderOpt: binder,
                    type: userMain.ReturnType)
                {
                    WasCompilerGenerated = true
                };

                // The diagnostics that would be produced here will already have been captured and returned.
                var droppedBag = DiagnosticBag.GetInstance();
                var success    = binder.GetAwaitableExpressionInfo(userMainInvocation, out _getAwaiterGetResultCall !, _userMainReturnTypeSyntax, droppedBag);

                droppedBag.Free();

                Debug.Assert(
                    ReturnType.IsVoidType() ||
                    ReturnType.SpecialType == SpecialType.System_Int32);
            }
Ejemplo n.º 9
0
        internal override BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax)
        {
            Debug.Assert(this.Name == this.Name.ToLowerInvariant());
            var method = container.GetOrAddSynthesizedMethod(
                this.Name,
                (c, n, s) =>
            {
                var returnType = compilation.GetWellKnownType(WellKnownType.System_Exception);
                return(new PlaceholderMethodSymbol(
                           c,
                           s,
                           n,
                           returnType,
                           m => ImmutableArray <ParameterSymbol> .Empty));
            });
            var call = BoundCall.Synthesized(syntax, receiverOpt: null, method: method);

            return(ConvertToLocalType(compilation, call, this.Type));
        }
Ejemplo n.º 10
0
        public override BoundNode VisitPropertyAccess(BoundPropertyAccess node)
        {
            // Avoid rewriting if node has errors since the accessor may not exist.
            if (node.HasErrors)
            {
                return(base.VisitPropertyAccess(node));
            }

            // Rewrite property access into call to getter.
            var property  = node.PropertySymbol.GetBaseProperty();
            var getMethod = property.GetMethod;

            Debug.Assert(getMethod != null);
            Debug.Assert(getMethod.Parameters.Count == 0);
            Debug.Assert(!getMethod.IsOverride);

            var rewrittenReceiver = (BoundExpression)Visit(node.ReceiverOpt);

            return(BoundCall.SynthesizedCall(rewrittenReceiver, getMethod));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Synthesize a no-argument call to a given method, possibly applying a conversion to the receiver.
        ///
        /// If the receiver is of struct type and the method is an interface method, then skip the conversion
        /// and just call the interface method directly - the code generator will detect this and generate a
        /// constrained virtual call.
        /// </summary>
        /// <param name="syntax">A syntax node to attach to the synthesized bound node.</param>
        /// <param name="receiver">Receiver of method call.</param>
        /// <param name="method">Method to invoke.</param>
        /// <param name="receiverConversion">Conversion to be applied to the receiver if not calling an interface method on a struct.</param>
        /// <param name="convertedReceiverType">Type of the receiver after applying the conversion.</param>
        /// <returns>A BoundExpression representing the call.</returns>
        private static BoundExpression SynthesizeCall(SyntaxNode syntax, BoundExpression receiver, MethodSymbol method, Conversion receiverConversion, TypeSymbol convertedReceiverType)
        {
            if (receiver.Type.TypeKind == TypeKind.Struct && method.ContainingType.TypeKind == TypeKind.Interface)
            {
                Debug.Assert(receiverConversion.IsBoxing);

                // NOTE: The spec says that disposing of a struct enumerator won't cause any
                // unnecessary boxing to occur.  However, Dev10 extends this improvement to the
                // GetEnumerator call as well.

                // We're going to let the emitter take care of avoiding the extra boxing.
                // When it sees an interface call to a struct, it will generate a constrained
                // virtual call, which will skip boxing, if possible.

                // CONSIDER: In cases where the struct implicitly implements the interface method
                // (i.e. with a public method), we could save a few bytes of IL by creating a
                // BoundCall to the struct method rather than the interface method (so that the
                // emitter wouldn't need to create a constrained virtual call).  It is not clear
                // what effect this would have on back compat.

                // NOTE: This call does not correspond to anything that can be written in C# source.
                // We're invoking the interface method directly on the struct (which may have a private
                // explicit implementation).  The code generator knows how to handle it though.

                // receiver.InterfaceMethod()
                return(BoundCall.Synthesized(syntax, receiver, method));
            }
            else
            {
                // ((Interface)receiver).InterfaceMethod()
                return(BoundCall.Synthesized(
                           syntax: syntax,
                           receiverOpt: SynthesizeConversion(
                               syntax: syntax,
                               operand: receiver,
                               conversion: receiverConversion,
                               type: convertedReceiverType),
                           method: method));
            }
        }
Ejemplo n.º 12
0
        public override BoundNode VisitCall(BoundCall node)
        {
            var rewrittenMethodSymbol = VisitMethodSymbol(node.Method);
            var rewrittenReceiver     = (BoundExpression)this.Visit(node.ReceiverOpt);
            var rewrittenArguments    =
                (ImmutableArray <BoundExpression>) this.VisitList(node.Arguments);
            var rewrittenType = this.VisitType(node.Type);

            Debug.Assert(
                rewrittenMethodSymbol.IsMetadataVirtual() == node.Method.IsMetadataVirtual()
                );

            // If the original receiver was a base access and it was rewritten,
            // change the method to point to the wrapper method
            if (
                BaseReferenceInReceiverWasRewritten(node.ReceiverOpt, rewrittenReceiver) &&
                node.Method.IsMetadataVirtual()
                )
            {
                rewrittenMethodSymbol = GetMethodWrapperForBaseNonVirtualCall(
                    rewrittenMethodSymbol,
                    node.Syntax
                    );
            }

            return(node.Update(
                       rewrittenReceiver,
                       rewrittenMethodSymbol,
                       rewrittenArguments,
                       node.ArgumentNamesOpt,
                       node.ArgumentRefKindsOpt,
                       node.IsDelegateCall,
                       node.Expanded,
                       node.InvokedAsExtensionMethod,
                       node.ArgsToParamsOpt,
                       node.DefaultArguments,
                       node.ResultKind,
                       rewrittenType
                       ));
        }
Ejemplo n.º 13
0
        internal void Parse(BoundCall boundCall)
        {
            base.Parse(boundCall);
            this.Method = boundCall.Method;
            if (boundCall.ReceiverOpt != null && boundCall.ReceiverOpt.Kind != BoundKind.ConditionalReceiver)
            {
                this.ReceiverOpt = Deserialize(boundCall.ReceiverOpt) as Expression;
                // special case to avoid calling (*xxx).method() and replace with xxx->method();
                var pointerIndirectionOperator = this.ReceiverOpt as PointerIndirectionOperator;
                if (pointerIndirectionOperator != null)
                {
                    this.ReceiverOpt             = pointerIndirectionOperator.Operand;
                    this.ReceiverOpt.IsReference = true;
                }
            }

            foreach (var expression in boundCall.Arguments)
            {
                var argument = Deserialize(expression) as Expression;
                Debug.Assert(argument != null);
                this._arguments.Add(argument);
            }
        }
Ejemplo n.º 14
0
        public override object VisitCall(BoundCall node, object unused)
        {
            // If the method being called is a partial method without a definition, or is a conditional method
            // whose condition is not true, then the call has no effect and it is ignored for the purposes of
            // definite assignment analysis.  That means that subexpressions (including lambdas) are not even
            // analyzed.
            if (node.MethodSymbol.CallsAreOmitted(this.compilation))
            {
                return(null);
            }

            VisitExpression(node.Receiver);
            foreach (var arg in node.Arguments)
            {
                if (arg.Kind == BoundKind.MakeRefOperator)
                {
                    Unimplemented(arg, "ref argument");
                    // TODO: if it is an "out" reference, bind as an lvalue
                }
                VisitExpression(arg);
            }
            return(null);
        }
Ejemplo n.º 15
0
        internal void Parse(BoundCall boundCall)
        {
            base.Parse(boundCall);
            this.SpecialCaseCreateInstanceNewObjectReplacement = boundCall.Method.IsCreateInstaneNewReplacement();
            this.Method = this.SpecialCaseCreateInstanceNewObjectReplacement ? GenerateNativeCreateInstanceMethod(boundCall.Method) : boundCall.Method;
            if (boundCall.ReceiverOpt != null)
            {
                this.ReceiverOpt = Deserialize(boundCall.ReceiverOpt) as Expression;
                // special case to avoid calling (*xxx).method() and replace with xxx->method();
                var pointerIndirectionOperator = this.ReceiverOpt as PointerIndirectionOperator;
                if (pointerIndirectionOperator != null)
                {
                    this.ReceiverOpt             = pointerIndirectionOperator.Operand;
                    this.ReceiverOpt.IsReference = true;
                }
            }

            foreach (var expression in boundCall.Arguments)
            {
                var argument = Deserialize(expression) as Expression;
                Debug.Assert(argument != null);
                this._arguments.Add(argument);
            }
        }
Ejemplo n.º 16
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.º 17
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 = 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
                };

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

                return(new BoundBlock(syntax,
                                      ImmutableArray.Create <LocalSymbol>(submissionLocal.LocalSymbol),
                                      ImmutableArray.Create <BoundStatement>(submissionAssignment, returnStatement))
                {
                    WasCompilerGenerated = true
                });
            }
Ejemplo n.º 18
0
        public override BoundNode VisitCall(BoundCall node)
        {
            var receiver = node.ReceiverOpt;

            // matches or a bit stronger than EmitReceiverRef
            // if there are any doubts that receiver is a ref type, 
            // assume we will need an address (that will prevent scheduling of receiver).
            if (!node.Method.IsStatic)
            {
                receiver = VisitCallReceiver(receiver);
            }
            else
            {
                // TODO: for some reason receiver could be not null even if method is static...
                //       it seems wrong, ignore for now.
                _counter += 1;
                receiver = null;
            }

            MethodSymbol method = node.Method;
            var rewrittenArguments = VisitArguments(node.Arguments, method.Parameters);

            return node.Update(receiver, method, rewrittenArguments);
        }
Ejemplo n.º 19
0
        public override BoundNode VisitCall(BoundCall node)
        {
            var rewrittenMethodSymbol = VisitMethodSymbol(node.Method);
            var rewrittenReceiver = (BoundExpression)this.Visit(node.ReceiverOpt);
            var rewrittenArguments = (ImmutableArray<BoundExpression>)this.VisitList(node.Arguments);
            var rewrittenType = this.VisitType(node.Type);

            Debug.Assert(rewrittenMethodSymbol.IsMetadataVirtual() == node.Method.IsMetadataVirtual());

            // If the original receiver was a base access and it was rewritten, 
            // change the method to point to the wrapper method
            if (BaseReferenceInReceiverWasRewritten(node.ReceiverOpt, rewrittenReceiver) && node.Method.IsMetadataVirtual())
            {
                rewrittenMethodSymbol = GetMethodWrapperForBaseNonVirtualCall(rewrittenMethodSymbol, node.Syntax);
            }

            return node.Update(
                rewrittenReceiver,
                rewrittenMethodSymbol,
                rewrittenArguments,
                node.ArgumentNamesOpt,
                node.ArgumentRefKindsOpt,
                node.IsDelegateCall,
                node.Expanded,
                node.InvokedAsExtensionMethod,
                node.ArgsToParamsOpt,
                node.ResultKind,
                rewrittenType);
        }
Ejemplo n.º 20
0
 // Calls are treated as having side effects, but properties and
 // indexers are not. (Since this visitor is run on the bound tree
 // before lowering, properties are not represented as calls.)
 public override BoundNode VisitCall(BoundCall node)
 {
     return this.SetMayHaveSideEffects();
 }
 // Calls are treated as having side effects, but properties and
 // indexers are not. (Since this visitor is run on the bound tree
 // before lowering, properties are not represented as calls.)
 public override BoundNode VisitCall(BoundCall node)
 {
     return(this.SetMayHaveSideEffects());
 }
        public override BoundNode VisitCall(BoundCall node)
        {
            Debug.Assert(node != null);

            // Avoid rewriting if node has errors since one or more
            // of the arguments may not be the correct rvalue/lvalue.
            if (node.HasErrors)
            {
                return node;
            }

            // Start by rewriting the arguments and receiver:
            var rewrittenReceiver = (BoundExpression)Visit(node.ReceiverOpt);
            var rewrittenArguments = VisitList(node.Arguments);
            var method = node.Method;

            // If the mapping from arguments to parameters is perfectly in order, no complex rewriting is needed.
            if (node.ArgsToParamsOpt.IsNull && !node.Expanded)
            {
                return node.Update(rewrittenReceiver, method, rewrittenArguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.Type);
            }

            var argumentRefKinds = node.ArgumentRefKindsOpt;
            ReadOnlyArray<LocalSymbol> temps;

            RewriteArguments(method,
                        node.Expanded,
                        node.ArgsToParamsOpt,
                        ref argumentRefKinds,
                        ref rewrittenArguments,
                        out temps);

            var delegateNode = node as BoundDelegateCall;
            if (temps.IsNullOrEmpty)
            {
                return (delegateNode != null)
                    ? delegateNode.Update(
                        rewrittenReceiver,
                        method,
                        rewrittenArguments,
                        ReadOnlyArray<string>.Null,
                        argumentRefKinds,
                        false,
                        ReadOnlyArray<int>.Null,
                        node.Type)
                    : node.Update(
                        rewrittenReceiver,
                        method,
                        rewrittenArguments,
                        ReadOnlyArray<string>.Null,
                        argumentRefKinds,
                        false,
                        ReadOnlyArray<int>.Null,
                        node.Type);
            }
            else
            {
                return new BoundSequence(
                    null,
                    null,
                    temps,
                    ReadOnlyArray<BoundExpression>.Empty,
                    (delegateNode != null)
                        ? new BoundDelegateCall(
                            node.Syntax,
                            node.SyntaxTree,
                            rewrittenReceiver,
                            method,
                            rewrittenArguments,
                            ReadOnlyArray<string>.Null,
                            argumentRefKinds,
                            false,
                            ReadOnlyArray<int>.Null,
                            node.Type)
                        : new BoundCall(
                            node.Syntax,
                            node.SyntaxTree,
                            rewrittenReceiver,
                            method,
                            rewrittenArguments,
                            ReadOnlyArray<string>.Null,
                            argumentRefKinds,
                            false,
                            ReadOnlyArray<int>.Null,
                            node.Type),
                    node.Type
                );
            }
        }
Ejemplo n.º 23
0
 public virtual void VisitCall(BoundCall node)
 {
     DefaultVisit(node);
 }
Ejemplo n.º 24
0
        /// <summary>
        /// Lower a foreach loop that will enumerate a collection using an enumerator.
        ///
        /// E e = ((C)(x)).GetEnumerator()
        /// try {
        ///     while (e.MoveNext()) {
        ///         V v = (V)(T)e.Current;
        ///         // body
        ///     }
        /// }
        /// finally {
        ///     // clean up e
        /// }
        /// </summary>
        private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            ForEachEnumeratorInfo enumeratorInfo = node.EnumeratorInfoOpt;

            Debug.Assert(enumeratorInfo != null);

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

            TypeSymbol enumeratorType = enumeratorInfo.GetEnumeratorMethod.ReturnType;
            TypeSymbol elementType    = enumeratorInfo.ElementType;

            // E e
            LocalSymbol enumeratorVar = new TempLocalSymbol(enumeratorType, RefKind.None, this.containingMethod);

            // Reference to e.
            BoundLocal boundEnumeratorVar = MakeBoundLocal(forEachSyntax, enumeratorVar, enumeratorType);

            // ((C)(x)).GetEnumerator() or (x).GetEnumerator();
            BoundExpression enumeratorVarInitValue = SynthesizeCall(forEachSyntax, rewrittenExpression, enumeratorInfo.GetEnumeratorMethod, enumeratorInfo.CollectionConversion, enumeratorInfo.CollectionType);

            // E e = ((C)(x)).GetEnumerator();
            BoundStatement enumeratorVarDecl = MakeLocalDeclaration(forEachSyntax, enumeratorVar, enumeratorVarInitValue);

            AddForEachExpressionSequencePoint(forEachSyntax, ref enumeratorVarDecl);

            // V v
            LocalSymbol iterationVar = node.IterationVariable;

            //(V)(T)e.Current
            BoundExpression iterationVarAssignValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: SynthesizeConversion(
                    syntax: forEachSyntax,
                    operand: BoundCall.Synthesized(
                        syntax: forEachSyntax,
                        receiverOpt: boundEnumeratorVar,
                        method: enumeratorInfo.CurrentPropertyGetter),
                    conversion: enumeratorInfo.CurrentConversion,
                    type: elementType),
                conversion: node.ElementConversion,
                type: iterationVar.Type);

            // V v = (V)(T)e.Current;
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarAssignValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // while (e.MoveNext()) {
            //     V v = (V)(T)e.Current;
            //     /* node.Body */
            // }
            BoundStatement whileLoop = RewriteWhileStatement(
                syntax: forEachSyntax,
                rewrittenCondition: BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundEnumeratorVar,
                    method: enumeratorInfo.MoveNextMethod),
                conditionSequencePointSpan: forEachSyntax.InKeyword.Span,
                rewrittenBody: new BoundBlock(rewrittenBody.Syntax,
                                              statements: ReadOnlyArray <BoundStatement> .CreateFrom(iterationVarDecl, rewrittenBody),
                                              localsOpt: ReadOnlyArray <LocalSymbol> .CreateFrom(iterationVar)),
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel,
                hasErrors: false);

            BoundStatement result;

            if (enumeratorInfo.DisposeMethodOpt != null)
            {
                BoundBlock finallyBlockOpt;
                var        idisposableTypeSymbol = enumeratorInfo.DisposeMethodOpt.ContainingType;
                var        conversions           = new TypeConversions(this.containingMethod.ContainingAssembly.CorLibrary);

                if (conversions.ClassifyImplicitConversion(enumeratorType, idisposableTypeSymbol).IsImplicit)
                {
                    Debug.Assert(enumeratorInfo.DisposeMethodOpt != null);

                    Conversion receiverConversion = enumeratorType.IsStructType() ?
                                                    Conversion.Boxing :
                                                    Conversion.ImplicitReference;

                    // ((IDisposable)e).Dispose(); or e.Dispose();
                    BoundStatement disposeCall = new BoundExpressionStatement(forEachSyntax,
                                                                              expression: SynthesizeCall(forEachSyntax, boundEnumeratorVar, enumeratorInfo.DisposeMethodOpt, receiverConversion, idisposableTypeSymbol));

                    BoundStatement disposeStmt;
                    if (enumeratorType.IsValueType)
                    {
                        // No way for the struct to be nullable and disposable.
                        Debug.Assert(((TypeSymbol)enumeratorType.OriginalDefinition).SpecialType != SpecialType.System_Nullable_T);

                        // For non-nullable structs, no null check is required.
                        disposeStmt = disposeCall;
                    }
                    else
                    {
                        // NB: cast to object missing from spec.  Needed to ignore user-defined operators and box type parameters.
                        // if ((object)e != null) ((IDisposable)e).Dispose();
                        disposeStmt = RewriteIfStatement(
                            syntax: forEachSyntax,
                            rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                                                        operatorKind: BinaryOperatorKind.NotEqual,
                                                                        left: SynthesizeConversion(
                                                                            syntax: forEachSyntax,
                                                                            operand: boundEnumeratorVar,
                                                                            conversion: enumeratorInfo.EnumeratorConversion,
                                                                            type: this.compilation.GetSpecialType(SpecialType.System_Object)),
                                                                        right: new BoundLiteral(forEachSyntax,
                                                                                                constantValueOpt: ConstantValue.Null,
                                                                                                type: null),
                                                                        constantValueOpt: null,
                                                                        methodOpt: null,
                                                                        resultKind: LookupResultKind.Viable,
                                                                        type: this.compilation.GetSpecialType(SpecialType.System_Boolean)),
                            rewrittenConsequence: disposeCall,
                            rewrittenAlternativeOpt: null,
                            hasErrors: false);
                    }

                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                                                     localsOpt: ReadOnlyArray <LocalSymbol> .Null,
                                                     statements: ReadOnlyArray <BoundStatement> .CreateFrom(disposeStmt));
                }
                else
                {
                    Debug.Assert(!enumeratorType.IsSealed);

                    // IDisposable d
                    LocalSymbol disposableVar = new TempLocalSymbol(idisposableTypeSymbol, RefKind.None, this.containingMethod);

                    // Reference to d.
                    BoundLocal boundDisposableVar = MakeBoundLocal(forEachSyntax, disposableVar, idisposableTypeSymbol);

                    BoundTypeExpression boundIDisposableTypeExpr = new BoundTypeExpression(forEachSyntax,
                                                                                           type: idisposableTypeSymbol);

                    // e as IDisposable
                    BoundExpression disposableVarInitValue = new BoundAsOperator(forEachSyntax,
                                                                                 operand: boundEnumeratorVar,
                                                                                 targetType: boundIDisposableTypeExpr,
                                                                                 conversion: Conversion.ExplicitReference, // Explicit so the emitter won't optimize it away.
                                                                                 type: idisposableTypeSymbol);

                    // IDisposable d = e as IDisposable;
                    BoundStatement disposableVarDecl = MakeLocalDeclaration(forEachSyntax, disposableVar, disposableVarInitValue);

                    // if (d != null) d.Dispose();
                    BoundStatement ifStmt = RewriteIfStatement(
                        syntax: forEachSyntax,
                        rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                                                    operatorKind: BinaryOperatorKind.NotEqual, // reference equality
                                                                    left: boundDisposableVar,
                                                                    right: new BoundLiteral(forEachSyntax,
                                                                                            constantValueOpt: ConstantValue.Null,
                                                                                            type: null),
                                                                    constantValueOpt: null,
                                                                    methodOpt: null,
                                                                    resultKind: LookupResultKind.Viable,
                                                                    type: this.compilation.GetSpecialType(SpecialType.System_Boolean)),
                        rewrittenConsequence: new BoundExpressionStatement(forEachSyntax,
                                                                           expression: BoundCall.Synthesized(
                                                                               syntax: forEachSyntax,
                                                                               receiverOpt: boundDisposableVar,
                                                                               method: enumeratorInfo.DisposeMethodOpt)),
                        rewrittenAlternativeOpt: null,
                        hasErrors: false);

                    // IDisposable d = e as IDisposable;
                    // if (d != null) d.Dispose();
                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                                                     localsOpt: ReadOnlyArray <LocalSymbol> .CreateFrom(disposableVar),
                                                     statements: ReadOnlyArray <BoundStatement> .CreateFrom(disposableVarDecl, ifStmt));
                }

                // try {
                //     while (e.MoveNext()) {
                //         V v = (V)(T)e.Current;
                //         /* loop body */
                //     }
                // }
                // finally {
                //     /* dispose of e */
                // }
                BoundStatement tryFinally = new BoundTryStatement(forEachSyntax,
                                                                  tryBlock: new BoundBlock(forEachSyntax,
                                                                                           localsOpt: ReadOnlyArray <LocalSymbol> .Empty,
                                                                                           statements: ReadOnlyArray <BoundStatement> .CreateFrom(whileLoop)),
                                                                  catchBlocks: ReadOnlyArray <BoundCatchBlock> .Empty,
                                                                  finallyBlockOpt: finallyBlockOpt);

                // E e = ((C)(x)).GetEnumerator();
                // try {
                //     /* as above */
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    localsOpt: ReadOnlyArray <LocalSymbol> .CreateFrom(enumeratorVar),
                    statements: ReadOnlyArray <BoundStatement> .CreateFrom(enumeratorVarDecl, tryFinally));
            }
            else
            {
                // E e = ((C)(x)).GetEnumerator();
                // while (e.MoveNext()) {
                //     V v = (V)(T)e.Current;
                //     /* loop body */
                // }
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    localsOpt: ReadOnlyArray <LocalSymbol> .CreateFrom(enumeratorVar),
                    statements: ReadOnlyArray <BoundStatement> .CreateFrom(enumeratorVarDecl, whileLoop));
            }

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return(result);
        }
Ejemplo n.º 25
0
        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);
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Lower a foreach loop that will enumerate the characters of a string.
        ///
        /// string s = x;
        /// for (int p = 0; p &lt; s.Length; p = p + 1) {
        ///     V v = (V)s.Chars[p];
        ///     // body
        /// }
        /// </summary>
        /// <remarks>
        /// We will follow Dev10 in diverging from the C# 4 spec by ignoring string's
        /// implementation of IEnumerable and just indexing into its characters.
        ///
        /// NOTE: We're assuming that sequence points have already been generated.
        /// Otherwise, lowering to for-loops would generated spurious ones.
        /// </remarks>
        private BoundStatement RewriteStringForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            TypeSymbol      stringType           = collectionExpression.Type;

            Debug.Assert(stringType.SpecialType == SpecialType.System_String);

            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);

            // string s;
            LocalSymbol stringVar = new TempLocalSymbol(stringType, RefKind.None, containingMethod);
            // int p;
            LocalSymbol positionVar = new TempLocalSymbol(intType, RefKind.None, containingMethod);

            // Reference to s.
            BoundLocal boundStringVar = MakeBoundLocal(forEachSyntax, stringVar, stringType);

            // Reference to p.
            BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType);

            // string s = /*expr*/;
            BoundStatement stringVarDecl = MakeLocalDeclaration(forEachSyntax, stringVar, rewrittenExpression);

            AddForEachExpressionSequencePoint(forEachSyntax, ref stringVarDecl);

            // int p = 0;
            BoundStatement positionVariableDecl = MakeLocalDeclaration(forEachSyntax, positionVar,
                                                                       new BoundLiteral(forEachSyntax, ConstantValue.ConstantValueZero.Int32, intType));

            // string s = /*node.Expression*/; int p = 0;
            BoundStatement initializer = new BoundStatementList(forEachSyntax,
                                                                statements: ReadOnlyArray <BoundStatement> .CreateFrom(stringVarDecl, positionVariableDecl));

            BoundExpression stringLength = BoundCall.Synthesized(
                syntax: forEachSyntax,
                receiverOpt: boundStringVar,
                method: (MethodSymbol)compilation.GetSpecialTypeMember(SpecialMember.System_String__Length),
                arguments: ReadOnlyArray <BoundExpression> .Empty);

            // p < s.Length
            BoundExpression exitCondition = new BoundBinaryOperator(
                syntax: forEachSyntax,
                operatorKind: BinaryOperatorKind.IntLessThan,
                left: boundPositionVar,
                right: stringLength,
                constantValueOpt: null,
                methodOpt: null,
                resultKind: LookupResultKind.Viable,
                type: boolType);

            // p = p + 1;
            BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType);

            LocalSymbol iterationVar     = node.IterationVariable;
            TypeSymbol  iterationVarType = iterationVar.Type;

            Debug.Assert(node.ElementConversion.Exists);

            // (V)s.Chars[p]
            BoundExpression iterationVarInitValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundStringVar,
                    method: (MethodSymbol)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__Chars),
                    arguments: ReadOnlyArray <BoundExpression> .CreateFrom(boundPositionVar)),
                conversion: node.ElementConversion,
                type: iterationVarType);

            // V v = (V)s.Chars[p];
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // { V v = (V)s.Chars[p]; /*node.Body*/ }
            BoundStatement loopBody = new BoundBlock(forEachSyntax,
                                                     localsOpt: ReadOnlyArray <LocalSymbol> .CreateFrom(iterationVar),
                                                     statements: ReadOnlyArray <BoundStatement> .CreateFrom(iterationVarDecl, rewrittenBody));

            // for (string s = /*node.Expression*/, int p = 0; p < s.Length; p = p + 1) {
            //     V v = (V)s.Chars[p];
            //     /*node.Body*/
            // }
            BoundStatement result = RewriteForStatement(
                syntax: forEachSyntax,
                locals: ReadOnlyArray <LocalSymbol> .CreateFrom(stringVar, positionVar),
                rewrittenInitializer: initializer,
                rewrittenCondition: exitCondition,
                conditionSyntax: forEachSyntax.InKeyword,
                rewrittenIncrement: positionIncrement,
                rewrittenBody: loopBody,
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel, hasErrors: node.HasErrors);

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return(result);
        }
        public override BoundNode VisitCall(BoundCall node)
        {
            var receiver = node.ReceiverOpt;

            // matches or a bit stronger than EmitReceiverRef
            // if there are any doubts that receiver is a ref type, 
            // assume we will need an address (that will prevent scheduling of receiver).
            if (!node.Method.IsStatic)
            {
                var receiverType = receiver.Type;
                ExprContext context;

                if (receiverType.IsReferenceType)
                {
                    if (receiverType.IsTypeParameter())
                    {
                        // type param receiver that we statically know is a reference will be boxed
                        context = ExprContext.Box;
                    }
                    else
                    {
                        // reference receivers will be used as values
                        context = ExprContext.Value;
                    }
                }
                else
                {
                    // everything else will get an address taken
                    context = ExprContext.Address;
                }

                receiver = VisitExpression(receiver, context);
            }
            else
            {
                // TODO: for some reason receiver could be not null even if method is static...
                //       it seems wrong, ignore for now.
                this.counter += 1;
                receiver = null;
            }

            MethodSymbol method = node.Method;
            var rewrittenArguments = VisitArguments(node.Arguments, method.Parameters);

            return node.Update(receiver, method, rewrittenArguments);
        }
            // 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 };
            }
Ejemplo n.º 29
0
        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));
            }
        }
Ejemplo n.º 30
0
        public override BoundNode VisitCall(BoundCall node)
        {
            Debug.Assert(node != null);

            // Avoid rewriting if node has errors since one or more
            // of the arguments may not be the correct rvalue/lvalue.
            if (node.HasErrors)
            {
                return(node);
            }

            // Start by rewriting the arguments and receiver:
            var rewrittenReceiver  = (BoundExpression)Visit(node.ReceiverOpt);
            var rewrittenArguments = VisitList(node.Arguments);
            var method             = node.Method;

            // If the mapping from arguments to parameters is perfectly in order, no complex rewriting is needed.
            if (node.ArgsToParamsOpt.IsNull && !node.Expanded)
            {
                return(node.Update(rewrittenReceiver, method, rewrittenArguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.Type));
            }

            var argumentRefKinds = node.ArgumentRefKindsOpt;
            ReadOnlyArray <LocalSymbol> temps;

            RewriteArguments(method,
                             node.Expanded,
                             node.ArgsToParamsOpt,
                             ref argumentRefKinds,
                             ref rewrittenArguments,
                             out temps);

            var delegateNode = node as BoundDelegateCall;

            if (temps.IsNullOrEmpty)
            {
                return((delegateNode != null)
                    ? delegateNode.Update(
                           rewrittenReceiver,
                           method,
                           rewrittenArguments,
                           ReadOnlyArray <string> .Null,
                           argumentRefKinds,
                           false,
                           ReadOnlyArray <int> .Null,
                           node.Type)
                    : node.Update(
                           rewrittenReceiver,
                           method,
                           rewrittenArguments,
                           ReadOnlyArray <string> .Null,
                           argumentRefKinds,
                           false,
                           ReadOnlyArray <int> .Null,
                           node.Type));
            }
            else
            {
                return(new BoundSequence(
                           null,
                           null,
                           temps,
                           ReadOnlyArray <BoundExpression> .Empty,
                           (delegateNode != null)
                        ? new BoundDelegateCall(
                               node.Syntax,
                               node.SyntaxTree,
                               rewrittenReceiver,
                               method,
                               rewrittenArguments,
                               ReadOnlyArray <string> .Null,
                               argumentRefKinds,
                               false,
                               ReadOnlyArray <int> .Null,
                               node.Type)
                        : new BoundCall(
                               node.Syntax,
                               node.SyntaxTree,
                               rewrittenReceiver,
                               method,
                               rewrittenArguments,
                               ReadOnlyArray <string> .Null,
                               argumentRefKinds,
                               false,
                               ReadOnlyArray <int> .Null,
                               node.Type),
                           node.Type
                           ));
            }
        }
Ejemplo n.º 31
0
        private void EmitCallExpression(BoundCall call, UseKind useKind)
        {
            var method = call.Method;
            var receiver = call.ReceiverOpt;
            LocalDefinition tempOpt = null;

            // Calls to the default struct constructor are emitted as initobj, rather than call.
            // NOTE: constructor invocations are represented as BoundObjectCreationExpressions,
            // rather than BoundCalls.  This is why we can be confident that if we see a call to a
            // constructor, it has this very specific form.
            if (method.IsDefaultValueTypeConstructor())
            {
                Debug.Assert(method.IsImplicitlyDeclared);
                Debug.Assert(method.ContainingType == receiver.Type);
                Debug.Assert(receiver.Kind == BoundKind.ThisReference);

                tempOpt = EmitReceiverRef(receiver);
                _builder.EmitOpCode(ILOpCode.Initobj);    //  initobj  <MyStruct>
                EmitSymbolToken(method.ContainingType, call.Syntax);
                FreeOptTemp(tempOpt);

                return;
            }

            var arguments = call.Arguments;

            CallKind callKind;

            if (method.IsStatic)
            {
                callKind = CallKind.Call;
            }
            else
            {
                var receiverType = receiver.Type;

                if (receiverType.IsVerifierReference())
                {
                    tempOpt = EmitReceiverRef(receiver, isAccessConstrained: false);

                    // In some cases CanUseCallOnRefTypeReceiver returns true which means that 
                    // null check is unnecessary and we can use "call"
                    if (receiver.SuppressVirtualCalls ||
                        (!method.IsMetadataVirtual() && CanUseCallOnRefTypeReceiver(receiver)))
                    {
                        callKind = CallKind.Call;
                    }
                    else
                    {
                        callKind = CallKind.CallVirt;
                    }
                }
                else if (receiverType.IsVerifierValue())
                {
                    NamedTypeSymbol methodContainingType = method.ContainingType;
                    if (methodContainingType.IsVerifierValue() && MayUseCallForStructMethod(method))
                    {
                        // NOTE: this should be either a method which overrides some abstract method or 
                        //       does not override anything (with few exceptions, see MayUseCallForStructMethod); 
                        //       otherwise we should not use direct 'call' and must use constrained call;

                        // calling a method defined in a value type
                        Debug.Assert(receiverType == methodContainingType);
                        tempOpt = EmitReceiverRef(receiver);
                        callKind = CallKind.Call;
                    }
                    else
                    {
                        if (method.IsMetadataVirtual())
                        {
                            // When calling a method that is virtual in metadata on a struct receiver, 
                            // we use a constrained virtual call. If possible, it will skip boxing.
                            tempOpt = EmitReceiverRef(receiver, isAccessConstrained: true);
                            callKind = CallKind.ConstrainedCallVirt;
                        }
                        else
                        {
                            // calling a method defined in a base class.
                            EmitExpression(receiver, used: true);
                            EmitBox(receiverType, receiver.Syntax);
                            callKind = CallKind.Call;
                        }
                    }
                }
                else
                {
                    // receiver is generic and method must come from the base or an interface or a generic constraint
                    // if the receiver is actually a value type it would need to be boxed.
                    // let .constrained sort this out. 
                    callKind = receiverType.IsReferenceType && !IsRef(receiver) ?
                                CallKind.CallVirt :
                                CallKind.ConstrainedCallVirt;

                    tempOpt = EmitReceiverRef(receiver, isAccessConstrained: callKind == CallKind.ConstrainedCallVirt);
                }
            }

            // When emitting a callvirt to a virtual method we always emit the method info of the
            // method that first declared the virtual method, not the method info of an
            // overriding method. It would be a subtle breaking change to change that rule;
            // see bug 6156 for details.

            MethodSymbol actualMethodTargetedByTheCall = method;
            if (method.IsOverride && callKind != CallKind.Call)
            {
                actualMethodTargetedByTheCall = method.GetConstructedLeastOverriddenMethod(_method.ContainingType);
            }

            if (callKind == CallKind.ConstrainedCallVirt && actualMethodTargetedByTheCall.ContainingType.IsValueType)
            {
                // special case for overridden methods like ToString(...) called on
                // value types: if the original method used in emit cannot use callvirt in this
                // case, change it to Call.
                callKind = CallKind.Call;
            }

            // Devirtualizing of calls to effectively sealed methods.
            if (callKind == CallKind.CallVirt)
            {
                // NOTE: we check that we call method in same module just to be sure
                // that it cannot be recompiled as not final and make our call not verifiable. 
                // such change by adversarial user would arguably be a compat break, but better be safe...
                // In reality we would typically have one method calling another method in the same class (one GetEnumerator calling another).
                // Other scenarios are uncommon since base class cannot be sealed and 
                // referring to a derived type in a different module is not an easy thing to do.
                if (IsThisReceiver(receiver) && actualMethodTargetedByTheCall.ContainingType.IsSealed &&
                        (object)actualMethodTargetedByTheCall.ContainingModule == (object)_method.ContainingModule)
                {
                    // special case for target is in a sealed class and "this" receiver.
                    Debug.Assert(receiver.Type.IsVerifierReference());
                    callKind = CallKind.Call;
                }

                // NOTE: we do not check that we call method in same module.
                // Because of the "GetOriginalConstructedOverriddenMethod" above, the actual target
                // can only be final when it is "newslot virtual final".
                // In such case Dev11 emits "call" and we will just replicate the behavior. (see DevDiv: 546853 )
                else if (actualMethodTargetedByTheCall.IsMetadataFinal && CanUseCallOnRefTypeReceiver(receiver))
                {
                    // special case for calling 'final' virtual method on reference receiver
                    Debug.Assert(receiver.Type.IsVerifierReference());
                    callKind = CallKind.Call;
                }
            }

            EmitArguments(arguments, method.Parameters);
            int stackBehavior = GetCallStackBehavior(call);
            switch (callKind)
            {
                case CallKind.Call:
                    _builder.EmitOpCode(ILOpCode.Call, stackBehavior);
                    break;

                case CallKind.CallVirt:
                    _builder.EmitOpCode(ILOpCode.Callvirt, stackBehavior);
                    break;

                case CallKind.ConstrainedCallVirt:
                    _builder.EmitOpCode(ILOpCode.Constrained);
                    EmitSymbolToken(receiver.Type, receiver.Syntax);
                    _builder.EmitOpCode(ILOpCode.Callvirt, stackBehavior);
                    break;
            }

            EmitSymbolToken(actualMethodTargetedByTheCall, call.Syntax,
                            actualMethodTargetedByTheCall.IsVararg ? (BoundArgListOperator)call.Arguments[call.Arguments.Length - 1] : null);

            if (!method.ReturnsVoid)
            {
                EmitPopIfUnused(useKind != UseKind.Unused);
            }
            else if (_ilEmitStyle == ILEmitStyle.Debug)
            {
                // The only void methods with usable return values are constructors and we represent those
                // as BoundObjectCreationExpressions, not BoundCalls.
                Debug.Assert(useKind == UseKind.Unused, "Using the return value of a void method.");
                Debug.Assert(_method.GenerateDebugInfo, "Implied by this.emitSequencePoints");

                // DevDiv #15135.  When a method like System.Diagnostics.Debugger.Break() is called, the
                // debugger sees an event indicating that a user break (vs a breakpoint) has occurred.
                // When this happens, it uses ICorDebugILFrame.GetIP(out uint, out CorDebugMappingResult)
                // to determine the current instruction pointer.  This method returns the instruction
                // *after* the call.  The source location is then given by the last sequence point before
                // or on this instruction.  As a result, if the instruction after the call has its own
                // sequence point, then that sequence point will be used to determine the source location
                // and the debugging experience will be disrupted.  The easiest way to ensure that the next
                // instruction does not have a sequence point is to insert a nop.  Obviously, we only do this
                // if debugging is enabled and optimization is disabled.

                // From ILGENREC::genCall:
                //   We want to generate a NOP after CALL opcodes that end a statement so the debugger
                //   has better stepping behavior

                // CONSIDER: In the native compiler, there's an additional restriction on when this nop is
                // inserted.  It is quite complicated, but it basically seems to say that, if we thought
                // we could omit the temp-and-copy for a struct construction and it turned out that we
                // couldn't (perhaps because the assigned local was captured by a lambda), and if we're
                // not using the result of the constructor call (how can this even happen?), then we don't
                // want to insert the nop.  Since the consequence of not implementing this complicated logic
                // is an extra nop in debug code, this is likely not a priority.

                // CONSIDER: The native compiler also checks !(tree->flags & EXF_NODEBUGINFO).  We don't have
                // this mutable bit on our bound nodes, so we can't exactly match the behavior.  We might be
                // able to approximate the native behavior by inspecting call.WasCompilerGenerated, but it is
                // not in a reliable state after lowering.

                _builder.EmitOpCode(ILOpCode.Nop);
            }

            if (useKind == UseKind.UsedAsValue && method.RefKind != RefKind.None)
            {
                EmitLoadIndirect(method.ReturnType, call.Syntax);
            }
            else if (useKind == UseKind.UsedAsAddress)
            {
                Debug.Assert(method.RefKind != RefKind.None);
            }

            FreeOptTemp(tempOpt);
        }
Ejemplo n.º 32
0
        private static int GetCallStackBehavior(BoundCall call)
        {
            int stack = 0;

            if (!call.Method.ReturnsVoid)
            {
                // The call puts the return value on the stack.
                stack += 1;
            }

            if (!call.Method.IsStatic)
            {
                // The call pops the receiver off the stack.
                stack -= 1;
            }

            if (call.Method.IsVararg)
            {
                // The call pops all the arguments, fixed and variadic.
                int fixedArgCount = call.Arguments.Length - 1;
                int varArgCount = ((BoundArgListOperator)call.Arguments[fixedArgCount]).Arguments.Length;
                stack -= fixedArgCount;
                stack -= varArgCount;
            }
            else
            {
                // The call pops all the arguments.
                stack -= call.Arguments.Length;
            }

            return stack;
        }
Ejemplo n.º 33
0
        private BoundValueType EmitCall(BoundCall node)
        {
            // Emit the arguments to the call.

            EmitExpression(node.Method);
            IL.Emit(OpCodes.Castclass, typeof(JsObject));
            _scope.EmitLoad(SpecialLocal.Runtime);
            EmitBox(EmitExpression(node.Target));

            return EmitMethodArgumentsAndGenerics(
                _objectExecute,
                node.Arguments,
                node.Generics
            );
        }