From d237df718e748409e9dfab1b0cf6538ae2b42bb0 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Wed, 25 Jan 2023 11:01:38 +0100 Subject: [PATCH] [runtime] Create a version of our runtime that can be used with NativeAOT. This contributes towards https://github.com/xamarin/xamarin-macios/issues/17339. --- Make.config | 4 +++ mk/rules.mk | 2 ++ runtime/Makefile | 19 +++++++++++++- runtime/coreclr-bridge.m | 13 ++++++--- runtime/nativeaot-bridge.m | 42 ++++++++++++++++++++++++++++++ runtime/runtime.m | 2 ++ runtime/xamarin/nativeaot-bridge.h | 26 ++++++++++++++++++ src/ObjCRuntime/Runtime.cs | 14 ++++++++++ 8 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 runtime/nativeaot-bridge.m create mode 100644 runtime/xamarin/nativeaot-bridge.h diff --git a/Make.config b/Make.config index bea6e8b483ff..03eb0da13e78 100644 --- a/Make.config +++ b/Make.config @@ -682,6 +682,7 @@ DOTNET_PLATFORMS= ifdef INCLUDE_IOS DOTNET_PLATFORMS+=iOS DOTNET_IOS_BITNESSES+=64 +DOTNET_NATIVEAOT_PLATFORMS+=iOS # 32-bit architectures ifdef IOS_SUPPORTS_32BIT_ARCHITECTURES @@ -705,6 +706,7 @@ endif # INCLUDE_IOS ifdef INCLUDE_TVOS DOTNET_PLATFORMS+=tvOS DOTNET_TVOS_BITNESSES+=64 +DOTNET_NATIVEAOT_PLATFORMS+=tvOS ifdef INCLUDE_DEVICE DOTNET_TVOS_RUNTIME_IDENTIFIERS=tvos-arm64 tvossimulator-x64 tvossimulator-arm64 else @@ -728,6 +730,7 @@ endif ifdef INCLUDE_MACCATALYST DOTNET_PLATFORMS+=MacCatalyst DOTNET_MACCATALYST_BITNESSES+=64 +DOTNET_NATIVEAOT_PLATFORMS+=MacCatalyst DOTNET_MACCATALYST_RUNTIME_IDENTIFIERS=maccatalyst-x64 maccatalyst-arm64 DOTNET_MACCATALYST_RUNTIME_IDENTIFIERS_64+=$(DOTNET_MACCATALYST_RUNTIME_IDENTIFIERS) endif @@ -736,6 +739,7 @@ ifdef INCLUDE_MAC DOTNET_PLATFORMS+=macOS DOTNET_CORECLR_PLATFORMS+=macOS DOTNET_MACOS_BITNESSES+=64 +DOTNET_NATIVEAOT_PLATFORMS+=macOS DOTNET_MACOS_RUNTIME_IDENTIFIERS=osx-x64 osx-arm64 DOTNET_MACOS_RUNTIME_IDENTIFIERS_64=$(DOTNET_MACOS_RUNTIME_IDENTIFIERS) endif diff --git a/mk/rules.mk b/mk/rules.mk index 2d309e3389fa..6910cdda651e 100644 --- a/mk/rules.mk +++ b/mk/rules.mk @@ -297,6 +297,8 @@ $(eval $(call NativeCompilationTemplate,-dotnet,-O2 -DDOTNET)) $(eval $(call NativeCompilationTemplate,-dotnet-debug,-DDEBUG -DDOTNET)) $(eval $(call NativeCompilationTemplate,-dotnet-coreclr,-O2 -DCORECLR_RUNTIME -DDOTNET)) $(eval $(call NativeCompilationTemplate,-dotnet-coreclr-debug,-DDEBUG -DCORECLR_RUNTIME -DDOTNET)) +$(eval $(call NativeCompilationTemplate,-dotnet-nativeaot,-O2 -DCORECLR_RUNTIME -DDOTNET -DNATIVEAOT)) +$(eval $(call NativeCompilationTemplate,-dotnet-nativeaot-debug,-DDEBUG -DCORECLR_RUNTIME -DDOTNET -DNATIVEAOT)) .libs/iphoneos .libs/iphonesimulator .libs/watchos .libs/watchsimulator .libs/tvos .libs/tvsimulator .libs/maccatalyst .libs/mac: $(Q) mkdir -p $@ diff --git a/runtime/Makefile b/runtime/Makefile index 2db40b5d7b0f..ea15e991e25c 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -22,7 +22,7 @@ SHIPPED_HEADERS += \ xamarin/monovm-bridge.h \ xamarin/coreclr-bridge.h \ -SHARED_SOURCES += mono-runtime.m bindings.m bindings-generated.m shared.m runtime.m trampolines.m trampolines-invoke.m xamarin-support.m nsstring-localization.m trampolines-varargs.m monovm-bridge.m coreclr-bridge.m +SHARED_SOURCES += mono-runtime.m bindings.m bindings-generated.m shared.m runtime.m trampolines.m trampolines-invoke.m xamarin-support.m nsstring-localization.m trampolines-varargs.m monovm-bridge.m coreclr-bridge.m nativeaot-bridge.m SHARED_I386_SOURCES += trampolines-i386.m trampolines-i386-asm.s trampolines-i386-objc_msgSend.s trampolines-i386-objc_msgSendSuper.s trampolines-i386-objc_msgSend_stret.s trampolines-i386-objc_msgSendSuper_stret.s SHARED_X86_64_SOURCES += trampolines-x86_64.m trampolines-x86_64-asm.s trampolines-x86_64-objc_msgSend.s trampolines-x86_64-objc_msgSendSuper.s trampolines-x86_64-objc_msgSend_stret.s trampolines-x86_64-objc_msgSendSuper_stret.s SHARED_ARM64_SOURCES += trampolines-arm64.m trampolines-arm64-asm.s trampolines-arm64-objc_msgSend.s trampolines-arm64-objc_msgSendSuper.s @@ -454,6 +454,11 @@ MAC_LIBS = \ # This is used when using the CoreCLR runtime instead of Mono. # CORECLR_RUNTIME is defined for these versions of libxamarin. # +# libxamarin-nativeaot.a: +# This is used when using NativeAOT. +# CORECLR_RUNTIME is defined for these versions of libxamarin (because the nativeaot bridge shares *a lot* of code with the coreclr bridge) +# NATIVEAOT is defined for these versions of libxamarin +# ifdef INCLUDE_XAMARIN_LEGACY all-local:: $(TARGETS) @@ -614,6 +619,15 @@ endef $(foreach platform,$(DOTNET_CORECLR_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(eval $(call DotNetCoreClrLibTemplate,$(platform),$(rid))))) +define DotNetNativeAotLibTemplate +DOTNET_TARGETS += \ + $(DOTNET_DESTDIR)/Microsoft.$(1).Runtime.$(2)/runtimes/$(2)/native/libxamarin-dotnet-nativeaot.a \ + $(DOTNET_DESTDIR)/Microsoft.$(1).Runtime.$(2)/runtimes/$(2)/native/libxamarin-dotnet-nativeaot-debug.a \ + +endef + +$(foreach platform,$(DOTNET_NATIVEAOT_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(eval $(call DotNetNativeAotLibTemplate,$(platform),$(rid))))) + # a few lookup tables, because the data we have is not always in the format we need it DOTNET_iphonesimulator_DYLIB_FLAGS=-lmonosgen-2.0 -licudata -licui18n -licuuc -framework UIKit DOTNET_iphoneos_DYLIB_FLAGS=-lmonosgen-2.0 -licudata -licui18n -licuuc -framework UIKit @@ -704,6 +718,8 @@ $(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIM $(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(foreach arch,$(DOTNET_$(rid)_ARCHITECTURES),$(eval $(call DotNetLibXamarinTemplate,$(DOTNET_$(rid)_SDK_PLATFORM),$(rid),$(arch),_DEBUG,-dotnet-debug,,.mono))))) $(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(foreach arch,$(DOTNET_$(rid)_ARCHITECTURES),$(eval $(call DotNetLibXamarinTemplate,$(DOTNET_$(rid)_SDK_PLATFORM),$(rid),$(arch),_CORECLR,-dotnet-coreclr,_CORECLR))))) $(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(foreach arch,$(DOTNET_$(rid)_ARCHITECTURES),$(eval $(call DotNetLibXamarinTemplate,$(DOTNET_$(rid)_SDK_PLATFORM),$(rid),$(arch),_CORECLR_DEBUG,-dotnet-coreclr-debug,_CORECLR))))) +$(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(foreach arch,$(DOTNET_$(rid)_ARCHITECTURES),$(eval $(call DotNetLibXamarinTemplate,$(DOTNET_$(rid)_SDK_PLATFORM),$(rid),$(arch),_NATIVEAOT,-dotnet-nativeaot,_NATIVEAOT,.mono))))) +$(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(foreach arch,$(DOTNET_$(rid)_ARCHITECTURES),$(eval $(call DotNetLibXamarinTemplate,$(DOTNET_$(rid)_SDK_PLATFORM),$(rid),$(arch),_NATIVEAOT_DEBUG,-dotnet-nativeaot-debug,_NATIVEAOT,.mono))))) # # DotNetLibExtensionTemplate builds lib[tv]extension.a @@ -731,6 +747,7 @@ endef $(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(foreach arch,$(DOTNET_$(rid)_ARCHITECTURES),$(eval $(call DotNetLibExtensionTemplate,$(DOTNET_$(rid)_SDK_PLATFORM),$(rid),$(arch),,-dotnet,,))))) $(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(foreach arch,$(DOTNET_$(rid)_ARCHITECTURES),$(eval $(call DotNetLibExtensionTemplate,$(DOTNET_$(rid)_SDK_PLATFORM),$(rid),$(arch),_CORECLR,-dotnet-coreclr,_CORECLR))))) +$(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(foreach arch,$(DOTNET_$(rid)_ARCHITECTURES),$(eval $(call DotNetLibExtensionTemplate,$(DOTNET_$(rid)_SDK_PLATFORM),$(rid),$(arch),_NATOVEAOT,-dotnet-nativeaot,_NATOVEAOT))))) dotnet: $(DOTNET_TARGETS) diff --git a/runtime/coreclr-bridge.m b/runtime/coreclr-bridge.m index 287c3f963534..ba7ec923e6fc 100644 --- a/runtime/coreclr-bridge.m +++ b/runtime/coreclr-bridge.m @@ -11,6 +11,7 @@ #include #include #include +#include #include "product.h" #include "runtime-internal.h" @@ -477,6 +478,7 @@ munmap ((void *) buf, fd_len); } +#if !defined (NATIVEAOT) bool xamarin_bridge_vm_initialize (int propertyCount, const char **propertyKeys, const char **propertyValues) { @@ -510,6 +512,7 @@ return rv == 0; } +#endif // !defined (NATIVEAOT) void xamarin_install_nsautoreleasepool_hooks () @@ -537,18 +540,20 @@ xamarin_assertion_message ("%s threw an exception: %p = %s", method, gchandle, [xamarin_print_all_exceptions (gchandle) UTF8String]); } -typedef void (*xamarin_runtime_initialize_decl)(struct InitializationOptions* options); +#if !defined (NATIVEAOT) +typedef void (*xamarin_runtime_initialize_decl)(struct InitializationOptions* options, GCHandle* exception_gchandle); void xamarin_bridge_call_runtime_initialize (struct InitializationOptions* options, GCHandle* exception_gchandle) { void *del = NULL; - int rv = coreclr_create_delegate (coreclr_handle, coreclr_domainId, PRODUCT ", Version=0.0.0.0", "ObjCRuntime.Runtime", "Initialize", &del); + int rv = coreclr_create_delegate (coreclr_handle, coreclr_domainId, PRODUCT ", Version=0.0.0.0", "ObjCRuntime.Runtime", "SafeInitialize", &del); if (rv != 0) xamarin_assertion_message ("xamarin_bridge_call_runtime_initialize: failed to create delegate: %i\n", rv); xamarin_runtime_initialize_decl runtime_initialize = (xamarin_runtime_initialize_decl) del; - runtime_initialize (options); + runtime_initialize (options, exception_gchandle); } +#endif // !defined (NATIVEAOT) void xamarin_bridge_register_product_assembly (GCHandle* exception_gchandle) @@ -737,6 +742,7 @@ return rv; } +#if !defined (NATIVEAOT) int mono_jit_exec (MonoDomain * domain, MonoAssembly * assembly, int argc, const char** argv) { @@ -766,6 +772,7 @@ return (int) exitCode; } +#endif // !defined (NATIVEAOT) MonoGHashTable * mono_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type) diff --git a/runtime/nativeaot-bridge.m b/runtime/nativeaot-bridge.m new file mode 100644 index 000000000000..74587bb31399 --- /dev/null +++ b/runtime/nativeaot-bridge.m @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* +* Authors: Rolf Bjarne Kvinge +* +* Copyright (C) 2023 Microsoft Corp. +* +*/ + +#if defined (NATIVEAOT) + +#include +#include +#include +#include +#include + +#include "product.h" +#include "runtime-internal.h" +#include "slinked-list.h" +#include "xamarin/xamarin.h" +#include "xamarin/coreclr-bridge.h" +#include "xamarin/nativeaot-bridge.h" + +void +xamarin_bridge_call_runtime_initialize (struct InitializationOptions* options, GCHandle* exception_gchandle) +{ + xamarin_objcruntime_runtime_nativeaotinitialize (options, exception_gchandle); +} + +bool +xamarin_bridge_vm_initialize (int propertyCount, const char **propertyKeys, const char **propertyValues) +{ + return true; +} + +int +mono_jit_exec (MonoDomain * domain, MonoAssembly * assembly, int argc, const char** argv) +{ + return __managed__Main (argc, argv); +} + +#endif // NATIVEAOT diff --git a/runtime/runtime.m b/runtime/runtime.m index b38ff6661f8a..5b08ef437011 100644 --- a/runtime/runtime.m +++ b/runtime/runtime.m @@ -1304,12 +1304,14 @@ -(void) xamarinSetFlags: (enum XamarinGCHandleFlags) flags; #endif #if defined (CORECLR_RUNTIME) +#if !defined(__arm__) // the dynamic trampolines haven't been implemented in 32-bit ARM assembly. options.xamarin_objc_msgsend = (void *) xamarin_dyn_objc_msgSend; options.xamarin_objc_msgsend_super = (void *) xamarin_dyn_objc_msgSendSuper; #if !defined(__aarch64__) options.xamarin_objc_msgsend_stret = (void *) xamarin_dyn_objc_msgSend_stret; options.xamarin_objc_msgsend_super_stret = (void *) xamarin_dyn_objc_msgSendSuper_stret; #endif // !defined(__aarch64__) +#endif // !defined(__arm__) options.unhandled_exception_handler = (void *) &xamarin_coreclr_unhandled_exception_handler; options.reference_tracking_begin_end_callback = (void *) &xamarin_coreclr_reference_tracking_begin_end_callback; options.reference_tracking_is_referenced_callback = (void *) &xamarin_coreclr_reference_tracking_is_referenced_callback; diff --git a/runtime/xamarin/nativeaot-bridge.h b/runtime/xamarin/nativeaot-bridge.h new file mode 100644 index 000000000000..6de5ad88117b --- /dev/null +++ b/runtime/xamarin/nativeaot-bridge.h @@ -0,0 +1,26 @@ + +/* Support for using NativeAOT */ + +#if defined (NATIVEAOT) + +#ifndef __NATIVEAOT_BRIDGE__ +#define __NATIVEAOT_BRIDGE__ + +#include + +#include "runtime.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void xamarin_objcruntime_runtime_nativeaotinitialize (struct InitializationOptions* options, GCHandle* exception_gchandle); +int __managed__Main (int argc, const char** argv); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __NATIVEAOT_BRIDGE__ */ + +#endif // NATIVEAOT diff --git a/src/ObjCRuntime/Runtime.cs b/src/ObjCRuntime/Runtime.cs index f411a851b93e..7d63d96aba60 100644 --- a/src/ObjCRuntime/Runtime.cs +++ b/src/ObjCRuntime/Runtime.cs @@ -249,6 +249,20 @@ internal static bool Initialized { static extern int _NSGetExecutablePath (byte[] buf, ref int bufsize); #endif +#if NET + [Preserve] // called from native - nativeaot-bridge.m and coreclr-bridge.m. + [UnmanagedCallersOnly (EntryPoint = "xamarin_objcruntime_runtime_nativeaotinitialize")] + unsafe static void SafeInitialize (InitializationOptions* options, IntPtr* exception_gchandle) + { + *exception_gchandle = IntPtr.Zero; + try { + Initialize (options); + } catch (Exception e) { + *exception_gchandle = AllocGCHandle (e); + } + } +#endif + [Preserve] // called from native - runtime.m. [BindingImpl (BindingImplOptions.Optimizable)] // To inline the Runtime.DynamicRegistrationSupported code if possible. unsafe static void Initialize (InitializationOptions* options)