From 19cb058da6c8d5de79fcfd754206eed535571232 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 8 Sep 2026 18:44:31 +0200 Subject: [PATCH 1/7] [CoreCLR] Avoid optimistic ARM64 instructions in ReadyToRun Default ARM64 Android ReadyToRun to conservative instruction selection. Crossgen2's optimistic RCPC2 code is rejected on CPUs without RCPC2, forcing otherwise precompiled startup methods through Tier 0 JIT. Resolve the default after package imports and before R2R preparation. Preserve explicit normal/composite instruction-set arguments and leave other architectures, Mono, NativeAOT, and runtime tiering unchanged. Add policy coverage and document the override behavior. Fixed-profile untraced sample startup improved about 10% on Samsung A16; S23 results do not establish sub-percent non-regression. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../building-apps/build-properties.md | 11 +++++ .../Microsoft.Android.Sdk.CoreCLR.targets | 11 +++++ .../Xamarin.Android.Build.Tests/BuildTest2.cs | 44 +++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/Documentation/docs-mobile/building-apps/build-properties.md b/Documentation/docs-mobile/building-apps/build-properties.md index 634d78840db..dc863a24113 100644 --- a/Documentation/docs-mobile/building-apps/build-properties.md +++ b/Documentation/docs-mobile/building-apps/build-properties.md @@ -1903,6 +1903,17 @@ ReadyToRun compilation is composite by default. See [`$(MauiEnableFullReadyToRun)`](#mauienablefullreadytorun) to opt in to full ReadyToRun. +On ARM64, .NET for Android defaults crossgen2 to +`--instruction-set:-optimistic`. This avoids generating precompiled code +that requires optional CPU instructions and would fall back to JIT +compilation on devices without those instructions. It does not disable +hardware-specific optimizations in the JIT or tiered compilation. + +An explicit `--instruction-set` option in +`$(PublishReadyToRunCrossgen2ExtraArgs)` overrides this default. +For composite compilation, an instruction-set option in +`$(PublishReadyToRunCrossgen2CompositeExtraArgs)` is also respected. + For more information, see [Runtimes and compilation in .NET MAUI][maui-runtimes-compilation]. diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets index 9d687057a26..397a5729368 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets @@ -25,6 +25,17 @@ This file contains the CoreCLR-specific MSBuild logic for .NET for Android. true + + + + $(PublishReadyToRunCrossgen2ExtraArgs);--instruction-set:-optimistic + + + $""" + + + {extraArgs} + {compositeArgs} + + + + + + + """, + }); + using var builder = CreateApkBuilder (); + builder.Target = "CheckReadyToRunArguments"; + Assert.IsTrue (builder.Build (proj), "ReadyToRun arguments should preserve explicit instruction-set choices and other flags."); + } + [Test] public void AndroidEnableMarshalMethodsWithReadyToRunFailsBuild () { From 472af4378a0f0b4bfca3884d4c73a5da51625203 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 8 Sep 2026 20:09:23 +0200 Subject: [PATCH 2/7] [CoreCLR] Clarify explicit ReadyToRun ISA override scope Preserve build-wide opt-out for composite-only ISA overrides: the SDK concatenates both argument lists, and crossgen2 rejects duplicate instruction-set options. Document how to apply a policy to composite exclusions via the common arguments and include exclusions in the policy regression cases. Dispose the ReadyToRun application test builder as requested in review. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../docs-mobile/building-apps/build-properties.md | 15 +++++++++++++-- .../Xamarin.Android.Build.Tests/BuildTest2.cs | 6 +++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Documentation/docs-mobile/building-apps/build-properties.md b/Documentation/docs-mobile/building-apps/build-properties.md index dc863a24113..82130dc3141 100644 --- a/Documentation/docs-mobile/building-apps/build-properties.md +++ b/Documentation/docs-mobile/building-apps/build-properties.md @@ -1911,8 +1911,19 @@ hardware-specific optimizations in the JIT or tiered compilation. An explicit `--instruction-set` option in `$(PublishReadyToRunCrossgen2ExtraArgs)` overrides this default. -For composite compilation, an instruction-set option in -`$(PublishReadyToRunCrossgen2CompositeExtraArgs)` is also respected. +For composite builds, an instruction-set option in +`$(PublishReadyToRunCrossgen2CompositeExtraArgs)` also opts the entire +build out of this default, including assemblies in +`@(PublishReadyToRunCompositeExclusions)`. The .NET SDK concatenates the +normal and composite arguments for the composite image, and crossgen2 +does not accept multiple `--instruction-set` options. + +To apply an instruction-set policy to both the composite image and +excluded assemblies, set it in +`$(PublishReadyToRunCrossgen2ExtraArgs)`, not in the composite-only +arguments. For example, `--instruction-set:-optimistic` in the normal +arguments keeps both conservative. Do not specify the option in both +argument properties. For more information, see [Runtimes and compilation in .NET MAUI][maui-runtimes-compilation]. diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index c2dd7e0315a..1ac8597d6dc 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -75,7 +75,7 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value proj.SetProperty ("AndroidEnableAssemblyCompression", "false"); proj.SetProperty ("PublishReadyToRunComposite", isComposite.ToString ()); - var b = CreateApkBuilder (); + using var b = CreateApkBuilder (); Assert.IsTrue (b.Build (proj), "Build should have succeeded."); if (rid == "android-arm64") { StringAssertEx.Contains ("--instruction-set:-optimistic", b.LastBuildOutput); @@ -111,6 +111,7 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value [TestCase ("android-arm64", true, true, "--partial;--instruction-set:armv8-a", "", "--partial;--instruction-set:armv8-a")] [TestCase ("android-arm64", true, true, "--instruction-set armv8-a", "", "--instruction-set armv8-a")] [TestCase ("android-arm64", true, true, "--instruction-set:-optimistic", "", "--instruction-set:-optimistic")] + [TestCase ("android-arm64", true, true, "", "--instruction-set:-optimistic", "")] [TestCase ("android-arm64", true, true, "--partial", "--instruction-set:armv8-a", "--partial")] [TestCase ("android-arm64", true, false, "--partial", "--instruction-set:armv8-a", "--partial;--instruction-set:-optimistic")] [TestCase ("android-arm64", false, false, "--map", "", "--map")] @@ -131,6 +132,9 @@ public void ReadyToRunInstructionSet (string rid, bool readyToRun, bool composit {extraArgs} {compositeArgs} + + + From 616de6a21de80710220e2cc040918c69c159c8a6 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 8 Sep 2026 21:26:26 +0200 Subject: [PATCH 3/7] [CoreCLR] Apply conservative ReadyToRun policy across architectures Remove the ARM64-only guard and simplify explicit ISA override detection. Add the private _AndroidUseConservativeReadyToRunInstructionSet=false escape hatch without disabling R2R or changing existing compiler arguments. Extend argument-policy coverage to x64 and ARM, composite/non-composite overrides and the private escape hatch. Keep measured startup claims scoped to the ARM64 phones. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../building-apps/build-properties.md | 7 ++-- .../Microsoft.Android.Sdk.CoreCLR.targets | 6 ++-- .../Xamarin.Android.Build.Tests/BuildTest2.cs | 35 ++++++++++--------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Documentation/docs-mobile/building-apps/build-properties.md b/Documentation/docs-mobile/building-apps/build-properties.md index 82130dc3141..e3789fcee27 100644 --- a/Documentation/docs-mobile/building-apps/build-properties.md +++ b/Documentation/docs-mobile/building-apps/build-properties.md @@ -1903,7 +1903,7 @@ ReadyToRun compilation is composite by default. See [`$(MauiEnableFullReadyToRun)`](#mauienablefullreadytorun) to opt in to full ReadyToRun. -On ARM64, .NET for Android defaults crossgen2 to +.NET for Android defaults crossgen2 to `--instruction-set:-optimistic`. This avoids generating precompiled code that requires optional CPU instructions and would fall back to JIT compilation on devices without those instructions. It does not disable @@ -1911,12 +1911,13 @@ hardware-specific optimizations in the JIT or tiered compilation. An explicit `--instruction-set` option in `$(PublishReadyToRunCrossgen2ExtraArgs)` overrides this default. -For composite builds, an instruction-set option in +An instruction-set option in `$(PublishReadyToRunCrossgen2CompositeExtraArgs)` also opts the entire build out of this default, including assemblies in `@(PublishReadyToRunCompositeExclusions)`. The .NET SDK concatenates the normal and composite arguments for the composite image, and crossgen2 -does not accept multiple `--instruction-set` options. +does not accept multiple `--instruction-set` options. The opt-out applies +even when `$(PublishReadyToRunComposite)` is `false`. To apply an instruction-set policy to both the composite image and excluded assemblies, set it in diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets index 397a5729368..b0a32a17653 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets @@ -25,13 +25,13 @@ This file contains the CoreCLR-specific MSBuild logic for .NET for Android. true - - + Condition=" '$(AndroidApplication)' == 'true' and '$(PublishReadyToRun)' == 'true' and '$(_AndroidUseConservativeReadyToRunInstructionSet)' != 'false' "> + $(PublishReadyToRunCrossgen2ExtraArgs);--instruction-set:-optimistic diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 1ac8597d6dc..288b9126b21 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -77,11 +77,7 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value using var b = CreateApkBuilder (); Assert.IsTrue (b.Build (proj), "Build should have succeeded."); - if (rid == "android-arm64") { - StringAssertEx.Contains ("--instruction-set:-optimistic", b.LastBuildOutput); - } else { - StringAssertEx.DoesNotContain ("--instruction-set:-optimistic", b.LastBuildOutput); - } + StringAssertEx.Contains ("--instruction-set:-optimistic", b.LastBuildOutput); var assemblyName = proj.ProjectName; var apk = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath, rid, $"{proj.PackageName}-Signed.apk"); @@ -106,17 +102,23 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value StringAssert.Contains ("@uncompressed_assemblies_data_buffer = dso_local local_unnamed_addr global [0 x i8] zeroinitializer, align 1", compressedAssembliesSourceText); } - [TestCase ("android-arm64", true, true, "", "", ";--instruction-set:-optimistic")] - [TestCase ("android-arm64", true, false, "--partial;--map", "", "--partial;--map;--instruction-set:-optimistic")] - [TestCase ("android-arm64", true, true, "--partial;--instruction-set:armv8-a", "", "--partial;--instruction-set:armv8-a")] - [TestCase ("android-arm64", true, true, "--instruction-set armv8-a", "", "--instruction-set armv8-a")] - [TestCase ("android-arm64", true, true, "--instruction-set:-optimistic", "", "--instruction-set:-optimistic")] - [TestCase ("android-arm64", true, true, "", "--instruction-set:-optimistic", "")] - [TestCase ("android-arm64", true, true, "--partial", "--instruction-set:armv8-a", "--partial")] - [TestCase ("android-arm64", true, false, "--partial", "--instruction-set:armv8-a", "--partial;--instruction-set:-optimistic")] - [TestCase ("android-arm64", false, false, "--map", "", "--map")] - [TestCase ("android-x64", true, true, "--partial", "", "--partial")] - public void ReadyToRunInstructionSet (string rid, bool readyToRun, bool composite, string extraArgs, string compositeArgs, string expected) + [TestCase ("android-arm64", true, true, "", "", ";--instruction-set:-optimistic", "")] + [TestCase ("android-arm64", true, false, "--partial;--map", "", "--partial;--map;--instruction-set:-optimistic", "")] + [TestCase ("android-arm64", true, true, "--partial;--instruction-set:armv8-a", "", "--partial;--instruction-set:armv8-a", "")] + [TestCase ("android-arm64", true, true, "--instruction-set armv8-a", "", "--instruction-set armv8-a", "")] + [TestCase ("android-arm64", true, true, "--instruction-set:-optimistic", "", "--instruction-set:-optimistic", "")] + [TestCase ("android-arm64", true, true, "", "--instruction-set:-optimistic", "", "")] + [TestCase ("android-arm64", true, true, "--partial", "--instruction-set:armv8-a", "--partial", "")] + [TestCase ("android-arm64", true, false, "--partial", "--instruction-set:armv8-a", "--partial", "")] + [TestCase ("android-arm64", false, false, "--map", "", "--map", "")] + [TestCase ("android-x64", true, true, "--partial", "", "--partial;--instruction-set:-optimistic", "")] + [TestCase ("android-x64", true, false, "", "", ";--instruction-set:-optimistic", "")] + [TestCase ("android-x64", true, true, "--instruction-set:x86-64", "", "--instruction-set:x86-64", "")] + [TestCase ("android-arm", true, true, "", "", ";--instruction-set:-optimistic", "")] + [TestCase ("android-arm64", true, true, "--map", "", "--map", "false")] + [TestCase ("android-arm64", true, true, "--map", "", "--map;--instruction-set:-optimistic", "true")] + public void ReadyToRunInstructionSet (string rid, bool readyToRun, bool composite, string extraArgs, string compositeArgs, + string expected, string conservativeInstructionSet) { var proj = new XamarinAndroidApplicationProject { IsRelease = true, @@ -125,6 +127,7 @@ public void ReadyToRunInstructionSet (string rid, bool readyToRun, bool composit proj.SetProperty ("RuntimeIdentifier", rid); proj.SetProperty ("PublishReadyToRun", readyToRun.ToString ()); proj.SetProperty ("PublishReadyToRunComposite", composite.ToString ()); + proj.SetProperty ("_AndroidUseConservativeReadyToRunInstructionSet", conservativeInstructionSet); proj.Imports.Add (new Import ("CrossgenArguments.targets") { TextContent = () => $""" From 4d8a8a7e08987ef5e2f17b0abbf36c32eec1b740 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 9 Sep 2026 15:04:57 +0200 Subject: [PATCH 4/7] [CoreCLR] Use an explicit ARM64 ReadyToRun ISA baseline Keep the tested ARM64 instruction set except RCPC2, without encoding an RCPC2-absence assertion. Preserve other architectures, explicit overrides and the private opt-out, and document the higher baseline requirements. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../building-apps/build-properties.md | 21 ++++++++++++++----- .../Microsoft.Android.Sdk.CoreCLR.targets | 7 ++++--- .../Xamarin.Android.Build.Tests/BuildTest2.cs | 14 +++++++++---- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/Documentation/docs-mobile/building-apps/build-properties.md b/Documentation/docs-mobile/building-apps/build-properties.md index e3789fcee27..4f12aca2d42 100644 --- a/Documentation/docs-mobile/building-apps/build-properties.md +++ b/Documentation/docs-mobile/building-apps/build-properties.md @@ -1903,11 +1903,22 @@ ReadyToRun compilation is composite by default. See [`$(MauiEnableFullReadyToRun)`](#mauienablefullreadytorun) to opt in to full ReadyToRun. -.NET for Android defaults crossgen2 to -`--instruction-set:-optimistic`. This avoids generating precompiled code -that requires optional CPU instructions and would fall back to JIT -compilation on devices without those instructions. It does not disable -hardware-specific optimizations in the JIT or tiered compilation. +For ARM64, .NET for Android defaults crossgen2 to: + +```text +--instruction-set:-optimistic,aes,crc,dotprod,lse,rcpc,rdma,sha1,sha2 +``` + +This disables automatic optimistic instruction-set additions and explicitly +enables the listed features, excluding RCPC2 without requiring RCPC2 to be +absent. The listed features become baseline requirements for the precompiled +image, rather than optional optimistic features. Devices without a required +feature can reject the image's ReadyToRun code and fall back to JIT compilation. + +Other CPU architectures default to `--instruction-set:-optimistic`, which +disables automatic optimistic instruction-set additions while retaining the +normal baseline requirements. Neither policy disables hardware-specific +optimizations in the JIT or tiered compilation. An explicit `--instruction-set` option in `$(PublishReadyToRunCrossgen2ExtraArgs)` overrides this default. diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets index b0a32a17653..96367bf2447 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets @@ -25,14 +25,15 @@ This file contains the CoreCLR-specific MSBuild logic for .NET for Android. true - - $(PublishReadyToRunCrossgen2ExtraArgs);--instruction-set:-optimistic + $(PublishReadyToRunCrossgen2ExtraArgs);--instruction-set:-optimistic,aes,crc,dotprod,lse,rcpc,rdma,sha1,sha2 + $(PublishReadyToRunCrossgen2ExtraArgs);--instruction-set:-optimistic diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 288b9126b21..7c694b00515 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -24,6 +24,8 @@ namespace Xamarin.Android.Build.Tests [Parallelizable (ParallelScope.Children)] public partial class BuildTest2 : BaseTest { + const string Arm64ReadyToRunInstructionSet = "--instruction-set:-optimistic,aes,crc,dotprod,lse,rcpc,rdma,sha1,sha2"; + static object [] MarshalMethodsDefaultStatusSource = new object [] { new object[] { /* isRelease */ true, @@ -77,7 +79,8 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value using var b = CreateApkBuilder (); Assert.IsTrue (b.Build (proj), "Build should have succeeded."); - StringAssertEx.Contains ("--instruction-set:-optimistic", b.LastBuildOutput); + var expectedInstructionSet = rid == "android-arm64" ? Arm64ReadyToRunInstructionSet : "--instruction-set:-optimistic"; + StringAssertEx.Contains (expectedInstructionSet, b.LastBuildOutput); var assemblyName = proj.ProjectName; var apk = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath, rid, $"{proj.PackageName}-Signed.apk"); @@ -102,12 +105,14 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value StringAssert.Contains ("@uncompressed_assemblies_data_buffer = dso_local local_unnamed_addr global [0 x i8] zeroinitializer, align 1", compressedAssembliesSourceText); } - [TestCase ("android-arm64", true, true, "", "", ";--instruction-set:-optimistic", "")] - [TestCase ("android-arm64", true, false, "--partial;--map", "", "--partial;--map;--instruction-set:-optimistic", "")] + [TestCase ("android-arm64", true, true, "", "", ";" + Arm64ReadyToRunInstructionSet, "")] + [TestCase ("android-arm64", true, false, "--partial;--map", "", "--partial;--map;" + Arm64ReadyToRunInstructionSet, "")] [TestCase ("android-arm64", true, true, "--partial;--instruction-set:armv8-a", "", "--partial;--instruction-set:armv8-a", "")] [TestCase ("android-arm64", true, true, "--instruction-set armv8-a", "", "--instruction-set armv8-a", "")] [TestCase ("android-arm64", true, true, "--instruction-set:-optimistic", "", "--instruction-set:-optimistic", "")] + [TestCase ("android-arm64", true, true, Arm64ReadyToRunInstructionSet, "", Arm64ReadyToRunInstructionSet, "")] [TestCase ("android-arm64", true, true, "", "--instruction-set:-optimistic", "", "")] + [TestCase ("android-arm64", true, false, "", Arm64ReadyToRunInstructionSet, "", "")] [TestCase ("android-arm64", true, true, "--partial", "--instruction-set:armv8-a", "--partial", "")] [TestCase ("android-arm64", true, false, "--partial", "--instruction-set:armv8-a", "--partial", "")] [TestCase ("android-arm64", false, false, "--map", "", "--map", "")] @@ -115,8 +120,9 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value [TestCase ("android-x64", true, false, "", "", ";--instruction-set:-optimistic", "")] [TestCase ("android-x64", true, true, "--instruction-set:x86-64", "", "--instruction-set:x86-64", "")] [TestCase ("android-arm", true, true, "", "", ";--instruction-set:-optimistic", "")] + [TestCase ("android-x86", true, true, "", "", ";--instruction-set:-optimistic", "")] [TestCase ("android-arm64", true, true, "--map", "", "--map", "false")] - [TestCase ("android-arm64", true, true, "--map", "", "--map;--instruction-set:-optimistic", "true")] + [TestCase ("android-arm64", true, true, "--map", "", "--map;" + Arm64ReadyToRunInstructionSet, "true")] public void ReadyToRunInstructionSet (string rid, bool readyToRun, bool composite, string extraArgs, string compositeArgs, string expected, string conservativeInstructionSet) { From 2729fea1216163b90d7b008fc32b320a64213a30 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 9 Sep 2026 22:37:51 +0200 Subject: [PATCH 5/7] [tests] Restrict R2R ISA cases to supported CoreCLR RIDs Remove the android-x86 and android-arm cases from the CoreCLR argument-policy test. Keep the matrix on android-arm64 and android-x64, and clarify the documented x64 default. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- Documentation/docs-mobile/building-apps/build-properties.md | 2 +- .../Tests/Xamarin.Android.Build.Tests/BuildTest2.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/docs-mobile/building-apps/build-properties.md b/Documentation/docs-mobile/building-apps/build-properties.md index 4f12aca2d42..720a7744d28 100644 --- a/Documentation/docs-mobile/building-apps/build-properties.md +++ b/Documentation/docs-mobile/building-apps/build-properties.md @@ -1915,7 +1915,7 @@ absent. The listed features become baseline requirements for the precompiled image, rather than optional optimistic features. Devices without a required feature can reject the image's ReadyToRun code and fall back to JIT compilation. -Other CPU architectures default to `--instruction-set:-optimistic`, which +x64 defaults to `--instruction-set:-optimistic`, which disables automatic optimistic instruction-set additions while retaining the normal baseline requirements. Neither policy disables hardware-specific optimizations in the JIT or tiered compilation. diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 7c694b00515..12fe1bfd7e4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -119,8 +119,6 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value [TestCase ("android-x64", true, true, "--partial", "", "--partial;--instruction-set:-optimistic", "")] [TestCase ("android-x64", true, false, "", "", ";--instruction-set:-optimistic", "")] [TestCase ("android-x64", true, true, "--instruction-set:x86-64", "", "--instruction-set:x86-64", "")] - [TestCase ("android-arm", true, true, "", "", ";--instruction-set:-optimistic", "")] - [TestCase ("android-x86", true, true, "", "", ";--instruction-set:-optimistic", "")] [TestCase ("android-arm64", true, true, "--map", "", "--map", "false")] [TestCase ("android-arm64", true, true, "--map", "", "--map;" + Arm64ReadyToRunInstructionSet, "true")] public void ReadyToRunInstructionSet (string rid, bool readyToRun, bool composite, string extraArgs, string compositeArgs, From 338bfdb1afb2d246521c79ba69b43c007b36c670 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 9 Sep 2026 22:42:31 +0200 Subject: [PATCH 6/7] [tests] Preserve supported ARM ReadyToRun coverage Use the checked-in NDK support metadata: CoreCLR remains enabled for ARM, ARM64 and x64; only x86 is disabled. Restore the ARM case and retain the existing architecture-neutral documentation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- Documentation/docs-mobile/building-apps/build-properties.md | 2 +- .../Tests/Xamarin.Android.Build.Tests/BuildTest2.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/docs-mobile/building-apps/build-properties.md b/Documentation/docs-mobile/building-apps/build-properties.md index 720a7744d28..4f12aca2d42 100644 --- a/Documentation/docs-mobile/building-apps/build-properties.md +++ b/Documentation/docs-mobile/building-apps/build-properties.md @@ -1915,7 +1915,7 @@ absent. The listed features become baseline requirements for the precompiled image, rather than optional optimistic features. Devices without a required feature can reject the image's ReadyToRun code and fall back to JIT compilation. -x64 defaults to `--instruction-set:-optimistic`, which +Other CPU architectures default to `--instruction-set:-optimistic`, which disables automatic optimistic instruction-set additions while retaining the normal baseline requirements. Neither policy disables hardware-specific optimizations in the JIT or tiered compilation. diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 12fe1bfd7e4..8e857ee0a00 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -119,6 +119,7 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value [TestCase ("android-x64", true, true, "--partial", "", "--partial;--instruction-set:-optimistic", "")] [TestCase ("android-x64", true, false, "", "", ";--instruction-set:-optimistic", "")] [TestCase ("android-x64", true, true, "--instruction-set:x86-64", "", "--instruction-set:x86-64", "")] + [TestCase ("android-arm", true, true, "", "", ";--instruction-set:-optimistic", "")] [TestCase ("android-arm64", true, true, "--map", "", "--map", "false")] [TestCase ("android-arm64", true, true, "--map", "", "--map;" + Arm64ReadyToRunInstructionSet, "true")] public void ReadyToRunInstructionSet (string rid, bool readyToRun, bool composite, string extraArgs, string compositeArgs, From df9fb7d7762cab500541c395f8d08dfcdc653ae1 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 9 Sep 2026 22:59:01 +0200 Subject: [PATCH 7/7] [CoreCLR] Rename optimistic ISA opt-out and simplify coverage Use _AndroidUseOptimisticReadyToRunInstructionSet=true to skip the default ISA override. Remove the dedicated ReadyToRunInstructionSet test while retaining the existing ReadyToRun integration assertion. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Microsoft.Android.Sdk.CoreCLR.targets | 2 +- .../Xamarin.Android.Build.Tests/BuildTest2.cs | 52 ------------------- 2 files changed, 1 insertion(+), 53 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets index 96367bf2447..0e1dc763530 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets @@ -30,7 +30,7 @@ This file contains the CoreCLR-specific MSBuild logic for .NET for Android. Resolve this after project/package imports have supplied their crossgen2 arguments. --> + Condition=" '$(AndroidApplication)' == 'true' and '$(PublishReadyToRun)' == 'true' and '$(_AndroidUseOptimisticReadyToRunInstructionSet)' != 'true' "> $(PublishReadyToRunCrossgen2ExtraArgs);--instruction-set:-optimistic,aes,crc,dotprod,lse,rcpc,rdma,sha1,sha2 $(PublishReadyToRunCrossgen2ExtraArgs);--instruction-set:-optimistic diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 8e857ee0a00..8059ba1d0fd 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -105,58 +105,6 @@ public void BasicApplicationPublishReadyToRun ([Values] bool isComposite, [Value StringAssert.Contains ("@uncompressed_assemblies_data_buffer = dso_local local_unnamed_addr global [0 x i8] zeroinitializer, align 1", compressedAssembliesSourceText); } - [TestCase ("android-arm64", true, true, "", "", ";" + Arm64ReadyToRunInstructionSet, "")] - [TestCase ("android-arm64", true, false, "--partial;--map", "", "--partial;--map;" + Arm64ReadyToRunInstructionSet, "")] - [TestCase ("android-arm64", true, true, "--partial;--instruction-set:armv8-a", "", "--partial;--instruction-set:armv8-a", "")] - [TestCase ("android-arm64", true, true, "--instruction-set armv8-a", "", "--instruction-set armv8-a", "")] - [TestCase ("android-arm64", true, true, "--instruction-set:-optimistic", "", "--instruction-set:-optimistic", "")] - [TestCase ("android-arm64", true, true, Arm64ReadyToRunInstructionSet, "", Arm64ReadyToRunInstructionSet, "")] - [TestCase ("android-arm64", true, true, "", "--instruction-set:-optimistic", "", "")] - [TestCase ("android-arm64", true, false, "", Arm64ReadyToRunInstructionSet, "", "")] - [TestCase ("android-arm64", true, true, "--partial", "--instruction-set:armv8-a", "--partial", "")] - [TestCase ("android-arm64", true, false, "--partial", "--instruction-set:armv8-a", "--partial", "")] - [TestCase ("android-arm64", false, false, "--map", "", "--map", "")] - [TestCase ("android-x64", true, true, "--partial", "", "--partial;--instruction-set:-optimistic", "")] - [TestCase ("android-x64", true, false, "", "", ";--instruction-set:-optimistic", "")] - [TestCase ("android-x64", true, true, "--instruction-set:x86-64", "", "--instruction-set:x86-64", "")] - [TestCase ("android-arm", true, true, "", "", ";--instruction-set:-optimistic", "")] - [TestCase ("android-arm64", true, true, "--map", "", "--map", "false")] - [TestCase ("android-arm64", true, true, "--map", "", "--map;" + Arm64ReadyToRunInstructionSet, "true")] - public void ReadyToRunInstructionSet (string rid, bool readyToRun, bool composite, string extraArgs, string compositeArgs, - string expected, string conservativeInstructionSet) - { - var proj = new XamarinAndroidApplicationProject { - IsRelease = true, - }; - proj.SetRuntime (AndroidRuntime.CoreCLR); - proj.SetProperty ("RuntimeIdentifier", rid); - proj.SetProperty ("PublishReadyToRun", readyToRun.ToString ()); - proj.SetProperty ("PublishReadyToRunComposite", composite.ToString ()); - proj.SetProperty ("_AndroidUseConservativeReadyToRunInstructionSet", conservativeInstructionSet); - proj.Imports.Add (new Import ("CrossgenArguments.targets") { - TextContent = () => $""" - - - {extraArgs} - {compositeArgs} - - - - - - - - - - """, - }); - using var builder = CreateApkBuilder (); - builder.Target = "CheckReadyToRunArguments"; - Assert.IsTrue (builder.Build (proj), "ReadyToRun arguments should preserve explicit instruction-set choices and other flags."); - } - [Test] public void AndroidEnableMarshalMethodsWithReadyToRunFailsBuild () {