From 1d9ff9eff0593e3b2cc83f8aeb699ff6d05d795d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksey=20Kliger=20=28=CE=BBgeek=29?= Date: Wed, 2 Jun 2021 13:00:34 -0400 Subject: [PATCH] [mono] Add a no-exec code manager for AOT compilation; switch Catalyst CI to JustInterp AOT mode (#53197) * Initial pass at trying to run catalyst in aot interp only mode * Cleanup * Remove yml dup * Incorporate changes and identify native libraries to skip during System.Diagnostics.FileVersionInfo test run * [mini] Add a no-exec code manager for AOT compilation Don't allocate pages with execute permission if we're never going to be executing code. Also don't try to toggle per-thread write protection if we're not expecting to write to executable pages. * also set no_exec earlier and create the ALC codeman with noexec * Don't assert on Catalyst in mono_codeman_enable_write We defensively also toggle the page write protect bits when resolving some AOT patch targets in mono_resolve_patch_target_ext. Instead allow the call, but don't do anything. * Set ENABLE_MONOTOUCH for MacCatalyst arm64. Define MONOTOUCH in one place * [aot] mscorlib.dll isn't CoreLib on netcore It's a forwarding assembly. Don't treat it specially * [testing] In JustInterp mode, only AOT System.Private.CoreLib We only need to AOT the trampolines in System.Private.CoreLib in interpreter-only mode. We don't need to AOT any of the user code in other assemblies. Side effect: fixes the System.Runtime.Loader.DefaultContext testsuite in JustInterp mode. Still broken in Full AOT mode. (That testsuite references the System.Runtime.Loader.Noop.Assembly assembly, but with a different filename System.Runtime.Loader.Noop.Assembly_test.dll which causes linking errors due to incorrect symbols in AOT module registration in AppleAppBuilder) * Update iOS sample to use JustInterp and adhoc signing * Don't run iOS sample on the CI build machine * Disable some tests Fixes https://github.com/dotnet/runtime/issues/53106 Co-authored-by: Steve Pfister Co-authored-by: Steve Pfister --- eng/pipelines/runtime-staging.yml | 43 ++++++- eng/testing/tests.mobile.targets | 21 +++- ...m.Diagnostics.FileVersionInfo.Tests.csproj | 5 + .../tests/MemoryMappedViewAccessor.Tests.cs | 1 + .../tests/MemoryMappedViewStream.Tests.cs | 1 + .../tests/InterpreterTests.cs | 1 + src/mono/CMakeLists.txt | 17 ++- src/mono/Directory.Build.props | 3 +- src/mono/mono/metadata/memory-manager.c | 6 +- src/mono/mono/mini/aot-compiler.c | 3 +- src/mono/mono/mini/aot-runtime.c | 8 +- src/mono/mono/mini/mini-runtime.c | 31 ++++-- src/mono/mono/utils/mono-codeman.c | 105 +++++++++++++++--- src/mono/mono/utils/mono-codeman.h | 3 +- src/mono/mono/utils/mono-mmap.c | 2 +- src/mono/sample/iOS/Makefile | 4 +- src/mono/sample/iOS/Program.csproj | 24 +++- src/tasks/AppleAppBuilder/AppleAppBuilder.cs | 2 +- src/tasks/AppleAppBuilder/Templates/runtime.m | 10 +- src/tasks/AppleAppBuilder/Xcode.cs | 3 +- 20 files changed, 239 insertions(+), 54 deletions(-) diff --git a/eng/pipelines/runtime-staging.yml b/eng/pipelines/runtime-staging.yml index 89746d6f7f855..eaaa9e08fe2c5 100644 --- a/eng/pipelines/runtime-staging.yml +++ b/eng/pipelines/runtime-staging.yml @@ -66,7 +66,6 @@ jobs: platforms: - iOSSimulator_x64 - tvOSSimulator_x64 - - MacCatalyst_x64 variables: # map dependencies variables to local variables - name: librariesContainsChange @@ -96,6 +95,48 @@ jobs: eq(variables['monoContainsChange'], true), eq(variables['isFullMatrix'], true)) +# +# MacCatalyst interp - requires AOT Compilation and Interp flags +# Build the whole product using Mono and run libraries tests +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - MacCatalyst_x64 + - MacCatalyst_arm64 + variables: + # map dependencies variables to local variables + - name: librariesContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: monoContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] + jobParameters: + testGroup: innerloop + nameSuffix: AllSubsets_Mono + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:RunAOTCompilation=true /p:MonoForceInterpreter=true + timeoutInMinutes: 180 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), + eq(variables['isFullMatrix'], true)) + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + interpreter: true + testRunNamePrefixSuffix: Mono_$(_BuildConfig) + condition: >- + or( + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true), + eq(variables['isFullMatrix'], true)) + # # Build the whole product using Mono and run libraries tests # diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets index 61d7421402d89..38d568edb2c7e 100644 --- a/eng/testing/tests.mobile.targets +++ b/eng/testing/tests.mobile.targets @@ -152,12 +152,25 @@ AppleTestRunner.dll <_MobileIntermediateOutputPath Condition="'$(RunAOTCompilation)' == 'true'">$(IntermediateOutputPath)mobile + + Full + Full + JustInterp + - + <_AotExcludeAssemblies Include="$(PublishDir)System.Runtime.WindowsRuntime.dll" /> + <_AotExcludeAssemblies Include="@(NativeLibraries->'$(PublishDir)%(Identity)')" /> + + + <_AotIncludeAssemblies Condition="'$(RunAOTCompilation)' == 'true' and '$(AOTMode)' == 'JustInterp'" Include="$(PublishDir)System.Private.CoreLib.dll" /> + <_AotIncludeAssemblies Condition="'$(RunAOTCompilation)' == 'true' and '$(AOTMode)' != 'JustInterp'" Include="$(PublishDir)*.dll" /> + + @(MonoAOTCompilerDefaultAotArguments, ';') @(MonoAOTCompilerDefaultProcessArguments, ';') + <_BundleNonAotAssemblies Condition="'$(RunAOTCompilation)' == 'true' and '$(AOTMode)' == 'JustInterp'" Include="$(PublishDir)*.dll" Exclude="$(PublishDir)System.Private.CoreLib.dll" /> + + + + PreserveNewest + + + + + diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs index 512748b10f925..b4db65b5a851f 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs @@ -75,6 +75,7 @@ public void InvalidArguments() [InlineData(MemoryMappedFileAccess.ReadWrite, MemoryMappedFileAccess.CopyOnWrite)] [InlineData(MemoryMappedFileAccess.Read, MemoryMappedFileAccess.Read)] [InlineData(MemoryMappedFileAccess.Read, MemoryMappedFileAccess.CopyOnWrite)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/53601", runtimes: TestRuntimes.Mono, platforms: TestPlatforms.MacCatalyst)] public void ValidAccessLevelCombinations(MemoryMappedFileAccess mapAccess, MemoryMappedFileAccess viewAccess) { const int Capacity = 4096; diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs index 5903d4756ed97..a29a5bf353876 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs @@ -75,6 +75,7 @@ public void InvalidArguments() [InlineData(MemoryMappedFileAccess.ReadWrite, MemoryMappedFileAccess.CopyOnWrite)] [InlineData(MemoryMappedFileAccess.Read, MemoryMappedFileAccess.Read)] [InlineData(MemoryMappedFileAccess.Read, MemoryMappedFileAccess.CopyOnWrite)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/53601", runtimes: TestRuntimes.Mono, platforms: TestPlatforms.MacCatalyst)] public void ValidAccessLevelCombinations(MemoryMappedFileAccess mapAccess, MemoryMappedFileAccess viewAccess) { const int Capacity = 4096; diff --git a/src/libraries/System.Linq.Expressions/tests/InterpreterTests.cs b/src/libraries/System.Linq.Expressions/tests/InterpreterTests.cs index 11c22f7418324..146dffb4be4c4 100644 --- a/src/libraries/System.Linq.Expressions/tests/InterpreterTests.cs +++ b/src/libraries/System.Linq.Expressions/tests/InterpreterTests.cs @@ -102,6 +102,7 @@ .maxcontinuation 1 } [Fact] + [ActiveIssue ("https://github.com/dotnet/runtime/issues/53599", platforms: TestPlatforms.MacCatalyst, runtimes: TestRuntimes.Mono)] public static void ConstructorThrows_StackTrace() { Expression> e = () => new Thrower(true); diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt index 1e7fa7a08c4bd..5eaaaa91b6504 100644 --- a/src/mono/CMakeLists.txt +++ b/src/mono/CMakeLists.txt @@ -160,11 +160,11 @@ if(NOT AOT_TARGET_TRIPLE STREQUAL "") elseif(AOT_TARGET_TRIPLE STREQUAL "x86_64-apple-maccatalyst") set(TARGET_SYSTEM_NAME "Darwin") set(TARGET_ARCH "x86_64") - set(CMAKE_SYSTEM_VARIANT "MacCatalyst") + set(TARGET_MACCAT 1) elseif(AOT_TARGET_TRIPLE STREQUAL "aarch64-apple-maccatalyst") set(TARGET_SYSTEM_NAME "Darwin") set(TARGET_ARCH "arm64") - set(CMAKE_SYSTEM_VARIANT "MacCatalyst") + set(TARGET_MACCAT 1) elseif(AOT_TARGET_TRIPLE STREQUAL "wasm32-unknown-none") set(TARGET_SYSTEM_NAME "Emscripten") set(TARGET_ARCH "wasm") @@ -225,7 +225,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "tvOS") set(DISABLE_EXECUTABLES 1) set(DISABLE_CRASH_REPORTING 1) set(ENABLE_MONOTOUCH 1) - add_definitions(-DMONOTOUCH=1) add_definitions("-DSMALL_CONFIG") add_definitions("-D_XOPEN_SOURCE") add_definitions("-DHAVE_LARGE_FILE_SUPPORT=1") @@ -307,7 +306,6 @@ elseif(TARGET_SYSTEM_NAME STREQUAL "iOS" OR TARGET_SYSTEM_NAME STREQUAL "tvOS") set(TARGET_TVOS 1) endif() set(ENABLE_MONOTOUCH 1) - add_definitions(-DMONOTOUCH=1) elseif(TARGET_SYSTEM_NAME STREQUAL "Linux") set(TARGET_LINUX 1) elseif(TARGET_SYSTEM_NAME STREQUAL "Android") @@ -431,6 +429,15 @@ else() message(FATAL_ERROR "TARGET_ARCH='${TARGET_ARCH}' not supported.") endif() +# arm64 MacCatalyst runtime host or AOT target is more like Apple mobile targets than x64 +if ((HOST_MACCAT AND HOST_ARCH STREQUAL "arm64") OR (TARGET_MACCAT AND TARGET_ARCH STREQUAL "arm64")) + set(ENABLE_MONOTOUCH 1) +endif() + +if(ENABLE_MONOTOUCH) + add_definitions(-DMONOTOUCH=1) +endif() + ###################################### # HEADER/FUNCTION CHECKS ###################################### @@ -765,7 +772,7 @@ set(FULL_VERSION ${product_version_string}) ###################################### # OS SPECIFIC CHECKS ###################################### -if(TARGET_IOS OR TARGET_ANDROID OR TARGET_MACCAT) +if(HOST_IOS OR HOST_ANDROID OR HOST_MACCAT) # FIXME: the mobile products use mono_dllmap_insert so allow this unset(DISABLE_DLLMAP) else() diff --git a/src/mono/Directory.Build.props b/src/mono/Directory.Build.props index fc54d02cf4231..35e223f09c80a 100644 --- a/src/mono/Directory.Build.props +++ b/src/mono/Directory.Build.props @@ -18,7 +18,8 @@ 2.0 5.1 10.13 - 11.0 + + 11.0 diff --git a/src/mono/mono/metadata/memory-manager.c b/src/mono/mono/metadata/memory-manager.c index 38979f4bd6520..04f489124c0da 100644 --- a/src/mono/mono/metadata/memory-manager.c +++ b/src/mono/mono/metadata/memory-manager.c @@ -105,7 +105,11 @@ mono_mem_manager_new (MonoAssemblyLoadContext **alcs, int nalcs, gboolean collec mono_os_mutex_init (&memory_manager->mp_mutex); memory_manager->_mp = mono_mempool_new (); - memory_manager->code_mp = mono_code_manager_new (); + if (mono_runtime_get_no_exec()) { + memory_manager->code_mp = mono_code_manager_new_aot (); + } else { + memory_manager->code_mp = mono_code_manager_new (); + } memory_manager->lock_free_mp = lock_free_mempool_new (); memory_manager->alcs = mono_mempool_alloc0 (memory_manager->_mp, sizeof (MonoAssemblyLoadContext *) * nalcs); diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index a64fa4959dbf0..f0168f04decc6 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -14091,7 +14092,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, #endif /* required for mixed mode */ - if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) { + if (strcmp (acfg->image->assembly->aname.name, MONO_ASSEMBLY_CORLIB_NAME) == 0) { add_gc_wrappers (acfg); for (int i = 0; i < MONO_JIT_ICALL_count; ++i) diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index 7aad2d1788958..545487122f098 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -1577,7 +1577,7 @@ check_usable (MonoAssembly *assembly, MonoAotFileInfo *info, guint8 *blob, char msg = g_strdup ("compiled with --aot=full"); usable = FALSE; } - if (mono_use_interpreter && !interp && !strcmp (assembly->aname.name, "mscorlib")) { + if (mono_use_interpreter && !interp && !strcmp (assembly->aname.name, MONO_ASSEMBLY_CORLIB_NAME)) { /* mscorlib contains necessary interpreter trampolines */ msg = g_strdup ("not compiled with --aot=interp"); usable = FALSE; @@ -2183,8 +2183,10 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer amodule->trampolines [MONO_AOT_TRAMP_FTNPTR_ARG] = (guint8 *)info->ftnptr_arg_trampolines; amodule->trampolines [MONO_AOT_TRAMP_UNBOX_ARBITRARY] = (guint8 *)info->unbox_arbitrary_trampolines; - if (mono_is_corlib_image (assembly->image) || !strcmp (assembly->aname.name, "mscorlib") || !strcmp (assembly->aname.name, "System.Private.CoreLib")) + if (mono_is_corlib_image (assembly->image) || !strcmp (assembly->aname.name, MONO_ASSEMBLY_CORLIB_NAME)) { + g_assert (!mscorlib_aot_module); mscorlib_aot_module = amodule; + } /* Compute method addresses */ amodule->methods = (void **)g_malloc0 (amodule->info.nmethods * sizeof (gpointer)); @@ -5834,7 +5836,7 @@ aot_is_slim_amodule (MonoAotModule *amodule) return FALSE; /* "slim" only applies to mscorlib.dll */ - if (strcmp (amodule->aot_name, "mscorlib")) + if (strcmp (amodule->aot_name, MONO_ASSEMBLY_CORLIB_NAME)) return FALSE; guint32 f = amodule->info.flags; diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index 0443d8ed7af67..7f30902b62604 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -378,7 +378,10 @@ void *(mono_global_codeman_reserve) (int size) if (!global_codeman) { /* This can happen during startup */ - global_codeman = mono_code_manager_new (); + if (!mono_compile_aot) + global_codeman = mono_code_manager_new (); + else + global_codeman = mono_code_manager_new_aot (); return mono_code_manager_reserve (global_codeman, size); } else { @@ -4292,8 +4295,12 @@ mini_init (const char *filename, const char *runtime_version) mono_tls_init_runtime_keys (); - if (!global_codeman) - global_codeman = mono_code_manager_new (); + if (!global_codeman) { + if (!mono_compile_aot) + global_codeman = mono_code_manager_new (); + else + global_codeman = mono_code_manager_new_aot (); + } memset (&callbacks, 0, sizeof (callbacks)); callbacks.create_ftnptr = mini_create_ftnptr; @@ -4346,7 +4353,7 @@ mini_init (const char *filename, const char *runtime_version) mini_parse_debug_options (); } - mono_code_manager_init (); + mono_code_manager_init (mono_compile_aot); #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING @@ -4444,6 +4451,15 @@ mini_init (const char *filename, const char *runtime_version) if (mini_debug_options.collect_pagefault_stats) mono_aot_set_make_unreadable (TRUE); + /* set no-exec before the default ALC is created */ + if (mono_compile_aot) { + /* + * Avoid running managed code when AOT compiling, since the platform + * might only support aot-only execution. + */ + mono_runtime_set_no_exec (TRUE); + } + if (runtime_version) domain = mono_init_version (filename, runtime_version); else @@ -4500,13 +4516,6 @@ mini_init (const char *filename, const char *runtime_version) register_trampolines (domain); - if (mono_compile_aot) - /* - * Avoid running managed code when AOT compiling, since the platform - * might only support aot-only execution. - */ - mono_runtime_set_no_exec (TRUE); - mono_mem_account_register_counters (); #define JIT_RUNTIME_WORKS diff --git a/src/mono/mono/utils/mono-codeman.c b/src/mono/mono/utils/mono-codeman.c index 10cc823eddf64..c7ff9326ed710 100644 --- a/src/mono/mono/utils/mono-codeman.c +++ b/src/mono/mono/utils/mono-codeman.c @@ -70,6 +70,7 @@ static const MonoCodeManagerCallbacks *code_manager_callbacks; #endif #define MONO_PROT_RWX (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC|MONO_MMAP_JIT) +#define MONO_PROT_RW (MONO_MMAP_READ|MONO_MMAP_WRITE) typedef struct _CodeChunk CodeChunk; @@ -94,6 +95,7 @@ struct _MonoCodeManager { CodeChunk *last; int dynamic : 1; int read_only : 1; + int no_exec : 1; }; #define ALIGN_INT(val,alignment) (((val) + (alignment - 1)) & ~(alignment - 1)) @@ -105,7 +107,7 @@ static GHashTable *valloc_freelists; static MonoNativeTlsKey write_level_tls_id; static void* -codechunk_valloc (void *preferred, guint32 size) +codechunk_valloc (void *preferred, guint32 size, gboolean no_exec) { void *ptr; GSList *freelist; @@ -128,9 +130,14 @@ codechunk_valloc (void *preferred, guint32 size) freelist = g_slist_delete_link (freelist, freelist); g_hash_table_insert (valloc_freelists, GUINT_TO_POINTER (size), freelist); } else { - ptr = mono_valloc (preferred, size, MONO_PROT_RWX | ARCH_MAP_FLAGS, MONO_MEM_ACCOUNT_CODE); + int prot; + if (!no_exec) + prot = MONO_PROT_RWX | ARCH_MAP_FLAGS; + else + prot = MONO_PROT_RW | ARCH_MAP_FLAGS; + ptr = mono_valloc (preferred, size, prot, MONO_MEM_ACCOUNT_CODE); if (!ptr && preferred) - ptr = mono_valloc (NULL, size, MONO_PROT_RWX | ARCH_MAP_FLAGS, MONO_MEM_ACCOUNT_CODE); + ptr = mono_valloc (NULL, size, prot, MONO_MEM_ACCOUNT_CODE); } mono_os_mutex_unlock (&valloc_mutex); return ptr; @@ -173,14 +180,34 @@ codechunk_cleanup (void) g_hash_table_destroy (valloc_freelists); } +/* non-zero if we don't need to toggle write protection on individual threads */ +static int +codeman_no_exec; + +/** + * mono_codeman_set_code_no_exec: + * + * If set to a non-zero value, + * \c mono_codeman_enable_write and \c mono_codeman_disable_write turn into no-ops. + * + * The AOT compiler should do this if it is allocating RW (no X) memory for code. + */ +static void +mono_codeman_set_code_no_exec (int no_exec) +{ + codeman_no_exec = no_exec; +} + void -mono_code_manager_init (void) +mono_code_manager_init (gboolean no_exec) { mono_counters_register ("Dynamic code allocs", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_alloc_count); mono_counters_register ("Dynamic code bytes", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_bytes_count); mono_counters_register ("Dynamic code frees", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_frees_count); mono_native_tls_alloc (&write_level_tls_id, NULL); + + mono_codeman_set_code_no_exec (no_exec); } void @@ -206,6 +233,34 @@ mono_codeman_allocation_type (MonoCodeManager const *cman) #endif } +enum CodeManagerType { + MONO_CODEMAN_TYPE_JIT, + MONO_CODEMAN_TYPE_DYNAMIC, + MONO_CODEMAN_TYPE_AOT, +}; + +static gboolean +codeman_type_is_dynamic (int codeman_type) +{ + switch (codeman_type) { + case MONO_CODEMAN_TYPE_DYNAMIC: + return TRUE; + default: + return FALSE; + } +} + +static gboolean +codeman_type_is_aot (int codeman_type) +{ + switch (codeman_type) { + case MONO_CODEMAN_TYPE_AOT: + return TRUE; + default: + return FALSE; + } +} + /** * mono_code_manager_new_internal * @@ -213,11 +268,12 @@ mono_codeman_allocation_type (MonoCodeManager const *cman) */ static MonoCodeManager* -mono_code_manager_new_internal (gboolean dynamic) +mono_code_manager_new_internal (int codeman_type) { MonoCodeManager* cman = g_new0 (MonoCodeManager, 1); if (cman) { - cman->dynamic = dynamic; + cman->dynamic = codeman_type_is_dynamic (codeman_type); + cman->no_exec = codeman_type_is_aot (codeman_type); #if _WIN32 // It would seem the heap should live and die with the codemanager, // but that was failing, so try a global. @@ -250,7 +306,7 @@ mono_code_manager_new_internal (gboolean dynamic) MonoCodeManager* mono_code_manager_new (void) { - return mono_code_manager_new_internal (FALSE); + return mono_code_manager_new_internal (MONO_CODEMAN_TYPE_JIT); } /** @@ -265,7 +321,21 @@ mono_code_manager_new (void) MonoCodeManager* mono_code_manager_new_dynamic (void) { - return mono_code_manager_new_internal (TRUE); + return mono_code_manager_new_internal (MONO_CODEMAN_TYPE_DYNAMIC); +} + +/** + * mono_code_manager_new_aot: + * + * Creates a new code manager that will hold code that is never + * executed. This can be used by the AOT compiler to allocate pages + * on W^X platforms without asking for execute permission (which may + * require additional entitlements, or AOT-time OS calls). + */ +MonoCodeManager* +mono_code_manager_new_aot (void) +{ + return mono_code_manager_new_internal (MONO_CODEMAN_TYPE_AOT); } static gpointer @@ -424,6 +494,7 @@ new_codechunk (MonoCodeManager *cman, int size) { CodeChunk * const last = cman->last; int const dynamic = cman->dynamic; + int const no_exec = cman->no_exec; int chunk_size, bsize = 0; CodeChunk *chunk; void *ptr; @@ -440,8 +511,8 @@ new_codechunk (MonoCodeManager *cman, int size) chunk_size = minsize; else { /* Allocate MIN_ALIGN-1 more than we need so we can still */ - /* guarantee MIN_ALIGN alignment for individual allocs */ - /* from mono_code_manager_reserve_align. */ + /* guarantee MIN_ALIGN alignment for individual allocs */ + /* from mono_code_manager_reserve_align. */ size += MIN_ALIGN - 1; size &= ~(MIN_ALIGN - 1); chunk_size = size; @@ -476,9 +547,9 @@ new_codechunk (MonoCodeManager *cman, int size) /* Try to allocate code chunks next to each other to help the VM */ ptr = NULL; if (last) - ptr = codechunk_valloc ((guint8*)last->data + last->size, chunk_size); + ptr = codechunk_valloc ((guint8*)last->data + last->size, chunk_size, no_exec); if (!ptr) - ptr = codechunk_valloc (NULL, chunk_size); + ptr = codechunk_valloc (NULL, chunk_size, no_exec); if (!ptr) return NULL; } @@ -661,6 +732,8 @@ mono_code_manager_size (MonoCodeManager *cman, int *used_size) void mono_codeman_enable_write (void) { + if (codeman_no_exec) + return; #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP if (__builtin_available (macOS 11, *)) { int level = GPOINTER_TO_INT (mono_native_tls_get_value (write_level_tls_id)); @@ -669,8 +742,7 @@ mono_codeman_enable_write (void) pthread_jit_write_protect_np (0); } #elif defined(HOST_MACCAT) && defined(__aarch64__) - /* JITing in Catalyst apps is not allowed on Apple Silicon. */ - g_assert_not_reached (); + /* JITing in Catalyst apps is not allowed on Apple Silicon, so assume if we're here we don't really have executable pages. */ #endif } @@ -683,6 +755,8 @@ mono_codeman_enable_write (void) void mono_codeman_disable_write (void) { + if (codeman_no_exec) + return; #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP if (__builtin_available (macOS 11, *)) { int level = GPOINTER_TO_INT (mono_native_tls_get_value (write_level_tls_id)); @@ -693,7 +767,6 @@ mono_codeman_disable_write (void) pthread_jit_write_protect_np (1); } #elif defined(HOST_MACCAT) && defined(__aarch64__) - /* JITing in Catalyst apps is not allowed on Apple Silicon. */ - g_assert_not_reached (); + /* JITing in Catalyst apps is not allowed on Apple Silicon, so assume if we're here we don't really have executable pages */ #endif } diff --git a/src/mono/mono/utils/mono-codeman.h b/src/mono/mono/utils/mono-codeman.h index fbe2a2f2d4f44..69893b401c911 100644 --- a/src/mono/mono/utils/mono-codeman.h +++ b/src/mono/mono/utils/mono-codeman.h @@ -24,6 +24,7 @@ typedef struct { MonoCodeManager* mono_code_manager_new (void); MonoCodeManager* mono_code_manager_new_dynamic (void); +MonoCodeManager* mono_code_manager_new_aot (void); void mono_code_manager_destroy (MonoCodeManager *cman); void mono_code_manager_invalidate (MonoCodeManager *cman); void mono_code_manager_set_read_only (MonoCodeManager *cman); @@ -33,7 +34,7 @@ void* mono_code_manager_reserve_align (MonoCodeManager *cman, int siz void* mono_code_manager_reserve (MonoCodeManager *cman, int size); void mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize); int mono_code_manager_size (MonoCodeManager *cman, int *used_size); -void mono_code_manager_init (void); +void mono_code_manager_init (gboolean no_exec); void mono_code_manager_cleanup (void); void mono_code_manager_install_callbacks (const MonoCodeManagerCallbacks* callbacks); diff --git a/src/mono/mono/utils/mono-mmap.c b/src/mono/mono/utils/mono-mmap.c index e362b698dc454..08ce984f25e6c 100644 --- a/src/mono/mono/utils/mono-mmap.c +++ b/src/mono/mono/utils/mono-mmap.c @@ -305,7 +305,7 @@ mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type) } if ((flags & MONO_MMAP_JIT) && (use_mmap_jit || is_hardened_runtime == 1)) mflags |= MAP_JIT; -#if defined(HOST_ARM64) +#if defined(HOST_ARM64) && !defined(HOST_MACCAT) /* Patching code on apple silicon seems to cause random crashes without this flag */ /* No __builtin_available in old versions of Xcode that could be building Mono on x86 or amd64 */ if (__builtin_available (macOS 11, *)) diff --git a/src/mono/sample/iOS/Makefile b/src/mono/sample/iOS/Makefile index 5cbd1277aa89a..0cea32121e602 100644 --- a/src/mono/sample/iOS/Makefile +++ b/src/mono/sample/iOS/Makefile @@ -47,7 +47,7 @@ run-catalyst: /p:TargetOS=MacCatalyst \ /p:TargetArchitecture=$(MONO_ARCH) \ /p:UseLLVM=False \ - /p:ForceAOT=False + /p:ForceAOT=True run-sim-interp: clean appbuilder $(DOTNET) publish \ @@ -66,7 +66,7 @@ run-catalyst-interp: /p:TargetOS=MacCatalyst \ /p:TargetArchitecture=$(MONO_ARCH) \ /p:UseLLVM=False \ - /p:ForceAOT=False \ + /p:ForceAOT=True \ /p:MonoForceInterpreter=true clean: diff --git a/src/mono/sample/iOS/Program.csproj b/src/mono/sample/iOS/Program.csproj index 6c238dc62484d..b9718a6bdb5f2 100644 --- a/src/mono/sample/iOS/Program.csproj +++ b/src/mono/sample/iOS/Program.csproj @@ -3,7 +3,7 @@ Exe bin $(NetCoreAppToolCurrent) - iOS + iOS iOSSimulator $(ArtifactsBinDir)microsoft.netcore.app.runtime.$(TargetOS.ToLower())-$(TargetArchitecture)\$(Configuration)\runtimes\$(TargetOS.ToLower())-$(TargetArchitecture)\ false @@ -18,7 +18,7 @@ - - + adhoc @@ -56,10 +56,16 @@ + + Full + Full + JustInterp + + + + + + @@ -106,8 +118,8 @@ - diff --git a/src/tasks/AppleAppBuilder/AppleAppBuilder.cs b/src/tasks/AppleAppBuilder/AppleAppBuilder.cs index 68ce0e1850013..b436241de9a29 100644 --- a/src/tasks/AppleAppBuilder/AppleAppBuilder.cs +++ b/src/tasks/AppleAppBuilder/AppleAppBuilder.cs @@ -198,7 +198,7 @@ public override bool Execute() throw new InvalidOperationException("Need list of AOT files for device builds."); } - if (ForceInterpreter && ForceAOT) + if (TargetOS != TargetNames.MacCatalyst && ForceInterpreter && ForceAOT) { throw new InvalidOperationException("Interpreter and AOT cannot be enabled at the same time"); } diff --git a/src/tasks/AppleAppBuilder/Templates/runtime.m b/src/tasks/AppleAppBuilder/Templates/runtime.m index e45455507a138..e0eb0a7e81d83 100644 --- a/src/tasks/AppleAppBuilder/Templates/runtime.m +++ b/src/tasks/AppleAppBuilder/Templates/runtime.m @@ -293,14 +293,22 @@ monovm_initialize (sizeof (appctx_keys) / sizeof (appctx_keys [0]), appctx_keys, appctx_values); -#if FORCE_INTERPRETER +#if (FORCE_INTERPRETER && !FORCE_AOT) + // interp w/ JIT fallback. Assumption is that your configuration can JIT os_log_info (OS_LOG_DEFAULT, "INTERP Enabled"); mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_ONLY); #elif (!TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST) || FORCE_AOT register_dllmap (); // register modules register_aot_modules (); + +#if (FORCE_INTERPRETER && TARGET_OS_MACCATALYST) + os_log_info (OS_LOG_DEFAULT, "AOT INTERP Enabled"); + mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP); +#else mono_jit_set_aot_mode (MONO_AOT_MODE_FULL); +#endif + #endif mono_debug_init (MONO_DEBUG_FORMAT_MONO); diff --git a/src/tasks/AppleAppBuilder/Xcode.cs b/src/tasks/AppleAppBuilder/Xcode.cs index 4409043f00a42..d237434e03d20 100644 --- a/src/tasks/AppleAppBuilder/Xcode.cs +++ b/src/tasks/AppleAppBuilder/Xcode.cs @@ -198,7 +198,8 @@ public Xcode(string target, string arch) { defines.AppendLine("add_definitions(-DFORCE_INTERPRETER=1)"); } - else if (forceAOT) + + if (forceAOT) { defines.AppendLine("add_definitions(-DFORCE_AOT=1)"); }