Skip to content

Aot annotation on System.Text.Json#67582

Closed
LakshanF wants to merge 1 commit intodotnet:mainfrom
LakshanF:AotJsonAnnotation
Closed

Aot annotation on System.Text.Json#67582
LakshanF wants to merge 1 commit intodotnet:mainfrom
LakshanF:AotJsonAnnotation

Conversation

@LakshanF
Copy link
Copy Markdown
Contributor

@LakshanF LakshanF commented Apr 5, 2022

The annotation falls into two categories

  1. DynamicMethod calls: All DynamicMethod calls are behind the runtime feature switch and propagated up to the switch method and suppressed
  2. Copy the annotation that was used for MakeGenericXXX in the trimmer but by using RequiresDynamicCode (same message as trimmer)

This PR takes a dependency on a pending API request and hence is in a draft form.

@ghost
Copy link
Copy Markdown

ghost commented Apr 5, 2022

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost
Copy link
Copy Markdown

ghost commented Apr 5, 2022

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis
See info in area-owners.md if you want to be subscribed.

Issue Details

The annotation falls into two categories

  1. DynamicMethod calls: All DynamicMethod calls are behind the runtime feature switch and propagated up to the switch method and suppressed
  2. Copy the annotation that was used for MakeGenericXXX in the trimmer but by using RequiresDynamicCode (same message as trimmer)

This PR takes a dependency on a pending API request and hence is in a draft form.

Author: LakshanF
Assignees: LakshanF
Labels:

area-System.Text.Json, new-api-needs-documentation

Milestone: -

@LakshanF LakshanF marked this pull request as draft April 5, 2022 12:39
/// The object to be added to the end of the <see cref="JsonArray"/>.
/// </param>
[RequiresUnreferencedCode(JsonValue.CreateUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonValue.CreateUnreferencedCodeMessage)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you need to update the ref code as well for all public changes.


[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "Workaround for https://github.com/mono/linker/issues/1416. All usages are marked as unsafe.")]
[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The strings in the second string, IL3050 are really long. Can they just be simplified to `IL3050:RequiresDynamicCodeAttribute".
  2. All justification should be filled out.
  3. Is the justification the same as the existing suppress message - working around Linker warns about generic type flown into lambda method linker#1416? That doesn't seem right. Maybe this method should just have [RequiresDynamicCode] on it.

/// for <typeparamref name="TValue"/> or its serializable members.
/// </exception>
[RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(SerializationUnreferencedCodeMessage)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure the existing SerializationUnreferencedCodeMessage is the right message for RequiresDynamicCode. It says:

"JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved."

I'm not sure that advice works correctly for requiring dynamic code.


[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "The ctor is marked with RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could they re-use same attributes rather than doubling them?

{
public override bool CanConvert(Type typeToConvert) => GetAsyncEnumerableInterface(typeToConvert) is not null;

[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless we have guarantees that the typeToConvert and elementType are always reference type, or the code got compiled through other means, this is not safe to suppress.

return converter;
}

[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless the key type and value type are reference types or code for that instantiation is available through other means, this is not safe to suppress.

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:MakeGenericType",
Justification = "'EnumConverter<T> where T : struct' implies 'T : new()', so the trimmer is warning calling MakeGenericType here because enumType's constructors are not annotated. " +
"But EnumConverter doesn't call new T(), so this is safe.")]
[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum types are valuetypes, the MakeGenericType will likely throw 100% of time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might consider suppressing the warning here and add an annotation in the converter factory constructor, as is done here:

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "The ctor is marked RequiresUnreferencedCode.")]

The factory constructors are only invoked in the context of reflection serialization code paths, with the notable exception of JsonStringEnumConverter which is a public class. It would likely require an annotation on its constructors.

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:MakeGenericType",
Justification = "'NullableConverter<T> where T : struct' implies 'T : new()', so the trimmer is warning calling MakeGenericType here because valueTypeToConvert's constructors are not annotated. " +
"But NullableConverter doesn't call new T(), so this is safe.")]
[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as for the EnumConverter above.

#endif
}

[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same concern as the other MakeGenericType comments

{
#if NETCOREAPP
[RequiresDynamicCode("Runtime code generation is not available for Aot form factor")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3051:RequiresDynamicCode",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look right that we need this suppression if the type is RDC.

{
#if NETCOREAPP
[RequiresDynamicCode("Runtime code generation is not available for Aot form factor")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3051:RequiresDynamicCode",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same - we shouldn't need this. If this type is RDC, we can't construct an instance of it without a warning. It should be okay to have mismatched virtual override annotations after that because we'd be warned at the time the instance is constructed.

@eiriktsarpalis
Copy link
Copy Markdown
Member

I'm guessing we should we close this in favor of #68464?

@LakshanF LakshanF closed this May 10, 2022
@LakshanF LakshanF deleted the AotJsonAnnotation branch May 10, 2022 13:20
@ghost ghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants