[mono] Add a no-exec code manager for AOT compilation; switch Catalyst CI to JustInte...
authorAleksey Kliger (λgeek) <alklig@microsoft.com>
Wed, 2 Jun 2021 17:00:34 +0000 (13:00 -0400)
committerGitHub <noreply@github.com>
Wed, 2 Jun 2021 17:00:34 +0000 (13:00 -0400)
* 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 <steve.pfister@microsoft.com>
Co-authored-by: Steve Pfister <steve@Steves-M1.fios-router.home>
20 files changed:
eng/pipelines/runtime-staging.yml
eng/testing/tests.mobile.targets
src/libraries/System.Diagnostics.FileVersionInfo/tests/System.Diagnostics.FileVersionInfo.Tests/System.Diagnostics.FileVersionInfo.Tests.csproj
src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs
src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs
src/libraries/System.Linq.Expressions/tests/InterpreterTests.cs
src/mono/CMakeLists.txt
src/mono/Directory.Build.props
src/mono/mono/metadata/memory-manager.c
src/mono/mono/mini/aot-compiler.c
src/mono/mono/mini/aot-runtime.c
src/mono/mono/mini/mini-runtime.c
src/mono/mono/utils/mono-codeman.c
src/mono/mono/utils/mono-codeman.h
src/mono/mono/utils/mono-mmap.c
src/mono/sample/iOS/Makefile
src/mono/sample/iOS/Program.csproj
src/tasks/AppleAppBuilder/AppleAppBuilder.cs
src/tasks/AppleAppBuilder/Templates/runtime.m
src/tasks/AppleAppBuilder/Xcode.cs

index 89746d6..eaaa9e0 100644 (file)
@@ -66,7 +66,6 @@ jobs:
     platforms:
     - iOSSimulator_x64
     - tvOSSimulator_x64
-    - MacCatalyst_x64
     variables:
       # map dependencies variables to local variables
       - name: librariesContainsChange
@@ -97,6 +96,48 @@ jobs:
           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
 #
 - template: /eng/pipelines/common/platform-matrix.yml
index 61d7421..38d568e 100644 (file)
       <MainLibraryFileName Condition="'$(MainLibraryFileName)' == ''">AppleTestRunner.dll</MainLibraryFileName>
       <_MobileIntermediateOutputPath Condition="'$(RunAOTCompilation)' == 'true'">$(IntermediateOutputPath)mobile</_MobileIntermediateOutputPath>
     </PropertyGroup>
+    <PropertyGroup>
+      <AOTMode Condition="'$(TargetOS)' != 'MacCatalyst'">Full</AOTMode>
+      <AOTMode Condition="'$(TargetOS)' == 'MacCatalyst' and '$(MonoForceInterpreter)' != 'true'">Full</AOTMode>
+      <AOTMode Condition="'$(TargetOS)' == 'MacCatalyst' and '$(MonoForceInterpreter)' == 'true'">JustInterp</AOTMode>
+    </PropertyGroup>
     <ItemGroup>
-      <AotInputAssemblies Condition="'$(RunAOTCompilation)' == 'true'" Include="$(PublishDir)*.dll" Exclude="$(PublishDir)System.Runtime.WindowsRuntime.dll">
+      <_AotExcludeAssemblies Include="$(PublishDir)System.Runtime.WindowsRuntime.dll" />
+      <_AotExcludeAssemblies Include="@(NativeLibraries->'$(PublishDir)%(Identity)')" />
+
+      <!-- JustInterp only needs to AOT CoreLib, the other assemblies will just get added to BundleAssemblies via _BundleNonAotAssemblies -->
+      <_AotIncludeAssemblies Condition="'$(RunAOTCompilation)' == 'true' and '$(AOTMode)' == 'JustInterp'" Include="$(PublishDir)System.Private.CoreLib.dll" />
+      <_AotIncludeAssemblies Condition="'$(RunAOTCompilation)' == 'true' and '$(AOTMode)' != 'JustInterp'" Include="$(PublishDir)*.dll" />
+
+      <AotInputAssemblies Condition="'$(RunAOTCompilation)' == 'true'" Include="@(_AotIncludeAssemblies)" Exclude="@(_AotExcludeAssemblies)">
         <AotArguments>@(MonoAOTCompilerDefaultAotArguments, ';')</AotArguments>
         <ProcessArguments>@(MonoAOTCompilerDefaultProcessArguments, ';')</ProcessArguments>
       </AotInputAssemblies>
       <BundleAssemblies Condition="'$(RunAOTCompilation)' != 'true'" Include="$(PublishDir)*.dll" />
+      <_BundleNonAotAssemblies Condition="'$(RunAOTCompilation)' == 'true' and '$(AOTMode)' == 'JustInterp'" Include="$(PublishDir)*.dll" Exclude="$(PublishDir)System.Private.CoreLib.dll" />
     </ItemGroup>
 
     <MakeDir Directories="$(_MobileIntermediateOutputPath)"
     <MonoAOTCompiler Condition="'$(RunAOTCompilation)' == 'true'"
         CompilerBinaryPath="$(MonoAotCrossCompilerPath)"
         OutputDir="$(_MobileIntermediateOutputPath)"
-        Mode="Full"
+        Mode="$(AOTMode)"
         OutputType="AsmOnly"
         Assemblies="@(AotInputAssemblies)"
         AotModulesTablePath="$(BundleDir)\modules.m"
         <Output TaskParameter="CompiledAssemblies" ItemName="BundleAssemblies" />
     </MonoAOTCompiler>
 
+    <ItemGroup>
+      <BundleAssemblies Include="@(_BundleNonAotAssemblies)" />
+    </ItemGroup>
+
     <!-- Run App bundler, it uses AOT libs (if needed), link all native bits, compile simple UI (written in ObjC)
          and produce an app bundle (with xcode project) -->
     <AppleAppBuilderTask
index 7efbc8b..ad027e8 100644 (file)
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
   </ItemGroup>
+  <ItemGroup Condition="'$(RunAOTCompilation)' == 'true'">
+    <!-- Identifies native libraries that should be skipped during AOT -->
+    <NativeLibraries Include="NativeLibrary.dll" />
+    <NativeLibraries Include="SecondNativeLibrary.dll" />
+  </ItemGroup>
   <ItemGroup>
     <Compile Include="FileVersionInfoTest.cs" />
     <Compile Include="AssemblyInfo.cs" />
index 512748b..b4db65b 100644 (file)
@@ -75,6 +75,7 @@ namespace System.IO.MemoryMappedFiles.Tests
         [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;
index 5903d47..a29a5bf 100644 (file)
@@ -75,6 +75,7 @@ namespace System.IO.MemoryMappedFiles.Tests
         [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;
index 11c22f7..146dffb 100644 (file)
@@ -102,6 +102,7 @@ namespace System.Linq.Expressions.Tests
         }
 
         [Fact]
+        [ActiveIssue ("https://github.com/dotnet/runtime/issues/53599", platforms: TestPlatforms.MacCatalyst, runtimes: TestRuntimes.Mono)]
         public static void ConstructorThrows_StackTrace()
         {
             Expression<Func<Thrower>> e = () => new Thrower(true);
index 1e7fa7a..5eaaaa9 100644 (file)
@@ -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()
index fc54d02..35e223f 100644 (file)
@@ -18,7 +18,8 @@
     <watchOSVersionMin>2.0</watchOSVersionMin>
     <watchOS64_32VersionMin>5.1</watchOS64_32VersionMin>
     <macOSVersionMin>10.13</macOSVersionMin>
-    <macOSVersionMin Condition="'$(TargetOS)' == 'OSX' and '$(TargetArchitecture)' == 'arm64'">11.0</macOSVersionMin>
+    <!-- FIXME: when we're building ios or tvOS cross-compilers hosted on OSX/arm64 targeting ios/arm64 we should set the min macOS version to 11.0, also -->
+    <macOSVersionMin Condition="('$(TargetOS)' == 'OSX' or '$(TargetOS)' == 'MacCatalyst') and '$(TargetArchitecture)' == 'arm64'">11.0</macOSVersionMin>
 
     <!-- Version of the OS SDK we target -->
     <iOSVersion></iOSVersion>
index 38979f4..04f4891 100644 (file)
@@ -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);
index a64fa49..f0168f0 100644 (file)
@@ -42,6 +42,7 @@
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/assembly.h>
+#include <mono/metadata/assembly-internals.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/reflection-internals.h>
 #include <mono/metadata/marshal.h>
@@ -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)
index 7aad2d1..5454871 100644 (file)
@@ -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;
index 0443d8e..7f30902 100644 (file)
@@ -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
index 10cc823..c7ff932 100644 (file)
@@ -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
 }
index fbe2a2f..69893b4 100644 (file)
@@ -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);
 
index e362b69..08ce984 100644 (file)
@@ -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, *))
index 5cbd127..0cea321 100644 (file)
@@ -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:
index 6c238dc..b9718a6 100644 (file)
@@ -3,7 +3,7 @@
     <OutputType>Exe</OutputType>
     <OutputPath>bin</OutputPath>
     <TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
-    <TargetOS>iOS</TargetOS>
+    <TargetOS Condition="'$(TargetOS)' == ''">iOS</TargetOS>
     <TargetOS Condition="'$(TargetsiOSSimulator)' == 'true'">iOSSimulator</TargetOS>
     <MicrosoftNetCoreAppRuntimePackDir>$(ArtifactsBinDir)microsoft.netcore.app.runtime.$(TargetOS.ToLower())-$(TargetArchitecture)\$(Configuration)\runtimes\$(TargetOS.ToLower())-$(TargetArchitecture)\</MicrosoftNetCoreAppRuntimePackDir>
     <EnableTargetingPackDownload>false</EnableTargetingPackDownload>
@@ -18,7 +18,7 @@
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(TargetOS)' == 'MacCatalyst'">
-    <DevTeamProvisioning Condition="'$(TargetOS)' == 'MacCatalyst' and '$(DevTeamProvisioning)' == ''">-</DevTeamProvisioning>
+    <DevTeamProvisioning Condition="'$(TargetOS)' == 'MacCatalyst' and '$(DevTeamProvisioning)' == ''">adhoc</DevTeamProvisioning>
   </PropertyGroup>
 
   <!-- Redirect 'dotnet publish' to in-tree runtime pack -->
       </AotInputAssemblies>
     </ItemGroup>
 
+    <PropertyGroup>
+      <AOTMode Condition="'$(TargetOS)' != 'MacCatalyst'">Full</AOTMode>
+      <AOTMode Condition="'$(TargetOS)' == 'MacCatalyst' and '$(MonoForceInterpreter)' != 'true'">Full</AOTMode>
+      <AOTMode Condition="'$(TargetOS)' == 'MacCatalyst' and '$(MonoForceInterpreter)' == 'true'">JustInterp</AOTMode>
+    </PropertyGroup>
+
     <MonoAOTCompiler
         Condition="'$(RunAOTCompilation)' == 'true'"
         CompilerBinaryPath="$(MonoAotCrossCompilerPath)"
-        Mode="Full"
+        Mode="$(AOTMode)"
         OutputType="AsmOnly"
         Assemblies="@(AotInputAssemblies)"
         AotModulesTablePath="$(AppDir)\modules.m"
@@ -82,7 +88,7 @@
         DevTeamProvisioning="$(DevTeamProvisioning)"
         OutputDirectory="$(AppDir)"
         Optimized="$(Optimized)"
-        ForceAOT="$(ForceAOT)"
+        ForceAOT="$(RunAOTCompilation)"
         ForceInterpreter="$(MonoForceInterpreter)"
         RuntimeComponents="$(RuntimeComponents)"
         DiagnosticPorts="$(DiagnosticPorts)"
 
     <Message Importance="High" Text="Xcode: $(XcodeProjectPath)"/>
     <Message Importance="High" Text="App:   $(AppBundlePath)"/>
+  </Target>
+
+  <Target Name="RunAppBundle"
+          AfterTargets="BuildAppBundle"
+          Condition="'$(ArchiveTests)' != 'true'">
+    <!-- FIXME: only run if the TargetArchitecture matches the current architecture -->
 
     <!-- install and run on ios simulator -->
     <Exec Condition="'$(IosSimulator)' != '' and '$(ArchiveTests)' != 'true'" Command="xcrun simctl shutdown &quot;$(IosSimulator)&quot;" ContinueOnError="WarnAndContinue" />
 
   </Target>
 
-  <Target Name="CopySampleAppToHelixTestDir" 
-          Condition="'$(ArchiveTests)' == 'true'" 
+  <Target Name="CopySampleAppToHelixTestDir"
+          Condition="'$(ArchiveTests)' == 'true'"
           AfterTargets="Build"
           DependsOnTargets="Publish;BuildAppBundle" >
     <PropertyGroup>
index 68ce0e1..b436241 100644 (file)
@@ -198,7 +198,7 @@ public class AppleAppBuilderTask : Task
             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");
         }
index e454555..e0eb0a7 100644 (file)
@@ -293,16 +293,24 @@ mono_ios_runtime_init (void)
 
     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);
     mono_install_assembly_preload_hook (assembly_preload_hook, NULL);
     mono_install_load_aot_data_hook (load_aot_data, free_aot_data, NULL);
index 4409043..d237434 100644 (file)
@@ -198,7 +198,8 @@ internal class Xcode
         {
             defines.AppendLine("add_definitions(-DFORCE_INTERPRETER=1)");
         }
-        else if (forceAOT)
+
+        if (forceAOT)
         {
             defines.AppendLine("add_definitions(-DFORCE_AOT=1)");
         }