< Summary

Information
Class: System.Text.Json.Serialization.Metadata.ReflectionEmitMemberAccessor
Assembly: System.Text.Json
File(s): C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\Metadata\ReflectionEmitMemberAccessor.cs
Line coverage
45%
Covered lines: 111
Uncovered lines: 135
Coverable lines: 246
Total lines: 400
Line coverage: 45.1%
Branch coverage
41%
Covered branches: 22
Total branches: 53
Branch coverage: 41.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\Metadata\ReflectionEmitMemberAccessor.cs

#LineLine coverage
 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
 4#if NETFRAMEWORK || NET
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Reflection;
 9using System.Reflection.Emit;
 10
 11namespace System.Text.Json.Serialization.Metadata
 12{
 13    [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 14    [RequiresUnreferencedCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 15    internal sealed class ReflectionEmitMemberAccessor : MemberAccessor
 16    {
 117        public ReflectionEmitMemberAccessor()
 118        {
 119        }
 20
 21        public override Func<object>? CreateParameterlessConstructor(Type type, ConstructorInfo? constructorInfo)
 334022        {
 334023            Debug.Assert(type != null);
 334024            Debug.Assert(constructorInfo is null || constructorInfo.GetParameters().Length == 0);
 25
 334026            if (type.IsAbstract)
 8827            {
 8828                return null;
 29            }
 30
 325231            if (constructorInfo is null && !type.IsValueType)
 99532            {
 99533                return null;
 34            }
 35
 225736            var dynamicMethod = new DynamicMethod(
 225737                ConstructorInfo.ConstructorName,
 225738                JsonTypeInfo.ObjectType,
 225739                Type.EmptyTypes,
 225740                typeof(ReflectionEmitMemberAccessor).Module,
 225741                skipVisibility: true);
 42
 225743            ILGenerator generator = dynamicMethod.GetILGenerator();
 44
 225745            if (constructorInfo is null)
 116946            {
 116947                Debug.Assert(type.IsValueType);
 48
 116949                LocalBuilder local = generator.DeclareLocal(type);
 50
 116951                generator.Emit(OpCodes.Ldloca_S, local);
 116952                generator.Emit(OpCodes.Initobj, type);
 116953                generator.Emit(OpCodes.Ldloc, local);
 116954                generator.Emit(OpCodes.Box, type);
 116955            }
 56            else
 108857            {
 108858                generator.Emit(OpCodes.Newobj, constructorInfo);
 108859                if (type.IsValueType)
 060                {
 61                    // Since C# 10 it's now possible to have parameterless constructors in structs
 062                    generator.Emit(OpCodes.Box, type);
 063                }
 108864            }
 65
 225766            generator.Emit(OpCodes.Ret);
 67
 225768            return CreateDelegate<Func<object>>(dynamicMethod);
 334069        }
 70
 71        public override Func<object[], T> CreateParameterizedConstructor<T>(ConstructorInfo constructor) =>
 73872            CreateDelegate<Func<object[], T>>(CreateParameterizedConstructor(constructor));
 73
 74        private static DynamicMethod CreateParameterizedConstructor(ConstructorInfo constructor)
 73875        {
 73876            Type? type = constructor.DeclaringType;
 77
 73878            Debug.Assert(type != null);
 73879            Debug.Assert(!type.IsAbstract);
 73880            Debug.Assert(constructor.IsPublic && !constructor.IsStatic);
 81
 73882            ParameterInfo[] parameters = constructor.GetParameters();
 73883            int parameterCount = parameters.Length;
 84
 73885            var dynamicMethod = new DynamicMethod(
 73886                ConstructorInfo.ConstructorName,
 73887                type,
 73888                new[] { typeof(object[]) },
 73889                typeof(ReflectionEmitMemberAccessor).Module,
 73890                skipVisibility: true);
 91
 73892            ILGenerator generator = dynamicMethod.GetILGenerator();
 93
 1033294            for (int i = 0; i < parameterCount; i++)
 442895            {
 442896                Type paramType = parameters[i].ParameterType;
 97
 442898                generator.Emit(OpCodes.Ldarg_0);
 442899                generator.Emit(OpCodes.Ldc_I4, i);
 4428100                generator.Emit(OpCodes.Ldelem_Ref);
 4428101                generator.Emit(OpCodes.Unbox_Any, paramType);
 4428102            }
 103
 738104            generator.Emit(OpCodes.Newobj, constructor);
 738105            generator.Emit(OpCodes.Ret);
 106
 738107            return dynamicMethod;
 738108        }
 109
 110        public override JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>?
 111            CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo constructor) =>
 0112            CreateDelegate<JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>>(
 0113                CreateParameterizedConstructor(constructor, typeof(TArg0), typeof(TArg1), typeof(TArg2), typeof(TArg3)))
 114
 115        private static DynamicMethod? CreateParameterizedConstructor(ConstructorInfo constructor, Type parameterType1, T
 0116        {
 0117            Type? type = constructor.DeclaringType;
 118
 0119            Debug.Assert(type != null);
 0120            Debug.Assert(!type.IsAbstract);
 0121            Debug.Assert(!constructor.IsStatic);
 122
 0123            ParameterInfo[] parameters = constructor.GetParameters();
 0124            int parameterCount = parameters.Length;
 125
 0126            var dynamicMethod = new DynamicMethod(
 0127                ConstructorInfo.ConstructorName,
 0128                type,
 0129                new[] { parameterType1, parameterType2, parameterType3, parameterType4 },
 0130                typeof(ReflectionEmitMemberAccessor).Module,
 0131                skipVisibility: true);
 132
 0133            ILGenerator generator = dynamicMethod.GetILGenerator();
 134
 0135            for (int index = 0; index < parameterCount; index++)
 0136            {
 0137                Debug.Assert(index <= JsonConstants.UnboxedParameterCountThreshold);
 138
 0139                generator.Emit(
 0140                    index switch
 0141                    {
 0142                        0 => OpCodes.Ldarg_0,
 0143                        1 => OpCodes.Ldarg_1,
 0144                        2 => OpCodes.Ldarg_2,
 0145                        3 => OpCodes.Ldarg_3,
 0146                        _ => throw new InvalidOperationException()
 0147                    });
 0148            }
 149
 0150            generator.Emit(OpCodes.Newobj, constructor);
 0151            generator.Emit(OpCodes.Ret);
 152
 0153            return dynamicMethod;
 0154        }
 155
 156        public override Action<TCollection, object?> CreateAddMethodDelegate<[DynamicallyAccessedMembers(DynamicallyAcce
 0157            CreateDelegate<Action<TCollection, object?>>(CreateAddMethodDelegate(typeof(TCollection)));
 158
 159        private static DynamicMethod CreateAddMethodDelegate(
 160            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type collectionType)
 0161        {
 162            // We verified this won't be null when we created the converter that calls this method.
 0163            MethodInfo realMethod = (collectionType.GetMethod("Push") ?? collectionType.GetMethod("Enqueue"))!;
 164
 0165            var dynamicMethod = new DynamicMethod(
 0166                realMethod.Name,
 0167                typeof(void),
 0168                new[] { collectionType, JsonTypeInfo.ObjectType },
 0169                typeof(ReflectionEmitMemberAccessor).Module,
 0170                skipVisibility: true);
 171
 0172            ILGenerator generator = dynamicMethod.GetILGenerator();
 173
 0174            generator.Emit(OpCodes.Ldarg_0);
 0175            generator.Emit(OpCodes.Ldarg_1);
 0176            generator.Emit(OpCodes.Callvirt, realMethod);
 0177            generator.Emit(OpCodes.Ret);
 178
 0179            return dynamicMethod;
 0180        }
 181
 182        public override Func<IEnumerable<TElement>, TCollection> CreateImmutableEnumerableCreateRangeDelegate<TCollectio
 0183            CreateDelegate<Func<IEnumerable<TElement>, TCollection>>(
 0184                CreateImmutableEnumerableCreateRangeDelegate(typeof(TCollection), typeof(TElement), typeof(IEnumerable<T
 185
 186        private static DynamicMethod CreateImmutableEnumerableCreateRangeDelegate(Type collectionType, Type elementType,
 0187        {
 0188            MethodInfo realMethod = collectionType.GetImmutableEnumerableCreateRangeMethod(elementType);
 189
 0190            var dynamicMethod = new DynamicMethod(
 0191                realMethod.Name,
 0192                collectionType,
 0193                new[] { enumerableType },
 0194                typeof(ReflectionEmitMemberAccessor).Module,
 0195                skipVisibility: true);
 196
 0197            ILGenerator generator = dynamicMethod.GetILGenerator();
 198
 0199            generator.Emit(OpCodes.Ldarg_0);
 0200            generator.Emit(OpCodes.Call, realMethod);
 0201            generator.Emit(OpCodes.Ret);
 202
 0203            return dynamicMethod;
 0204        }
 205
 206        public override Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection> CreateImmutableDictionaryCreateRangeD
 0207            CreateDelegate<Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection>>(
 0208                CreateImmutableDictionaryCreateRangeDelegate(typeof(TCollection), typeof(TKey), typeof(TValue), typeof(I
 209
 210        private static DynamicMethod CreateImmutableDictionaryCreateRangeDelegate(Type collectionType, Type keyType, Typ
 0211        {
 0212            MethodInfo realMethod = collectionType.GetImmutableDictionaryCreateRangeMethod(keyType, valueType);
 213
 0214            var dynamicMethod = new DynamicMethod(
 0215                realMethod.Name,
 0216                collectionType,
 0217                new[] { enumerableType },
 0218                typeof(ReflectionEmitMemberAccessor).Module,
 0219                skipVisibility: true);
 220
 0221            ILGenerator generator = dynamicMethod.GetILGenerator();
 222
 0223            generator.Emit(OpCodes.Ldarg_0);
 0224            generator.Emit(OpCodes.Call, realMethod);
 0225            generator.Emit(OpCodes.Ret);
 226
 0227            return dynamicMethod;
 0228        }
 229
 230        public override Func<object, TProperty> CreatePropertyGetter<TProperty>(PropertyInfo propertyInfo) =>
 7716231            CreateDelegate<Func<object, TProperty>>(CreatePropertyGetter(propertyInfo, typeof(TProperty)));
 232
 233        private static DynamicMethod CreatePropertyGetter(PropertyInfo propertyInfo, Type runtimePropertyType)
 7716234        {
 7716235            MethodInfo? realMethod = propertyInfo.GetMethod;
 7716236            Debug.Assert(realMethod != null);
 237
 7716238            Type? declaringType = propertyInfo.DeclaringType;
 7716239            Debug.Assert(declaringType != null);
 240
 7716241            Type declaredPropertyType = propertyInfo.PropertyType;
 242
 7716243            DynamicMethod dynamicMethod = CreateGetterMethod(propertyInfo.Name, runtimePropertyType);
 7716244            ILGenerator generator = dynamicMethod.GetILGenerator();
 245
 7716246            generator.Emit(OpCodes.Ldarg_0);
 247
 7716248            if (declaringType.IsValueType)
 0249            {
 0250                generator.Emit(OpCodes.Unbox, declaringType);
 0251                generator.Emit(OpCodes.Call, realMethod);
 0252            }
 253            else
 7716254            {
 7716255                generator.Emit(OpCodes.Castclass, declaringType);
 7716256                generator.Emit(OpCodes.Callvirt, realMethod);
 7716257            }
 258
 259            // declaredPropertyType: Type of the property
 260            // runtimePropertyType:  <T> of JsonConverter / JsonPropertyInfo
 261
 7716262            if (declaredPropertyType != runtimePropertyType && declaredPropertyType.IsValueType)
 0263            {
 264                // Not supported scenario: possible if declaredPropertyType == int? and runtimePropertyType == int
 265                // We should catch that particular case earlier in converter generation.
 0266                Debug.Assert(!runtimePropertyType.IsValueType);
 267
 0268                generator.Emit(OpCodes.Box, declaredPropertyType);
 0269            }
 270
 7716271            generator.Emit(OpCodes.Ret);
 272
 7716273            return dynamicMethod;
 7716274        }
 275
 276        public override Action<object, TProperty> CreatePropertySetter<TProperty>(PropertyInfo propertyInfo) =>
 7716277            CreateDelegate<Action<object, TProperty>>(CreatePropertySetter(propertyInfo, typeof(TProperty)));
 278
 279        private static DynamicMethod CreatePropertySetter(PropertyInfo propertyInfo, Type runtimePropertyType)
 7716280        {
 7716281            MethodInfo? realMethod = propertyInfo.SetMethod;
 7716282            Debug.Assert(realMethod != null);
 283
 7716284            Type? declaringType = propertyInfo.DeclaringType;
 7716285            Debug.Assert(declaringType != null);
 286
 7716287            Type declaredPropertyType = propertyInfo.PropertyType;
 288
 7716289            DynamicMethod dynamicMethod = CreateSetterMethod(propertyInfo.Name, runtimePropertyType);
 7716290            ILGenerator generator = dynamicMethod.GetILGenerator();
 291
 7716292            generator.Emit(OpCodes.Ldarg_0);
 7716293            generator.Emit(declaringType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, declaringType);
 7716294            generator.Emit(OpCodes.Ldarg_1);
 295
 296            // declaredPropertyType: Type of the property
 297            // runtimePropertyType:  <T> of JsonConverter / JsonPropertyInfo
 298
 7716299            if (declaredPropertyType != runtimePropertyType && declaredPropertyType.IsValueType)
 0300            {
 301                // Not supported scenario: possible if e.g. declaredPropertyType == int? and runtimePropertyType == int
 302                // We should catch that particular case earlier in converter generation.
 0303                Debug.Assert(!runtimePropertyType.IsValueType);
 304
 0305                generator.Emit(OpCodes.Unbox_Any, declaredPropertyType);
 0306            }
 307
 7716308            generator.Emit(declaringType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, realMethod);
 7716309            generator.Emit(OpCodes.Ret);
 310
 7716311            return dynamicMethod;
 7716312        }
 313
 314        public override Func<object, TProperty> CreateFieldGetter<TProperty>(FieldInfo fieldInfo) =>
 0315            CreateDelegate<Func<object, TProperty>>(CreateFieldGetter(fieldInfo, typeof(TProperty)));
 316
 317        private static DynamicMethod CreateFieldGetter(FieldInfo fieldInfo, Type runtimeFieldType)
 0318        {
 0319            Type? declaringType = fieldInfo.DeclaringType;
 0320            Debug.Assert(declaringType != null);
 321
 0322            Type declaredFieldType = fieldInfo.FieldType;
 323
 0324            DynamicMethod dynamicMethod = CreateGetterMethod(fieldInfo.Name, runtimeFieldType);
 0325            ILGenerator generator = dynamicMethod.GetILGenerator();
 326
 0327            generator.Emit(OpCodes.Ldarg_0);
 0328            generator.Emit(
 0329                declaringType.IsValueType
 0330                    ? OpCodes.Unbox
 0331                    : OpCodes.Castclass,
 0332                declaringType);
 0333            generator.Emit(OpCodes.Ldfld, fieldInfo);
 334
 335            // declaredFieldType: Type of the field
 336            // runtimeFieldType:  <T> of JsonConverter / JsonPropertyInfo
 337
 0338            if (declaredFieldType.IsValueType && declaredFieldType != runtimeFieldType)
 0339            {
 0340                generator.Emit(OpCodes.Box, declaredFieldType);
 0341            }
 342
 0343            generator.Emit(OpCodes.Ret);
 344
 0345            return dynamicMethod;
 0346        }
 347
 348        public override Action<object, TProperty> CreateFieldSetter<TProperty>(FieldInfo fieldInfo) =>
 0349            CreateDelegate<Action<object, TProperty>>(CreateFieldSetter(fieldInfo, typeof(TProperty)));
 350
 351        private static DynamicMethod CreateFieldSetter(FieldInfo fieldInfo, Type runtimeFieldType)
 0352        {
 0353            Type? declaringType = fieldInfo.DeclaringType;
 0354            Debug.Assert(declaringType != null);
 355
 0356            Type declaredFieldType = fieldInfo.FieldType;
 357
 0358            DynamicMethod dynamicMethod = CreateSetterMethod(fieldInfo.Name, runtimeFieldType);
 0359            ILGenerator generator = dynamicMethod.GetILGenerator();
 360
 0361            generator.Emit(OpCodes.Ldarg_0);
 0362            generator.Emit(declaringType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, declaringType);
 0363            generator.Emit(OpCodes.Ldarg_1);
 364
 365            // declaredFieldType: Type of the field
 366            // runtimeFieldType:  <T> of JsonConverter / JsonPropertyInfo
 367
 0368            if (declaredFieldType != runtimeFieldType && declaredFieldType.IsValueType)
 0369            {
 0370                generator.Emit(OpCodes.Unbox_Any, declaredFieldType);
 0371            }
 372
 0373            generator.Emit(OpCodes.Stfld, fieldInfo);
 0374            generator.Emit(OpCodes.Ret);
 375
 0376            return dynamicMethod;
 0377        }
 378
 379        private static DynamicMethod CreateGetterMethod(string memberName, Type memberType) =>
 7716380            new DynamicMethod(
 7716381                memberName + "Getter",
 7716382                memberType,
 7716383                new[] { JsonTypeInfo.ObjectType },
 7716384                typeof(ReflectionEmitMemberAccessor).Module,
 7716385                skipVisibility: true);
 386
 387        private static DynamicMethod CreateSetterMethod(string memberName, Type memberType) =>
 7716388            new DynamicMethod(
 7716389                memberName + "Setter",
 7716390                typeof(void),
 7716391                new[] { JsonTypeInfo.ObjectType, memberType },
 7716392                typeof(ReflectionEmitMemberAccessor).Module,
 7716393                skipVisibility: true);
 394
 395        [return: NotNullIfNotNull(nameof(method))]
 396        private static T? CreateDelegate<T>(DynamicMethod? method) where T : Delegate =>
 18427397            (T?)method?.CreateDelegate(typeof(T));
 398    }
 399}
 400#endif