/// <summary> /// Emits address as in & /// /// 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); }
/// <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); }
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 ); } }
/// <summary> /// Emits address as in & /// /// 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)); }
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); } }
/// <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); }
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)); }
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 }); }
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); }
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()); }
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); }
private bool HasHome(BoundExpression expression, AddressKind addressKind) => Binder.HasHome( expression, addressKind, _method, IsPeVerifyCompatEnabled(), _stackLocals );
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)); }
/// <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); }
/// <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); }
/// <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); }
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()); }
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; } }
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); }
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)); }
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); }
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)); }
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)); }
/// <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)); } }
/// <summary> /// Emits receiver in a form that allows member accesses ( O or & ). /// 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)); }
/// <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)); } }
/// <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); } }
/// <summary> /// Emits address as in & /// /// 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; }
/// <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); } }
/// <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; }
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); } }
/// <summary> /// Emits address as in & /// /// 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); }