Apply mitigations for a recent STJ performance regression (#89856)
authorEirik Tsarpalis <eirik.tsarpalis@gmail.com>
Wed, 2 Aug 2023 18:11:51 +0000 (21:11 +0300)
committerGitHub <noreply@github.com>
Wed, 2 Aug 2023 18:11:51 +0000 (19:11 +0100)
src/libraries/System.Text.Json/src/System/ReflectionExtensions.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Helpers.cs

index c9ace15..9dab389 100644 (file)
@@ -43,20 +43,20 @@ namespace System.Text.Json.Reflection
         private static bool HasJsonConstructorAttribute(ConstructorInfo constructorInfo)
             => constructorInfo.GetCustomAttribute<JsonConstructorAttribute>() != null;
 
-        public static bool HasRequiredMemberAttribute(this ICustomAttributeProvider memberInfo)
+        public static bool HasRequiredMemberAttribute(this MemberInfo memberInfo)
         {
             // For compiler related attributes we should only look at full type name rather than trying to do something different for version when attribute was introduced.
             // I.e. library is targeting netstandard2.0 with polyfilled attributes and is being consumed by an app targeting net7.0 or greater.
-            return memberInfo.HasCustomAttributeWithName("System.Runtime.CompilerServices.RequiredMemberAttribute", inherit: true);
+            return memberInfo.HasCustomAttributeWithName("System.Runtime.CompilerServices.RequiredMemberAttribute", inherit: false);
         }
 
-        public static bool HasSetsRequiredMembersAttribute(this ICustomAttributeProvider memberInfo)
+        public static bool HasSetsRequiredMembersAttribute(this MemberInfo memberInfo)
         {
             // See comment for HasRequiredMemberAttribute for why we need to always only look at full name
-            return memberInfo.HasCustomAttributeWithName("System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute", inherit: true);
+            return memberInfo.HasCustomAttributeWithName("System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute", inherit: false);
         }
 
-        private static bool HasCustomAttributeWithName(this ICustomAttributeProvider memberInfo, string fullName, bool inherit)
+        private static bool HasCustomAttributeWithName(this MemberInfo memberInfo, string fullName, bool inherit)
         {
             foreach (object attribute in memberInfo.GetCustomAttributes(inherit))
             {
index 9a13d7a..7ec9db9 100644 (file)
@@ -85,20 +85,17 @@ namespace System.Text.Json.Serialization.Metadata
             // Walk the type hierarchy starting from the current type up to the base type(s)
             foreach (Type currentType in typeInfo.Type.GetSortedTypeHierarchy())
             {
-                if (currentType == JsonTypeInfo.ObjectType)
+                if (currentType == JsonTypeInfo.ObjectType ||
+                    currentType == typeof(ValueType))
                 {
-                    // Don't process any members for typeof(object)
+                    // Don't process any members for typeof(object) or System.ValueType
                     break;
                 }
 
-                // Compiler adds RequiredMemberAttribute to type if any of the members are marked with 'required' keyword.
-                bool shouldCheckMembersForRequiredMemberAttribute =
-                    !constructorHasSetsRequiredMembersAttribute && currentType.HasRequiredMemberAttribute();
-
                 AddMembersDeclaredBySuperType(
                     typeInfo,
                     currentType,
-                    shouldCheckMembersForRequiredMemberAttribute,
+                    constructorHasSetsRequiredMembersAttribute,
                     ref state);
             }
 
@@ -113,7 +110,7 @@ namespace System.Text.Json.Serialization.Metadata
         private static void AddMembersDeclaredBySuperType(
             JsonTypeInfo typeInfo,
             Type currentType,
-            bool shouldCheckMembersForRequiredMemberAttribute,
+            bool constructorHasSetsRequiredMembersAttribute,
             ref JsonTypeInfo.PropertyHierarchyResolutionState state)
         {
             Debug.Assert(!typeInfo.IsReadOnly);
@@ -125,6 +122,10 @@ namespace System.Text.Json.Serialization.Metadata
                 BindingFlags.NonPublic |
                 BindingFlags.DeclaredOnly;
 
+            // Compiler adds RequiredMemberAttribute to type if any of the members are marked with 'required' keyword.
+            bool shouldCheckMembersForRequiredMemberAttribute =
+                !constructorHasSetsRequiredMembersAttribute && currentType.HasRequiredMemberAttribute();
+
             foreach (PropertyInfo propertyInfo in currentType.GetProperties(BindingFlags))
             {
                 // Ignore indexers and virtual properties that have overrides that were [JsonIgnore]d.