Skip to content

Commit d31a6bf

Browse files
[CoreCLR] Support marshal methods (#9912)
Context: 8d739f4 Context: ec0cbcf Make it possible to enable marshal methods in CoreCLR apps in the Release configuration by setting `$(AndroidEnableMarshalMethods)=true`. Note: It is not necessary to set `$(_AndroidUseManagedMarshalMethodsLookup)=true` manually when using CoreCLR, as it is the only marshal methods lookup method supported. To make this work: Add `xamarin_app_init` to the P/Invoke overrides. The configuration flags are now set and propagated correctly during initialization to ensure that the `xamarin_app_init` method is called when `$(AndroidEnableMarshalMethods)=true`. Update `MarshalMethodsAssemblyRewriter` to no longer emit `_mm_wrapper` methods around methods which already have `[UnmanagedCallersOnly]`. There was a bug in 8d739f4 which created a `n_Activate_mm_mm_wrapper` method which called the hand-written `n_Activate_mm` UCO. This wasn't caught earlier because Mono does not throw when a managed function calls a UCO. On CoreCLR, this codepath failed with: Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code.
1 parent 599bd6c commit d31a6bf

14 files changed

+47
-15
lines changed

src/Mono.Android/Android.Runtime/JNIEnvInit.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
134134
SetSynchronizationContext ();
135135
}
136136

137-
[DllImport ("xamarin-app")]
137+
[DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
138138
static extern unsafe void xamarin_app_init (IntPtr env, delegate* unmanaged <int, int, int, IntPtr*, void> get_function_pointer);
139139

140140
static void SetSynchronizationContext () =>

src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs

+1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ void AddEnvironment ()
342342
JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount,
343343
JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount,
344344
MarshalMethodsEnabled = EnableMarshalMethods,
345+
ManagedMarshalMethodsLookupEnabled = EnableManagedMarshalMethodsLookup,
345346
IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (),
346347
};
347348
} else {

src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs

+1
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,5 @@ sealed class ApplicationConfigCLR
4949
public uint jni_remapping_replacement_type_count;
5050
public uint jni_remapping_replacement_method_index_entry_count;
5151
public string android_package_name = String.Empty;
52+
public bool managed_marshal_methods_lookup_enabled;
5253
}

src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs

+2
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ sealed class XamarinAndroidBundledAssembly
207207
public PackageNamingPolicy PackageNamingPolicy { get; set; }
208208
public List<ITaskItem> NativeLibraries { get; set; }
209209
public bool MarshalMethodsEnabled { get; set; }
210+
public bool ManagedMarshalMethodsLookupEnabled { get; set; }
210211
public bool IgnoreSplitConfigs { get; set; }
211212

212213
public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary<string, string> environmentVariables, IDictionary<string, string> systemProperties,
@@ -256,6 +257,7 @@ protected override void Construct (LlvmIrModule module)
256257
uses_assembly_preload = UsesAssemblyPreload,
257258
jni_add_native_method_registration_attribute_present = JniAddNativeMethodRegistrationAttributePresent,
258259
marshal_methods_enabled = MarshalMethodsEnabled,
260+
managed_marshal_methods_lookup_enabled = ManagedMarshalMethodsLookupEnabled,
259261
ignore_split_configs = IgnoreSplitConfigs,
260262
number_of_runtime_properties = (uint)(runtimeProperties == null ? 0 : runtimeProperties.Count),
261263
package_naming_policy = (uint)PackageNamingPolicy,

src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsAssemblyRewriter.cs

+18
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.Build.Utilities;
77
using Mono.Cecil;
88
using Mono.Cecil.Cil;
9+
using Java.Interop.Tools.Cecil;
910
using Xamarin.Android.Tools;
1011

1112
namespace Xamarin.Android.Tasks
@@ -82,6 +83,12 @@ public void Rewrite (bool brokenExceptionTransitions)
8283
continue;
8384
}
8485

86+
if (HasUnmanagedCallersOnlyAttribute (method.NativeCallback)) {
87+
log.LogDebugMessage ($"[{targetArch}] Method '{method.NativeCallback.FullName}' does not need a wrapper, it already has UnmanagedCallersOnlyAttribute");
88+
method.NativeCallbackWrapper = method.NativeCallback;
89+
continue;
90+
}
91+
8592
method.NativeCallbackWrapper = GenerateWrapper (method, assemblyImports, brokenExceptionTransitions);
8693
if (method.Connector != null) {
8794
if (method.Connector.IsStatic && method.Connector.IsPrivate) {
@@ -186,6 +193,17 @@ void RemoveFile (string? path)
186193
log.LogDebugMessage ($"[{targetArch}] {ex.ToString ()}");
187194
}
188195
}
196+
197+
static bool HasUnmanagedCallersOnlyAttribute (MethodDefinition method)
198+
{
199+
foreach (CustomAttribute ca in method.CustomAttributes) {
200+
if (ca.Constructor.DeclaringType.FullName == "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute") {
201+
return true;
202+
}
203+
}
204+
205+
return false;
206+
}
189207
}
190208

191209
MethodDefinition GenerateWrapper (MarshalMethodEntry method, Dictionary<AssemblyDefinition, AssemblyImports> assemblyImports, bool brokenExceptionTransitions)

src/native/clr/host/generate-pinvoke-tables.cc

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const std::vector<std::string> internal_pinvoke_names = {
7979
// "recv_uninterrupted",
8080
// "send_uninterrupted",
8181
// "set_world_accessable",
82+
"xamarin_app_init",
8283

8384
// We can treat liblog as "internal", since we link against it
8485
"__android_log_print",

src/native/clr/host/host.cc

+3
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl
253253
init.jniAddNativeMethodRegistrationAttributePresent = application_config.jni_add_native_method_registration_attribute_present ? 1 : 0;
254254
init.jniRemappingInUse = application_config.jni_remapping_replacement_type_count > 0 || application_config.jni_remapping_replacement_method_index_entry_count > 0;
255255
init.marshalMethodsEnabled = application_config.marshal_methods_enabled;
256+
init.managedMarshalMethodsLookupEnabled = application_config.managed_marshal_methods_lookup_enabled;
257+
abort_unless (!init.marshalMethodsEnabled || init.managedMarshalMethodsLookupEnabled,
258+
"Managed marshal methods lookup must be enabled if marshal methods are enabled");
256259

257260
// GC threshold is 90% of the max GREF count
258261
init.grefGcThreshold = static_cast<int>(AndroidSystem::get_gref_gc_threshold ());

src/native/clr/host/pinvoke-tables.include

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111
namespace {
1212
#if INTPTR_MAX == INT64_MAX
1313
//64-bit internal p/invoke table
14-
std::array<PinvokeEntry, 10> internal_pinvokes {{
14+
std::array<PinvokeEntry, 11> internal_pinvokes {{
1515
{0x4310c1531ddddc14, "__android_log_print", reinterpret_cast<void*>(&__android_log_print)},
1616
{0x4b1956138764939a, "_monodroid_gref_log_new", reinterpret_cast<void*>(&_monodroid_gref_log_new)},
1717
{0x9187e6bc6294cacf, "clr_typemap_managed_to_java", reinterpret_cast<void*>(&clr_typemap_managed_to_java)},
1818
{0x9a946dfe9916a942, "clr_typemap_java_to_managed", reinterpret_cast<void*>(&clr_typemap_java_to_managed)},
1919
{0xa7f58f3ee428cc6b, "_monodroid_gref_log_delete", reinterpret_cast<void*>(&_monodroid_gref_log_delete)},
2020
{0xae3df96dda0143bd, "_monodroid_gref_log", reinterpret_cast<void*>(&_monodroid_gref_log)},
2121
{0xb8306f71b963cd3d, "monodroid_log", reinterpret_cast<void*>(&monodroid_log)},
22+
{0xb9bae9c43fb05089, "xamarin_app_init", reinterpret_cast<void*>(&xamarin_app_init)},
2223
{0xd1e121b94ea63f2e, "_monodroid_gref_get", reinterpret_cast<void*>(&_monodroid_gref_get)},
2324
{0xd5151b00eb33d85e, "monodroid_TypeManager_get_java_class_name", reinterpret_cast<void*>(&monodroid_TypeManager_get_java_class_name)},
2425
{0xf41c48df6f9be476, "monodroid_free", reinterpret_cast<void*>(&monodroid_free)},
@@ -515,7 +516,7 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x18
515516
constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5;
516517
#else
517518
//32-bit internal p/invoke table
518-
std::array<PinvokeEntry, 10> internal_pinvokes {{
519+
std::array<PinvokeEntry, 11> internal_pinvokes {{
519520
{0xb7a486a, "monodroid_TypeManager_get_java_class_name", reinterpret_cast<void*>(&monodroid_TypeManager_get_java_class_name)},
520521
{0x39e5b5d4, "__android_log_print", reinterpret_cast<void*>(&__android_log_print)},
521522
{0x656e00bd, "clr_typemap_managed_to_java", reinterpret_cast<void*>(&clr_typemap_managed_to_java)},
@@ -525,6 +526,7 @@ constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5;
525526
{0xbe8d7701, "_monodroid_gref_log_new", reinterpret_cast<void*>(&_monodroid_gref_log_new)},
526527
{0xc5146c54, "_monodroid_gref_log_delete", reinterpret_cast<void*>(&_monodroid_gref_log_delete)},
527528
{0xe7e77ca5, "_monodroid_gref_log", reinterpret_cast<void*>(&_monodroid_gref_log)},
529+
{0xeac7f6e3, "xamarin_app_init", reinterpret_cast<void*>(&xamarin_app_init)},
528530
{0xfa4e32ca, "monodroid_log", reinterpret_cast<void*>(&monodroid_log)},
529531
}};
530532

@@ -1019,6 +1021,6 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93
10191021
constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a;
10201022
#endif
10211023

1022-
constexpr size_t internal_pinvokes_count = 10;
1024+
constexpr size_t internal_pinvokes_count = 11;
10231025
constexpr size_t dotnet_pinvokes_count = 477;
10241026
} // end of anonymous namespace

src/native/clr/include/xamarin-app.hh

+3-4
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ struct AssemblyStoreSingleAssemblyRuntimeData final
215215
};
216216

217217
// Keep in strict sync with:
218-
// src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs
218+
// src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs
219219
// src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs
220220
struct ApplicationConfig
221221
{
@@ -394,8 +394,7 @@ struct MarshalMethodName
394394

395395
[[gnu::visibility("default")]] extern const char* const mm_class_names[];
396396
[[gnu::visibility("default")]] extern const MarshalMethodName mm_method_names[];
397+
#endif // def RELEASE
397398

398399
using get_function_pointer_fn = void(*)(uint32_t mono_image_index, uint32_t class_index, uint32_t method_token, void*& target_ptr);
399-
400-
[[gnu::visibility("default")]] extern void xamarin_app_init (JNIEnv *env, get_function_pointer_fn fn) noexcept;
401-
#endif // def RELEASE
400+
extern "C" [[gnu::visibility("default")]] void xamarin_app_init (JNIEnv *env, get_function_pointer_fn fn) noexcept;

src/native/clr/xamarin-app-stub/application_dso_stub.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,12 @@ const MarshalMethodName mm_method_names[] = {
216216
},
217217
};
218218

219+
#endif // def RELEASE
220+
219221
void xamarin_app_init ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] get_function_pointer_fn fn) noexcept
220222
{
221223
// Dummy
222224
}
223-
#endif // def RELEASE
224225

225226
static const JniRemappingIndexMethodEntry some_java_type_one_methods[] = {
226227
{

src/native/mono/pinvoke-override/generate-pinvoke-tables.cc

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ const std::vector<std::string> internal_pinvoke_names = {
7777
"recv_uninterrupted",
7878
"send_uninterrupted",
7979
"set_world_accessable",
80+
"xamarin_app_init",
8081
};
8182

8283
const std::vector<std::string> dotnet_pinvoke_names = {

src/native/mono/pinvoke-override/pinvoke-tables.include

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
namespace {
1212
#if INTPTR_MAX == INT64_MAX
1313
//64-bit internal p/invoke table
14-
std::array<PinvokeEntry, 45> internal_pinvokes {{
14+
std::array<PinvokeEntry, 46> internal_pinvokes {{
1515
{0xa50ce5de13bf8b5, "_monodroid_timezone_get_default_id", reinterpret_cast<void*>(&_monodroid_timezone_get_default_id)},
1616
{0x19055d65edfd668e, "_monodroid_get_network_interface_up_state", reinterpret_cast<void*>(&_monodroid_get_network_interface_up_state)},
1717
{0x2b3b0ca1d14076da, "monodroid_get_dylib", reinterpret_cast<void*>(&monodroid_get_dylib)},
@@ -35,6 +35,7 @@ namespace {
3535
{0xae3df96dda0143bd, "_monodroid_gref_log", reinterpret_cast<void*>(&_monodroid_gref_log)},
3636
{0xb6222d90af401865, "_monodroid_weak_gref_get", reinterpret_cast<void*>(&_monodroid_weak_gref_get)},
3737
{0xb8306f71b963cd3d, "monodroid_log", reinterpret_cast<void*>(&monodroid_log)},
38+
{0xb9bae9c43fb05089, "xamarin_app_init", reinterpret_cast<void*>(&xamarin_app_init)},
3839
{0xbc90bafd5ff9c99e, "_monodroid_get_dns_servers", reinterpret_cast<void*>(&_monodroid_get_dns_servers)},
3940
{0xbe5a300beec69c35, "monodroid_get_system_property", reinterpret_cast<void*>(&monodroid_get_system_property)},
4041
{0xbfbb924fbe190616, "monodroid_dylib_mono_free", reinterpret_cast<void*>(&monodroid_dylib_mono_free)},
@@ -549,7 +550,7 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x18
549550
constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5;
550551
#else
551552
//32-bit internal p/invoke table
552-
std::array<PinvokeEntry, 45> internal_pinvokes {{
553+
std::array<PinvokeEntry, 46> internal_pinvokes {{
553554
{0xb7a486a, "monodroid_TypeManager_get_java_class_name", reinterpret_cast<void*>(&monodroid_TypeManager_get_java_class_name)},
554555
{0xf562bd9, "monodroid_embedded_assemblies_set_assemblies_prefix", reinterpret_cast<void*>(&monodroid_embedded_assemblies_set_assemblies_prefix)},
555556
{0x227a2636, "monodroid_get_namespaced_system_property", reinterpret_cast<void*>(&monodroid_get_namespaced_system_property)},
@@ -588,6 +589,7 @@ constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5;
588589
{0xe4c3ee19, "monodroid_log_traces", reinterpret_cast<void*>(&monodroid_log_traces)},
589590
{0xe7e77ca5, "_monodroid_gref_log", reinterpret_cast<void*>(&_monodroid_gref_log)},
590591
{0xea2184e3, "_monodroid_gc_wait_for_bridge_processing", reinterpret_cast<void*>(&_monodroid_gc_wait_for_bridge_processing)},
592+
{0xeac7f6e3, "xamarin_app_init", reinterpret_cast<void*>(&xamarin_app_init)},
591593
{0xf4079b4a, "monodroid_dylib_mono_new", reinterpret_cast<void*>(&monodroid_dylib_mono_new)},
592594
{0xf5a0ac55, "set_world_accessable", reinterpret_cast<void*>(&set_world_accessable)},
593595
{0xf61941c3, "recv_uninterrupted", reinterpret_cast<void*>(&recv_uninterrupted)},
@@ -1087,6 +1089,6 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93
10871089
constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a;
10881090
#endif
10891091

1090-
constexpr size_t internal_pinvokes_count = 45;
1092+
constexpr size_t internal_pinvokes_count = 46;
10911093
constexpr size_t dotnet_pinvokes_count = 477;
10921094
} // end of anonymous namespace

src/native/mono/xamarin-app-stub/application_dso_stub.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,12 @@ const MarshalMethodName mm_method_names[] = {
221221
},
222222
};
223223

224+
#endif // def RELEASE
225+
224226
void xamarin_app_init ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] get_function_pointer_fn fn) noexcept
225227
{
226228
// Dummy
227229
}
228-
#endif // def RELEASE
229230

230231
static const JniRemappingIndexMethodEntry some_java_type_one_methods[] = {
231232
{

src/native/mono/xamarin-app-stub/xamarin-app.hh

+2-2
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,9 @@ struct MarshalMethodName
392392
MONO_API MONO_API_EXPORT const char* const mm_class_names[];
393393
MONO_API MONO_API_EXPORT const MarshalMethodName mm_method_names[];
394394

395-
using get_function_pointer_fn = void(*)(uint32_t mono_image_index, uint32_t class_index, uint32_t method_token, void*& target_ptr);
395+
#endif // def RELEASE
396396

397+
using get_function_pointer_fn = void(*)(uint32_t mono_image_index, uint32_t class_index, uint32_t method_token, void*& target_ptr);
397398
MONO_API MONO_API_EXPORT void xamarin_app_init (JNIEnv *env, get_function_pointer_fn fn) noexcept;
398-
#endif // def RELEASE
399399

400400
#endif // __XAMARIN_ANDROID_TYPEMAP_H

0 commit comments

Comments
 (0)