diff --git a/runtime/runtime.m b/runtime/runtime.m index 2289e3d3d8..80a17f17c5 100644 --- a/runtime/runtime.m +++ b/runtime/runtime.m @@ -79,6 +79,8 @@ bool xamarin_is_gc_coop = true; #else bool xamarin_is_gc_coop = false; #endif +enum MarshalObjectiveCExceptionMode xamarin_marshal_objectivec_exception_mode = MarshalObjectiveCExceptionModeDefault; +enum MarshalManagedExceptionMode xamarin_marshal_managed_exception_mode = MarshalManagedExceptionModeDefault; /* Callbacks */ diff --git a/runtime/xamarin/main.h b/runtime/xamarin/main.h index a9dfb06932..4aa8b38e29 100644 --- a/runtime/xamarin/main.h +++ b/runtime/xamarin/main.h @@ -19,6 +19,24 @@ extern "C" { #endif +/* This enum must always match the identical enum in src/ObjCRuntime/ExceptionMode.cs */ +enum MarshalObjectiveCExceptionMode : int { + MarshalObjectiveCExceptionModeDefault = 0, + MarshalObjectiveCExceptionModeUnwindManagedCode = 1, + MarshalObjectiveCExceptionModeThrowManagedException = 2, + MarshalObjectiveCExceptionModeAbort = 3, + MarshalObjectiveCExceptionModeDisable = 4, +}; + +/* This enum must always match the identical enum in src/ObjCRuntime/ExceptionMode.cs */ +enum MarshalManagedExceptionMode : int { + MarshalManagedExceptionModeDefault = 0, + MarshalManagedExceptionModeUnwindNativeCode = 1, + MarshalManagedExceptionModeThrowObjectiveCException = 2, + MarshalManagedExceptionModeAbort = 3, + MarshalManagedExceptionModeDisable = 4, +}; + extern bool mono_use_llvm; // this is defined inside mono extern bool xamarin_use_new_assemblies; @@ -32,6 +50,8 @@ extern int xamarin_log_level; extern const char *xamarin_executable_name; extern const char *xamarin_arch_name; extern bool xamarin_is_gc_coop; +extern enum MarshalObjectiveCExceptionMode xamarin_marshal_objectivec_exception_mode; +extern enum MarshalManagedExceptionMode xamarin_marshal_managed_exception_mode; #ifdef MONOTOUCH extern NSString* xamarin_crashlytics_api_key; diff --git a/src/ObjCRuntime/ExceptionMode.cs b/src/ObjCRuntime/ExceptionMode.cs new file mode 100644 index 0000000000..557f3d58fe --- /dev/null +++ b/src/ObjCRuntime/ExceptionMode.cs @@ -0,0 +1,30 @@ +// +// ExceptionMode.cs: +// +// Authors: +// Rolf Bjarne Kvinge +// +// Copyright 2016 Xamarin Inc. + +using System; +using XamCore.Foundation; + +namespace XamCore.ObjCRuntime { + /* This enum must always match the identical enum in runtime/xamarin/main.h */ + public enum MarshalObjectiveCExceptionMode { + Default = 0, + UnwindManagedCode = 1, // not available for watchOS/COOP, default for the other platforms + ThrowManagedException = 2, // default for watchOS/COOP + Abort = 3, + Disable = 4, // this will also prevent the corresponding event from working + } + + /* This enum must always match the identical enum in runtime/xamarin/main.h */ + public enum MarshalManagedExceptionMode { + Default = 0, + UnwindNativeCode = 1, // not available for watchOS/COOP, default for the other platforms + ThrowObjectiveCException = 2, // default for watchOS/COOP + Abort = 3, + Disable = 4, // this will also prevent the corresponding event from working + } +} diff --git a/src/frameworks.sources b/src/frameworks.sources index b97fd8caa6..08850f9fe9 100644 --- a/src/frameworks.sources +++ b/src/frameworks.sources @@ -1393,6 +1393,7 @@ SHARED_SOURCES = \ ObjCRuntime/Dlfcn.cs \ ObjCRuntime/DynamicRegistrar.cs \ ObjCRuntime/ErrorHelper.cs \ + ObjCRuntime/ExceptionMode.cs \ ObjCRuntime/IDynamicRegistrar.cs \ ObjCRuntime/Method.cs \ ObjCRuntime/MethodDescription.cs \ diff --git a/tools/common/Application.cs b/tools/common/Application.cs index d52e3d7bf5..06faad4b03 100644 --- a/tools/common/Application.cs +++ b/tools/common/Application.cs @@ -9,6 +9,8 @@ using Mono.Cecil.Mdb; using Xamarin.Utils; +using XamCore.ObjCRuntime; + namespace Xamarin.Bundler { [Flags] @@ -44,6 +46,8 @@ namespace Xamarin.Bundler { public Mono.Linker.I18nAssemblies I18n; public bool? EnableCoopGC; + public MarshalObjectiveCExceptionMode MarshalObjectiveCExceptions; + public MarshalManagedExceptionMode MarshalManagedExceptions; public string PlatformName { get { @@ -338,6 +342,41 @@ namespace Xamarin.Bundler { if (!EnableCoopGC.HasValue) EnableCoopGC = Platform == ApplePlatform.WatchOS; + + if (EnableCoopGC.Value) { + switch (MarshalObjectiveCExceptions) { + case MarshalObjectiveCExceptionMode.UnwindManagedCode: + case MarshalObjectiveCExceptionMode.Disable: + throw ErrorHelper.CreateError (89, "The option '{0}' cannot take the value '{1}' when the Coop GC is enabled.", "--marshal-objectivec-exceptions", MarshalObjectiveCExceptions.ToString ().ToLowerInvariant ()); + } + switch (MarshalManagedExceptions) { + case MarshalManagedExceptionMode.UnwindNativeCode: + case MarshalManagedExceptionMode.Disable: + throw ErrorHelper.CreateError (89, "The option '{0}' cannot take the value '{1}' when the Coop GC is enabled.", "--marshal-managed-exceptions", MarshalManagedExceptions.ToString ().ToLowerInvariant ()); + } + } + + + bool isSimulatorOrDesktopDebug = EnableDebug; +#if MTOUCH + isSimulatorOrDesktopDebug &= IsSimulatorBuild; +#endif + + if (MarshalObjectiveCExceptions == MarshalObjectiveCExceptionMode.Default) { + if (EnableCoopGC.Value) { + MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.ThrowManagedException; + } else { + MarshalObjectiveCExceptions = isSimulatorOrDesktopDebug ? MarshalObjectiveCExceptionMode.UnwindManagedCode : MarshalObjectiveCExceptionMode.Disable; + } + } + + if (MarshalManagedExceptions == MarshalManagedExceptionMode.Default) { + if (EnableCoopGC.Value) { + MarshalManagedExceptions = MarshalManagedExceptionMode.ThrowObjectiveCException; + } else { + MarshalManagedExceptions = isSimulatorOrDesktopDebug ? MarshalManagedExceptionMode.UnwindNativeCode : MarshalManagedExceptionMode.Disable; + } + } } } } diff --git a/tools/common/Driver.cs b/tools/common/Driver.cs index a0a2baa0e3..f0a0ba554e 100644 --- a/tools/common/Driver.cs +++ b/tools/common/Driver.cs @@ -14,12 +14,59 @@ using System.Runtime.InteropServices; using System.Text; using Xamarin.Utils; +using XamCore.ObjCRuntime; namespace Xamarin.Bundler { public partial class Driver { static void AddSharedOptions (Mono.Options.OptionSet options) { options.Add ("coop:", "If the Coop GC should be used.", v => { App.EnableCoopGC = ParseBool (v, "coop"); }, hidden: true); + options.Add ("marshal-objectivec-exceptions:", v => { + switch (v) { + case "default": + App.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Default; + break; + case "unwindmanaged": + case "unwindmanagedcode": + App.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.UnwindManagedCode; + break; + case "throwmanaged": + case "throwmanagedexception": + App.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.ThrowManagedException; + break; + case "abort": + App.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Abort; + break; + case "disable": + App.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Disable; + break; + default: + throw ErrorHelper.CreateError (26, "Could not parse the command line argument '{0}': {1}", "--marshal-objective-exceptions", "Invalid value: " + v); + } + }); + options.Add ("marshal-managed-exceptions:", v => { + switch (v) { + case "default": + App.MarshalManagedExceptions = MarshalManagedExceptionMode.Default; + break; + case "unwindnative": + case "unwindnativecode": + App.MarshalManagedExceptions = MarshalManagedExceptionMode.UnwindNativeCode; + break; + case "throwobjectivec": + case "throwobjectivecexception": + App.MarshalManagedExceptions = MarshalManagedExceptionMode.ThrowObjectiveCException; + break; + case "abort": + App.MarshalManagedExceptions = MarshalManagedExceptionMode.Abort; + break; + case "disable": + App.MarshalManagedExceptions = MarshalManagedExceptionMode.Disable; + break; + default: + throw ErrorHelper.CreateError (26, "Could not parse the command line argument '{0}': {1}", "--marshal-managed-exceptions", "Invalid value: " + v); + } + }); } #if MONOMAC diff --git a/tools/mmp/Makefile b/tools/mmp/Makefile index d2b5e59926..bcc577be9b 100644 --- a/tools/mmp/Makefile +++ b/tools/mmp/Makefile @@ -97,6 +97,7 @@ mmp_sources = \ $(TOP)/tools/common/cache.cs \ driver.cs \ $(TOP)/src/ObjCRuntime/ErrorHelper.cs \ + $(TOP)/src/ObjCRuntime/ExceptionMode.cs \ error.cs \ resolver.cs \ $(MONO_PATH)/mcs/class/Mono.Options/Mono.Options/Options.cs \ diff --git a/tools/mmp/driver.cs b/tools/mmp/driver.cs index 51eba6ac00..481565c262 100644 --- a/tools/mmp/driver.cs +++ b/tools/mmp/driver.cs @@ -48,6 +48,7 @@ using Mono.Tuner; using MonoMac.Tuner; using Xamarin.Utils; using Xamarin.Linker; +using XamCore.ObjCRuntime; namespace Xamarin.Bundler { public enum RegistrarMode { @@ -877,6 +878,8 @@ namespace Xamarin.Bundler { sw.WriteLine ("\txamarin_custom_bundle_name = @\"" + custom_bundle_name + "\";"); } sw.WriteLine ("\txamarin_use_il_registrar = {0};", registrar == RegistrarMode.IL ? "true" : "false"); + sw.WriteLine ("\txamarin_marshal_managed_exception_mode = MarshalManagedExceptionMode{0};", App.MarshalManagedExceptions); + sw.WriteLine ("\txamarin_marshal_objectivec_exception_mode = MarshalObjectiveCExceptionMode{0};", App.MarshalObjectiveCExceptions); sw.WriteLine (); if (Driver.registrar == RegistrarMode.Static) sw.WriteLine ("\txamarin_create_classes ();"); diff --git a/tools/mmp/error.cs b/tools/mmp/error.cs index 512db7b561..6211489ba6 100644 --- a/tools/mmp/error.cs +++ b/tools/mmp/error.cs @@ -34,6 +34,7 @@ namespace Xamarin.Bundler { // MM0079 Internal Error - No executable was copied into the app bundle. Please contact 'support@xamarin.com' // Warning MT0080 Disabling NewRefCount, --new-refcount:false, is deprecated. // MM0088 ** Reserved mtouch ** + // MM0089 ** Reserved mtouch ** // MM1xxx file copy / symlinks (project related) // MM14xx Product assemblies // MM1401 The required '{0}' assembly is missing from the references diff --git a/tools/mmp/mmp.csproj b/tools/mmp/mmp.csproj index 600c5c7324..40bb50d242 100644 --- a/tools/mmp/mmp.csproj +++ b/tools/mmp/mmp.csproj @@ -263,6 +263,9 @@ external\ErrorHelper.cs + + external\ExceptionMode.cs + external\Registrar.cs diff --git a/tools/mtouch/Makefile b/tools/mtouch/Makefile index ff063f80c3..e77afca594 100644 --- a/tools/mtouch/Makefile +++ b/tools/mtouch/Makefile @@ -91,6 +91,7 @@ COMMON_SOURCES = \ $(TOP)/src/build/ios/Constants.cs \ error.cs \ $(TOP)/src/ObjCRuntime/ErrorHelper.cs \ + $(TOP)/src/ObjCRuntime/ExceptionMode.cs \ $(MONO_DIR)/mcs/class/Mono.Options/Mono.Options/Options.cs MTOUCH_SOURCES = \ diff --git a/tools/mtouch/error.cs b/tools/mtouch/error.cs index 512374ba73..62389dcd06 100644 --- a/tools/mtouch/error.cs +++ b/tools/mtouch/error.cs @@ -96,6 +96,7 @@ namespace Xamarin.Bundler { // MT0086 A target framework (--target-framework) must be specified when building for TVOS or WatchOS. // Warning MT0087 // MT0088 Cannot disable the Coop GC for watchOS apps. Please remove the --coop:false argument to mtouch. + // MT0089 The option '{0}' cannot take the value '{1}' when the Coop GC is enabled. // MT0091 This version of Xamarin.iOS requires the {0} {1} SDK (shipped with Xcode {2}) when the managed linker is disabled. Either upgrade Xcode, or enable the managed linker. // MT0092 The option '{0}' is required. // MT0093 Could not find 'mlaunch'. diff --git a/tools/mtouch/mtouch.cs b/tools/mtouch/mtouch.cs index 408242453a..0230144821 100644 --- a/tools/mtouch/mtouch.cs +++ b/tools/mtouch/mtouch.cs @@ -63,6 +63,7 @@ using Mono.Tuner; using MonoTouch.Tuner; using XamCore.Registrar; +using XamCore.ObjCRuntime; using Xamarin.Linker; using Xamarin.Utils; @@ -651,6 +652,8 @@ namespace Xamarin.Bundler sw.WriteLine ("\tmono_use_llvm = {0};", enable_llvm ? "TRUE" : "FALSE"); sw.WriteLine ("\txamarin_log_level = {0};", verbose); sw.WriteLine ("\txamarin_arch_name = \"{0}\";", abi.AsArchString ()); + sw.WriteLine ("\txamarin_marshal_managed_exception_mode = MarshalManagedExceptionMode{0};", app.MarshalManagedExceptions); + sw.WriteLine ("\txamarin_marshal_objectivec_exception_mode = MarshalObjectiveCExceptionMode{0};", app.MarshalObjectiveCExceptions); if (app.EnableDebug) sw.WriteLine ("\txamarin_debug_mode = TRUE;"); if (!string.IsNullOrEmpty (app.MonoGCParams)) @@ -907,6 +910,9 @@ namespace Xamarin.Bundler if (app.Registrar == RegistrarMode.Static || app.Registrar == RegistrarMode.LegacyStatic || app.Registrar == RegistrarMode.LegacyDynamic) return false; + if (app.MarshalObjectiveCExceptions != MarshalObjectiveCExceptionMode.Default || app.Platform == ApplePlatform.WatchOS) + return false; + return true; } diff --git a/tools/mtouch/mtouch.csproj b/tools/mtouch/mtouch.csproj index 7b5e9644cf..4124bd5150 100644 --- a/tools/mtouch/mtouch.csproj +++ b/tools/mtouch/mtouch.csproj @@ -317,6 +317,9 @@ external\ErrorHelper.cs + + external\ExceptionMode.cs + diff --git a/tools/mtouch/simlauncher.m b/tools/mtouch/simlauncher.m index 79aa558c35..406ae9c58a 100644 --- a/tools/mtouch/simlauncher.m +++ b/tools/mtouch/simlauncher.m @@ -21,6 +21,12 @@ void xamarin_setup_impl () xamarin_create_classes_Xamarin_iOS (); #else xamarin_use_new_assemblies = FALSE; +#endif + xamarin_marshal_managed_exception_mode = MarshalManagedExceptionModeDisable; +#if DEBUG + xamarin_marshal_objectivec_exception_mode = MarshalObjectiveCExceptionModeUnwindManagedCode; +#else + xamarin_marshal_objectivec_exception_mode = MarshalObjectiveCExceptionModeDisabled; #endif }