Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitek Karas <vitek.karas@microsoft.com>2021-05-28 21:35:54 +0300
committerGitHub <noreply@github.com>2021-05-28 21:35:54 +0300
commitdd761f75c38eca0bae79597436320510ffc80702 (patch)
treefec26af4339cdc2273b243e1ed22cbd28c099bd4
parent7a5c445a69359415b7ff18b91cd24472ef9509ff (diff)
Fix applying All annotation on a type from "copy" assembly (#2060) (#2064)v6.0.100-preview.5.21278.1release/6.0-preview5
"Copy" assembly calls `MarkEntireType` on all types in the assembly, but it specified to not include base and interface types. We cache if a type was marked as a whole, so to not repeat the process (and also to avoid potential recursion). But the cache doesn't differentiate if the type was mark with its base/interface types or not. So in the "copy" assembly case, the type is first marked without base/interface marking, and that is cached. Later on we apply the All annotation to the type, which calls `MarkEntireType` again, but since it's already cached it doesn't do anything. But All annotation should preserve base/interface types as well, which will not happen in this case. Fixed this by making the cache aware of the base/interface flag and repeat the marking if base/interface is requested even if the type has already been marked as a whole but without base/interface marking. Added a test case.
-rw-r--r--src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs2
-rw-r--r--src/linker/Linker.Steps/MarkStep.cs31
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/Dependencies/MemberTypesAllBaseTypeAssembly.cs50
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/MemberTypesAllOnCopyAssembly.cs82
4 files changed, 150 insertions, 15 deletions
diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
index 6328b4a30..d599d7c8a 100644
--- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
@@ -2210,7 +2210,7 @@ namespace Mono.Linker.Dataflow
break;
case null:
var source = reflectionContext.Source;
- reflectionContext.RecordRecognizedPattern (typeDefinition, () => _markStep.MarkEntireType (typeDefinition, includeBaseTypes: true, includeInterfaceTypes: true, new DependencyInfo (DependencyKind.DynamicallyAccessedMember, source), source));
+ reflectionContext.RecordRecognizedPattern (typeDefinition, () => _markStep.MarkEntireType (typeDefinition, includeBaseAndInterfaceTypes: true, new DependencyInfo (DependencyKind.DynamicallyAccessedMember, source), source));
break;
}
}
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index 1997bc9d0..74be5459d 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -58,7 +58,7 @@ namespace Mono.Linker.Steps
readonly List<(TypeDefinition Type, MethodBody Body, Instruction Instr)> _pending_isinst_instr;
UnreachableBlocksOptimizer _unreachableBlocksOptimizer;
MarkStepContext _markContext;
- readonly HashSet<TypeDefinition> _entireTypesMarked;
+ readonly Dictionary<TypeDefinition, bool> _entireTypesMarked; // The value is markBaseAndInterfaceTypes flag used to mark the type
DynamicallyAccessedMembersTypeHierarchy _dynamicallyAccessedMembersTypeHierarchy;
internal DynamicallyAccessedMembersTypeHierarchy DynamicallyAccessedMembersTypeHierarchy {
@@ -190,7 +190,7 @@ namespace Mono.Linker.Steps
_dynamicInterfaceCastableImplementationTypes = new List<TypeDefinition> ();
_unreachableBodies = new List<MethodBody> ();
_pending_isinst_instr = new List<(TypeDefinition, MethodBody, Instruction)> ();
- _entireTypesMarked = new HashSet<TypeDefinition> ();
+ _entireTypesMarked = new Dictionary<TypeDefinition, bool> ();
}
public AnnotationStore Annotations => _context.Annotations;
@@ -302,30 +302,33 @@ namespace Mono.Linker.Steps
return false;
}
- internal void MarkEntireType (TypeDefinition type, bool includeBaseTypes, bool includeInterfaceTypes, in DependencyInfo reason, IMemberDefinition sourceLocationMember)
+ internal void MarkEntireType (TypeDefinition type, bool includeBaseAndInterfaceTypes, in DependencyInfo reason, IMemberDefinition sourceLocationMember)
{
- MarkEntireTypeInternal (type, includeBaseTypes, includeInterfaceTypes, reason, sourceLocationMember);
+ MarkEntireTypeInternal (type, includeBaseAndInterfaceTypes, reason, sourceLocationMember);
}
- private void MarkEntireTypeInternal (TypeDefinition type, bool includeBaseTypes, bool includeInterfaceTypes, in DependencyInfo reason, IMemberDefinition sourceLocationMember)
+ private void MarkEntireTypeInternal (TypeDefinition type, bool includeBaseAndInterfaceTypes, in DependencyInfo reason, IMemberDefinition sourceLocationMember)
{
#if DEBUG
if (!_entireTypeReasons.Contains (reason.Kind))
throw new InternalErrorException ($"Unsupported type dependency '{reason.Kind}'.");
#endif
- if (!_entireTypesMarked.Add (type))
+ if (_entireTypesMarked.TryGetValue (type, out bool alreadyIncludedBaseAndInterfaceTypes) &&
+ (!includeBaseAndInterfaceTypes || alreadyIncludedBaseAndInterfaceTypes))
return;
+ _entireTypesMarked[type] = includeBaseAndInterfaceTypes;
+
if (type.HasNestedTypes) {
foreach (TypeDefinition nested in type.NestedTypes)
- MarkEntireTypeInternal (nested, includeBaseTypes, includeInterfaceTypes, new DependencyInfo (DependencyKind.NestedType, type), type);
+ MarkEntireTypeInternal (nested, includeBaseAndInterfaceTypes, new DependencyInfo (DependencyKind.NestedType, type), type);
}
Annotations.Mark (type, reason);
var baseTypeDefinition = _context.ResolveTypeDefinition (type.BaseType);
- if (includeBaseTypes && baseTypeDefinition != null) {
- MarkEntireTypeInternal (baseTypeDefinition, includeBaseTypes: true, includeInterfaceTypes, new DependencyInfo (DependencyKind.BaseType, type), type);
+ if (includeBaseAndInterfaceTypes && baseTypeDefinition != null) {
+ MarkEntireTypeInternal (baseTypeDefinition, true, new DependencyInfo (DependencyKind.BaseType, type), type);
}
MarkCustomAttributes (type, new DependencyInfo (DependencyKind.CustomAttribute, type), type);
MarkTypeSpecialCustomAttributes (type);
@@ -333,8 +336,8 @@ namespace Mono.Linker.Steps
if (type.HasInterfaces) {
foreach (InterfaceImplementation iface in type.Interfaces) {
var interfaceTypeDefinition = _context.ResolveTypeDefinition (iface.InterfaceType);
- if (includeInterfaceTypes && interfaceTypeDefinition != null)
- MarkEntireTypeInternal (interfaceTypeDefinition, includeBaseTypes, includeInterfaceTypes: true, new DependencyInfo (reason.Kind, type), type);
+ if (includeBaseAndInterfaceTypes && interfaceTypeDefinition != null)
+ MarkEntireTypeInternal (interfaceTypeDefinition, true, new DependencyInfo (reason.Kind, type), type);
MarkInterfaceImplementation (iface, type);
}
@@ -930,7 +933,7 @@ namespace Mono.Linker.Steps
MarkInterfaceImplementation (interfaceType, sourceLocationMember, reason);
break;
case null:
- MarkEntireType (typeDefinition, includeBaseTypes: true, includeInterfaceTypes: true, reason, sourceLocationMember);
+ MarkEntireType (typeDefinition, includeBaseAndInterfaceTypes: true, reason, sourceLocationMember);
break;
}
}
@@ -994,7 +997,7 @@ namespace Mono.Linker.Steps
}
if (member == "*") {
- MarkEntireType (td, includeBaseTypes: false, includeInterfaceTypes: false, new DependencyInfo (DependencyKind.PreservedDependency, ca), sourceLocationMember);
+ MarkEntireType (td, includeBaseAndInterfaceTypes: false, new DependencyInfo (DependencyKind.PreservedDependency, ca), sourceLocationMember);
return;
}
@@ -1368,7 +1371,7 @@ namespace Mono.Linker.Steps
MarkCustomAttributes (module, new DependencyInfo (DependencyKind.AssemblyOrModuleAttribute, module), null);
foreach (TypeDefinition type in module.Types)
- MarkEntireType (type, includeBaseTypes: false, includeInterfaceTypes: false, new DependencyInfo (DependencyKind.TypeInAssembly, assembly), null);
+ MarkEntireType (type, includeBaseAndInterfaceTypes: false, new DependencyInfo (DependencyKind.TypeInAssembly, assembly), null);
foreach (ExportedType exportedType in module.ExportedTypes) {
MarkingHelpers.MarkExportedType (exportedType, module, new DependencyInfo (DependencyKind.ExportedType, assembly));
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/Dependencies/MemberTypesAllBaseTypeAssembly.cs b/test/Mono.Linker.Tests.Cases/DataFlow/Dependencies/MemberTypesAllBaseTypeAssembly.cs
new file mode 100644
index 000000000..63d3fa11e
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/Dependencies/MemberTypesAllBaseTypeAssembly.cs
@@ -0,0 +1,50 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Mono.Linker.Tests.Cases.DataFlow.Dependencies
+{
+ public class MemberTypesAllBaseType
+ {
+ static MemberTypesAllBaseType () { }
+ public MemberTypesAllBaseType () { }
+ private MemberTypesAllBaseType (bool _) { }
+
+ public void PublicMethod () { }
+ private void PrivateMethod () { }
+
+ public static void PublicStaticMethod () { }
+ private static void PrivateStaticMethod () { }
+
+ public int PublicField;
+ private int PrivateField;
+ public static int PublicStaticField;
+ private static int PrivateStaticField;
+
+ public bool PublicProperty { get; set; }
+ private bool PrivateProperty { get; set; }
+ public static bool PublicStaticProperty { get; set; }
+ private static bool PrivateStaticProperty { get; set; }
+
+ public event EventHandler<EventArgs> PublicEvent;
+ private event EventHandler<EventArgs> PrivateEvent;
+ public static event EventHandler<EventArgs> PublicStaticEvent;
+ private static event EventHandler<EventArgs> PrivateStaticEvent;
+
+ public class PublicNestedType
+ {
+ private void PrivateMethod () { }
+ }
+
+ private class PrivateNestedType
+ {
+ private void PrivateMethod () { }
+ }
+ }
+}
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MemberTypesAllOnCopyAssembly.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MemberTypesAllOnCopyAssembly.cs
new file mode 100644
index 000000000..152a935b9
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/MemberTypesAllOnCopyAssembly.cs
@@ -0,0 +1,82 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Mono.Linker.Tests.Cases.DataFlow.Dependencies;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Helpers;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DataFlow
+{
+ [SetupCompileBefore ("base.dll", new[] { "Dependencies/MemberTypesAllBaseTypeAssembly.cs" })]
+ [KeptAssembly ("base.dll")]
+ [SetupLinkerAction ("link", "base")]
+ [SetupLinkerAction ("copy", "test")]
+
+ [KeptTypeInAssembly ("base.dll", "Mono.Linker.Tests.Cases.DataFlow.Dependencies.MemberTypesAllBaseType")]
+ [KeptMemberInAssembly ("base.dll", "Mono.Linker.Tests.Cases.DataFlow.Dependencies.MemberTypesAllBaseType", new string[] {
+ ".cctor()",
+ ".ctor()",
+ ".ctor(System.Boolean)",
+ "PublicMethod()",
+ "PrivateMethod()",
+ "PublicStaticMethod()",
+ "PrivateStaticMethod()",
+ "PublicField",
+ "PrivateField",
+ "PublicStaticField",
+ "PrivateStaticField",
+ "PublicProperty",
+ "get_PublicProperty()",
+ "set_PublicProperty(System.Boolean)",
+ "PrivateProperty",
+ "get_PrivateProperty()",
+ "set_PrivateProperty(System.Boolean)",
+ "PublicStaticProperty",
+ "get_PublicStaticProperty()",
+ "set_PublicStaticProperty(System.Boolean)",
+ "PrivateStaticProperty",
+ "get_PrivateStaticProperty()",
+ "set_PrivateStaticProperty(System.Boolean)",
+ "PublicEvent",
+ "add_PublicEvent(System.EventHandler`1<System.EventArgs>)",
+ "remove_PublicEvent(System.EventHandler`1<System.EventArgs>)",
+ "PrivateEvent",
+ "add_PrivateEvent(System.EventHandler`1<System.EventArgs>)",
+ "remove_PrivateEvent(System.EventHandler`1<System.EventArgs>)",
+ "PublicStaticEvent",
+ "add_PublicStaticEvent(System.EventHandler`1<System.EventArgs>)",
+ "remove_PublicStaticEvent(System.EventHandler`1<System.EventArgs>)",
+ "PrivateStaticEvent",
+ "add_PrivateStaticEvent(System.EventHandler`1<System.EventArgs>)",
+ "remove_PrivateStaticEvent(System.EventHandler`1<System.EventArgs>)",
+ })]
+
+ [KeptTypeInAssembly ("base.dll", "Mono.Linker.Tests.Cases.DataFlow.Dependencies.MemberTypesAllBaseType/PublicNestedType")]
+ [KeptMemberInAssembly ("base.dll", "Mono.Linker.Tests.Cases.DataFlow.Dependencies.MemberTypesAllBaseType/PublicNestedType", new string[] { "PrivateMethod()" })]
+
+ [KeptTypeInAssembly ("base.dll", "Mono.Linker.Tests.Cases.DataFlow.Dependencies.MemberTypesAllBaseType/PrivateNestedType")]
+ [KeptMemberInAssembly ("base.dll", "Mono.Linker.Tests.Cases.DataFlow.Dependencies.MemberTypesAllBaseType/PrivateNestedType", new string[] { "PrivateMethod()" })]
+
+ [KeptMember (".ctor()")]
+ public class MemberTypesAllOnCopyAssembly
+ {
+ public static void Main ()
+ {
+ typeof (TestType).RequiresAll ();
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (MemberTypesAllBaseType))]
+ [KeptMember (".ctor()")]
+ class TestType : MemberTypesAllBaseType
+ {
+ }
+ }
+}