Example #1
0
        /// <summary>
        /// Emits address as in &amp;
        ///
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addressKind)
        {
            switch (expression.Kind)
            {
            case BoundKind.RefValueOperator:
                EmitRefValueAddress((BoundRefValueOperator)expression);
                break;

            case BoundKind.Local:
                EmitLocalAddress((BoundLocal)expression);
                break;

            case BoundKind.Dup:
                Debug.Assert(((BoundDup)expression).RefKind != RefKind.None, "taking address of a stack value?");
                builder.EmitOpCode(ILOpCode.Dup);
                break;

            case BoundKind.Parameter:
                EmitParameterAddress((BoundParameter)expression);
                break;

            case BoundKind.FieldAccess:
                return(EmitFieldAddress((BoundFieldAccess)expression));

            case BoundKind.ArrayAccess:
                //arrays are covariant, but elements can be written to.
                //the flag tells that we do not intend to use the address for writing.
                EmitArrayElementAddress((BoundArrayAccess)expression, addressKind);
                break;

            case BoundKind.ThisReference:
                Debug.Assert(expression.Type.IsValueType, "only valuetypes may need a ref to this");
                builder.EmitOpCode(ILOpCode.Ldarg_0);
                break;

            case BoundKind.PreviousSubmissionReference:
                // script references are lowered to a this reference and a field access
                throw ExceptionUtilities.UnexpectedValue(expression.Kind);

            case BoundKind.BaseReference:
                Debug.Assert(false, "base is always a reference type, why one may need a reference to it?");
                break;

            case BoundKind.Sequence:
                return(EmitSequenceAddress((BoundSequence)expression, addressKind));

            case BoundKind.PointerIndirectionOperator:
                // The address of a dereferenced address is that address.
                BoundExpression operand = ((BoundPointerIndirectionOperator)expression).Operand;
                Debug.Assert(operand.Type.IsPointerType());
                EmitExpression(operand, used: true);
                break;

            default:
                Debug.Assert(!HasHome(expression));
                return(EmitAddressOfTempClone(expression));
            }

            return(null);
        }
Example #2
0
        /// <summary>
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitSequenceAddress(BoundSequence sequence, AddressKind addressKind)
        {
            var hasLocals = !sequence.Locals.IsEmpty;

            if (hasLocals)
            {
                _builder.OpenLocalScope();

                foreach (var local in sequence.Locals)
                {
                    DefineLocal(local, sequence.Syntax);
                }
            }

            EmitSideEffects(sequence);
            var tempOpt = EmitAddress(sequence.Value, addressKind);

            // when a sequence is happened to be a byref receiver
            // we may need to extend the life time of the target until we are done accessing it
            // {.v ; v = Foo(); v}.Bar()     // v should be released only after Bar() is done.
            LocalSymbol doNotRelease = null;

            if (tempOpt == null)
            {
                doNotRelease = DigForValueLocal(sequence);
                if (doNotRelease != null)
                {
                    tempOpt = GetLocal(doNotRelease);
                }
            }

            FreeLocals(sequence, doNotRelease);
            return(tempOpt);
        }
Example #3
0
        private void EmitArrayElementAddress(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            EmitExpression(arrayAccess.Expression, used: true);
            EmitArrayIndices(arrayAccess.Indices);

            if (ShouldEmitReadOnlyPrefix(arrayAccess, addressKind))
            {
                _builder.EmitOpCode(ILOpCode.Readonly);
            }

            if (((ArrayTypeSymbol)arrayAccess.Expression.Type).IsSZArray)
            {
                _builder.EmitOpCode(ILOpCode.Ldelema);
                var elementType = arrayAccess.Type;
                EmitSymbolToken(elementType, arrayAccess.Syntax);
            }
            else
            {
                _builder.EmitArrayElementAddress(
                    _module.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type),
                    arrayAccess.Syntax,
                    _diagnostics
                    );
            }
        }
Example #4
0
        /// <summary>
        /// Emits address as in &amp; 
        /// 
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addressKind)
        {
            switch (expression.Kind)
            {
                case BoundKind.RefValueOperator:
                    EmitRefValueAddress((BoundRefValueOperator)expression);
                    break;

                case BoundKind.Local:
                    EmitLocalAddress((BoundLocal)expression);
                    break;

                case BoundKind.Dup:
                    Debug.Assert(((BoundDup)expression).RefKind != RefKind.None, "taking address of a stack value?");
                    builder.EmitOpCode(ILOpCode.Dup);
                    break;

                case BoundKind.Parameter:
                    EmitParameterAddress((BoundParameter)expression);
                    break;

                case BoundKind.FieldAccess:
                    return EmitFieldAddress((BoundFieldAccess)expression);

                case BoundKind.ArrayAccess:
                    //arrays are covariant, but elements can be written to.
                    //the flag tells that we do not intend to use the address for writing.
                    EmitArrayElementAddress((BoundArrayAccess)expression, addressKind);
                    break;

                case BoundKind.ThisReference:
                    Debug.Assert(expression.Type.IsValueType, "only valuetypes may need a ref to this");
                    builder.EmitOpCode(ILOpCode.Ldarg_0);
                    break;

                case BoundKind.PreviousSubmissionReference:
                    // script references are lowered to a this reference and a field access
                    throw ExceptionUtilities.UnexpectedValue(expression.Kind);

                case BoundKind.BaseReference:
                    Debug.Assert(false, "base is always a reference type, why one may need a reference to it?");
                    break;

                case BoundKind.Sequence:
                    return EmitSequenceAddress((BoundSequence)expression, addressKind);

                case BoundKind.PointerIndirectionOperator:
                    // The address of a dereferenced address is that address.
                    BoundExpression operand = ((BoundPointerIndirectionOperator)expression).Operand;
                    Debug.Assert(operand.Type.IsPointerType());
                    EmitExpression(operand, used: true);
                    break;

                default:
                    Debug.Assert(!HasHome(expression));
                    return EmitAddressOfTempClone(expression);
            }

            return null;
        }
        public async Task <ICollection <AddressAM> > GetNearestAddresses(AddressKind kind, Coordinate originCoordinate, double distance = 500, int maxResultCount = 5)
        {
            var coordinateBounds = await DirectionService.GetCoordinateBounds(originCoordinate, distance);

            var domainAddresses = await DomainAddressService.GetByCoordinateBounds(
                kind,
                coordinateBounds.MinLatitude,
                coordinateBounds.MinLongitude,
                coordinateBounds.MaxLatitude,
                coordinateBounds.MaxLongitude);

            var nearestDomainAddresses = new List <Address>();

            if (domainAddresses.Any())
            {
                var nearestCoordinates = await DirectionService.GetNearestCoordinates(originCoordinate, domainAddresses.Select(a => a.ToCoordinate()), maxResultCount);

                foreach (var coordinate in nearestCoordinates)
                {
                    var domainAddress = domainAddresses.First(a => a.Latitude.Equals(coordinate.Latitude) && a.Longitude.Equals(coordinate.Longitude));
                    nearestDomainAddresses.Add(domainAddress);
                }
            }

            return(FromDomainAddresses(nearestDomainAddresses));
        }
Example #6
0
        private void EmitArrayElementAddress(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            EmitExpression(arrayAccess.Expression, used: true);
            EmitArrayIndices(arrayAccess.Indices);

            if (addressKind == AddressKind.ReadOnly)
            {
                Debug.Assert(arrayAccess.Type.TypeKind == TypeKind.TypeParameter,
                             ".readonly is only needed when element type is a type param");

                _builder.EmitOpCode(ILOpCode.Readonly);
            }

            if (arrayAccess.Indices.Length == 1)
            {
                _builder.EmitOpCode(ILOpCode.Ldelema);
                var elementType = arrayAccess.Type;
                EmitSymbolToken(elementType, arrayAccess.Syntax);
            }
            else
            {
                _builder.EmitArrayElementAddress(Emit.PEModuleBuilder.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type),
                                                 arrayAccess.Syntax, _diagnostics);
            }
        }
Example #7
0
        /// <summary>
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitLocalAddress(BoundLocal localAccess, AddressKind addressKind)
        {
            var local = localAccess.LocalSymbol;

            if (!HasHome(localAccess, addressKind))
            {
                return(EmitAddressOfTempClone(localAccess));
            }

            if (IsStackLocal(local))
            {
                if (local.RefKind != RefKind.None)
                {
                    // do nothing, ref should be on the stack
                }
                else
                {
                    // cannot get address of a stack value.
                    // Something is wrong with optimizer
                    throw ExceptionUtilities.UnexpectedValue(local.RefKind);
                }
            }
            else
            {
                _builder.EmitLocalAddress(GetLocal(localAccess));
            }

            return(null);
        }
Example #8
0
        public Task <Address> Create(
            AddressKind kind,
            string request,
            string country,
            string province,
            string area,
            string locality,
            string district,
            string street,
            string house,
            double latitude,
            double longitude,
            double adjustedLatitude  = 0,
            double adjustedLongitude = 0)
        {
            var address = new Address
            {
                Kind              = kind,
                Request           = request,
                Country           = country,
                Province          = province,
                Area              = area,
                Locality          = locality,
                District          = district,
                Street            = street,
                House             = house,
                Latitude          = latitude,
                Longitude         = longitude,
                AdjustedLatitude  = adjustedLatitude,
                AdjustedLongitude = adjustedLongitude
            };

            return(Create(address));
        }
Example #9
0
 public static Address FromDB(dynamic record)
 {
     if (record == null)
     {
         return(null);
     }
     return(new Address
     {
         addressID = record.addressID,
         jobTitleID = record.jobTitleID,
         userID = record.userID,
         addressName = record.addressName,
         addressLine1 = record.addressLine1,
         addressLine2 = record.addressLine2,
         postalCodeID = record.postalCodeID,
         postalCode = record.postalCode,
         city = record.city,
         stateProvinceID = record.stateProvinceID,
         stateProvinceCode = record.stateProvinceCode,
         stateProvinceName = record.stateProvinceName,
         countryID = record.countryID,
         countryCode = record.countryCode,
         latitude = record.latitude,
         longitude = record.longitude,
         specialInstructions = record.specialInstructions,
         isServiceLocation = record.isServiceLocation,
         isServiceArea = record.isServiceArea,
         serviceRadius = N.D(record.serviceRadius) == null ? null : DataTypes.GetTypedValue <decimal?>(record.serviceRadius, 0),
         createdDate = record.createdDate,
         updatedDate = record.updatedDate,
         kind = AddressKind.GetFromAddressDBRecord(record),
         createdBy = record.createdBy
     });
 }
Example #10
0
        private void EmitConditionalOperatorAddress(
            BoundConditionalOperator expr,
            AddressKind addressKind
            )
        {
            Debug.Assert(
                expr.ConstantValue == null,
                "Constant value should have been emitted directly"
                );

            object consequenceLabel = new object();
            object doneLabel        = new object();

            EmitCondBranch(expr.Condition, ref consequenceLabel, sense: true);
            AddExpressionTemp(EmitAddress(expr.Alternative, addressKind));

            _builder.EmitBranch(ILOpCode.Br, doneLabel);

            // If we get to consequenceLabel, we should not have Alternative on stack, adjust for that.
            _builder.AdjustStack(-1);

            _builder.MarkLabel(consequenceLabel);
            AddExpressionTemp(EmitAddress(expr.Consequence, addressKind));

            _builder.MarkLabel(doneLabel);
        }
Example #11
0
 public async Task <ICollection <Address> > GetInCoordinateBounds(AddressKind kind, double minLatitude, double minLongitude, double maxLatitude, double maxLongitude)
 {
     return(await Entities.Where(i =>
                                 i.Kind.Equals(kind) &&
                                 (i.Latitude >= minLatitude) && (i.Latitude <= maxLatitude) &&
                                 (i.Longitude >= minLongitude) && (i.Longitude <= maxLongitude)).ToListAsync());
 }
Example #12
0
        private LocalDefinition EmitParameterAddress(
            BoundParameter parameter,
            AddressKind addressKind
            )
        {
            ParameterSymbol parameterSymbol = parameter.ParameterSymbol;

            if (!HasHome(parameter, addressKind))
            {
                // accessing a parameter that is not writable
                return(EmitAddressOfTempClone(parameter));
            }

            int slot = ParameterSlot(parameter);

            if (parameterSymbol.RefKind == RefKind.None)
            {
                _builder.EmitLoadArgumentAddrOpcode(slot);
            }
            else
            {
                _builder.EmitLoadArgumentOpcode(slot);
            }

            return(null);
        }
Example #13
0
 private bool HasHome(BoundExpression expression, AddressKind addressKind) =>
 Binder.HasHome(
     expression,
     addressKind,
     _method,
     IsPeVerifyCompatEnabled(),
     _stackLocals
     );
Example #14
0
        public Task <ICollection <string> > GetProvinces(AddressKind kind, string country, OrderingKind orderingKind = OrderingKind.None)
        {
            if (string.IsNullOrEmpty(country))
            {
                throw new ArgumentNullException("Country");
            }

            return(Repository.GetProvinces(kind, country, orderingKind));
        }
Example #15
0
        /// <summary>
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitSequenceAddress(BoundSequence sequence, AddressKind addressKind)
        {
            DefineAndRecordLocals(sequence);
            EmitSideEffects(sequence);
            var result = EmitAddress(sequence.Value, addressKind);

            CloseScopeAndKeepLocals(sequence);

            return(result);
        }
Example #16
0
        /// <summary>
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitDupAddress(BoundDup dup, AddressKind addressKind)
        {
            if (!HasHome(dup, needWriteable: addressKind != AddressKind.ReadOnly))
            {
                return(EmitAddressOfTempClone(dup));
            }

            _builder.EmitOpCode(ILOpCode.Dup);
            return(null);
        }
Example #17
0
        /// <summary>
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitDupAddress(BoundDup dup, AddressKind addressKind)
        {
            if (!HasHome(dup, addressKind))
            {
                return(EmitAddressOfTempClone(dup));
            }

            _builder.EmitOpCode(ILOpCode.Dup);
            return(null);
        }
Example #18
0
 public async Task <ICollection <Address> > GetByGeocoding(AddressKind kind, string country, string province = null, string locality = null, string district = null, string street = null, string house = null)
 {
     return(await Entities.Where(i =>
                                 i.Kind.Equals(kind) &&
                                 country.Equals(i.Country) &&
                                 ((province == null) || province.Equals(i.Province)) &&
                                 ((locality == null) || locality.Equals(i.Locality)) &&
                                 ((district == null) || district.Equals(i.District)) &&
                                 ((street == null) || street.Equals(i.Street))
                                 ).ToListAsync());
 }
Example #19
0
 internal MailAddress(Button buttonKind, TextBox textBox, ListBox listBox, Label dispSwitch, Label listReplyTo)
 {
     addressKind    = new AddressKind(this, buttonKind);
     this.textBox   = textBox;
     this.listBox   = listBox;
     replyToAddress = new ReplyToAddress(dispSwitch, listReplyTo);
     try {
         var def = Properties.Settings.Default;
         Connection = new Connection($"LDAP://{def.Host}:{def.Port}/{def.Base}");
     } catch (System.Exception) {
         Connection = null;
     }
 }
Example #20
0
        private void EmitArrayElementAddress(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            EmitExpression(arrayAccess.Expression, used: true);
            EmitArrayIndex(arrayAccess.Index);

            if (ShouldEmitReadOnlyPrefix(arrayAccess, addressKind))
            {
                _builder.EmitOpCode(ILOpCode.Readonly);
            }

            _builder.EmitOpCode(ILOpCode.Ldelema);
            var elementType = arrayAccess.Type;

            EmitSymbolToken(elementType, arrayAccess.Syntax);
        }
Example #21
0
        private bool ShouldEmitReadOnlyPrefix(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            if (addressKind == AddressKind.Constrained)
            {
                Debug.Assert(arrayAccess.Type.TypeKind == TypeKind.TypeParameter, "constrained call should only be used with type parameter types");
                return(true);
            }

            if (!IsAnyReadOnly(addressKind))
            {
                return(false);
            }

            // no benefits to value types
            return(!arrayAccess.Type.IsValueType);
        }
 public Task <Address> CreateDomainAddress(AddressKind kind, AddressAM address)
 {
     return(DomainAddressService.Create(
                kind,
                address.Request,
                address.Country,
                address.Province,
                address.Area,
                address.Locality,
                address.District,
                address.Street,
                address.House,
                address.Latitude,
                address.Longitude,
                address.AdjustedLatitude,
                address.AdjustedLongitude));
 }
Example #23
0
        private LocalDefinition EmitInstanceFieldAddress(
            BoundFieldAccess fieldAccess,
            AddressKind addressKind
            )
        {
            var field = fieldAccess.FieldSymbol;

            //NOTE: we are not propagating AddressKind.Constrained here.
            //      the reason is that while Constrained permits calls, it does not permit
            //      taking field addresses, so we have to turn Constrained into writeable.
            var tempOpt = EmitReceiverRef(
                fieldAccess.ReceiverOpt,
                addressKind == AddressKind.Constrained ? AddressKind.Writeable : addressKind
                );

            _builder.EmitOpCode(ILOpCode.Ldflda);
            EmitSymbolToken(field, fieldAccess.Syntax);

            // when loading an address of a fixed field, we actually
            // want to load the address of its "FixedElementField" instead.
            // Both the buffer backing struct and its only field should be at the same location,
            // so we could in theory just use address of the struct, but in some contexts that causes
            // PEVerify errors because the struct has unexpected type. (Ex: struct& when int& is expected)
            if (field.IsFixedSizeBuffer)
            {
                var fixedImpl         = field.FixedImplementationType(_module);
                var fixedElementField = fixedImpl.FixedElementField;

                // if we get a mildly corrupted FixedImplementationType which does
                // not happen to have fixedElementField
                // we just leave address of the whole struct.
                //
                // That seems an adequate fallback because:
                // 1) it should happen only in impossibly rare cases involving malformed types
                // 2) the address of the struct is same as that of the buffer, just type is wrong.
                //    and that only matters to the verifier and we are in unsafe context anyways.
                if ((object)fixedElementField != null)
                {
                    _builder.EmitOpCode(ILOpCode.Ldflda);
                    EmitSymbolToken(fixedElementField, fieldAccess.Syntax);
                }
            }

            return(tempOpt);
        }
Example #24
0
        private LocalDefinition EmitPassByCopyAddress(
            BoundPassByCopy passByCopyExpr,
            AddressKind addressKind
            )
        {
            // Normally we can just defer PassByCopy to the `default`,
            // but in some cases the value inside is already a temp that is local to that node.
            // In such case we can skip extra store/reload
            if (passByCopyExpr.Expression is BoundSequence sequence)
            {
                if (DigForValueLocal(sequence, sequence.Value) != null)
                {
                    return(EmitSequenceAddress(sequence, addressKind));
                }
            }

            return(EmitAddressOfTempClone(passByCopyExpr));
        }
Example #25
0
        public Task <ICollection <string> > GetDistricts(AddressKind kind, string country, string province, string locality, OrderingKind orderingKind = OrderingKind.None)
        {
            if (string.IsNullOrEmpty(country))
            {
                throw new ArgumentNullException("Country");
            }

            if (string.IsNullOrEmpty(province))
            {
                throw new ArgumentNullException("Province");
            }

            if (string.IsNullOrEmpty(locality))
            {
                throw new ArgumentNullException("Locality");
            }

            return(Repository.GetDistricts(kind, country, province, locality, orderingKind));
        }
Example #26
0
        /// <summary>
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitFieldAddress(BoundFieldAccess fieldAccess, AddressKind addressKind)
        {
            FieldSymbol field = fieldAccess.FieldSymbol;

            if (!HasHome(fieldAccess, addressKind))
            {
                // accessing a field that is not writable (const or readonly)
                return(EmitAddressOfTempClone(fieldAccess));
            }
            else if (fieldAccess.FieldSymbol.IsStatic)
            {
                EmitStaticFieldAddress(field, fieldAccess.Syntax);
                return(null);
            }
            else
            {
                return(EmitInstanceFieldAddress(fieldAccess, addressKind));
            }
        }
Example #27
0
        /// <summary>
        /// Emits receiver in a form that allows member accesses ( O or &amp; ).
        /// For verifier-reference types it is the actual reference.
        /// For the value types it is an address of the receiver.
        /// For generic types it is either a boxed receiver or the address of the receiver with readonly intent.
        ///
        /// addressKind - kind of address that is needed in case if receiver is not a reference type.
        ///
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitReceiverRef(BoundExpression receiver, AddressKind addressKind)
        {
            var receiverType = receiver.Type;

            if (receiverType.IsVerifierReference())
            {
                EmitExpression(receiver, used: true);
                return(null);
            }

            if (receiverType.TypeKind == TypeKind.TypeParameter)
            {
                //[Note: Constraints on a generic parameter only restrict the types that
                //the generic parameter may be instantiated with. Verification (see Partition III)
                //requires that a field, property or method that a generic parameter is known
                //to provide through meeting a constraint, cannot be directly accessed/called
                //via the generic parameter unless it is first boxed (see Partition III) or
                //the callvirt instruction is prefixed with the constrained. prefix instruction
                //(see Partition III). end note]
                if (addressKind == AddressKind.Constrained)
                {
                    return(EmitAddress(receiver, addressKind));
                }
                else
                {
                    EmitExpression(receiver, used: true);
                    // conditional receivers are already boxed if needed when pushed
                    if (receiver.Kind != BoundKind.ConditionalReceiver)
                    {
                        EmitBox(receiver.Type, receiver.Syntax);
                    }
                    return(null);
                }
            }

            Debug.Assert(receiverType.IsVerifierValue());
            return(EmitAddress(receiver, addressKind));
        }
Example #28
0
        /// <summary>
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitFieldAddress(BoundFieldAccess fieldAccess, AddressKind addressKind)
        {
            FieldSymbol field = fieldAccess.FieldSymbol;

            if (!HasHome(fieldAccess, addressKind != AddressKind.ReadOnly))
            {
                // accessing a field that is not writable (const or readonly)
                return(EmitAddressOfTempClone(fieldAccess));
            }
            else if (fieldAccess.FieldSymbol.IsStatic)
            {
                EmitStaticFieldAddress(field, fieldAccess.Syntax);
                return(null);
            }
            else
            {
                //NOTE: we are not propagating AddressKind here.
                //      the reason is that while Constrained permits calls, it does not permit
                //      taking field addresses, so we have to turn Constrained into writeable.
                //      It is less error prone to just pass a bool "isReadonly"
                return(EmitInstanceFieldAddress(fieldAccess, isReadonly: addressKind == AddressKind.ReadOnly));
            }
        }
Example #29
0
        /// <summary>
        /// Special HasHome for fields.
        /// Fields have readable homes when they are not constants.
        /// Fields have writeable homes unless they are readonly and used outside of the constructor.
        /// </summary>
        private bool HasHome(BoundFieldAccess fieldAccess, AddressKind addressKind)
        {
            FieldSymbol field = fieldAccess.FieldSymbol;

            // const fields are literal values with no homes. (ex: decimal.Zero)
            if (field.IsConst)
            {
                return(false);
            }

            // in readonly situations where ref to a copy is not allowed, consider fields as addressable
            if (addressKind == AddressKind.ReadOnlyStrict)
            {
                return(true);
            }

            // ReadOnly references can always be taken unless we are in peverify compat mode
            if (addressKind == AddressKind.ReadOnly && !EnablePEVerifyCompat())
            {
                return(true);
            }

            // Some field accesses must be values; values do not have homes.
            if (fieldAccess.IsByValue)
            {
                return(false);
            }

            if (!field.IsReadOnly)
            {
                // in a case if we have a writeable struct field with a receiver that only has a readable home we would need to pass it via a temp.
                // it would be advantageous to make a temp for the field, not for the the outer struct, since the field is smaller and we can get to is by fetching references.
                // NOTE: this would not be profitable if we have to satisfy verifier, since for verifiability
                //       we would not be able to dig for the inner field using references and the outer struct will have to be copied to a temp anyways.
                if (!EnablePEVerifyCompat())
                {
                    Debug.Assert(!IsReadOnly(addressKind));

                    var receiver = fieldAccess.ReceiverOpt;
                    if (receiver?.Type.IsValueType == true)
                    {
                        // Check receiver:
                        // has writeable home -> return true - the whole chain has writeable home (also a more common case)
                        // has readable home -> return false - we need to copy the field
                        // otherwise         -> return true  - the copy will be made at higher level so the leaf field can have writeable home

                        return(HasHome(receiver, addressKind) ||
                               !HasHome(receiver, AddressKind.ReadOnly));
                    }
                }

                return(true);
            }

            // while readonly fields have home it is not valid to refer to it when not constructing.
            if (field.ContainingType != _method.ContainingType)
            {
                return(false);
            }

            if (field.IsStatic)
            {
                return(_method.MethodKind == MethodKind.StaticConstructor);
            }
            else
            {
                return(_method.MethodKind == MethodKind.Constructor &&
                       fieldAccess.ReceiverOpt.Kind == BoundKind.ThisReference);
            }
        }
Example #30
0
        /// <summary>
        /// Emits address as in &amp; 
        /// 
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addressKind)
        {
            switch (expression.Kind)
            {
                case BoundKind.RefValueOperator:
                    EmitRefValueAddress((BoundRefValueOperator)expression);
                    break;

                case BoundKind.Local:
                    EmitLocalAddress((BoundLocal)expression);
                    break;

                case BoundKind.Dup:
                    Debug.Assert(((BoundDup)expression).RefKind != RefKind.None, "taking address of a stack value?");
                    _builder.EmitOpCode(ILOpCode.Dup);
                    break;

                case BoundKind.ConditionalReceiver:
                    // do nothing receiver ref must be already pushed
                    Debug.Assert(!expression.Type.IsReferenceType);
                    Debug.Assert(!expression.Type.IsValueType || expression.Type.IsNullableType());
                    break;

                case BoundKind.ComplexConditionalReceiver:
                    EmitComplexConditionalReceiverAddress((BoundComplexConditionalReceiver)expression);
                    break;

                case BoundKind.Parameter:
                    EmitParameterAddress((BoundParameter)expression);
                    break;

                case BoundKind.FieldAccess:
                    return EmitFieldAddress((BoundFieldAccess)expression);

                case BoundKind.ArrayAccess:
                    //arrays are covariant, but elements can be written to.
                    //the flag tells that we do not intend to use the address for writing.
                    EmitArrayElementAddress((BoundArrayAccess)expression, addressKind);
                    break;

                case BoundKind.ThisReference:
                    Debug.Assert(expression.Type.IsValueType, "only value types may need a ref to this");
                    _builder.EmitOpCode(ILOpCode.Ldarg_0);
                    break;

                case BoundKind.PreviousSubmissionReference:
                    // script references are lowered to a this reference and a field access
                    throw ExceptionUtilities.UnexpectedValue(expression.Kind);

                case BoundKind.BaseReference:
                    Debug.Assert(false, "base is always a reference type, why one may need a reference to it?");
                    break;

                case BoundKind.Sequence:
                    return EmitSequenceAddress((BoundSequence)expression, addressKind);

                case BoundKind.PointerIndirectionOperator:
                    // The address of a dereferenced address is that address.
                    BoundExpression operand = ((BoundPointerIndirectionOperator)expression).Operand;
                    Debug.Assert(operand.Type.IsPointerType());
                    EmitExpression(operand, used: true);
                    break;

                case BoundKind.PseudoVariable:
                    EmitPseudoVariableAddress((BoundPseudoVariable)expression);
                    break;

                case BoundKind.Call:
                    var call = (BoundCall)expression;
                    if (call.Method.RefKind == RefKind.None)
                    {
                        goto default;
                    }

                    EmitCallExpression(call, UseKind.UsedAsAddress);
                    break;

                case BoundKind.AssignmentOperator:
                    var assignment = (BoundAssignmentOperator)expression;
                    if (assignment.RefKind == RefKind.None)
                    {
                        goto default;
                    }

                    throw ExceptionUtilities.UnexpectedValue(assignment.RefKind);

                default:
                    Debug.Assert(!HasHome(expression));
                    return EmitAddressOfTempClone(expression);
            }

            return null;
        }
Example #31
0
        /// <summary>
        /// Checks if expression directly or indirectly represents a value with its own home. In
        /// such cases it is possible to get a reference without loading into a temporary.
        /// </summary>
        private bool HasHome(BoundExpression expression, AddressKind addressKind)
        {
            switch (expression.Kind)
            {
            case BoundKind.ArrayAccess:
                if (addressKind == AddressKind.ReadOnly &&
                    !expression.Type.IsValueType &&
                    EnablePEVerifyCompat())
                {
                    // due to array covariance getting a reference may throw ArrayTypeMismatch when element is not a struct,
                    // passing "readonly." prefix would prevent that, but it is unverifiable, so will make a copy in compat case
                    return(false);
                }

                return(true);

            case BoundKind.PointerIndirectionOperator:
            case BoundKind.RefValueOperator:
                return(true);

            case BoundKind.ThisReference:
                var type = expression.Type;
                if (type.IsReferenceType)
                {
                    Debug.Assert(IsReadOnly(addressKind), "`this` is readonly in classes");
                    return(true);
                }

                if (!IsReadOnly(addressKind) && type.IsReadOnly)
                {
                    return(_method.MethodKind == MethodKind.Constructor);
                }

                return(true);

            case BoundKind.ThrowExpression:
                // vacuously this is true, we can take address of throw without temps
                return(true);

            case BoundKind.Parameter:
                return(IsReadOnly(addressKind) ||
                       ((BoundParameter)expression).ParameterSymbol.RefKind != RefKind.In);

            case BoundKind.Local:
                // locals have home unless they are byval stack locals or ref-readonly
                // locals in a mutating call
                var local = ((BoundLocal)expression).LocalSymbol;
                return(!((IsStackLocal(local) && local.RefKind == RefKind.None) ||
                         (!IsReadOnly(addressKind) && local.RefKind == RefKind.RefReadOnly)));

            case BoundKind.Call:
                var methodRefKind = ((BoundCall)expression).Method.RefKind;
                return(methodRefKind == RefKind.Ref ||
                       (IsReadOnly(addressKind) && methodRefKind == RefKind.RefReadOnly));

            case BoundKind.Dup:
                //NB: Dup represents locals that do not need IL slot
                var dupRefKind = ((BoundDup)expression).RefKind;
                return(dupRefKind == RefKind.Ref ||
                       (IsReadOnly(addressKind) && dupRefKind == RefKind.RefReadOnly));

            case BoundKind.FieldAccess:
                return(HasHome((BoundFieldAccess)expression, addressKind));

            case BoundKind.Sequence:
                return(HasHome(((BoundSequence)expression).Value, addressKind));

            case BoundKind.AssignmentOperator:
                return(((BoundAssignmentOperator)expression).IsRef);

            case BoundKind.ComplexConditionalReceiver:
                Debug.Assert(HasHome(((BoundComplexConditionalReceiver)expression).ValueTypeReceiver, addressKind));
                Debug.Assert(HasHome(((BoundComplexConditionalReceiver)expression).ReferenceTypeReceiver, addressKind));
                goto case BoundKind.ConditionalReceiver;

            case BoundKind.ConditionalReceiver:
                //ConditionalReceiver is a noop from Emit point of view. - it represents something that has already been pushed.
                //We should never need a temp for it.
                return(true);

            case BoundKind.ConditionalOperator:
                var ternary = (BoundConditionalOperator)expression;

                // only ref ternary may be referenced as a variable
                if (!ternary.IsRef)
                {
                    return(false);
                }

                // branch that has no home will need a temporary
                // if both have no home, just say whole expression has no home
                // so we could just use one temp for the whole thing
                return(HasHome(ternary.Consequence, addressKind) && HasHome(ternary.Alternative, addressKind));

            default:
                return(false);
            }
        }
Example #32
0
        /// <summary>
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitSequenceAddress(BoundSequence sequence, AddressKind addressKind)
        {
            var hasLocals = !sequence.Locals.IsEmpty;

            if (hasLocals)
            {
                builder.OpenLocalScope();

                foreach (var local in sequence.Locals)
                {
                    DefineLocal(local, sequence.Syntax);
                }
            }

            EmitSideEffects(sequence);
            var tempOpt = EmitAddress(sequence.Value, addressKind);

            // when a sequence is happened to be a byref receiver
            // we may need to extend the life time of the target until we are done accessing it
            // {.v ; v = Foo(); v}.Bar()     // v should be released after Bar() is over.
            LocalSymbol doNotRelease = null;
            if (tempOpt == null)
            {
                BoundLocal referencedLocal = DigForLocal(sequence.Value);
                if (referencedLocal != null)
                {
                    doNotRelease = referencedLocal.LocalSymbol;
                }
            }

            if (hasLocals)
            {
                builder.CloseLocalScope();

                foreach (var local in sequence.Locals)
                {
                    if (local != doNotRelease)
                    {
                        FreeLocal(local);
                    }
                    else
                    {
                        tempOpt = GetLocal(doNotRelease);
                    }
                }
            }

            return tempOpt;
        }
Example #33
0
        private void EmitArrayElementAddress(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            EmitExpression(arrayAccess.Expression, used: true);
            EmitArrayIndices(arrayAccess.Indices);

            if (addressKind == AddressKind.ReadOnly)
            {
                Debug.Assert(arrayAccess.Type.TypeKind == TypeKind.TypeParameter,
                    ".readonly is only needed when element type is a type param");

                builder.EmitOpCode(ILOpCode.Readonly);
            }

            if (arrayAccess.Indices.Length == 1)
            {
                builder.EmitOpCode(ILOpCode.Ldelema);
                var elementType = arrayAccess.Type;
                EmitSymbolToken(elementType, arrayAccess.Syntax);
            }
            else
            {
                builder.EmitArrayElementAddress(Emit.PEModuleBuilder.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type),
                                                arrayAccess.Syntax, diagnostics);
            }
        }
Example #34
0
        /// <summary>
        /// Emits address as in &amp;
        ///
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addressKind)
        {
            switch (expression.Kind)
            {
            case BoundKind.RefValueOperator:
                EmitRefValueAddress((BoundRefValueOperator)expression);
                break;

            case BoundKind.Local:
                return(EmitLocalAddress((BoundLocal)expression, addressKind));

            case BoundKind.Dup:
                Debug.Assert(((BoundDup)expression).RefKind != RefKind.None, "taking address of a stack value?");
                return(EmitDupAddress((BoundDup)expression, addressKind));

            case BoundKind.ConditionalReceiver:
                // do nothing receiver ref must be already pushed
                Debug.Assert(!expression.Type.IsReferenceType);
                Debug.Assert(!expression.Type.IsValueType || expression.Type.IsNullableType());
                break;

            case BoundKind.ComplexConditionalReceiver:
                EmitComplexConditionalReceiverAddress((BoundComplexConditionalReceiver)expression);
                break;

            case BoundKind.Parameter:
                return(EmitParameterAddress((BoundParameter)expression, addressKind));

            case BoundKind.FieldAccess:
                return(EmitFieldAddress((BoundFieldAccess)expression, addressKind));

            case BoundKind.ArrayAccess:
                if (!HasHome(expression, addressKind))
                {
                    goto default;
                }

                EmitArrayElementAddress((BoundArrayAccess)expression, addressKind);
                break;

            case BoundKind.ThisReference:
                Debug.Assert(expression.Type.IsValueType || IsAnyReadOnly(addressKind), "'this' is readonly in classes");

                if (expression.Type.IsValueType)
                {
                    if (!HasHome(expression, addressKind))
                    {
                        // a readonly method is calling a non-readonly method, therefore we need to copy 'this'
                        goto default;
                    }

                    _builder.EmitLoadArgumentOpcode(0);
                }
                else
                {
                    _builder.EmitLoadArgumentAddrOpcode(0);
                }

                break;

            case BoundKind.PreviousSubmissionReference:
                // script references are lowered to a this reference and a field access
                throw ExceptionUtilities.UnexpectedValue(expression.Kind);

            case BoundKind.BaseReference:
                Debug.Assert(false, "base is always a reference type, why one may need a reference to it?");
                break;

            case BoundKind.PassByCopy:
                return(EmitPassByCopyAddress((BoundPassByCopy)expression, addressKind));

            case BoundKind.Sequence:
                return(EmitSequenceAddress((BoundSequence)expression, addressKind));

            case BoundKind.PointerIndirectionOperator:
                // The address of a dereferenced address is that address.
                BoundExpression operand = ((BoundPointerIndirectionOperator)expression).Operand;
                Debug.Assert(operand.Type.IsPointerType());
                EmitExpression(operand, used: true);
                break;

            case BoundKind.PseudoVariable:
                EmitPseudoVariableAddress((BoundPseudoVariable)expression);
                break;

            case BoundKind.Call:
                var call          = (BoundCall)expression;
                var methodRefKind = call.Method.RefKind;

                if (methodRefKind == RefKind.Ref ||
                    (IsAnyReadOnly(addressKind) && methodRefKind == RefKind.RefReadOnly))
                {
                    EmitCallExpression(call, UseKind.UsedAsAddress);
                    break;
                }

                goto default;

            case BoundKind.DefaultExpression:
                var type = expression.Type;

                var temp = this.AllocateTemp(type, expression.Syntax);
                _builder.EmitLocalAddress(temp);                      //  ldloca temp
                _builder.EmitOpCode(ILOpCode.Dup);                    //  dup
                _builder.EmitOpCode(ILOpCode.Initobj);                //  initobj  <type>
                EmitSymbolToken(type, expression.Syntax);
                return(temp);

            case BoundKind.ConditionalOperator:
                if (!HasHome(expression, addressKind))
                {
                    goto default;
                }

                EmitConditionalOperatorAddress((BoundConditionalOperator)expression, addressKind);
                break;

            case BoundKind.AssignmentOperator:
                var assignment = (BoundAssignmentOperator)expression;
                if (!assignment.IsRef || !HasHome(assignment, addressKind))
                {
                    goto default;
                }
                else
                {
                    EmitAssignmentExpression(assignment, UseKind.UsedAsAddress);
                    break;
                }

            case BoundKind.ThrowExpression:
                // emit value or address is the same here.
                EmitExpression(expression, used: true);
                return(null);

            default:
                Debug.Assert(!HasHome(expression, addressKind));
                return(EmitAddressOfTempClone(expression));
            }

            return(null);
        }