1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Reflection; 7 8 using Internal.Runtime.Augments; 9 using Internal.Reflection.Core.Execution; 10 11 namespace Internal.Reflection.Execution.FieldAccessors 12 { 13 internal abstract class InstanceFieldAccessor : FieldAccessor 14 { InstanceFieldAccessor(RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle, int offsetPlusHeader)15 public InstanceFieldAccessor(RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle, int offsetPlusHeader) 16 { 17 this.DeclaringTypeHandle = declaringTypeHandle; 18 this.FieldTypeHandle = fieldTypeHandle; 19 this.OffsetPlusHeader = offsetPlusHeader; 20 } 21 22 public abstract override int Offset { get; } 23 GetField(Object obj)24 public sealed override Object GetField(Object obj) 25 { 26 if (obj == null) 27 throw new TargetException(SR.RFLCT_Targ_StatFldReqTarg); 28 if (!RuntimeAugments.IsAssignable(obj, this.DeclaringTypeHandle)) 29 throw new ArgumentException(); 30 return UncheckedGetField(obj); 31 } 32 GetFieldDirect(TypedReference typedReference)33 public sealed override object GetFieldDirect(TypedReference typedReference) 34 { 35 if (RuntimeAugments.IsValueType(this.DeclaringTypeHandle)) 36 { 37 // We're being asked to read a field from the value type pointed to by the TypedReference. This code path 38 // avoids boxing that value type by adding this field's offset to the TypedReference's managed pointer. 39 Type targetType = TypedReference.GetTargetType(typedReference); 40 if (!(targetType.TypeHandle.Equals(this.DeclaringTypeHandle))) 41 throw new ArgumentException(); 42 return UncheckedGetFieldDirectFromValueType(typedReference); 43 } 44 else 45 { 46 // We're being asked to read a field from a reference type. There's no boxing to optimize out in that case so just handle it as 47 // if this was a FieldInfo.GetValue() call. 48 object obj = TypedReference.ToObject(typedReference); 49 return GetField(obj); 50 } 51 } 52 UncheckedGetFieldDirectFromValueType(TypedReference typedReference)53 protected abstract object UncheckedGetFieldDirectFromValueType(TypedReference typedReference); 54 SetField(Object obj, Object value, BinderBundle binderBundle)55 public sealed override void SetField(Object obj, Object value, BinderBundle binderBundle) 56 { 57 if (obj == null) 58 throw new TargetException(SR.RFLCT_Targ_StatFldReqTarg); 59 if (!RuntimeAugments.IsAssignable(obj, this.DeclaringTypeHandle)) 60 throw new ArgumentException(); 61 value = RuntimeAugments.CheckArgument(value, this.FieldTypeHandle, binderBundle); 62 UncheckedSetField(obj, value); 63 } 64 SetFieldDirect(TypedReference typedReference, object value)65 public sealed override void SetFieldDirect(TypedReference typedReference, object value) 66 { 67 if (RuntimeAugments.IsValueType(this.DeclaringTypeHandle)) 68 { 69 // We're being asked to store a field into the value type pointed to by the TypedReference. This code path 70 // bypasses boxing that value type by adding this field's offset to the TypedReference's managed pointer. 71 // (Otherwise, the store would go into a useless temporary copy rather than the intended destination.) 72 Type targetType = TypedReference.GetTargetType(typedReference); 73 if (!(targetType.TypeHandle.Equals(this.DeclaringTypeHandle))) 74 throw new ArgumentException(); 75 value = RuntimeAugments.CheckArgumentForDirectFieldAccess(value, this.FieldTypeHandle); 76 UncheckedSetFieldDirectIntoValueType(typedReference, value); 77 } 78 else 79 { 80 // We're being asked to store a field from a reference type. There's no boxing to bypass in that case so just handle it as 81 // if this was a FieldInfo.SetValue() call (but using SetValueDirect's argument coercing semantics) 82 object obj = TypedReference.ToObject(typedReference); 83 if (obj == null) 84 throw new TargetException(SR.RFLCT_Targ_StatFldReqTarg); 85 if (!RuntimeAugments.IsAssignable(obj, this.DeclaringTypeHandle)) 86 throw new ArgumentException(); 87 value = RuntimeAugments.CheckArgumentForDirectFieldAccess(value, this.FieldTypeHandle); 88 UncheckedSetField(obj, value); 89 } 90 } 91 UncheckedSetFieldDirectIntoValueType(TypedReference typedReference, object value)92 protected abstract void UncheckedSetFieldDirectIntoValueType(TypedReference typedReference, object value); 93 UncheckedGetField(Object obj)94 protected abstract Object UncheckedGetField(Object obj); UncheckedSetField(Object obj, Object value)95 protected abstract void UncheckedSetField(Object obj, Object value); 96 97 protected int OffsetPlusHeader { get; } 98 protected RuntimeTypeHandle DeclaringTypeHandle { get; } 99 protected RuntimeTypeHandle FieldTypeHandle { get; } 100 } 101 } 102