Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to new linker custom steps API #11374

Merged
merged 10 commits into from
May 12, 2021
Merged

Conversation

sbomer
Copy link
Contributor

@sbomer sbomer commented Apr 28, 2021

@spouliot @rolfbjarne here's a start on the update to the new custom steps API. It's not complete yet, but I'd be happy to get early feedback if you have a chance to look.

The changes so far are intended to turn steps into IMarkHandlers when applicable so that they are triggered by marking:

  • PreserveBlockCodeSubStep is triggered for marked types
  • ApplyPreserveAttribute is triggered for marked assemblies (and scans for attributes/members in them)
    • This means it won't find preserved things in assemblies that are unused. This is the same compromise made in Update to new linker custom steps API dotnet/android#5748.
    • For now I removed the functionality where an assembly-level attribute may point to another attribute type to indicate that it should be treated like "Preserve", since I don't see a good way to make this work without a pre-scan, but we'll need to figure out what to do here.
  • OptimizeGeneratedCodeSubStep is triggered for marked methods
    • I added a cache for checking whether an assembly has optimizable code, since the method processing can be interleaved for methods from different assemblies.
    • It looks like the type hierarchy checks for IsNsObject aren't cached because CoreTypeMapStep isn't part of the pipeline. I will look into changing things to use the type resolution cache that @marek-safar added in Unified handling of Resolve calls dotnet/linker#1979.
  • MarkNSObjects is triggered for marked assemblies (and scans for members in them)
    • Like Preserve, this won't discover members in unused assemblies.
    • I believe the check IsOverriddenInUserCode will miss overrides that are discovered by the linker later during marking. I think it could be fixed by inverting the logic to check whether a user method is an override of an exported method, and preserving it if it is.
  • PreserveSmartEnumConversions is triggered for marked methods, and just marks things (instead of conditionally preserving them like before)

@sbomer sbomer force-pushed the trimmerCustomSteps branch from 7480829 to 3e48452 Compare April 28, 2021 18:49
Copy link
Contributor

@spouliot spouliot left a comment

Choose a reason for hiding this comment

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

Looking good!
Few comments (some might even be fromcopy/paste code)

get {
if (_markHandlers == null) {
var pipeline = typeof (LinkContext).GetProperty ("Pipeline").GetGetMethod ().Invoke (Context, null);
_markHandlers = (List<IMarkHandler>) pipeline.GetType ().GetProperty ("MarkHandlers").GetValue (pipeline);
Copy link
Contributor

Choose a reason for hiding this comment

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

is there any plan to make those API public ?

Copy link
Contributor

Choose a reason for hiding this comment

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

@sbomer why is it needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was just to get something working - I am looking into passing all steps individually as --custom-step args.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SetupStep currently logs the pipeline steps which is one case where making this API public could be useful:

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}");

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to see that in linker together with timing details under verbose mode

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Per discussion with @spouliot and @rolfbjarne the plan is to remove the reflection once dotnet/linker#1314 is fixed, since there's no good workaround for sharing state without it. I also filed dotnet/linker#2013 about the suggestion to output diagnostic info.

Copy link
Contributor

Choose a reason for hiding this comment

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

I had quick look dotnet/linker#1314 won't be probably fixed anytime soon as it needs to introduce complex ALC handling. We could just add generic shared state holder to LinkContext and use that instead.

Copy link
Member

Choose a reason for hiding this comment

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

We could just add generic shared state holder to LinkContext and use that instead.

That won't solve the problem where the custom step assembly has a different identity every time it's loaded (so you can't use custom types when storing state).

tools/dotnet-linker/Steps/ExceptionalMarkHandler.cs Outdated Show resolved Hide resolved
tools/dotnet-linker/Steps/ExceptionalMarkHandler.cs Outdated Show resolved Hide resolved
tools/dotnet-linker/Steps/PreserveBlockCodeHandler.cs Outdated Show resolved Hide resolved
tools/dotnet-linker/Steps/PreserveBlockCodeHandler.cs Outdated Show resolved Hide resolved
Copy link
Member

@rolfbjarne rolfbjarne left a comment

Choose a reason for hiding this comment

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

Looks good so far!

tools/dotnet-linker/ApplyPreserveAttributeBase.cs Outdated Show resolved Hide resolved
tools/dotnet-linker/Steps/ExceptionalMarkHandler.cs Outdated Show resolved Hide resolved
tools/linker/CoreOptimizeGeneratedCode.cs Outdated Show resolved Hide resolved
@@ -18,16 +19,31 @@

namespace Xamarin.Linker {

#if NET
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't want to block this PR but wouldn't be better to adopt this method to net6? Looking at the logic it seems to be a simpler version of dead blocks elimination which linker does automatically. At first look, all the code looks like it can be replaced with few substitutions.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, it might be possible to port it to use substitutions. Our list of things to do is pretty big though, and the current code isn't blocking anything.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also much easier to debug / compare by doing this step-by-step.

Copy link
Contributor

@spouliot spouliot May 6, 2021

Choose a reason for hiding this comment

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

I'm not sure substitutions, as available today, would work here. At least not for IsDirectBinding since the decision to always make it true is based on each individual type (computed in an earlier step) and not on some global state (known before build) given to the linker.

There are other places where substitutions would work (e.g. what remains of RemoveCode). We can start there and compare the results (since it won't be identical).

Copy link
Contributor

Choose a reason for hiding this comment

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

Captured my thoughts on this as I went over the code in #11477

@rolfbjarne
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff

Test results

9 tests failed, 98 tests passed.

Failed tests

  • link all/iOS Unified 64-bits - simulator/Debug [dotnet]: BuildFailure
  • link all/iOS Unified 64-bits - simulator/Release [dotnet]: BuildFailure
  • link all/tvOS - simulator/Debug [dotnet]: BuildFailure
  • link all/tvOS - simulator/Release [dotnet]: BuildFailure
  • link sdk/iOS Unified 64-bits - simulator/Debug [dotnet]: BuildFailure
  • link sdk/iOS Unified 64-bits - simulator/Release [dotnet]: BuildFailure
  • link sdk/tvOS - simulator/Debug [dotnet]: BuildFailure
  • link sdk/tvOS - simulator/Release [dotnet]: BuildFailure
  • DotNet tests: Failed (Execution failed with exit code 1)

Pipeline on Agent XAMBOT-1104.BigSur'
Merge 3e48452 into b4b8ee7

@spouliot
Copy link
Contributor

@sbomer tests are failing with

10:25:14.9458470 10:25:14.945   1:7>ILLink : error IL1012: IL Linker has encountered an unexpected error. Please report the issue at https://github.com/mono/linker/issues [/Users/builder/azdo/_work/1/s/xamarin-macios/tests/xharness/tmp-test-dir/link all31/link all.csproj]
10:25:14.9544980                      Fatal error in IL Linker (TaskId:221)
10:25:14.9634970                      Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'key') (TaskId:221)
10:25:14.9635610                         at System.Runtime.CompilerServices.ConditionalWeakTable`2.TryGetValue(TKey key, TValue& value) in System.Private.CoreLib.dll:token 0x6004846+0x8 (TaskId:221)
10:25:14.9636290                         at Xamarin.Linker.LinkerConfiguration.GetInstance(LinkContext context, Boolean createIfNotFound) in dotnet-linker.dll:token 0x60003e5+0x1 (TaskId:221)
10:25:14.9636620                         at Xamarin.Linker.ExceptionalMarkHandler.get_Configuration() in dotnet-linker.dll:token 0x600041e+0x6 (TaskId:221)
10:25:14.9636900                         at Xamarin.Linker.ExceptionalMarkHandler.get_LinkContext() in dotnet-linker.dll:token 0x600041a+0x0 (TaskId:221)
10:25:14.9637110                         at Xamarin.Linker.OptimizeGeneratedCodeHandler.get_Optimizations() in dotnet-linker.dll:token 0x600044b+0x1 (TaskId:221)
10:25:14.9637510                         at Xamarin.Linker.OptimizeGeneratedCodeHandler.Initialize(LinkContext context, MarkContext markContext) in dotnet-linker.dll:token 0x600044e+0x1 (TaskId:221)
10:25:14.9637710                         at Mono.Linker.Pipeline.InitializeMarkHandlers(LinkContext context, MarkContext markContext) in illink.dll:token 0x600024f+0xf (TaskId:221)
10:25:14.9637870                         at Mono.Linker.Steps.MarkStep.Initialize() in illink.dll:token 0x600036e+0x6 (TaskId:221)
10:25:14.9638270                         at Mono.Linker.Steps.MarkStep.Process(LinkContext context) in illink.dll:token 0x600036d+0x35 (TaskId:221)
10:25:14.9638510                         at Mono.Linker.Pipeline.ProcessStep(LinkContext context, IStep step) in illink.dll:token 0x600024d+0x0 (TaskId:221)
10:25:14.9638700                         at Mono.Linker.Pipeline.Process(LinkContext context) in illink.dll:token 0x600024c+0xf (TaskId:221)
10:25:14.9638910                         at Mono.Linker.Driver.Run(ILogger customLogger) in illink.dll:token 0x60000fa+0x20 (TaskId:221)
10:25:14.9639300                         at Mono.Linker.Driver.Main(String[] args) in illink.dll:token 0x60000f4+0x29 (TaskId:221)

@rolfbjarne
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff

API & Generator diff

API Diff (from PR only) (no change)
Generator Diff (no change)

Test results

36 tests failed, 71 tests passed.

Failed tests

  • monotouch-test/Mac [dotnet]/Debug [dotnet]: BuildFailure
  • monotouch-test/iOS Unified 64-bits - simulator/Debug [dotnet]: BuildFailure
  • monotouch-test/iOS Unified 64-bits - simulator/Debug (LinkSdk) [dotnet]: BuildFailure
  • monotouch-test/iOS Unified 64-bits - simulator/Debug (static registrar) [dotnet]: BuildFailure
  • monotouch-test/iOS Unified 64-bits - simulator/Release (all optimizations) [dotnet]: BuildFailure
  • monotouch-test/tvOS - simulator/Debug [dotnet]: BuildFailure
  • monotouch-test/tvOS - simulator/Debug (LinkSdk) [dotnet]: BuildFailure
  • monotouch-test/tvOS - simulator/Debug (static registrar) [dotnet]: BuildFailure
  • monotouch-test/tvOS - simulator/Release (all optimizations) [dotnet]: BuildFailure
  • link all/Mac Catalyst/Debug: Failed (Tests run: 95 Passed: 91 Inconclusive: 0 Failed: 1 Ignored: 3)
  • link all/iOS Unified 64-bits - simulator/Debug: Failed
  • link all/iOS Unified 64-bits - simulator/Release: Failed
  • link all/iOS Unified 64-bits - simulator/Debug [dotnet]: BuildFailure
  • link all/iOS Unified 64-bits - simulator/Release [dotnet]: BuildFailure
  • link all/tvOS - simulator/Debug: Failed
  • link all/tvOS - simulator/Release: Failed
  • link all/tvOS - simulator/Debug [dotnet]: BuildFailure
  • link all/tvOS - simulator/Release [dotnet]: BuildFailure
  • link sdk/Mac Catalyst/Debug: Failed (Tests run: 135 Passed: 122 Inconclusive: 6 Failed: 1 Ignored: 12)
  • link sdk/iOS Unified 64-bits - simulator/Debug: Failed
  • link sdk/iOS Unified 64-bits - simulator/Release: Failed
  • link sdk/iOS Unified 64-bits - simulator/Debug [dotnet]: BuildFailure
  • link sdk/iOS Unified 64-bits - simulator/Release [dotnet]: BuildFailure
  • link sdk/tvOS - simulator/Debug: Failed
  • link sdk/tvOS - simulator/Release: Failed
  • link sdk/tvOS - simulator/Debug [dotnet]: BuildFailure
  • link sdk/tvOS - simulator/Release [dotnet]: BuildFailure
  • interdependent-binding-projects/iOS Unified 64-bits - simulator/Debug [dotnet]: BuildFailure
  • introspection/iOS Unified 64-bits - simulator/Debug [dotnet]: BuildFailure
  • introspection/tvOS - simulator/Debug [dotnet]: BuildFailure
  • dont link/iOS Unified 64-bits - simulator/Debug [dotnet]: BuildFailure
  • dont link/iOS Unified 64-bits - simulator/Release [dotnet]: BuildFailure
  • dont link/tvOS - simulator/Debug [dotnet]: BuildFailure
  • dont link/tvOS - simulator/Release [dotnet]: BuildFailure
  • MSBuild tests/Integration: Failed (Execution failed with exit code 32)
  • DotNet tests: Failed (Execution failed with exit code 1)

Pipeline on Agent XAMBOT-1100.BigSur'
Merge 5ec5c50 into 8e9f86a

sbomer added 4 commits May 6, 2021 09:02
- Fix indentation
- Add Initialize(LinkContext) to ExceptionalMarkHandler
- Remove unnecessary ifdef
- Use IsSetter/IsGetter
- Use [0] instead of Single()
- Avoid allocating empty collections
@sbomer sbomer force-pushed the trimmerCustomSteps branch from 1ac94cb to 7362b74 Compare May 6, 2021 18:20
@sbomer sbomer marked this pull request as ready for review May 6, 2021 18:21
@spouliot
Copy link
Contributor

spouliot commented May 6, 2021

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ [PR Build] Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff

API & Generator diff

API Diff (from PR only) (no change)
Generator Diff (no change)

Test results

4 tests failed, 103 tests passed.

Failed tests

  • link all/iOS Unified 64-bits - simulator/Debug [dotnet]: Failed
  • link all/iOS Unified 64-bits - simulator/Release [dotnet]: Failed
  • link all/tvOS - simulator/Debug [dotnet]: Failed
  • link all/tvOS - simulator/Release [dotnet]: Failed

Pipeline on Agent XAMBOT-1096.BigSur'
Merge 7362b74 into 5fba609

@spouliot
Copy link
Contributor

spouliot commented May 7, 2021

4 tests failed, 103 tests passed.

@sbomer those are unrelated to your PR and already fixed in HEAD (just rebase to get the fix)

Copy link
Contributor

@spouliot spouliot left a comment

Choose a reason for hiding this comment

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

I tested this (rebased on HEAD) and it does work.

The app size increases a bit - but we were missing stuff (that did not trigger crash in the small sample used to check the minimal app size).

I'll be comparing the app diff but any further work should be based on those changes anyway so I don't see any reason not to merge this and continue work on different PR.

detection code.

This solve the issue that `ILLink` does a similar job _before_ we have
the chance to disable the dynamic registrar.
Copy link
Contributor

@spouliot spouliot left a comment

Choose a reason for hiding this comment

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

back on track :)

@rolfbjarne
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ [PR Build] Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff

API & Generator diff

API Diff (from PR only) (no change)
Generator Diff (no change)

Test results

6 tests failed, 101 tests passed.

Failed tests

  • link all/iOS Unified 64-bits - simulator/Debug [dotnet]: Failed
  • link all/iOS Unified 64-bits - simulator/Release [dotnet]: Failed
  • link all/tvOS - simulator/Debug [dotnet]: Failed
  • link all/tvOS - simulator/Release [dotnet]: Failed
  • monotouch-test/iOS Unified 64-bits - simulator/Release (all optimizations): Failed
  • monotouch-test/tvOS - simulator/Release (all optimizations): Failed

Pipeline on Agent XAMBOT-1104.BigSur'
Merge 224c3d4 into 4aa8d9a

@spouliot spouliot added do-not-merge Do not merge this pull request run-all-tests Run all our tests. skip-device-tests Skip device tests labels May 10, 2021
@spouliot
Copy link
Contributor

4 tests failed, 103 tests passed.

@sbomer those are unrelated to your PR and already fixed in HEAD (just rebase to get the fix)

I was wrong (same suites but different reasons or I opened the wrong log file).

The failures are related to the PR and are still present in the last build (along new ones).

[FAIL] PreserveTypeWithCustomAttribute : type 
[FAIL] IntPtrSizeTest : empty body 
Tests run: 83 Passed: 81 Inconclusive: 0 Failed: 2 Ignored: 13

Those might have to be adapted since the dotnet linker behave differently. Lack of custom preserve and how IntPtr.Size is removed.

The two "new" ones happens because the dynamic registrar is removed - but some tests are not happy (meaning something else is missing to make this work properly).

@sbomer
Copy link
Contributor Author

sbomer commented May 10, 2021

Thanks, I'm looking into it.

when it is itself preserved at the assembly-level.

This ignored test is checking that feature so it cannot be enabled
for `NET`

Added to known breaking changes xamarin#8900
@spouliot
Copy link
Contributor

@sbomer I already know what the issues are :)

PreserveTypeWithCustomAttribute is fixed (above commit)

IntPtrSizeTest is because the ILLink's substitution of IntPtr.Size is inferior to what our optimizations are doing. The test fails because there's a lot more IL (all conditions) instead of a single ret instruction in the test code.

The monotouch-test failures is because I only tested dotnet while fixing the dynamic registrar removal (and I broke legacy).

@sbomer
Copy link
Contributor Author

sbomer commented May 10, 2021

Ah, even better. Thanks!

@spouliot
Copy link
Contributor

well I just learned that ilspy uses CTRL (not command) and C for copy... :-(

IntPtrSizeTest fails because the original code

		[CompilerGenerated] // Trigger optimizations
		[Foundation.Export ("alsoRequiredForOptimizations")]
		void Size8Test ()
		{
			// Everything in this method should be optimized away (when building for 64-bits)
			if (IntPtr.Size != 8)
				throw new NUnit.Framework.Internal.NUnitException ("1");
			if (IntPtr.Size == 4)
				throw new NUnit.Framework.Internal.NUnitException ("2");
			if (IntPtr.Size > 8)
				throw new NUnit.Framework.Internal.NUnitException ("3");
			if (IntPtr.Size < 8)
				throw new NUnit.Framework.Internal.NUnitException ("4");
			if (IntPtr.Size >= 9)
				throw new NUnit.Framework.Internal.NUnitException ("5");
			if (IntPtr.Size <= 7)
				throw new NUnit.Framework.Internal.NUnitException ("6");
		}

becomes

[CompilerGenerated]
[Export("alsoRequiredForOptimizations")]
private void Size8Test()
{
	if (IntPtr.Size != 8)
	{
	}
	if (IntPtr.Size == 4)
	{
	}
	if (IntPtr.Size > 8)
	{
	}
	if (IntPtr.Size < 8)
	{
	}
	if (IntPtr.Size >= 9)
	{
	}
	if (IntPtr.Size > 7)
	{
	}
}

instead of

[Export("alsoRequiredForOptimizations")]
private void Size8Test()
{
}

@sbomer
Copy link
Contributor Author

sbomer commented May 10, 2021

ilspy uses CTRL (not command) and C for copy

Good to know :)

I think this is happening because the following is (unintentionally) dead code after my changes:

// This will inline IntPtr.Size to load the corresponding constant value instead
// Verify we're checking the right get_Size call
var mr = ins.Operand as MethodReference;
if (!mr.DeclaringType.Is ("System", "IntPtr"))
return;
// We're fine, inline the get_Size call
ins.OpCode = Arch == 8 ? OpCodes.Ldc_I4_8 : OpCodes.Ldc_I4_4;
ins.Operand = null;

I missed that something needs to set InlineIntPtrSize when the step is triggered for a method. Do we still want to optimize the above into

[Export("alsoRequiredForOptimizations")]
private void Size8Test()
{
}

or is it enough to rely on the linker's built-in constant propagation, which leaves in the IntPtr.Size != 8 checks? I think we could get the full optimizations even with the new custom steps.

@rolfbjarne
Copy link
Member

linker's built-in constant propagation, which leaves in the IntPtr.Size != 8 checks?

I think that's the same issue I filed here: dotnet/linker#1106

@marek-safar
Copy link
Contributor

becomes

That's for now intentional and is removed by AOT/JIT/interpreter compilers so the impact is minimal

@spouliot
Copy link
Contributor

Do we still want to optimize the above into

Yes, the code exists and has never been an issue (only applies to our generated binding code). Even if it has a minimal impact (we can measure later) it's has zero cost, so infinite value ;-)

interpreter

That I did not expect, nice!

@spouliot
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ [PR Build] Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff

API & Generator diff

API Diff (from PR only) (no change)
Generator Diff (no change)

Test results

2 tests failed, 216 tests passed.

Failed tests

  • monotouch-test/iOS Unified 32-bits - simulator/Debug: Failed
  • introspection/watchOS 32-bits - simulator/Debug (watchOS 5.0): Failed

Pipeline on Agent XAMBOT-1104.BigSur'
Merge f48385d into 4b2ee6c

@spouliot
Copy link
Contributor

Right now the net effect of the PR is (dotnet numbers only)

Application Comparer

  • A ./main-dotnet-MySingleView.app/
  • B ./gh11374-dotnet-MySingleView.app/
Directories / Files A B diff %
./_CodeSignature
./
    embedded.mobileprovision 12,391 12,391 0 0.0%
    icudt.dat 1,713,152 1,713,152 0 0.0%
    Info.plist 1,053 1,067 14 1.3%
    MySingleView 7,446,304 7,446,304 0 0.0%
    MySingleView.aotdata.arm64 792 792 0 0.0%
    MySingleView.dll 4,608 4,608 0 0.0%
    PkgInfo 8 8 0 0.0%
    System.Private.CoreLib.aotdata.arm64 670,416 670,416 0 0.0%
    System.Private.CoreLib.dll 782,848 782,848 0 0.0%
    System.Runtime.aotdata.arm64 504 504 0 0.0%
    System.Runtime.dll 5,120 5,120 0 0.0%
    Xamarin.iOS.aotdata.arm64 53,536 53,584 48 0.1%
    Xamarin.iOS.dll 91,136 91,136 0 0.0%
Statistics
Native subtotal 8,171,552 8,171,600 48 0.0%
    Executable 7,446,304 7,446,304 0 0.0%
    AOT data 725,248 725,296 48 0.0%
Managed *.dll/exe 883,712 883,712 0 0.0%
TOTAL 10,787,493 10,787,555 62 0.0%

The order of changes (to the IL) differs so empty branches (and properties) are left around (see decompiled diff). Not enough to be seen (within padding limits) in the .dll [1] but visible (48 bytes) in the .aotdata.arm64 file [2].

[1] which is not a matter since we'll (at some point) do an IL strip like it's done for legacy.
[2] if only related to DynamicRegistrationSupported property (and not the IL) then it should not scale with the size of the linked Xamarin.iOS.dll (91,136 versus 19,704,832 bytes)

--- dotnet-Xamarin.iOS.cs	2021-05-10 22:39:30.000000000 -0400
+++ sbomer-Xamarin.iOS.cs	2021-05-11 09:23:58.000000000 -0400
@@ -483,6 +483,8 @@
 
 		public static Arch Arch;
 
+		public static bool DynamicRegistrationSupported => false;
+
 		[MonoPInvokeCallback(typeof(gc_collect_delegate))]
 		private static void gc_collect(out IntPtr exception_gchandle)
 		{
@@ -1319,6 +1321,9 @@
 			options->Delegates->bridge_is_valuetype = GetFunctionPointer(new bridge_is_valuetype_delegate(bridge_is_valuetype));
 			options->Delegates->bridge_is_delegate = GetFunctionPointer(new bridge_is_delegate_delegate(bridge_is_delegate));
 			options->Delegates->bridge_is_class_of_type = GetFunctionPointer(new bridge_is_class_of_type_delegate(bridge_is_class_of_type));
+			if (!DynamicRegistrationSupported)
+			{
+			}
 		}
 
 		private unsafe static void Initialize(InitializationOptions* options)
@@ -1331,6 +1336,8 @@
 			}
 			if (8 != sizeof(nint))
 			{
+				_ = 8;
+				_ = 8;
 				string text2 = string.Format("Native type size mismatch between Xamarin.iOS.dll and the executing architecture. Xamarin.iOS.dll was built for {0}-bit, while the current process is {1}-bit.", "32", "64");
 				NSLog(text2);
 				throw ErrorHelper.CreateError(8010, text2);
@@ -1344,6 +1351,9 @@
 			intptr_bool_ctor_cache = new Dictionary<Type, ConstructorInfo>(TypeEqualityComparer);
 			lock_obj = new object();
 			NSObjectClass = NSObject.Initialize();
+			if (DynamicRegistrationSupported)
+			{
+			}
 			RegisterDelegates(options);
 			Class.Initialize(options);
 			InitializePlatform(options);
@@ -2911,7 +2921,7 @@
 		[DllImport("__Internal")]
 		private static extern IntPtr xamarin_get_block_descriptor();
 
-		public unsafe void SetupBlockImpl(Delegate trampoline, Delegate userDelegate, bool safe, string signature)
+		private unsafe void SetupBlockImpl(Delegate trampoline, Delegate userDelegate, bool safe, string signature)
 		{
 			isa = NSConcreteStackBlock;
 			invoke = Marshal.GetFunctionPointerForDelegate(trampoline);
@@ -3025,6 +3035,9 @@
 			BlockLiteral block = default(BlockLiteral);
 			if (signature == null)
 			{
+				if (Runtime.DynamicRegistrationSupported)
+				{
+				}
 				throw ErrorHelper.CreateError(8026, "BlockLiteral.GetBlockForDelegate with a null signature is not supported when the dynamic registrar has been linked away (delegate type: " + @delegate.GetType().FullName + ").");
 			}
 			block.SetupBlockImpl((Delegate)value, (Delegate)@delegate, safe: true, signature);
@@ -3070,6 +3083,7 @@
 			if (registrationMap != null)
 			{
 				class_to_type = new Type[registrationMap->map_count];
+				_ = Runtime.DynamicRegistrationSupported;
 			}
 		}
 
@@ -3119,7 +3133,6 @@
 
 		private static IntPtr GetClassHandle(Type type, bool throw_if_failure, out bool is_custom_type)
 		{
-			//Discarded unreachable code: IL_00ea
 			IntPtr value = IntPtr.Zero;
 			if (type.IsByRef || type.IsPointer || type.IsArray)
 			{
@@ -3149,6 +3162,7 @@
 			}
 			if (value == IntPtr.Zero)
 			{
+				_ = Runtime.DynamicRegistrationSupported;
 				if (throw_if_failure)
 				{
 					throw ErrorHelper.CreateError(8026, "Can't register the class " + type.FullName + " when the dynamic registrar has been linked away.");
@@ -3200,9 +3214,13 @@
 				{
 					return type;
 				}
+				_ = Runtime.DynamicRegistrationSupported;
 				intPtr = class_getSuperclass(intPtr);
 			}
 			while (intPtr != IntPtr.Zero);
+			if (Runtime.DynamicRegistrationSupported)
+			{
+			}
 			if (throw_on_error)
 			{
 				throw ErrorHelper.CreateError(8026, "Can't lookup the Objective-C class 0x" + klass.ToString("x") + " (" + Marshal.PtrToStringAuto(class_getName(klass)) + ") when the dynamic registrar has been linked away.");
@@ -3858,15 +3876,16 @@
 		[Export("setTitle:forState:")]
 		public virtual void SetTitle(string title, UIControlState forState)
 		{
-			//Discarded unreachable code: IL_0030
 			UIApplication.EnsureUIThread();
 			IntPtr arg = NSString.CreateNative(title);
 			if (base.IsDirectBinding)
 			{
+				_ = 8;
 				Messaging.void_objc_msgSend_IntPtr_UInt64(base.Handle, Selector.GetHandle("setTitle:forState:"), arg, (ulong)forState);
 			}
 			else
 			{
+				_ = 8;
 				Messaging.void_objc_msgSendSuper_IntPtr_UInt64(base.SuperHandle, Selector.GetHandle("setTitle:forState:"), arg, (ulong)forState);
 			}
 			NSString.ReleaseNative(arg);
@@ -3929,12 +3948,14 @@
 			[Export("bounds")]
 			get
 			{
-				//Discarded unreachable code: IL_0030
+				//Discarded unreachable code: IL_002f
 				UIApplication.EnsureUIThread();
 				if (base.IsDirectBinding)
 				{
+					_ = 8;
 					return Messaging.CGRect_objc_msgSend(base.Handle, Selector.GetHandle("bounds"));
 				}
+				_ = 8;
 				return Messaging.CGRect_objc_msgSendSuper(base.SuperHandle, Selector.GetHandle("bounds"));
 			}
 		}
@@ -3980,11 +4001,13 @@
 			[Export("bounds")]
 			get
 			{
-				//Discarded unreachable code: IL_002b
+				//Discarded unreachable code: IL_002a
 				if (base.IsDirectBinding)
 				{
+					_ = 8;
 					return Messaging.CGRect_objc_msgSend(base.Handle, Selector.GetHandle("bounds"));
 				}
+				_ = 8;
 				return Messaging.CGRect_objc_msgSendSuper(base.SuperHandle, Selector.GetHandle("bounds"));
 			}
 		}
@@ -4626,12 +4649,13 @@
 		[Export("compare:")]
 		public virtual NSComparisonResult Compare(NSString aString)
 		{
-			//Discarded unreachable code: IL_0030
 			IntPtr nonNullHandle = NativeObjectExtensions.GetNonNullHandle(aString, "aString");
 			if (base.IsDirectBinding)
 			{
+				_ = 8;
 				return (NSComparisonResult)Messaging.Int64_objc_msgSend_IntPtr(base.Handle, Selector.GetHandle("compare:"), nonNullHandle);
 			}
+			_ = 8;
 			return (NSComparisonResult)Messaging.Int64_objc_msgSendSuper_IntPtr(base.SuperHandle, Selector.GetHandle("compare:"), nonNullHandle);
 		}
 
@@ -5201,6 +5225,7 @@
 			{
 				return true;
 			}
+			_ = Runtime.DynamicRegistrationSupported;
 			return false;
 		}
 

@spouliot
Copy link
Contributor

monotouch-test/iOS Unified 32-bits - simulator/Debug: Failed

This is new...

[FAIL] TestCallbackPlayAlert : TestCallbackPlayAlert 
[FAIL] TestCallbackPlaySystem : TestCallbackPlaySystem 
[FAIL] EnumValues_22351 : AppleMoveTime could not be created: System.ArgumentNullException: Value cannot be null.
[FAIL] ReturnReleaseTest : System.NullReferenceException : Object reference not set to an instance of an object 
[FAIL] TryCopyCurrentNetworkInfo : Dictionary 
Tests run: 2460 Passed: 2410 Inconclusive: 45 Failed: 5 Ignored: 342

Unlikely to come from this PR (but not impossible) since that project's configuration is not linked. It might be coming from merging main back into the PR. @rolfbjarne any failure ring a bell ? ^ (ReturnReleaseTest in particular)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
not-notes-worthy Ignore for release notes run-all-tests Run all our tests. skip-device-tests Skip device tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants