From 3890e9e64707162380330815b920a81a2649b80f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 17 Mar 2026 12:03:42 +0100 Subject: [PATCH 1/6] Resolve CORINFO_HELP_THROW_* to managed ThrowHelpers in R2R compilation Resolve CORINFO_HELP_THROW_ARGUMENTEXCEPTION, CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, and CORINFO_HELP_THROW_NOT_IMPLEMENTED to managed method entrypoints in Internal.Runtime.CompilerHelpers.ThrowHelpers instead of throwing RequiresRuntimeJitException. This precompiles ~2,970 ARM intrinsic methods in System.Private.CoreLib that previously fell back to the interpreter on iOS/MacCatalyst in full R2R mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 59f6d750c9e74a..4187609b64c31e 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -1276,17 +1276,21 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) id = ReadyToRunHelper.InitInstClass; break; - case CorInfoHelpFunc.CORINFO_HELP_GETSYNCFROMCLASSHANDLE: - case CorInfoHelpFunc.CORINFO_HELP_GETCLASSFROMMETHODPARAM: case CorInfoHelpFunc.CORINFO_HELP_THROW_ARGUMENTEXCEPTION: + return GetThrowHelperMethodEntrypoint("ThrowArgumentException"u8); case CorInfoHelpFunc.CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION: + return GetThrowHelperMethodEntrypoint("ThrowArgumentOutOfRangeException"u8); case CorInfoHelpFunc.CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED: + return GetThrowHelperMethodEntrypoint("ThrowPlatformNotSupportedException"u8); + case CorInfoHelpFunc.CORINFO_HELP_THROW_NOT_IMPLEMENTED: + return GetThrowHelperMethodEntrypoint("ThrowNotImplementedException"u8); + + case CorInfoHelpFunc.CORINFO_HELP_GETSYNCFROMCLASSHANDLE: + case CorInfoHelpFunc.CORINFO_HELP_GETCLASSFROMMETHODPARAM: case CorInfoHelpFunc.CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL: case CorInfoHelpFunc.CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL: case CorInfoHelpFunc.CORINFO_HELP_GETREFANY: case CorInfoHelpFunc.CORINFO_HELP_NEW_MDARR_RARE: - // For Vector256.Create and similar cases - case CorInfoHelpFunc.CORINFO_HELP_THROW_NOT_IMPLEMENTED: // For x86 tailcall where helper is required we need runtime JIT. case CorInfoHelpFunc.CORINFO_HELP_TAILCALL: // DirectOnThreadLocalData helper is used at runtime during R2R fixup resolution, not during R2R compilation @@ -1300,6 +1304,19 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) return _compilation.NodeFactory.GetReadyToRunHelperCell(id); } + private ISymbolNode GetThrowHelperMethodEntrypoint(ReadOnlySpan methodName) + { + MetadataType throwHelpersType = _compilation.TypeSystemContext.SystemModule.GetKnownType( + "Internal.Runtime.CompilerHelpers"u8, "ThrowHelpers"u8); + MethodDesc method = throwHelpersType.GetKnownMethod(methodName, null); + ModuleToken moduleToken = _compilation.NodeFactory.Resolver.GetModuleTokenForMethod(method, allowDynamicallyCreatedReference: true, throwIfNotFound: true); + return _compilation.NodeFactory.MethodEntrypoint( + new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null), + isInstantiatingStub: false, + isPrecodeImportRequired: false, + isJumpableImportRequired: false); + } + private void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) { var method = HandleToObject(ftn); From 40cf24bb48eb3b171c867518ee79537d2c31b6a9 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 18 Mar 2026 16:12:02 +0100 Subject: [PATCH 2/6] Add ReadyToRunHelper IDs for throw helpers instead of method name lookup Replace GetThrowHelperMethodEntrypoint (method-name-based lookup that only works in large version bubble) with proper ReadyToRunHelper IDs (0x28-0x2B) for ThrowArgument, ThrowArgumentOutOfRange, ThrowPlatformNotSupported, and ThrowNotImplemented. This follows the same pattern as existing ThrowNullRef and ThrowDivZero helpers, and resolves the 'Data pointer is outside of loaded image' assert seen in non-large-version-bubble scenarios. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/inc/readytorun.h | 4 +++ src/coreclr/inc/readytorunhelpers.h | 4 +++ .../Internal/Runtime/ReadyToRunConstants.cs | 9 +++---- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 25 ++++++------------- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h index 37dad7c9aa4daf..0f760d66951da0 100644 --- a/src/coreclr/inc/readytorun.h +++ b/src/coreclr/inc/readytorun.h @@ -342,6 +342,10 @@ enum ReadyToRunHelper READYTORUN_HELPER_ThrowNullRef = 0x25, READYTORUN_HELPER_ThrowDivZero = 0x26, READYTORUN_HELPER_ThrowExact = 0x27, + READYTORUN_HELPER_ThrowArgument = 0x28, + READYTORUN_HELPER_ThrowArgumentOutOfRange = 0x29, + READYTORUN_HELPER_ThrowPlatformNotSupported = 0x2A, + READYTORUN_HELPER_ThrowNotImplemented = 0x2B, // Write barriers READYTORUN_HELPER_WriteBarrier = 0x30, diff --git a/src/coreclr/inc/readytorunhelpers.h b/src/coreclr/inc/readytorunhelpers.h index 35ff922e413a6d..5c7f17c6723f58 100644 --- a/src/coreclr/inc/readytorunhelpers.h +++ b/src/coreclr/inc/readytorunhelpers.h @@ -21,6 +21,10 @@ HELPER(READYTORUN_HELPER_FailFast, CORINFO_HELP_FAIL_FAST, HELPER(READYTORUN_HELPER_ThrowNullRef, CORINFO_HELP_THROWNULLREF, OPTIMIZEFORSIZE) HELPER(READYTORUN_HELPER_ThrowDivZero, CORINFO_HELP_THROWDIVZERO, OPTIMIZEFORSIZE) HELPER(READYTORUN_HELPER_ThrowExact, CORINFO_HELP_THROWEXACT, OPTIMIZEFORSIZE) +HELPER(READYTORUN_HELPER_ThrowArgument, CORINFO_HELP_THROW_ARGUMENTEXCEPTION, OPTIMIZEFORSIZE) +HELPER(READYTORUN_HELPER_ThrowArgumentOutOfRange, CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, OPTIMIZEFORSIZE) +HELPER(READYTORUN_HELPER_ThrowPlatformNotSupported, CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, OPTIMIZEFORSIZE) +HELPER(READYTORUN_HELPER_ThrowNotImplemented, CORINFO_HELP_THROW_NOT_IMPLEMENTED, OPTIMIZEFORSIZE) HELPER(READYTORUN_HELPER_WriteBarrier, CORINFO_HELP_ASSIGN_REF, ) HELPER(READYTORUN_HELPER_CheckedWriteBarrier, CORINFO_HELP_CHECKED_ASSIGN_REF, ) diff --git a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs index bb877a077e3b74..63e9d707b7c1f1 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs @@ -234,6 +234,10 @@ public enum ReadyToRunHelper ThrowNullRef = 0x25, ThrowDivZero = 0x26, ThrowExact = 0x27, + ThrowArgument = 0x28, + ThrowArgumentOutOfRange = 0x29, + ThrowPlatformNotSupported = 0x2A, + ThrowNotImplemented = 0x2B, // Write barriers WriteBarrier = 0x30, @@ -372,11 +376,6 @@ public enum ReadyToRunHelper // Marker to be used in asserts. FirstFakeHelper, - ThrowArgumentOutOfRange, - ThrowArgument, - ThrowPlatformNotSupported, - ThrowNotImplemented, - DebugBreak, GetRuntimeType, diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 4187609b64c31e..469126823cdc7b 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -1277,13 +1277,17 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) break; case CorInfoHelpFunc.CORINFO_HELP_THROW_ARGUMENTEXCEPTION: - return GetThrowHelperMethodEntrypoint("ThrowArgumentException"u8); + id = ReadyToRunHelper.ThrowArgument; + break; case CorInfoHelpFunc.CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION: - return GetThrowHelperMethodEntrypoint("ThrowArgumentOutOfRangeException"u8); + id = ReadyToRunHelper.ThrowArgumentOutOfRange; + break; case CorInfoHelpFunc.CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED: - return GetThrowHelperMethodEntrypoint("ThrowPlatformNotSupportedException"u8); + id = ReadyToRunHelper.ThrowPlatformNotSupported; + break; case CorInfoHelpFunc.CORINFO_HELP_THROW_NOT_IMPLEMENTED: - return GetThrowHelperMethodEntrypoint("ThrowNotImplementedException"u8); + id = ReadyToRunHelper.ThrowNotImplemented; + break; case CorInfoHelpFunc.CORINFO_HELP_GETSYNCFROMCLASSHANDLE: case CorInfoHelpFunc.CORINFO_HELP_GETCLASSFROMMETHODPARAM: @@ -1304,19 +1308,6 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) return _compilation.NodeFactory.GetReadyToRunHelperCell(id); } - private ISymbolNode GetThrowHelperMethodEntrypoint(ReadOnlySpan methodName) - { - MetadataType throwHelpersType = _compilation.TypeSystemContext.SystemModule.GetKnownType( - "Internal.Runtime.CompilerHelpers"u8, "ThrowHelpers"u8); - MethodDesc method = throwHelpersType.GetKnownMethod(methodName, null); - ModuleToken moduleToken = _compilation.NodeFactory.Resolver.GetModuleTokenForMethod(method, allowDynamicallyCreatedReference: true, throwIfNotFound: true); - return _compilation.NodeFactory.MethodEntrypoint( - new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null), - isInstantiatingStub: false, - isPrecodeImportRequired: false, - isJumpableImportRequired: false); - } - private void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) { var method = HandleToObject(ftn); From cd3f654d9f2385071ab36919433aabf98ce21cb4 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 18 Mar 2026 16:12:58 +0100 Subject: [PATCH 3/6] Fix formatting of throw helper definitions in readytorunhelpers.h --- src/coreclr/inc/readytorunhelpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/inc/readytorunhelpers.h b/src/coreclr/inc/readytorunhelpers.h index 5c7f17c6723f58..7ec5bf65884a03 100644 --- a/src/coreclr/inc/readytorunhelpers.h +++ b/src/coreclr/inc/readytorunhelpers.h @@ -23,8 +23,8 @@ HELPER(READYTORUN_HELPER_ThrowDivZero, CORINFO_HELP_THROWDIVZERO, HELPER(READYTORUN_HELPER_ThrowExact, CORINFO_HELP_THROWEXACT, OPTIMIZEFORSIZE) HELPER(READYTORUN_HELPER_ThrowArgument, CORINFO_HELP_THROW_ARGUMENTEXCEPTION, OPTIMIZEFORSIZE) HELPER(READYTORUN_HELPER_ThrowArgumentOutOfRange, CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, OPTIMIZEFORSIZE) -HELPER(READYTORUN_HELPER_ThrowPlatformNotSupported, CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, OPTIMIZEFORSIZE) -HELPER(READYTORUN_HELPER_ThrowNotImplemented, CORINFO_HELP_THROW_NOT_IMPLEMENTED, OPTIMIZEFORSIZE) +HELPER(READYTORUN_HELPER_ThrowPlatformNotSupported, CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, OPTIMIZEFORSIZE) +HELPER(READYTORUN_HELPER_ThrowNotImplemented, CORINFO_HELP_THROW_NOT_IMPLEMENTED, OPTIMIZEFORSIZE) HELPER(READYTORUN_HELPER_WriteBarrier, CORINFO_HELP_ASSIGN_REF, ) HELPER(READYTORUN_HELPER_CheckedWriteBarrier, CORINFO_HELP_CHECKED_ASSIGN_REF, ) From 79d7518ca45ae4f8562caf0d4b7c1dea486a90f0 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 18 Mar 2026 16:13:46 +0100 Subject: [PATCH 4/6] Fix formatting of throw helper definitions in readytorunhelpers.h --- src/coreclr/inc/readytorunhelpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/inc/readytorunhelpers.h b/src/coreclr/inc/readytorunhelpers.h index 7ec5bf65884a03..e4402eaf0743e7 100644 --- a/src/coreclr/inc/readytorunhelpers.h +++ b/src/coreclr/inc/readytorunhelpers.h @@ -23,8 +23,8 @@ HELPER(READYTORUN_HELPER_ThrowDivZero, CORINFO_HELP_THROWDIVZERO, HELPER(READYTORUN_HELPER_ThrowExact, CORINFO_HELP_THROWEXACT, OPTIMIZEFORSIZE) HELPER(READYTORUN_HELPER_ThrowArgument, CORINFO_HELP_THROW_ARGUMENTEXCEPTION, OPTIMIZEFORSIZE) HELPER(READYTORUN_HELPER_ThrowArgumentOutOfRange, CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, OPTIMIZEFORSIZE) -HELPER(READYTORUN_HELPER_ThrowPlatformNotSupported, CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, OPTIMIZEFORSIZE) -HELPER(READYTORUN_HELPER_ThrowNotImplemented, CORINFO_HELP_THROW_NOT_IMPLEMENTED, OPTIMIZEFORSIZE) +HELPER(READYTORUN_HELPER_ThrowPlatformNotSupported, CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, OPTIMIZEFORSIZE) +HELPER(READYTORUN_HELPER_ThrowNotImplemented, CORINFO_HELP_THROW_NOT_IMPLEMENTED, OPTIMIZEFORSIZE) HELPER(READYTORUN_HELPER_WriteBarrier, CORINFO_HELP_ASSIGN_REF, ) HELPER(READYTORUN_HELPER_CheckedWriteBarrier, CORINFO_HELP_CHECKED_ASSIGN_REF, ) From eabf190ac6ad78ee0adfc59da20ec191d30ff845 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 19 Mar 2026 12:07:05 +0100 Subject: [PATCH 5/6] Bump R2R minor version to 18.4 for new throw helpers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/inc/readytorun.h | 4 +++- src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h | 2 +- src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h index 0f760d66951da0..97d829bc1603b3 100644 --- a/src/coreclr/inc/readytorun.h +++ b/src/coreclr/inc/readytorun.h @@ -20,7 +20,7 @@ // If you update this, ensure you run `git grep MINIMUM_READYTORUN_MAJOR_VERSION` // and handle pending work. #define READYTORUN_MAJOR_VERSION 18 -#define READYTORUN_MINOR_VERSION 0x0002 +#define READYTORUN_MINOR_VERSION 0x0004 #define MINIMUM_READYTORUN_MAJOR_VERSION 18 @@ -53,6 +53,8 @@ // R2R Version 17.1 adds the READYTORUN_FLAG_PLATFORM_NATIVE_IMAGE flag to specify that the R2R image pointed to by OwnerCompositeExecutable is in the platform native format. // R2R Version 18 updates fields layout algorithm // R2R Version 18.2 adds InitClass and InitInstClass helpers +// R2R Version 18.3 adds the ExternalTypeMaps, ProxyTypeMaps, TypeMapAssemblyTargets sections +// R2R Version 18.4 adds ThrowArgument, ThrowArgumentOutOfRange, ThrowPlatformNotSupported, and ThrowNotImplemented helpers struct READYTORUN_CORE_HEADER { diff --git a/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h b/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h index 1b841d864b9c92..33a69be66da6cd 100644 --- a/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h +++ b/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h @@ -12,7 +12,7 @@ struct ReadyToRunHeaderConstants static const uint32_t Signature = 0x00525452; // 'RTR' static const uint32_t CurrentMajorVersion = 18; - static const uint32_t CurrentMinorVersion = 2; + static const uint32_t CurrentMinorVersion = 4; }; struct ReadyToRunHeader diff --git a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs index 2d6e5b0265f404..56d898395a004d 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs @@ -16,7 +16,7 @@ internal struct ReadyToRunHeaderConstants public const uint Signature = 0x00525452; // 'RTR' public const ushort CurrentMajorVersion = 18; - public const ushort CurrentMinorVersion = 2; + public const ushort CurrentMinorVersion = 4; } #if READYTORUN #pragma warning disable 0169 From a9264ddc1f4b8ecd311a168a269e5d7cc19d1657 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 20 Mar 2026 09:59:58 +0100 Subject: [PATCH 6/6] Add new throw helpers to R2RDump ParseHelper Add case statements for ThrowArgument, ThrowArgumentOutOfRange, ThrowPlatformNotSupported, and ThrowNotImplemented in the R2RDump signature decoder so it can parse the new R2R helper fixups without throwing BadImageFormatException. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ReadyToRunSignature.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs index 2547a936f57f0b..406effbb5305aa 100644 --- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs +++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs @@ -1690,6 +1690,22 @@ private void ParseHelper(StringBuilder builder) builder.Append("THROW_DIV_ZERO"); break; + case ReadyToRunHelper.ThrowArgument: + builder.Append("THROW_ARGUMENT"); + break; + + case ReadyToRunHelper.ThrowArgumentOutOfRange: + builder.Append("THROW_ARGUMENT_OUT_OF_RANGE"); + break; + + case ReadyToRunHelper.ThrowPlatformNotSupported: + builder.Append("THROW_PLATFORM_NOT_SUPPORTED"); + break; + + case ReadyToRunHelper.ThrowNotImplemented: + builder.Append("THROW_NOT_IMPLEMENTED"); + break; + // Write barriers case ReadyToRunHelper.WriteBarrier: builder.Append("WRITE_BARRIER");