Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Annotate reflection fallback for S.P.DataContractSerialization (#31533)
Browse files Browse the repository at this point in the history
This adds [removable feature annotation](dotnet/designs#42) to data
contract serialization.

If the user specifies that they would like to remove support for this
at publish/native compilation time, the linker/compiler is going to
replace the annotated method bodies with a throwing method body.
The exception message is going to inform the user that the feature
has been removed because they opted into the removal. The throwing
method body is significantly smaller than the transitive closure
of code reachable from the original method body.

Contributes to #30597. Turning this feature off in the UWP People app
saves 4% of size. This is a size on disk regression that came with
the new version of CoreFX and blocks the Windows team in picking up
the latest framework. There is a zero size growth goal.
  • Loading branch information
MichalStrehovsky authored Aug 10, 2018
1 parent 8ce7ff4 commit d21453e
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
<Compile Include="$(CommonPath)\System\NotImplemented.cs">
<Link>Common\System\NotImplemented.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Runtime\CompilerServices\RemovableFeatureAttribute.cs">
<Link>System\Runtime\CompilerServices\RemovableFeatureAttribute</Link>
</Compile>
<Compile Include="$(RuntimeSerializationSources)\Attributes.cs" />
<Compile Include="$(RuntimeSerializationSources)\CodeGenerator.cs" />
<Compile Include="$(RuntimeSerializationSources)\ClassDataContract.cs" />
Expand Down Expand Up @@ -144,6 +147,7 @@
<Compile Include="System\Runtime\Serialization\IExtensibleDataObject.cs" />
<Compile Include="System\Runtime\Serialization\Json\ReflectionJsonFormatReader.cs" />
<Compile Include="System\Runtime\Serialization\Json\ReflectionJsonFormatWriter.cs" />
<Compile Include="System\Runtime\Serialization\ReflectionFeature.cs" />
<Compile Include="System\Runtime\Serialization\ReflectionReader.cs" />
<Compile Include="System\Runtime\Serialization\ReflectionClassWriter.cs" />
<Compile Include="System\Runtime\Serialization\ReflectionXmlFormatReader.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace System.Runtime.Serialization
using System.IO;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Xml;
using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
Expand Down Expand Up @@ -242,6 +243,14 @@ internal bool CreateNewInstanceViaDefaultConstructor(out object obj)
return true;
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private XmlFormatClassWriterDelegate CreateXmlFormatWriterDelegate()
{
return new XmlFormatWriterGenerator().GenerateClassWriter(this);
}

#if uapaot
private XmlFormatClassWriterDelegate _xmlFormatWriterDelegate;
public XmlFormatClassWriterDelegate XmlFormatWriterDelegate
Expand All @@ -264,7 +273,7 @@ internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
{
if (_helper.XmlFormatWriterDelegate == null)
{
XmlFormatClassWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateClassWriter(this);
XmlFormatClassWriterDelegate tempDelegate = CreateXmlFormatWriterDelegate();
Interlocked.MemoryBarrier();
_helper.XmlFormatWriterDelegate = tempDelegate;
}
Expand All @@ -280,6 +289,14 @@ internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
}
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private XmlFormatClassReaderDelegate CreateXmlFormatReaderDelegate()
{
return new XmlFormatReaderGenerator().GenerateClassReader(this);
}

#if uapaot
private XmlFormatClassReaderDelegate _xmlFormatReaderDelegate;
public XmlFormatClassReaderDelegate XmlFormatReaderDelegate
Expand All @@ -302,7 +319,7 @@ internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate
{
if (_helper.XmlFormatReaderDelegate == null)
{
XmlFormatClassReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateClassReader(this);
XmlFormatClassReaderDelegate tempDelegate = CreateXmlFormatReaderDelegate();
Interlocked.MemoryBarrier();
_helper.XmlFormatReaderDelegate = tempDelegate;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace System.Runtime.Serialization
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Xml;
using System.Linq;
Expand Down Expand Up @@ -336,6 +337,14 @@ internal string InvalidCollectionInSharedContractMessage
{ return _helper.InvalidCollectionInSharedContractMessage; }
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private XmlFormatCollectionWriterDelegate CreateXmlFormatWriterDelegate()
{
return new XmlFormatWriterGenerator().GenerateCollectionWriter(this);
}

#if uapaot
private XmlFormatCollectionWriterDelegate _xmlFormatWriterDelegate;
public XmlFormatCollectionWriterDelegate XmlFormatWriterDelegate
Expand All @@ -358,7 +367,7 @@ internal XmlFormatCollectionWriterDelegate XmlFormatWriterDelegate
{
if (_helper.XmlFormatWriterDelegate == null)
{
XmlFormatCollectionWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateCollectionWriter(this);
XmlFormatCollectionWriterDelegate tempDelegate = CreateXmlFormatWriterDelegate();
Interlocked.MemoryBarrier();
_helper.XmlFormatWriterDelegate = tempDelegate;
}
Expand All @@ -374,6 +383,14 @@ internal XmlFormatCollectionWriterDelegate XmlFormatWriterDelegate
}
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private XmlFormatCollectionReaderDelegate CreateXmlFormatReaderDelegate()
{
return new XmlFormatReaderGenerator().GenerateCollectionReader(this);
}

#if uapaot
private XmlFormatCollectionReaderDelegate _xmlFormatReaderDelegate;
public XmlFormatCollectionReaderDelegate XmlFormatReaderDelegate
Expand All @@ -396,7 +413,7 @@ internal XmlFormatCollectionReaderDelegate XmlFormatReaderDelegate
{
if (_helper.XmlFormatReaderDelegate == null)
{
XmlFormatCollectionReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateCollectionReader(this);
XmlFormatCollectionReaderDelegate tempDelegate = CreateXmlFormatReaderDelegate();
Interlocked.MemoryBarrier();
_helper.XmlFormatReaderDelegate = tempDelegate;
}
Expand All @@ -412,6 +429,15 @@ internal XmlFormatCollectionReaderDelegate XmlFormatReaderDelegate
}
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private XmlFormatGetOnlyCollectionReaderDelegate CreateXmlFormatGetOnlyCollectionReaderDelegate()
{
return new XmlFormatReaderGenerator().GenerateGetOnlyCollectionReader(this);
}


#if uapaot
private XmlFormatGetOnlyCollectionReaderDelegate _xmlFormatGetOnlyCollectionReaderDelegate;
public XmlFormatGetOnlyCollectionReaderDelegate XmlFormatGetOnlyCollectionReaderDelegate
Expand Down Expand Up @@ -444,7 +470,7 @@ internal XmlFormatGetOnlyCollectionReaderDelegate XmlFormatGetOnlyCollectionRead
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GetOnlyCollectionMustHaveAddMethod, GetClrTypeFullName(UnderlyingType))));
}

XmlFormatGetOnlyCollectionReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateGetOnlyCollectionReader(this);
XmlFormatGetOnlyCollectionReaderDelegate tempDelegate = CreateXmlFormatGetOnlyCollectionReaderDelegate();
Interlocked.MemoryBarrier();
_helper.XmlFormatGetOnlyCollectionReaderDelegate = tempDelegate;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public sealed class DataContractSerializer : XmlObjectSerializer
private ISerializationSurrogateProvider _serializationSurrogateProvider;
private bool _serializeReadOnlyTypes;

private static SerializationOption _option = SerializationOption.ReflectionAsBackup;
private static SerializationOption _option = IsReflectionBackupAllowed() ? SerializationOption.ReflectionAsBackup : SerializationOption.CodeGenOnly;
private static bool _optionAlreadySet;
internal static SerializationOption Option
{
Expand All @@ -50,6 +50,17 @@ internal static SerializationOption Option
}
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name, UseNopBody = true)]
#endif
private static bool IsReflectionBackupAllowed()
{
// The RemovableFeature annotation above is going to replace this with
// "return false" if reflection based serialization feature was removed
// at publishing time.
return true;
}

public DataContractSerializer(Type type)
: this(type, (IEnumerable<Type>)null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Xml;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Runtime.Serialization.Json
{
Expand All @@ -19,6 +20,14 @@ public JsonClassDataContract(ClassDataContract traditionalDataContract)
_helper = base.Helper as JsonClassDataContractCriticalHelper;
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private JsonFormatClassReaderDelegate CreateJsonFormatReaderDelegate()
{
return new ReflectionJsonClassReader(TraditionalClassDataContract).ReflectionReadClass;
}

internal JsonFormatClassReaderDelegate JsonFormatReaderDelegate
{
get
Expand All @@ -32,13 +41,13 @@ internal JsonFormatClassReaderDelegate JsonFormatReaderDelegate
JsonFormatClassReaderDelegate tempDelegate;
if (DataContractSerializer.Option == SerializationOption.ReflectionOnly)
{
tempDelegate = new ReflectionJsonClassReader(TraditionalClassDataContract).ReflectionReadClass;
tempDelegate = CreateJsonFormatReaderDelegate();
}
#if uapaot
else if (DataContractSerializer.Option == SerializationOption.ReflectionAsBackup)
{
tempDelegate = JsonDataContract.TryGetReadWriteDelegatesFromGeneratedAssembly(TraditionalClassDataContract)?.ClassReaderDelegate;
tempDelegate = tempDelegate ?? new ReflectionJsonClassReader(TraditionalClassDataContract).ReflectionReadClass;
tempDelegate = tempDelegate ?? CreateJsonFormatReaderDelegate();

if (tempDelegate == null)
throw new InvalidDataContractException(SR.Format(SR.SerializationCodeIsMissingForType, TraditionalClassDataContract.UnderlyingType.ToString()));
Expand All @@ -62,6 +71,14 @@ internal JsonFormatClassReaderDelegate JsonFormatReaderDelegate
}
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private JsonFormatClassWriterDelegate CreateJsonFormatWriterDelegate()
{
return new ReflectionJsonFormatWriter().ReflectionWriteClass;
}

internal JsonFormatClassWriterDelegate JsonFormatWriterDelegate
{
get
Expand All @@ -75,13 +92,13 @@ internal JsonFormatClassWriterDelegate JsonFormatWriterDelegate
JsonFormatClassWriterDelegate tempDelegate;
if (DataContractSerializer.Option == SerializationOption.ReflectionOnly)
{
tempDelegate = new ReflectionJsonFormatWriter().ReflectionWriteClass;
tempDelegate = CreateJsonFormatWriterDelegate();
}
#if uapaot
else if (DataContractSerializer.Option == SerializationOption.ReflectionAsBackup)
{
tempDelegate = JsonDataContract.TryGetReadWriteDelegatesFromGeneratedAssembly(TraditionalClassDataContract)?.ClassWriterDelegate;
tempDelegate = tempDelegate ?? new ReflectionJsonFormatWriter().ReflectionWriteClass;
tempDelegate = tempDelegate ?? CreateJsonFormatWriterDelegate();

if (tempDelegate == null)
throw new InvalidDataContractException(SR.Format(SR.SerializationCodeIsMissingForType, TraditionalClassDataContract.UnderlyingType.ToString()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Xml;

Expand All @@ -18,6 +19,14 @@ public JsonCollectionDataContract(CollectionDataContract traditionalDataContract
_helper = base.Helper as JsonCollectionDataContractCriticalHelper;
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private JsonFormatCollectionReaderDelegate CreateJsonFormatReaderDelegate()
{
return new ReflectionJsonCollectionReader().ReflectionReadCollection;
}

internal JsonFormatCollectionReaderDelegate JsonFormatReaderDelegate
{
get
Expand All @@ -31,13 +40,13 @@ internal JsonFormatCollectionReaderDelegate JsonFormatReaderDelegate
JsonFormatCollectionReaderDelegate tempDelegate;
if (DataContractSerializer.Option == SerializationOption.ReflectionOnly)
{
tempDelegate = new ReflectionJsonCollectionReader().ReflectionReadCollection;
tempDelegate = CreateJsonFormatReaderDelegate();
}
#if uapaot
else if (DataContractSerializer.Option == SerializationOption.ReflectionAsBackup)
{
tempDelegate = JsonDataContract.TryGetReadWriteDelegatesFromGeneratedAssembly(TraditionalCollectionDataContract)?.CollectionReaderDelegate;
tempDelegate = tempDelegate ?? new ReflectionJsonCollectionReader().ReflectionReadCollection;
tempDelegate = tempDelegate ?? CreateJsonFormatReaderDelegate();

if (tempDelegate == null)
throw new InvalidDataContractException(SR.Format(SR.SerializationCodeIsMissingForType, TraditionalCollectionDataContract.UnderlyingType.ToString()));
Expand All @@ -61,6 +70,14 @@ internal JsonFormatCollectionReaderDelegate JsonFormatReaderDelegate
}
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private JsonFormatGetOnlyCollectionReaderDelegate CreateJsonFormatGetOnlyReaderDelegate()
{
return new ReflectionJsonCollectionReader().ReflectionReadGetOnlyCollection;
}

internal JsonFormatGetOnlyCollectionReaderDelegate JsonFormatGetOnlyReaderDelegate
{
get
Expand All @@ -80,13 +97,13 @@ internal JsonFormatGetOnlyCollectionReaderDelegate JsonFormatGetOnlyReaderDelega
JsonFormatGetOnlyCollectionReaderDelegate tempDelegate;
if (DataContractSerializer.Option == SerializationOption.ReflectionOnly)
{
tempDelegate = new ReflectionJsonCollectionReader().ReflectionReadGetOnlyCollection;
tempDelegate = CreateJsonFormatGetOnlyReaderDelegate();
}
#if uapaot
else if (DataContractSerializer.Option == SerializationOption.ReflectionAsBackup)
{
tempDelegate = JsonDataContract.TryGetReadWriteDelegatesFromGeneratedAssembly(TraditionalCollectionDataContract)?.GetOnlyCollectionReaderDelegate;
tempDelegate = tempDelegate ?? new ReflectionJsonCollectionReader().ReflectionReadGetOnlyCollection;
tempDelegate = tempDelegate ?? CreateJsonFormatGetOnlyReaderDelegate();

if (tempDelegate == null)
throw new InvalidDataContractException(SR.Format(SR.SerializationCodeIsMissingForType, TraditionalCollectionDataContract.UnderlyingType.ToString()));
Expand All @@ -97,7 +114,7 @@ internal JsonFormatGetOnlyCollectionReaderDelegate JsonFormatGetOnlyReaderDelega
#if uapaot
tempDelegate = JsonDataContract.GetReadWriteDelegatesFromGeneratedAssembly(TraditionalCollectionDataContract).GetOnlyCollectionReaderDelegate;
#else
tempDelegate = new JsonFormatReaderGenerator().GenerateGetOnlyCollectionReader(TraditionalCollectionDataContract);
tempDelegate = new JsonFormatReaderGenerator().GenerateGetOnlyCollectionReader(TraditionalCollectionDataContract);
#endif
}

Expand All @@ -110,6 +127,15 @@ internal JsonFormatGetOnlyCollectionReaderDelegate JsonFormatGetOnlyReaderDelega
}
}

#if uapaot
[RemovableFeature(ReflectionBasedSerializationFeature.Name)]
#endif
private JsonFormatCollectionWriterDelegate CreateJsonFormatWriterDelegate()
{
return new ReflectionJsonFormatWriter().ReflectionWriteCollection;
}


internal JsonFormatCollectionWriterDelegate JsonFormatWriterDelegate
{
get
Expand All @@ -123,13 +149,13 @@ internal JsonFormatCollectionWriterDelegate JsonFormatWriterDelegate
JsonFormatCollectionWriterDelegate tempDelegate;
if (DataContractSerializer.Option == SerializationOption.ReflectionOnly)
{
tempDelegate = new ReflectionJsonFormatWriter().ReflectionWriteCollection;
tempDelegate = CreateJsonFormatWriterDelegate();
}
#if uapaot
else if (DataContractSerializer.Option == SerializationOption.ReflectionAsBackup)
{
tempDelegate = JsonDataContract.TryGetReadWriteDelegatesFromGeneratedAssembly(TraditionalCollectionDataContract)?.CollectionWriterDelegate;
tempDelegate = tempDelegate ?? new ReflectionJsonFormatWriter().ReflectionWriteCollection;
tempDelegate = tempDelegate ?? CreateJsonFormatWriterDelegate();

if (tempDelegate == null)
throw new InvalidDataContractException(SR.Format(SR.SerializationCodeIsMissingForType, TraditionalCollectionDataContract.UnderlyingType.ToString()));
Expand Down Expand Up @@ -217,4 +243,4 @@ internal CollectionDataContract TraditionalCollectionDataContract
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace System.Runtime.Serialization
{
class ReflectionBasedSerializationFeature
{
public const string Name = "System.Runtime.Serialization.ReflectionBasedSerialization";
}
}
Loading

0 comments on commit d21453e

Please sign in to comment.