If an extension is sharing code with the container app, then assemblies may be
placed in:
* The container app's Framework directory (for assemblies whose code is
shared, and the build action is 'framework'). We already handle this case.
* The container app's root directory (for assemblies whose code is shared, and
the build action is not 'framework'). This case we didn't handle, and we're
now fixing it.
* In the extension (for assemblies whose code is not shared). We already
handle this case.
Add support for finding assembly-related resources (debug files, config files,
satellite assemblies, aotdata files, etc) in multiple locations:
* The bundle's root directory.
* A pointer-size specific size directory (.monotouch-32|64)
* A framework's MonoBundle directory (and the framework may not be named after
the assembly, which means it's not necessarily possible to deduce the
framework's name at runtime).
* In a container bundle.
Some files may also have an arch-specific suffix.
* [XM] Seperate parsing from compilation in AOT code
- Parsing command line options was too entangled with actually compiling
- Refactor test code to centralize Compile, reducing some complexity of tests
- Groundwork for hybrid vs non-hybrid AOT work
* Add hybrid/standard AOT support
* Add xammac_tests to makefile/jenkins
* Add flag to force AOT
* Disable MonoTouchFixtures.Contacts.ContactStoreTest.GetUnifiedContacts on XM due to prompts on Jenkins
Use metadata tokens instead of strings to find types and methods.
This makes the code to find methods more compact (a lot less strings in the
executable, and additionally in most cases a compact representation (32-bit
integer) of the corresponding metadata token and additional information can be
used, which results in less executable code (fewer parameters to methods,
etc)), resulting in smaller executables.
Size savings are around 200kb for dont link apps, and 20-60kb for linked apps
(this obviously varies a lot depending on how much has to registered by the
registrar).
| | Before | After | Diff |
|----------------|--------------:|--------------:|------------------:|
| dontlink/32bit | 102.810.144 | 102.609.456 | -200.688 = -0,20% |
| dontlink/64bit | 107.420.576 | 107.221.792 | -198.784 = -0,19% |
| linksdk/32bit | 40.957.296 | 40.936.864 | -20.432 = -0,05% |
| linksdk/64bit | 43.113.136 | 43.093.936 | -19.200 = -0,04% |
| linkall/32bit | 38.410.032 | 38.348.288 | -61.744 = -0,16% |
| linkall/64bit | 40.315.200 | 40.267.344 | -47.856 = -0,12% |
Additionally I've removed the `lazy_map` dictionary, which we populated at
startup and was used to map between Class instances and the corresponding
managed type's FullName, and instead iterate over a native array of Class ->
metadata token mappings whenever we need to look up the managed type for a
certain Class instance.
This is slightly slower for each type we need to look up (for a non-linked app
there might be a 2000-3000 entries in the native array, which would be
iterated instead of using a hashtable lookup), but it's only done once per
type and there's a significant startup memory improvement.
For a non-linked test app I get the following using the Xamarin profiler:
| | Before | After | Diff |
|-------------------|--------:|--------:|----------------:|
| Memory allocated | 2,8 MB | 2,4 MB | -0,4 MB = -14 % |
| Objects allocated | 43678 | 38463 | -5215 = -12 % |
| Private bytes | 26,6 MB | 24,4 MB | -2,2 MB = -8,3% |
| Working set | 26,6 MB | 24,4 MB | -2,2 MB = -8,3% |
Managed exception marshaling interferes with the debugger, because it adds
exception handlers to executing code, which makes the Mono runtime think an
exception is handled when logically it's not (although technically it is).
The consequence is that the IDEs will only be notified when we re-throw the
exception after catching it, making it impossible for the IDEs to stop when
the exception is thrown (they will instead stop when we re-throw the
exception).
So disable managed exception marshaling (unless the user changed the default
behavior) when a debugger is attached.
This is the same behavior as Xamarin.Android.
https://bugzilla.xamarin.com/show_bug.cgi?id=45116
Setting this option prints this to stdout:
> Mono Warning: option gen-compact-seq-points is deprecated.
and it's ignored, so just don't set this option.
Example code:
public override void ViewDidLoad ()
{
throw new Exception ("USELESS");
}
Current output with unhandled exceptions that are marshaled:
Unhandled Exception:
System.Exception: USELESS
at (wrapper managed-to-native) AppKit.NSApplication:NSApplicationMain (int,string[])
at AppKit.NSApplication.Main (System.String[] args) [0x00041] in /work/maccore/master/xamarin-macios/src/AppKit/NSApplication.cs:98
at UselessExceptions.MainClass.Main (System.String[] args) [0x00007] in /Users/rolf/Downloads/filed-bug-test-cases-master/Xamarin/bxc45742/Main.cs:10
[ERROR] FATAL UNHANDLED EXCEPTION: UselessExceptions.CustomException: USELESS
at (wrapper managed-to-native) AppKit.NSApplication:NSApplicationMain (int,string[])
at AppKit.NSApplication.Main (System.String[] args) [0x00041] in /work/maccore/master/xamarin-macios/src/AppKit/NSApplication.cs:98
at UselessExceptions.MainClass.Main (System.String[] args) [0x00007] in /Users/rolf/Downloads/filed-bug-test-cases-master/Xamarin/bxc45742/Main.cs:10
Note how the managed frame where the exception was thrown does not show up.
This is because we technically catch exceptions when marshaling them, and then
later we call mono_raise_exception to raise the same exception. Unfortunately
that leads to overwriting the initial stack trace, and we end up with a stack
trace that does not include the location where the original exception was
thrown.
So instead of calling mono_raise_exception to rethrow the same exception, we
use ExceptionDispatchInfo, which is able to capture the stack trace for both
the original exception and the new exception, producing the following output:
System.Exception: USELESS
at UselessExceptions.ViewController.ViewDidLoad () [0x0000c] in /Users/rolf/Downloads/filed-bug-test-cases-master/Xamarin/bxc45742/ViewController.cs:27
--- End of stack trace from previous location where exception was thrown ---
at (wrapper managed-to-native) AppKit.NSApplication:NSApplicationMain (int,string[])
at AppKit.NSApplication.Main (System.String[] args) [0x00041] in /work/maccore/master/xamarin-macios/src/AppKit/NSApplication.cs:98
at UselessExceptions.MainClass.Main (System.String[] args) [0x00007] in /Users/rolf/Downloads/filed-bug-test-cases-master/Xamarin/bxc45742/Main.cs:10
[ERROR] FATAL UNHANDLED EXCEPTION: UselessExceptions.CustomException: USELESS
at UselessExceptions.ViewController.ViewDidLoad () [0x0000c] in /Users/rolf/Downloads/filed-bug-test-cases-master/Xamarin/bxc45742/ViewController.cs:27
--- End of stack trace from previous location where exception was thrown ---
at (wrapper managed-to-native) AppKit.NSApplication:NSApplicationMain (int,string[])
at AppKit.NSApplication.Main (System.String[] args) [0x00041] in /work/maccore/master/xamarin-macios/src/AppKit/NSApplication.cs:98
at UselessExceptions.MainClass.Main (System.String[] args) [0x00007] in /Users/rolf/Downloads/filed-bug-test-cases-master/Xamarin/bxc45742/Main.cs:10
Incidently this is how Xamarin.Android does it [1].
[1]: 9387f2fe16https://bugzilla.xamarin.com/show_bug.cgi?id=45742
* [tests] Remove Classic SDK tests.
* Remove XI/Classic support.
This also means we can remove support for the legacy registrars.
* [monotouch-test] Remove legacy registrar tests.
* [tests/mtouch] Remove Classic tests (and legacy registrar logic).
* [tests/scripted] Fix tests to reference Xamarin.iOS.dll.
We've used the dynamic registrar for years now when selecting the IL registrar
(and I've never heard about anybody doing it), so just remove all the related
(and in fact dead) code.
* [runtime] Use printf on watchOS, NSLog doesn't shown up (by default).
* [runtime] Use a wrapper function for logging.
So that we can chose between printf and NSLog at runtime,
depending on where we're running.
This way we can pass pointers to managed objects to the native objects
without the coop GC interfering (since icalls won't automatically
switch to "gc safe" mode).
In particular NSMethodSignature chokes on encodings like this:
[NSDecimalNumber initWithDecimal:] = "@36@0:8{?=b8b4b1b1b18[8S]}16"
with an exception:
NSInvalidArgumentException Reason: +[NSMethodSignature signatureWithObjCTypes:]: unsupported type encoding spec '{?}'
so implement our own code to calculate the frame size.