/// <summary>
        /// <![CDATA[
        /// fixed(int* ptr = &v){ ... }    == becomes ===>
        ///
        /// pinned ref int pinnedTemp = ref v;    // pinning managed ref
        /// int* ptr = (int*)&pinnedTemp;         // unsafe cast to unmanaged ptr
        ///   . . .
        /// ]]>
        /// </summary>
        private BoundStatement InitializeFixedStatementRegularLocal(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol pinnedTemp)
        {
            TypeSymbol      localType       = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);

            // initializer expr should be either an address(&) of something or a fixed field access.
            // either should lower into addressof
            Debug.Assert(initializerExpr.Kind == BoundKind.AddressOfOperator);

            TypeSymbol initializerType = ((PointerTypeSymbol)initializerExpr.Type).PointedAtType;

            // initializer expressions are bound/lowered right into addressof operators here
            // that is a bit too far
            // we need to pin the underlying field, and only then take the address.
            initializerExpr = ((BoundAddressOfOperator)initializerExpr).Operand;

            // intervening parens may have been skipped by the binder; find the declarator
            VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclaratorSyntax>();

            Debug.Assert(declarator != null);

            pinnedTemp = factory.SynthesizedLocal(
                initializerType,
                syntax: declarator,
                isPinned: true,
                //NOTE: different from the array and string cases
                //      RefReadOnly to allow referring to readonly variables. (technically we only "read" through the temp anyways)
                refKind: RefKind.RefReadOnly,
                kind: SynthesizedLocalKind.FixedReference);

            // NOTE: we pin the reference, not the pointer.
            Debug.Assert(pinnedTemp.IsPinned);
            Debug.Assert(!localSymbol.IsPinned);

            // pinnedTemp = ref v;
            BoundStatement pinnedTempInit = factory.Assignment(factory.Local(pinnedTemp), initializerExpr, isRef: true);

            // &pinnedTemp
            var addr = new BoundAddressOfOperator(
                factory.Syntax,
                factory.Local(pinnedTemp),
                type: fixedInitializer.ElementPointerType);

            // (int*)&pinnedTemp
            var pointerValue = factory.Convert(
                localType,
                addr,
                fixedInitializer.ElementPointerTypeConversion);

            // ptr = (int*)&pinnedTemp;
            BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol,
                                                                             factory.Assignment(factory.Local(localSymbol), pointerValue));

            return(factory.Block(pinnedTempInit, localInit));
        }
Пример #2
0
        public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
        {
            BoundSpillSequenceBuilder builder = null;
            var expr = VisitExpression(ref builder, node.Operand);

            return(UpdateExpression(builder, node.Update(expr, node.IsManaged, node.Type)));
        }
 public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
 {
     // Pretend address-of is a pure read (i.e. no write) - would we see an
     // unassigned diagnostic?
     VisitRvalue(node.Operand);
     return(null);
 }
Пример #4
0
        private BoundExpression MakeFieldAccess(
            SyntaxNode syntax,
            BoundExpression rewrittenReceiver,
            FieldSymbol fieldSymbol,
            ConstantValue constantValueOpt,
            LookupResultKind resultKind,
            TypeSymbol type,
            BoundFieldAccess oldNodeOpt = null)
        {
            if (fieldSymbol.IsTupleField)
            {
                return(MakeTupleFieldAccess(syntax, fieldSymbol, rewrittenReceiver, constantValueOpt, resultKind));
            }

            BoundExpression result = oldNodeOpt != null?
                                     oldNodeOpt.Update(rewrittenReceiver, fieldSymbol, constantValueOpt, resultKind, type) :
                                         new BoundFieldAccess(syntax, rewrittenReceiver, fieldSymbol, constantValueOpt, resultKind, type);

            if (fieldSymbol.IsFixedSizeBuffer)
            {
                // a reference to a fixed buffer is translated into its address
                result = new BoundAddressOfOperator(syntax, result, type, false);
            }

            return(result);
        }
Пример #5
0
        public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
        {
            BoundSpillSequence2 ss = null;
            var expr = VisitExpression(ref ss, node.Operand);

            return(UpdateExpression(ss, node.Update(expr, node.IsFixedStatementAddressOf, node.Type)));
        }
 public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
 {
     // Pretend address-of is a pure read (i.e. no write) - would we see an 
     // unassigned diagnostic?
     VisitRvalue(node.Operand);
     return null;
 }
Пример #7
0
        public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
        {
            CheckUnsafeType(node);
            BoundExpression operand = node.Operand;

            if (operand.Kind == BoundKind.FieldAccess)
            {
                CheckFieldAddress((BoundFieldAccess)operand, consumerOpt: null);
            }
            return(base.VisitAddressOfOperator(node));
        }
        private BoundStatement InitializeFixedStatementArrayLocal(
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol arrayTemp)
        {
            // From ExpressionBinder::BindPtrToArray:
            // (((temp = array) != null && temp.Length > 0) ? loc = &temp[0] : loc = null)
            // NOTE: The assignment needs to be inside the EK_QUESTIONMARK. See Whidbey bug #397859.
            // We can't do loc = (... ? ... : ...) since the CLR type of &temp[0] is a managed
            // pointer and null is a UIntPtr - which confuses the JIT. We can't just convert
            // &temp[0] to UIntPtr with a conv.u instruction because then if a GC occurs between
            // the time of the cast and the assignment to the local, we're toast.

            TypeSymbol      localType       = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol      initializerType = initializerExpr.Type;

            arrayTemp = factory.SynthesizedLocal(initializerType);
            ArrayTypeSymbol arrayType        = (ArrayTypeSymbol)arrayTemp.Type;
            TypeSymbol      arrayElementType = arrayType.ElementType;
            int             arrayRank        = arrayType.Rank;

            // NOTE: we pin the pointer, not the array.
            Debug.Assert(!arrayTemp.IsPinned);
            Debug.Assert(localSymbol.IsPinned);

            //(temp = array)
            BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(arrayTemp), initializerExpr);

            //(temp = array) != null
            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual);

            BoundExpression lengthCall;

            if (arrayRank == 1)
            {
                lengthCall = factory.ArrayLength(factory.Local(arrayTemp));
            }
            else
            {
                MethodSymbol lengthMethod;
                if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod))
                {
                    lengthCall = factory.Call(factory.Local(arrayTemp), lengthMethod);
                }
                else
                {
                    lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(factory.Local(arrayTemp)), ErrorTypeSymbol.UnknownResultType);
                }
            }

            // NOTE: dev10 comment says ">", but code actually checks "!="
            //temp.Length != 0
            BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0));

            //((temp = array) != null && temp.Length != 0)
            BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck);

            //temp[0]
            BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(arrayTemp));

            // NOTE: this is a fixed statement address-of in that it's the initial value of pinned local.
            //&temp[0]
            BoundExpression firstElementAddress          = new BoundAddressOfOperator(factory.Syntax, firstElement, isFixedStatementAddressOf: true, type: new PointerTypeSymbol(arrayElementType));
            BoundExpression convertedFirstElementAddress = factory.Convert(
                localType,
                firstElementAddress,
                fixedInitializer.ElementPointerTypeConversion);

            //loc = &temp[0]
            BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress);

            //loc = null
            BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType));

            //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null)
            BoundStatement localInit = factory.ExpressionStatement(
                new BoundConditionalOperator(factory.Syntax, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType));

            return(AddLocalDeclarationSequencePointIfNecessary(fixedInitializer.Syntax.Parent.Parent, localSymbol, localInit));
        }
        private BoundStatement InitializeFixedStatementArrayLocal(
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol arrayTemp)
        {
            // From ExpressionBinder::BindPtrToArray:
            // (((temp = array) != null && temp.Length > 0) ? loc = &temp[0] : loc = null)
            // NOTE: The assignment needs to be inside the EK_QUESTIONMARK. See Whidbey bug #397859.
            // We can't do loc = (... ? ... : ...) since the CLR type of &temp[0] is a managed
            // pointer and null is a UIntPtr - which confuses the JIT. We can't just convert
            // &temp[0] to UIntPtr with a conv.u instruction because then if a GC occurs between
            // the time of the cast and the assignment to the local, we're toast.

            TypeSymbol localType = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol initializerType = initializerExpr.Type;

            arrayTemp = factory.SynthesizedLocal(initializerType);
            ArrayTypeSymbol arrayType = (ArrayTypeSymbol)arrayTemp.Type;
            TypeSymbol arrayElementType = arrayType.ElementType;
            int arrayRank = arrayType.Rank;

            // NOTE: we pin the pointer, not the array.
            Debug.Assert(!arrayTemp.IsPinned);
            Debug.Assert(localSymbol.IsPinned);

            //(temp = array)
            BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(arrayTemp), initializerExpr);

            //(temp = array) != null
            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual);

            BoundExpression lengthCall;

            if (arrayRank == 1)
            {
                lengthCall = factory.ArrayLength(factory.Local(arrayTemp));
            }
            else
            {
                MethodSymbol lengthMethod;
                if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod))
                {
                    lengthCall = factory.Call(factory.Local(arrayTemp), lengthMethod);
                }
                else
                {
                    lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(factory.Local(arrayTemp)), ErrorTypeSymbol.UnknownResultType);
                }
            }

            // NOTE: dev10 comment says ">", but code actually checks "!="
            //temp.Length != 0
            BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0));

            //((temp = array) != null && temp.Length != 0)
            BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck);

            //temp[0]
            BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(arrayTemp));

            // NOTE: this is a fixed statement address-of in that it's the initial value of pinned local.
            //&temp[0]
            BoundExpression firstElementAddress = new BoundAddressOfOperator(factory.Syntax, firstElement, isFixedStatementAddressOf: true, type: new PointerTypeSymbol(arrayElementType));
            BoundExpression convertedFirstElementAddress = factory.Convert(
                localType,
                firstElementAddress, 
                fixedInitializer.ElementPointerTypeConversion);

            //loc = &temp[0]
            BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress);

            //loc = null
            BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType));

            //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null)
            BoundStatement localInit = factory.ExpressionStatement(
                new BoundConditionalOperator(factory.Syntax, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType));

            return AddLocalDeclarationSequencePointIfNecessary(fixedInitializer.Syntax.Parent.Parent, localSymbol, localInit);
        }
Пример #10
0
 public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
 {
     BoundSpillSequence2 ss = null;
     var expr = VisitExpression(ref ss, node.Operand);
     return UpdateExpression(ss, node.Update(expr, node.IsFixedStatementAddressOf, node.Type));
 }
        /// <summary>
        /// <![CDATA[
        /// fixed(int* ptr = arr){ ... }    == becomes ===>
        ///
        /// pinned int[] pinnedTemp = arr;         // pinning managed ref
        /// int* ptr = pinnedTemp != null && pinnedTemp.Length != 0
        ///                (int*)&pinnedTemp[0]:   // unsafe cast to unmanaged ptr
        ///                0;
        ///   . . .
        ///   ]]>
        /// </summary>
        private BoundStatement InitializeFixedStatementArrayLocal(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol pinnedTemp)
        {
            TypeSymbol      localType       = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol      initializerType = initializerExpr.Type;

            pinnedTemp = factory.SynthesizedLocal(initializerType, isPinned: true);
            ArrayTypeSymbol     arrayType        = (ArrayTypeSymbol)pinnedTemp.Type;
            TypeWithAnnotations arrayElementType = arrayType.ElementTypeWithAnnotations;

            // NOTE: we pin the array, not the pointer.
            Debug.Assert(pinnedTemp.IsPinned);
            Debug.Assert(!localSymbol.IsPinned);

            //(pinnedTemp = array)
            BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(pinnedTemp), initializerExpr);

            //(pinnedTemp = array) != null
            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual);

            BoundExpression lengthCall;

            if (arrayType.IsSZArray)
            {
                lengthCall = factory.ArrayLength(factory.Local(pinnedTemp));
            }
            else
            {
                MethodSymbol lengthMethod;
                if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod))
                {
                    lengthCall = factory.Call(factory.Local(pinnedTemp), lengthMethod);
                }
                else
                {
                    lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(factory.Local(pinnedTemp)), ErrorTypeSymbol.UnknownResultType);
                }
            }

            // NOTE: dev10 comment says ">", but code actually checks "!="
            //temp.Length != 0
            BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0));

            //((temp = array) != null && temp.Length != 0)
            BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck);

            //temp[0]
            BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(pinnedTemp));

            // NOTE: this is a fixed statement address-of in that it's the initial value of the pointer.
            //&temp[0]
            BoundExpression firstElementAddress          = new BoundAddressOfOperator(factory.Syntax, firstElement, type: new PointerTypeSymbol(arrayElementType));
            BoundExpression convertedFirstElementAddress = factory.Convert(
                localType,
                firstElementAddress,
                fixedInitializer.ElementPointerTypeConversion);

            //loc = &temp[0]
            BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress);

            //loc = null
            BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType));

            //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null)
            BoundStatement localInit = factory.ExpressionStatement(
                new BoundConditionalOperator(factory.Syntax, false, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType));

            return(InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, localInit));
        }
        /// <summary>
        /// <![CDATA[
        /// fixed(int* ptr = &v){ ... }    == becomes ===>
        ///
        /// pinned ref int pinnedTemp = ref v;    // pinning managed ref
        /// int* ptr = (int*)&pinnedTemp;         // unsafe cast to unmanaged ptr
        ///   . . .
        /// ]]>
        /// </summary>
        private BoundStatement InitializeFixedStatementGetPinnable(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol pinnedTemp)
        {
            TypeSymbol      localType       = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);

            var initializerType   = initializerExpr.Type;
            var initializerSyntax = initializerExpr.Syntax;
            var getPinnableMethod = fixedInitializer.GetPinnableOpt;

            // intervening parens may have been skipped by the binder; find the declarator
            VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclaratorSyntax>();

            Debug.Assert(declarator != null);

            // pinned ref int pinnedTemp
            pinnedTemp = factory.SynthesizedLocal(
                getPinnableMethod.ReturnType,
                syntax: declarator,
                isPinned: true,
                //NOTE: different from the array and string cases
                //      RefReadOnly to allow referring to readonly variables. (technically we only "read" through the temp anyways)
                refKind: RefKind.RefReadOnly,
                kind: SynthesizedLocalKind.FixedReference);

            BoundExpression callReceiver;
            int             currentConditionalAccessID = 0;

            bool needNullCheck = !initializerType.IsValueType;

            if (needNullCheck)
            {
                currentConditionalAccessID = ++_currentConditionalAccessID;
                callReceiver = new BoundConditionalReceiver(
                    initializerSyntax,
                    currentConditionalAccessID,
                    initializerType);
            }
            else
            {
                callReceiver = initializerExpr;
            }

            // .GetPinnable()
            var getPinnableCall = getPinnableMethod.IsStatic ?
                                  factory.Call(null, getPinnableMethod, callReceiver) :
                                  factory.Call(callReceiver, getPinnableMethod);

            // temp =ref .GetPinnable()
            var tempAssignment = factory.AssignmentExpression(
                factory.Local(pinnedTemp),
                getPinnableCall,
                isRef: true);

            // &pinnedTemp
            var addr = new BoundAddressOfOperator(
                factory.Syntax,
                factory.Local(pinnedTemp),
                type: fixedInitializer.ElementPointerType);

            // (int*)&pinnedTemp
            var pointerValue = factory.Convert(
                localType,
                addr,
                fixedInitializer.ElementPointerTypeConversion);

            // {pinnedTemp =ref .GetPinnable(), (int*)&pinnedTemp}
            BoundExpression pinAndGetPtr = factory.Sequence(
                locals: ImmutableArray <LocalSymbol> .Empty,
                sideEffects: ImmutableArray.Create <BoundExpression>(tempAssignment),
                result: pointerValue);

            if (needNullCheck)
            {
                // initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default;
                pinAndGetPtr = new BoundLoweredConditionalAccess(
                    initializerSyntax,
                    initializerExpr,
                    hasValueMethodOpt: null,
                    whenNotNull: pinAndGetPtr,
                    whenNullOpt: null, // just return default(T*)
                    currentConditionalAccessID,
                    localType);
            }

            // ptr = initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default;
            BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, factory.Assignment(factory.Local(localSymbol), pinAndGetPtr));

            return(localInit);
        }
 public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
 {
     CheckUnsafeType(node);
     BoundExpression operand = node.Operand;
     if (operand.Kind == BoundKind.FieldAccess)
     {
         CheckFieldAddress((BoundFieldAccess)operand, consumerOpt: null);
     }
     return base.VisitAddressOfOperator(node);
 }
 public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
 {
     _mightAssignSomething = true;
     return(null);
 }