This means using NativeHandle in numerous signatures, as well as adding a few .NET-specific
signatures (because sometimes the IntPtr version would still be needed).
This makes it easier to iterate over all the *_SDK_VERSION variables in
template code, because they're all named using the standard platform names we
use elsewhere.
* [generator] Use '[U]IntPtr' in the P/Invoke signature for native enums.
* Use '[U]IntPtr' as the parameter type in the P/Invoke signature for native enum
parameters.
* Use '[U]IntPtr' in the P/Invoke method name for native enum parameters.
* Add an explicit conversion from UIntPtr to nuint (like we already have from IntPtr
to nint).
This makes the code identical between .NET and legacy Xamarin when using C# n[u]ints,
because those are really [U]IntPtrs.
* Use IntPtr/UIntPtr for all nint/nuint types in P/Invokes, not only native enums.
* Add a few more casts
Fixes these generator tests:
* GeneratorTests.BGenTests.FieldEnumTests
* GeneratorTests.BGenTests.NativeEnum
* [registrar] Handle UIntPtr like we do IntPtr.
Fixes this error in numerous tests:
error MT4169: Failed to generate a P/Invoke wrapper for objc_msgSend(System.IntPtr,System.IntPtr): The registrar cannot build a signature for type `System.Void' in method `ObjCRuntime.Messaging.objc_msgSend`.
* [NativeTypes] Make IntPtr and UIntPtr behave the same.
This fixes an issue where the linked output for a 32-bit mscorlib.dll and a
64-bit mscorlib.dll would be different, because different explicit operators
for UIntPtr would be kept.
The fix works because the conversion operators for nuint will not use
UIntPtr's explicit conversion operators anymore, it will just operate on plain
memory instead.
The deadlock goes like this:
1. Thread A holds the framework_peer_release_lock lock, and tries to lock the
refcount_mutex lock.
2. Thread B holds the refcount_mutex, and is waiting for the GC to complete
3. Thread C is trying to lock the framework_peer_release_lock while running
the GC.
The fix is in thread A, by not doing anything at all with the
framework_peer_release_lock lock locked.
The code contains extensive comments explaining the situation and the solution.
Fixes https://github.com/xamarin/xamarin-macios/issues/13066.
Co-authored-by: Chris Hamons <chris.hamons@xamarin.com>
P/Invokes may point to a dylib, while the actual library linked into the .app
might be a static library, so make sure to compare without the extension.
This fixes an issue when linking with the static version of the runtime libraries.
Defining xm_nint_t to be 32-bit sized only on i386 is not the right thing to do for armv7.
Strangely enough this caused just a single test failure:
MonoTouchFixtures.Foundation.CalendarTest
[FAIL] TestFindNextDateAfterDateMatching : Expected: <Foundation.MonoTouchException>
But was: null
at MonoTouchFixtures.Foundation.CalendarTest.TestFindNextDateAfterDateMatching()
and that happened because:
1. We use a wrapper function around objc_msgSend:
void *
xamarin_IntPtr_objc_msgSend_IntPtr_IntPtr_nuint_exception (id self, SEL sel, void * p0, void * p1, xm_nuint_t p2, GCHandle *exception_gchandle)
{
@try {
return ((func_xamarin_IntPtr_objc_msgSend_IntPtr_IntPtr_nuint_exception) objc_msgSend) (self, sel, p0, p1, p2);
} @catch (NSException *e) {
xamarin_process_nsexception_using_mode (e, true, exception_gchandle);
return NULL;
}
}
2. Note that the second to last argument is an 'xm_nuint_t'. We told the
native compiler this was a 64-bit value, when the managed P/Invoke would
give it a 32-bit value. This had no effect on the 'p2' parameter, but it
meant that clang would thing the next argument, 'exception_gchandle', would
be somewhere it wasn't (the managed function would pass two 32-bit values,
'p2' and 'exception_gchandle', which clang would merge into a single 64-bit
'p2' argument, and then read random stuff for 'exception_gchandle').
3. Finally things would go sideways when we caught the exception and passed
'exception_gchandle' to xamarin_process_nsexception_using_mode. In effect
we'd ask xamarin_process_nsexception_using_mode to store the resulting
gchandle in random memory. Amazingly it only resulted in a test failure
(because upon return the managed location for the 'exception_gchandle'
wasn't touched, and would have its initial value of 0, thus managed code
would think no exception occurred).
So fix this to use the correct underlying types, instead of trying to figure
out the correct #if condition.
I'm not sure why we're using our own types here anyways, but this fix is the
smallest.
Instead of generating one native P/Invoke signature with an int parameter and
another with a long parameter for methods that take [Native] enums, generate a
single nint parameter (and the same for the unsigned version).
This simplifies both the generator code and the generated code. The generator
diff contains *a lot* of changes like this:
- if (IntPtr.Size == 8) {
- ret = (ARAppClipCodeUrlDecodingState) global::ObjCRuntime.Messaging.Int64_objc_msgSend (this.Handle, Selector.GetHandle ("urlDecodingState"));
- } else {
- ret = (ARAppClipCodeUrlDecodingState) global::ObjCRuntime.Messaging.int_objc_msgSend (this.Handle, Selector.GetHandle ("urlDecodingState"));
- }
+ ret = (ARKit.ARAppClipCodeUrlDecodingState) (long) global::ObjCRuntime.Messaging.nint_objc_msgSend (this.Handle, Selector.GetHandle ("urlDecodingState"));
An unlinked Xamarin.iOS.dll is ~300kb smaller (once linked the difference
should be minimal though).
I also made the min/max detection logic (check for int32.MinValue/MaxValue and
convert to int64.MinValue/MaxValue) specific to ARCH_32, since we don't need
it in 64-bit code.
Setting the XAMARIN_LOG_MARSHALLED_EXCEPTIONS environment variable will now
make us print all exceptions that go through exception marshalling, and how
we'll handle them.
Fixes https://github.com/xamarin/xamarin-macios/issues/12343.
* Add support for Mono Components.
* Modify how we look up symbols from native libraries shipped with Mono: we keep
track of which native libraries we linked with, and depending on how we linked
to those assemblies, we look the symbols up at runtime in either the current executable
(if linking statically), or the actual library (where the P/Invoke says they're
supposed to be).
* This means that we have to propagate how libmono is linked from the MSBuild code
to the Application class so that our existing logic is able to correctly determine
which native mono lib to use.
* Modify how we list the P/Invokes we need to preserve by taking into account the
list of native libraries from Mono we have to link with (for .NET). For legacy
Xamarin, I've reverted the logic to how it was before we started adding .NET support.
Fixes https://github.com/xamarin/xamarin-macios/issues/10950.
Fixes https://github.com/xamarin/xamarin-macios/issues/11145.
Fixes https://github.com/xamarin/xamarin-macios/issues/12100.
List all the assemblies in the app bundle and pass them to MonoVM/CoreCLR's in
the TRUSTED_PLATFORM_ASSEMBLIES initialization property.
This way CoreCLR knows where to find System.Private.CoreLib.dll for fat apps
(it's in the runtimeidentifier-specific subdirectory, and by default CoreCLR
will only look next to libcoreclr.dylib).
Fixes https://github.com/xamarin/xamarin-macios/issues/12265.
This also meant propagating how libmono is linked from the MSBuild code to the Application
class so that our existing logic is able to correctly determine which native mono
lib to use.
We need to process the runtimeconfig.json file somehow when using CoreCLR, and
the embedding API we use (coreclr_initialize) won't parse it for us. So re-use
the logic we already have to process runtimeconfig.json for MonoVM (which
involves converting it to a binary format at build time, which we then process
at runtime).
* Use the Apple-provided TARGET_OS_SIMULATOR define to determine if we're
running in a simulator, instead of checking the current architecture. This
way we properly detect ARM64-based simulators (and it'll work correctly in
the future).
* Always set Runtime.Arch = SIMULATOR for Mac Catalyst. The final value for
Runtime.Arch for Mac Catalyst is tracked in #10312, but this is a stop-gap
measure to make sure we have the same value between X64 and ARM64 on Mac
Catalyst, and until now we've had Runtime.Arch = SIMULATOR for X64, so just
go with that for now.
Return early when we're not going to try resolving anything, which means that
if we didn't find something by the end, we know that it's because we failed
(and not because we weren't supposed to try), and we log that.
This makes it easier to diagnose a few failure conditions.
To have consistent behavior in .NET, set the current directory to the root of
the app bundle for all platforms.
This is a breaking change for legacy Xamarin.Mac, which used to set the
current directory to the Contents/Resources subdirectory, but there's a simple
workaround for customers that depend on the old behavior (change it in Main
themselves), and I believe the consistent experience across platforms warrants
this change.
Note that we already had a breaking change here for macOS/.NET: we were
(unintentionally) setting the current directory to the Contents/MonoBundle
directory, which neither matched mobile platforms, nor the legacy Xamarin.Mac
behavior.
This solves the problem of what to do for Mac Catalyst apps, because there's
no need to choose between the macOS or the mobile behavior, since they're the
same.
This required changing the launch of macOS apps using CoreCLR to pass the full
path to the entry assembly, since the entry assembly isn't in the current
directory anymore.
The code contains comments explaining the new behavior.
Some tests that poked into the private 'flags' field on NSObject had to be
updated, because the field is now named differently in .NET.
I also added two more tests for toggle ref scenarios.
No more leaks!
Before:
There were 205834 MonoObjects created, 205834 MonoObjects freed, so no leaked MonoObjects. (static registrar)
There were 258092 MonoObjects created, 258013 MonoObjects freed, so 79 were not freed. (dynamic registrar)
After:
✅ There were 205834 MonoObjects created, 205834 MonoObjects freed, so no leaked MonoObjects. (static registrar)
✅ There were 258100 MonoObjects created, 258100 MonoObjects freed, so no leaked MonoObjects. (dynamic registrar)
Before:
There were 258096 MonoObjects created, 246948 MonoObjects freed, so 11148 were not freed. (dynamic registrar)
There were 205834 MonoObjects created, 205214 MonoObjects freed, so 620 were not freed. (static registrar)
After:
There were 205834 MonoObjects created, 205222 MonoObjects freed, so 612 were not freed. (dynamic registrar)
There were 258100 MonoObjects created, 258019 MonoObjects freed, so 81 were not freed. (static registrar)
* If the return value from xamarin_get_reflection_method_method is cached in a
static variable, we can only release at process exist.
* Otherwise just release at the end of the current method.
Before:
There were 258096 MonoObjects created, 246948 MonoObjects freed, so 11148 were not freed. (dynamic registrar)
There were 205834 MonoObjects created, 205214 MonoObjects freed, so 620 were not freed. (static registrar)
After:
There were 258092 MonoObjects created, 246945 MonoObjects freed, so 11147 were not freed. (dynamic registrar)
There were 205834 MonoObjects created, 205600 MonoObjects freed, so 234 were not freed. (static registrar)
While not strictly necessary to not leak (because the process is exiting
anyway), it makes it easier to read leak reports, because these dictionaries
won't show up as leaked memory anymore.
Before:
There were 258096 MonoObjects created, 258015 MonoObjects freed, so 81 were not freed. (dynamic registrar)
There were 205834 MonoObjects created, 205833 MonoObjects freed, so 1 were not freed. (static registrar)
After:
There were 258104 MonoObjects created, 258025 MonoObjects freed, so 79 were not freed. (dynamic registrar)
There were 205834 MonoObjects created, 205834 MonoObjects freed, so no leaked MonoObjects. (static registrar)
* [runtime] Add support for exception marshalling to CoreCLR.
* [runtime] Add an empty implementation of the toggle ref machinery.
We need this to use the unhandled exception handler support in CoreCLR,
because the ObjectiveCMarshal.Initialize call to initialize unhandled
exception support requires passing toggle ref callbacks as well.
* [tests] The TestConstrainedGenericType test can now be re-enabled, after a few updates.
Before:
There were 258042 MonoObjects created, 235166 MonoObjects freed, so 22876 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 204219 MonoObjects freed, so 1585 were not freed. (static registrar)
After:
There were 258066 MonoObjects created, 246781 MonoObjects freed, so 11285 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 204491 MonoObjects freed, so 1313 were not freed. (static registrar)
Before:
There were 258042 MonoObjects created, 235166 MonoObjects freed, so 22876 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 204219 MonoObjects freed, so 1585 were not freed. (static registrar)
After:
There were 258050 MonoObjects created, 235177 MonoObjects freed, so 22873 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 204219 MonoObjects freed, so 1585 were not freed. (static registrar)
Before:
There were 258042 MonoObjects created, 235166 MonoObjects freed, so 22876 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 204219 MonoObjects freed, so 1585 were not freed. (static registrar)
After:
There were 258058 MonoObjects created, 235308 MonoObjects freed, so 22750 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 204219 MonoObjects freed, so 1585 were not freed. (static registrar)
Before:
There were 258046 MonoObjects created, 235142 MonoObjects freed, so 22904 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 204193 MonoObjects freed, so 1611 were not freed. (static registrar)
After:
There were 258054 MonoObjects created, 235172 MonoObjects freed, so 22882 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 205190 MonoObjects freed, so 614 were not freed. (static registrar)
Before:
There were 258046 MonoObjects created, 235142 MonoObjects freed, so 22904 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 204193 MonoObjects freed, so 1611 were not freed. (static registrar)
After:
There were 258054 MonoObjects created, 235172 MonoObjects freed, so 22882 were not freed. (dynamic registrar)
There were 205804 MonoObjects created, 204193 MonoObjects freed, so 1611 were not freed. (static registrar)
Due to the following reasons:
* Desktop apps like macOS and Mac catalyst can be launched directly from the
command line by users.
* It's trivial to set environment variables for desktop apps before launching
them.
* All the different command line arguments we support for mobile targets can
also be set using environment variables.
We don't need additional command line argument parsing for desktop platforms,
so just remove it.
The end result is that instead of doing this to run a specific unit test:
path/to/macOS/app/MacOS/Contents/theapp --app-arg --test --app-arg MyTestFixture
This will now work:
path/to/macOS/app/MacOS/Contents/theapp --test MyTestFixture
Which is how apps on desktop platforms should work anyway.
Before:
There were 257927 MonoObjects created, 144942 MonoObjects freed, so 112985 were not freed. (dynamic registrar)
There were 205700 MonoObjects created, 113865 MonoObjects freed, so 91835 were not freed. (static registrar)
After:
There were 257931 MonoObjects created, 235062 MonoObjects freed, so 22869 were not freed. (dynamic registrar)
There were 205700 MonoObjects created, 203983 MonoObjects freed, so 1717 were not freed. (static registrar)
The workaround doesn't work anymore anyway, this is printed on every launch:
> MonoTouch: Could not install sigaction override, unexpected sigaction implementation.
Ref: 054bbdce96
* [runtime] Add support for tracking created and destroyed MonoObject* instances for CoreCLR.
Implement a rudimentary way of tracking created and destroyed MonoObject*
instances, so that it's easy to find leaks.
* Add a xamarin_bridge_shutdown method that's called just before returning from xamarin_main.
And use it to dump the leaked MonoObject*s.
* [runtime] Mark numerous Mono Embedding API as used only by the MonoVM bridge.
* [runtime] Exclude more unused code from the CoreCLR build.
* There's no tracing in CoreCLR, so no need to process the MONO_TRACE environment
variable (and set the trace options).
* There's no sdb debuggger, so that code can be skipped.
* The profiler support is very different, so skip that code too.
* We don't support AOT, nor aot data files, so skip that.
* [runtime] Stop generating dummy implementations of the Mono Embedding API for CoreCLR.
All of the Mono Embedding API now falls in either of these two categories:
* Only used by the MonoVM bridge.
* Has a CoreCLR implementation.
Which means that we don't need the code to generate dummy implementations for
methods that aren't in any of these two categories anymore.
The native xamarin_bridge_get_method_declaring_type method and the
corresponding managed method (GetMethodDeclaringType) takes and returns a
MonoObject*, not a GCHandle.
Due to the wonders of void pointers, this worked just fine before - there's no
actual change to the compiled code - but the code is now more consistent and
less confusing.
The value should never be used if everything is working fine, but if something
is wrong, then this value will at least get consistent behavior.
The visible result for us right now is that monotouch-test will fail with a
test failure instead of crashing.
CoreCLR is being added for macOS only. We can eliminate a lot of recent
code additions (about half a megabyte in the past week) by eliminate code
branches under `if (IsCoreCLR)`.
Unlike handling (non required at runtime) custom attributes the
`ILLink.Substitutions.xml` will vary quite a bit across platforms so we
use a unique file for each platform.
* Remove a few unused xamarin_get_*_class functions.
* Make the remaining two (xamarin_get_[nsnumber|nsvalue]_type) return a
MonoType* instead of MonoClass* - that makes things slightly simpler for
CoreCLR (the MonoClass* return values from the previous functions were
always converted to MonoType*s anyway).
* Implement the xamarin_get_[nsnumber|nsvalue]_type functions.
* Make the existing mono_get_string_class use the new (and more generic)
xamarin_bridge_lookup_class method instead of the specific
xamarin_bridge_get_string_class (which can now be removed).
* Make 'throw Objective-C exception' the default for managed exception marshalling.
* Make 'throw managed exception' the default for Objective-C exception marshalling.
* Disallow the 'unwind through native frames' option: CoreCLR won't do it.
* Disallow the 'unwind through managed frames' option: it's the safeset
option by far, and also matches the reverse case.
* Disallow the 'disable' option: this is also not safe, let's try to go the
safe route with CoreCLR.
* Change the default in native code too.
Partial fix for #10940.
This makes it easier for CoreCLR. Also, at least for CoreCLR, it's unlikely to
be slower, since we'd have to compute the MONO_TYPE_* value in any
compatibility function.
Passing a 'MonoObject*' to a function that expects a GCHandle doesn't quite
work, so make sure to get a GCHandle for the exception we want to print
information about.
We need additional API in CoreCLR to support pending exception properly, and
this is in progress [1]. In the meantime, stub out parts of it, so that the
process doesn't abort. This way we'll have failing tests instead (and work in
other areas can progress, since the process doesn't abort).
[1]: https://github.com/dotnet/runtime/pull/52146
This is not the fastest implementation, but it's the simplest I could come up
with, with the target of sharing as much code as possible with MonoVM. It can
be improved later if we find out it's a slow path (these functions are not in
a common code path, very few API bindings end up here).
* Implement our xamarin_dyn_objc_msgSend[Super] overrides for ARM64.
* Modify mmp to use those overrides.
* Fix an issue with the existing xamarin_arm64_common_trampoline that caused
exceptions to not unwind correctly.
* Add an ARM64 variation of xammac tests in xharness.
* Various test fixes.
Also add Call Frame Information (CFI) / Canonical Frame Address (CFA) directives.
This is required for native exceptions to work properly (otherwise the native runtime
won’t be able to unwind stack frames correctly).
When using the MonoVM, we compare MonoClass instances by pointer. This turns
out a bit complicated for CoreCLR, because our MonoClass instances are not
unique (there can be multiple MonoClass instances that refer to the same
type), so instead implement helper methods that do the comparison. This also
has the benefit of not requiring any memory allocations on CoreCLR.