Fixes for .NET 6 linker (#11739)
* Pass custom steps separately from msbuild * Remove reflection over linker pipeline * Fix ListExportedSymbols ctor * Add CoreTypeMapStep * PR feedback - Avoid unnecessary tracking of loaded assemblies (Use GetLoadedAssembly instead) - Create extension method on LinkContext to avoid conditional code - Rename dispatchers to reflect when they run * Fix PreMarkDispatcher * Fix DoneStep ordering * Fix other order-dependent steps, test asserts * Handle cyclic assembly references * Simplify reference search By using the already-loaded Assembly closure * Fix warning number Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com> * PR feedback - Undo whitespace changes - Move comment to a more appropriate place Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com>
This commit is contained in:
Родитель
2837a9c6bb
Коммит
045ccaf3a6
|
@ -317,11 +317,55 @@
|
|||
<!-- Mark our entry assembly as a root assembly. -->
|
||||
<TrimmerRootAssembly Include="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.Filename)' == '$(AssemblyName)' And '%(ResolvedFileToPublish.Extension)' == '.dll'" />
|
||||
|
||||
<!-- add a custom step which inserts any other steps we need -->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)">
|
||||
<BeforeStep>MarkStep</BeforeStep>
|
||||
<Type>Xamarin.SetupStep</Type>
|
||||
</_TrimmerCustomSteps>
|
||||
<!--
|
||||
pre-mark custom steps
|
||||
-->
|
||||
<!-- TODO: reverse the pre-mark steps once we get the fix from https://github.com/mono/linker/pull/2082 -->
|
||||
<!-- TODO: these steps should probably run after mark. -->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" />
|
||||
<!-- The final decision to remove/keep the dynamic registrar must be done before the linking step -->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.CoreTypeMapStep" />
|
||||
<!-- Load the list of assemblies loaded by the linker. -->
|
||||
<!-- This would not be needed if LinkContext.GetAssemblies () was exposed to us. -->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.CollectAssembliesStep" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.SetupStep" />
|
||||
|
||||
<!--
|
||||
IMarkHandlers which run during Mark
|
||||
-->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.OptimizeGeneratedCodeHandler" />
|
||||
<!-- MarkDispatcher substeps will run for all marked assemblies. -->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.MarkDispatcher" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreserveSmartEnumConversionsHandler" />
|
||||
|
||||
<!--
|
||||
post-sweep custom steps
|
||||
-->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="SweepStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PostSweepDispatcher" />
|
||||
|
||||
<!--
|
||||
pre-output custom steps
|
||||
-->
|
||||
<!-- TODO: reverse the pre-output steps once we get the fix from https://github.com/mono/linker/pull/2082 -->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.PreOutputDispatcher" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.ExtractBindingLibrariesStep" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.LoadNonSkippedAssembliesStep" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.ListExportedSymbols" />
|
||||
|
||||
<!--
|
||||
post-output steps
|
||||
-->
|
||||
<!-- TODO: remove AfterStep="OutputStep" from the post-output steps once we get the fix from https://github.com/mono/linker/pull/2082 -->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.RegistrarStep" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.GenerateMainStep" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.GenerateReferencesStep" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.GatherFrameworksStep" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.ComputeNativeBuildFlagsStep" />
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.ComputeAOTArguments" />
|
||||
<!-- Must be the last step. -->
|
||||
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.DoneStep" />
|
||||
|
||||
<!-- _BundlerXmlDefinitions comes from any -xml arguments to mtouch/mmp -->
|
||||
<TrimmerRootDescriptor Include="@(_BundlerXmlDefinitions)" />
|
||||
|
|
|
@ -443,14 +443,14 @@ namespace Xamarin.Tests {
|
|||
{
|
||||
var output = BinLog.PrintToString (result.BinLogPath);
|
||||
Assert.That (output, Does.Contain ("Building target \"_RunILLink\" completely."), "Linker did not executed as expected.");
|
||||
Assert.That (output, Does.Contain ("Pipeline Steps:"), "Custom steps did not run as expected.");
|
||||
Assert.That (output, Does.Contain ("LinkerConfiguration:"), "Custom steps did not run as expected.");
|
||||
}
|
||||
|
||||
void AssertThatLinkerDidNotExecute (ExecutionResult result)
|
||||
{
|
||||
var output = BinLog.PrintToString (result.BinLogPath);
|
||||
Assert.That (output, Does.Not.Contain ("Building target \"_RunILLink\" completely."), "Linker did not executed as expected.");
|
||||
Assert.That (output, Does.Not.Contain ("Pipeline Steps:"), "Custom steps did not run as expected.");
|
||||
Assert.That (output, Does.Not.Contain ("LinkerConfiguration:"), "Custom steps did not run as expected.");
|
||||
}
|
||||
|
||||
void AssertAppContents (ApplePlatform platform, string app_directory)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
using Mono.Cecil;
|
||||
using Mono.Linker;
|
||||
using Mono.Tuner;
|
||||
using System;
|
||||
|
||||
namespace Xamarin.Linker {
|
||||
public static class Extensions {
|
||||
public static bool Inherits (this TypeReference self, string @namespace, string name, IMetadataResolver resolver)
|
||||
{
|
||||
if (@namespace == null)
|
||||
throw new ArgumentNullException ("namespace");
|
||||
if (name == null)
|
||||
throw new ArgumentNullException ("name");
|
||||
if (self == null)
|
||||
return false;
|
||||
|
||||
TypeReference current = resolver.Resolve (self);
|
||||
while (current != null) {
|
||||
if (current.Is (@namespace, name))
|
||||
return true;
|
||||
if (current.Is ("System", "Object"))
|
||||
return false;
|
||||
|
||||
TypeDefinition td = resolver.Resolve (current);
|
||||
if (td == null)
|
||||
return false; // could not resolve type
|
||||
current = td.BaseType;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,129 +17,12 @@ namespace Xamarin {
|
|||
protected override string Name { get; } = "Setup";
|
||||
protected override int ErrorCode { get; } = 2300;
|
||||
|
||||
List<IStep> _steps;
|
||||
public List<IStep> Steps {
|
||||
get {
|
||||
if (_steps == null) {
|
||||
var pipeline = typeof (LinkContext).GetProperty ("Pipeline").GetGetMethod ().Invoke (Context, null);
|
||||
_steps = (List<IStep>) pipeline.GetType ().GetField ("_steps", BindingFlags.Instance | BindingFlags.NonPublic).GetValue (pipeline);
|
||||
}
|
||||
return _steps;
|
||||
}
|
||||
}
|
||||
|
||||
List<IMarkHandler> _markHandlers;
|
||||
List<IMarkHandler> MarkHandlers {
|
||||
get {
|
||||
if (_markHandlers == null) {
|
||||
var pipeline = typeof (LinkContext).GetProperty ("Pipeline").GetGetMethod ().Invoke (Context, null);
|
||||
_markHandlers = (List<IMarkHandler>) pipeline.GetType ().GetProperty ("MarkHandlers").GetValue (pipeline);
|
||||
}
|
||||
return _markHandlers;
|
||||
}
|
||||
}
|
||||
|
||||
void InsertBefore (IStep step, string stepName)
|
||||
{
|
||||
for (int i = 0; i < Steps.Count; i++) {
|
||||
if (Steps [i].GetType ().Name == stepName) {
|
||||
Steps.Insert (i, step);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DumpSteps ();
|
||||
throw new InvalidOperationException ($"Could not insert {step} before {stepName} because {stepName} wasn't found.");
|
||||
}
|
||||
|
||||
void InsertAfter (IStep step, string stepName)
|
||||
{
|
||||
for (int i = 0; i < Steps.Count;) {
|
||||
if (Steps [i++].GetType ().Name == stepName) {
|
||||
Steps.Insert (i, step);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DumpSteps ();
|
||||
throw new InvalidOperationException ($"Could not insert {step} after {stepName} because {stepName} wasn't found.");
|
||||
}
|
||||
|
||||
protected override void TryProcess ()
|
||||
{
|
||||
// Don't use --custom-step to load each step, because this assembly
|
||||
// is loaded into the current process once per --custom-step,
|
||||
// which makes it very difficult to share state between steps.
|
||||
|
||||
// Load the list of assemblies loaded by the linker.
|
||||
// This would not be needed of LinkContext.GetAssemblies () was exposed to us.
|
||||
InsertBefore (new CollectAssembliesStep (), "MarkStep");
|
||||
|
||||
// the final decision to remove/keep the dynamic registrar must be done before the linking step
|
||||
InsertBefore (new RegistrarRemovalTrackingStep (), "MarkStep");
|
||||
|
||||
var pre_mark_substeps = new DotNetSubStepDispatcher ();
|
||||
InsertBefore (pre_mark_substeps, "MarkStep");
|
||||
|
||||
var post_sweep_substeps = new DotNetSubStepDispatcher ();
|
||||
InsertAfter (post_sweep_substeps, "SweepStep");
|
||||
|
||||
if (Configuration.LinkMode != LinkMode.None) {
|
||||
MarkHandlers.Add (new PreserveBlockCodeHandler ());
|
||||
|
||||
// We need to run the ApplyPreserveAttribute step even we're only linking sdk assemblies, because even
|
||||
// though we know that sdk assemblies will never have Preserve attributes, user assemblies may have
|
||||
// [assembly: LinkSafe] attributes, which means we treat them as sdk assemblies and those may have
|
||||
// Preserve attributes.
|
||||
MarkHandlers.Add (new DotNetMarkAssemblySubStepDispatcher (new ApplyPreserveAttribute ()));
|
||||
MarkHandlers.Add (new OptimizeGeneratedCodeHandler ());
|
||||
MarkHandlers.Add (new DotNetMarkAssemblySubStepDispatcher (new MarkNSObjects ()));
|
||||
MarkHandlers.Add (new PreserveSmartEnumConversionsHandler ());
|
||||
|
||||
// This step could be run after Mark to avoid tracking all members:
|
||||
// https://github.com/xamarin/xamarin-macios/issues/11447
|
||||
pre_mark_substeps.Add (new CollectUnmarkedMembersSubStep ());
|
||||
pre_mark_substeps.Add (new StoreAttributesStep ());
|
||||
|
||||
post_sweep_substeps.Add (new RemoveAttributesStep ());
|
||||
}
|
||||
|
||||
InsertBefore (new ListExportedSymbols (null), "OutputStep");
|
||||
InsertBefore (new LoadNonSkippedAssembliesStep (), "OutputStep");
|
||||
InsertBefore (new ExtractBindingLibrariesStep (), "OutputStep");
|
||||
InsertBefore (new DotNetSubStepDispatcher (new RemoveUserResourcesSubStep ()), "OutputStep");
|
||||
Steps.Add (new RegistrarStep ());
|
||||
Steps.Add (new GenerateMainStep ());
|
||||
Steps.Add (new GenerateReferencesStep ());
|
||||
Steps.Add (new GatherFrameworksStep ());
|
||||
Steps.Add (new ComputeNativeBuildFlagsStep ());
|
||||
Steps.Add (new ComputeAOTArguments ());
|
||||
Steps.Add (new DoneStep ()); // Must be the last step.
|
||||
|
||||
Configuration.Write ();
|
||||
|
||||
if (Configuration.Verbosity > 0) {
|
||||
DumpSteps ();
|
||||
}
|
||||
|
||||
ErrorHelper.Platform = Configuration.Platform;
|
||||
Directory.CreateDirectory (Configuration.ItemsDirectory);
|
||||
Directory.CreateDirectory (Configuration.CacheDirectory);
|
||||
}
|
||||
|
||||
void DumpSteps ()
|
||||
{
|
||||
Console.WriteLine ();
|
||||
Console.WriteLine ("Pipeline Steps:");
|
||||
foreach (var step in Steps) {
|
||||
Console.WriteLine ($" {step}");
|
||||
if (step is SubStepsDispatcher) {
|
||||
var substeps = typeof (SubStepsDispatcher).GetField ("substeps", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue (step) as IEnumerable<ISubStep>;
|
||||
if (substeps != null) {
|
||||
foreach (var substep in substeps) {
|
||||
Console.WriteLine ($" {substep}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
using Mono.Linker.Steps;
|
||||
|
||||
namespace Xamarin.Linker.Steps {
|
||||
// MarkSubStepsDispatcher is abstract, so create a subclass we can instantiate.
|
||||
// Can be removed when we update to the preview4 linker, which makes MarkSubStepsDispatcher non-abstract.
|
||||
class DotNetMarkAssemblySubStepDispatcher : MarkSubStepsDispatcher {
|
||||
public DotNetMarkAssemblySubStepDispatcher (params BaseSubStep[] subSteps) : base (subSteps)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using Mono.Linker.Steps;
|
||||
using Xamarin.Linker;
|
||||
|
||||
namespace Xamarin.Linker.Steps {
|
||||
class MarkDispatcher : MarkSubStepsDispatcher {
|
||||
public MarkDispatcher ()
|
||||
: base (new BaseSubStep[] {
|
||||
new ApplyPreserveAttribute (),
|
||||
new MarkNSObjects ()
|
||||
})
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using Mono.Linker.Steps;
|
||||
using Xamarin.Linker;
|
||||
|
||||
namespace Xamarin.Linker.Steps {
|
||||
class PostSweepDispatcher : SubStepsDispatcher {
|
||||
public PostSweepDispatcher ()
|
||||
: base (new [] { new RemoveAttributesStep () })
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using Mono.Linker.Steps;
|
||||
using Xamarin.Linker;
|
||||
|
||||
namespace Xamarin.Linker.Steps {
|
||||
class PreMarkDispatcher : SubStepsDispatcher {
|
||||
public PreMarkDispatcher ()
|
||||
: base (new BaseSubStep [] {
|
||||
new CollectUnmarkedMembersSubStep (),
|
||||
new StoreAttributesStep ()
|
||||
})
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using Mono.Linker.Steps;
|
||||
using Xamarin.Linker;
|
||||
|
||||
namespace Xamarin.Linker.Steps {
|
||||
class PreOutputDispatcher : SubStepsDispatcher {
|
||||
public PreOutputDispatcher ()
|
||||
: base (new [] { new RemoveUserResourcesSubStep () })
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -106,6 +106,9 @@
|
|||
<Compile Include="..\linker\CoreOptimizeGeneratedCode.cs">
|
||||
<Link>external\tools\linker\CoreOptimizeGeneratedCode.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\linker\CoreTypeMapStep.cs">
|
||||
<Link>external\tools\linker\CoreTypeMapStep.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\src\ObjCRuntime\Registrar.cs">
|
||||
<Link>external\src\ObjCRuntime\Registrar.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -17,6 +17,10 @@ namespace Xamarin.Linker.Steps {
|
|||
HashSet<TypeDefinition> preserve_synonyms;
|
||||
#endif
|
||||
|
||||
// We need to run the ApplyPreserveAttribute step even if we're only linking sdk assemblies, because even
|
||||
// though we know that sdk assemblies will never have Preserve attributes, user assemblies may have
|
||||
// [assembly: LinkSafe] attributes, which means we treat them as sdk assemblies and those may have
|
||||
// Preserve attributes.
|
||||
public override bool IsActiveFor (AssemblyDefinition assembly)
|
||||
{
|
||||
return Annotations.GetAction (assembly) == AssemblyAction.Link;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Mono.Cecil;
|
||||
using Mono.Linker.Steps;
|
||||
|
@ -20,27 +21,152 @@ using Xamarin.Tuner;
|
|||
namespace MonoTouch.Tuner {
|
||||
|
||||
// This class is shared between Xamarin.Mac and Xamarin.iOS
|
||||
public class CoreTypeMapStep : TypeMapStep {
|
||||
HashSet<TypeDefinition> cached_isnsobject = new HashSet<TypeDefinition> ();
|
||||
Dictionary<TypeDefinition, bool?> isdirectbinding_value = new Dictionary<TypeDefinition, bool?> ();
|
||||
public class CoreTypeMapStep :
|
||||
#if NET
|
||||
ConfigurationAwareStep
|
||||
#else
|
||||
TypeMapStep
|
||||
#endif
|
||||
{
|
||||
|
||||
#if NET
|
||||
protected override string Name { get; } = "CoreTypeMap";
|
||||
protected override int ErrorCode { get; } = 2390;
|
||||
|
||||
Profile Profile => new Profile (Configuration);
|
||||
|
||||
// Get the reverse mapping from assemblies to assemblies which reference them directly.
|
||||
Dictionary<AssemblyDefinition, HashSet<AssemblyDefinition>> _reversedReferences;
|
||||
Dictionary<AssemblyDefinition, HashSet<AssemblyDefinition>> GetReversedReferences ()
|
||||
{
|
||||
if (_reversedReferences != null)
|
||||
return _reversedReferences;
|
||||
|
||||
_reversedReferences = new Dictionary<AssemblyDefinition, HashSet<AssemblyDefinition>> ();
|
||||
foreach (var assembly in Configuration.Assemblies) {
|
||||
if (!_reversedReferences.ContainsKey (assembly))
|
||||
_reversedReferences.Add (assembly, new HashSet<AssemblyDefinition> ());
|
||||
|
||||
foreach (var reference in assembly.MainModule.AssemblyReferences) {
|
||||
var resolvedReference = Configuration.Context.GetLoadedAssembly (reference.Name);
|
||||
if (resolvedReference == null)
|
||||
continue;
|
||||
|
||||
if (!_reversedReferences.TryGetValue (resolvedReference, out var referrers)) {
|
||||
referrers = new HashSet<AssemblyDefinition> ();
|
||||
_reversedReferences.Add (resolvedReference, referrers);
|
||||
}
|
||||
|
||||
referrers.Add (assembly);
|
||||
}
|
||||
}
|
||||
return _reversedReferences;
|
||||
}
|
||||
|
||||
Dictionary<AssemblyDefinition, bool> _transitivelyReferencesProduct;
|
||||
bool TransitivelyReferencesProduct (AssemblyDefinition assembly)
|
||||
{
|
||||
if (_transitivelyReferencesProduct != null) {
|
||||
Debug.Assert (_transitivelyReferencesProduct.ContainsKey (assembly));
|
||||
return _transitivelyReferencesProduct.TryGetValue (assembly, out bool result) && result;
|
||||
}
|
||||
|
||||
_transitivelyReferencesProduct = new Dictionary<AssemblyDefinition, bool> ();
|
||||
|
||||
// A depth-first search is insufficient because there are reference cycles, so we
|
||||
// get the set of transitive references, and do a reverse BFS.
|
||||
var reversedReferences = GetReversedReferences ();
|
||||
Debug.Assert (reversedReferences.ContainsKey (assembly));
|
||||
var referencesProductToProcess = new Queue<AssemblyDefinition> ();
|
||||
|
||||
// We start the BFS from the product assembly.
|
||||
foreach (var reference in reversedReferences.Keys) {
|
||||
if (Profile.IsProductAssembly (reference)) {
|
||||
_transitivelyReferencesProduct.Add (reference, true);
|
||||
referencesProductToProcess.Enqueue (reference);
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the reverse references to find out which referencing assemblies
|
||||
// are reachable from the product assembly (that is, transitively reference the product).
|
||||
while (referencesProductToProcess.TryDequeue (out var reference)) {
|
||||
foreach (var referrer in reversedReferences[reference]) {
|
||||
if (_transitivelyReferencesProduct.TryGetValue (referrer, out bool referencesProduct)) {
|
||||
Debug.Assert (referencesProduct);
|
||||
// Any which were already determined to reference the product assembly
|
||||
// don't need to be scanned again.
|
||||
continue;
|
||||
}
|
||||
|
||||
_transitivelyReferencesProduct.Add (referrer, true);
|
||||
referencesProductToProcess.Enqueue (referrer);
|
||||
}
|
||||
}
|
||||
|
||||
// Any remaining references that we didn't discover during the search
|
||||
// don't reference the product assembly.
|
||||
foreach (var reference in reversedReferences.Keys)
|
||||
_transitivelyReferencesProduct.TryAdd (reference, false);
|
||||
|
||||
return _transitivelyReferencesProduct[assembly];
|
||||
}
|
||||
|
||||
protected override void TryProcessAssembly (AssemblyDefinition assembly)
|
||||
{
|
||||
// We are only interested in types transitively derived from NSObject,
|
||||
// which lives in the product assembly.
|
||||
if (!TransitivelyReferencesProduct (assembly))
|
||||
return;
|
||||
|
||||
foreach (var type in assembly.MainModule.Types)
|
||||
ProcessType (type);
|
||||
}
|
||||
|
||||
void ProcessType (TypeDefinition type)
|
||||
{
|
||||
MapType (type);
|
||||
|
||||
if (!type.HasNestedTypes)
|
||||
return;
|
||||
|
||||
foreach (var nestedType in type.NestedTypes)
|
||||
ProcessType (nestedType);
|
||||
}
|
||||
|
||||
DerivedLinkContext LinkContext => Configuration.DerivedLinkContext;
|
||||
#else
|
||||
DerivedLinkContext LinkContext {
|
||||
get {
|
||||
return (DerivedLinkContext) base.Context;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
HashSet<TypeDefinition> cached_isnsobject = new HashSet<TypeDefinition> ();
|
||||
Dictionary<TypeDefinition, bool?> isdirectbinding_value = new Dictionary<TypeDefinition, bool?> ();
|
||||
|
||||
#if NET
|
||||
protected override void TryEndProcess ()
|
||||
{
|
||||
#else
|
||||
protected override void EndProcess ()
|
||||
{
|
||||
base.EndProcess ();
|
||||
#endif
|
||||
|
||||
LinkContext.CachedIsNSObject = cached_isnsobject;
|
||||
LinkContext.IsDirectBindingValue = isdirectbinding_value;
|
||||
}
|
||||
|
||||
protected override void MapType (TypeDefinition type)
|
||||
protected
|
||||
#if !NET
|
||||
override
|
||||
#endif
|
||||
void MapType (TypeDefinition type)
|
||||
{
|
||||
#if !NET
|
||||
base.MapType (type);
|
||||
#endif
|
||||
|
||||
// additional checks for NSObject to check if the type is a *generated* bindings
|
||||
// bonus: we cache, for every type, whether or not it inherits from NSObject (very useful later)
|
||||
|
@ -77,7 +203,7 @@ namespace MonoTouch.Tuner {
|
|||
|
||||
bool rv;
|
||||
if (!ci_filter_types.TryGetValue (type, out rv)) {
|
||||
rv = type.Is (Namespaces.CoreImage, "CIFilter") || IsCIFilter (type.Resolve ().BaseType);
|
||||
rv = type.Is (Namespaces.CoreImage, "CIFilter") || IsCIFilter (Context.Resolve (type).BaseType);
|
||||
ci_filter_types [type] = rv;
|
||||
}
|
||||
return rv;
|
||||
|
@ -97,10 +223,10 @@ namespace MonoTouch.Tuner {
|
|||
// * https://bugzilla.xamarin.com/show_bug.cgi?id=15465
|
||||
if (IsCIFilter (type)) {
|
||||
isdirectbinding_value [type] = null;
|
||||
var base_type = type.BaseType.Resolve ();
|
||||
var base_type = Context.Resolve (type.BaseType);
|
||||
while (base_type != null && IsNSObject (base_type)) {
|
||||
isdirectbinding_value [base_type] = null;
|
||||
base_type = base_type.BaseType.Resolve ();
|
||||
base_type = Context.Resolve (base_type.BaseType);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -111,11 +237,11 @@ namespace MonoTouch.Tuner {
|
|||
isdirectbinding_value [type] = false;
|
||||
|
||||
// We must clear IsDirectBinding for any wrapper superclasses.
|
||||
var base_type = type.BaseType.Resolve ();
|
||||
var base_type = Context.Resolve (type.BaseType);
|
||||
while (base_type != null && IsNSObject (base_type)) {
|
||||
if (IsWrapperType (base_type))
|
||||
isdirectbinding_value [base_type] = null;
|
||||
base_type = base_type.BaseType.Resolve ();
|
||||
base_type = Context.Resolve (base_type.BaseType);
|
||||
}
|
||||
} else {
|
||||
isdirectbinding_value [type] = true; // Let's try 'true' first, any derived non-wrapper classes will clear it if needed
|
||||
|
|
|
@ -85,7 +85,6 @@ namespace Xamarin.Linker.Steps {
|
|||
continue;
|
||||
|
||||
// not optimal if "Link all" is used as the override might be removed later
|
||||
// this may miss some overrides with the .NET6 linker (https://github.com/xamarin/xamarin-macios/issues/11449)
|
||||
if (!IsOverridenInUserCode (method))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Linker;
|
||||
|
||||
using Mono.Tuner;
|
||||
|
||||
|
@ -21,5 +22,13 @@ namespace MonoTouch.Tuner {
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extension method to avoid conditional code for files shared between
|
||||
// .NET linker and Legacy (where LinkContext doesn't implement IMetadataResolver).
|
||||
// This doesn't actually use the LinkContext.
|
||||
public static TypeDefinition Resolve (this LinkContext context, TypeReference type)
|
||||
{
|
||||
return type.Resolve ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ namespace Xamarin.Linker.Steps
|
|||
}
|
||||
}
|
||||
|
||||
public ListExportedSymbols () : this (null)
|
||||
{
|
||||
}
|
||||
|
||||
internal ListExportedSymbols (PInvokeWrapperGenerator state, bool skip_sdk_assemblies = false)
|
||||
{
|
||||
this.state = state;
|
||||
|
|
|
@ -84,7 +84,13 @@ namespace Xamarin.Linker {
|
|||
const string INativeObject = Namespaces.ObjCRuntime + ".INativeObject";
|
||||
public static bool IsNSObject (this TypeReference type, DerivedLinkContext link_context)
|
||||
{
|
||||
return type.Resolve ().IsNSObject (link_context);
|
||||
return
|
||||
#if NET
|
||||
link_context.LinkerConfiguration.Context.Resolve (type)
|
||||
#else
|
||||
type.Resolve ()
|
||||
#endif
|
||||
.IsNSObject (link_context);
|
||||
}
|
||||
|
||||
// warning: *Is* means does 'type' inherits from MonoTouch.Foundation.NSObject ?
|
||||
|
@ -93,7 +99,11 @@ namespace Xamarin.Linker {
|
|||
if (link_context?.CachedIsNSObject != null)
|
||||
return link_context.CachedIsNSObject.Contains (type);
|
||||
|
||||
return type.Inherits (Namespaces.Foundation, "NSObject");
|
||||
return type.Inherits (Namespaces.Foundation, "NSObject"
|
||||
#if NET
|
||||
, link_context.LinkerConfiguration.Context
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsNativeObject (this TypeDefinition type)
|
||||
|
|
Загрузка…
Ссылка в новой задаче