Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ If possible, avoid using reflection-based serializers with trimming, and prefer

As a last resort, the linker does have limited heuristics that can be enabled to keep _some_ of the types and members required for serialization, but this provides no correctness guarantees; apps which use reflection-based serializers are still considered "broken" as far as the static analysis can tell, and it is up to you to make sure that the app works as intended.

Serialization discovery is disabled by default, and can be enabled by passing `--enable-serialization-discovery`.

## History

The linker has historically been used for Xamarin scenarios that use reflection-based serializers like XmlSerializer, since before the introduction of the trim analysis warnings. There were limited heuristics to satisfy some simple uses of serializers. To provide backwards compatibility for such scenarios, the linker has built-in heuristics that makes some simple cases "just work", albeit in an opaque and unpredictable way.

Consider disabling this behavior by passing `--disable-serialization-discovery` if possible, but it may be necessary when using legacy serializers that don't provide source generators or a similar solution that is statically analyzable. The following is a description of the heuristics for anyone who is unfortunate enough to have to rely on this behavior.
Consider disabling this behavior if possible, but it may be necessary when using legacy serializers that don't provide source generators or a similar solution that is statically analyzable. The following is a description of the heuristics for anyone who is unfortunate enough to have to rely on this behavior.

## Heuristics

Serialization discovery is enabled by default, and can be disabled by passing `--disable-serialization-discovery`. There are four parts to the heuristics:
There are four parts to the heuristics:
- Activation: which conditions cause the discovered roots and their recursive types to be kept
- Root discovery: logic to discover types and members are entry points to serialization
- Type graph: recursive logic to build a set of types to consider for serialization, starting from the roots
Expand Down
5 changes: 5 additions & 0 deletions src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ Copyright (c) .NET Foundation. All rights reserved.
<NoWarn Condition=" '$(PlatformTarget)' != 'x64' AND '$(PlatformTarget)' != 'arm64'">$(NoWarn);IL2009;IL2012</NoWarn> <!-- Unresolved field referenced in XML -->
</PropertyGroup>

<!-- Enable serialization discovery for compat in < 7.0 -->
<PropertyGroup Condition="$([MSBuild]::VersionLessThan('$(TargetFrameworkVersion)', '7.0')">
<_ExtraTrimmerArgs>--enable-serialization-discovery $(_ExtraTrimmerArgs)</_ExtraTrimmerArgs>
</PropertyGroup>

<!-- Set a default value for TrimmerRemoveSymbols unless set explicitly. -->
<PropertyGroup Condition=" '$(TrimmerRemoveSymbols)' == '' ">
<!-- The default is to remove symbols when debugger support is disabled, and keep them otherwise. -->
Expand Down
6 changes: 3 additions & 3 deletions src/linker/Linker/Driver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,8 @@ protected int SetupContext (ILogger? customLogger = null)
continue;
}

case "--disable-serialization-discovery":
if (!GetBoolParam (token, l => context.DisableSerializationDiscovery = l))
case "--enable-serialization-discovery":
if (!GetBoolParam (token, l => context.EnableSerializationDiscovery = l))
return -1;

continue;
Expand Down Expand Up @@ -773,7 +773,7 @@ protected int SetupContext (ILogger? customLogger = null)
// SealerStep
// OutputStep

if (!context.DisableSerializationDiscovery)
if (context.EnableSerializationDiscovery)
p.MarkHandlers.Add (new DiscoverSerializationHandler ());

if (!context.DisableOperatorDiscovery)
Expand Down
2 changes: 1 addition & 1 deletion src/linker/Linker/LinkContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public Pipeline Pipeline {

public bool KeepUsedAttributeTypesOnly { get; set; }

public bool DisableSerializationDiscovery { get; set; }
public bool EnableSerializationDiscovery { get; set; }

public bool DisableOperatorDiscovery { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ namespace Mono.Linker.Tests.Cases.Serialization
{
[Reference ("System.Xml.ReaderWriter.dll")]
[Reference ("System.Xml.XmlSerializer.dll")]
[SetupLinkerArgument ("--disable-serialization-discovery")]
public class CanDisableSerializationDiscovery
{
public static void Main ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Mono.Linker.Tests.Cases.Serialization
[Reference ("System.Runtime.Serialization.dll")]
[Reference ("System.Runtime.Serialization.Primitives.dll")]
[Reference ("System.Runtime.Serialization.Json.dll")]
[SetupLinkerArgument ("--enable-serialization-discovery")]
public class DataContractJsonSerialization
{
public static void Main ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Mono.Linker.Tests.Cases.Serialization
[Reference ("System.Runtime.Serialization.dll")]
[Reference ("System.Runtime.Serialization.Xml.dll")]
[Reference ("System.Runtime.Serialization.Primitives.dll")]
[SetupLinkerArgument ("--enable-serialization-discovery")]
public class DataContractSerialization
{
public static void Main ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Mono.Linker.Tests.Cases.Serialization
[Reference ("System.Xml.ReaderWriter.dll")]
[Reference ("System.Xml.XmlSerializer.dll")]
[SetupCompileArgument ("/unsafe")]
[SetupLinkerArgument ("--enable-serialization-discovery")]
public class SerializationTypeRecursion
{
public static void Main ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Mono.Linker.Tests.Cases.Serialization
{
[Reference ("System.Xml.ReaderWriter.dll")]
[Reference ("System.Xml.XmlSerializer.dll")]
[SetupLinkerArgument ("--enable-serialization-discovery")]
public class XmlSerialization
{
public static void Main ()
Expand Down