diff --git a/src/mono/mono/metadata/external-only.c b/src/mono/mono/metadata/external-only.c index f936d7bcd2828b..f4612deeb5ce67 100644 --- a/src/mono/mono/metadata/external-only.c +++ b/src/mono/mono/metadata/external-only.c @@ -23,6 +23,7 @@ #include "assembly-internals.h" #include "external-only.h" #include +#include #include "threads-types.h" #include "jit-info.h" @@ -696,3 +697,25 @@ mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot) { return mono_mem_manager_mp_contains_addr (mono_mem_manager_get_ambient (), vtable_slot); } + +/** + * mono_method_get_unmanaged_callers_only_ftnptr: + * \param method method to generate a thunk for. + * \param error set on error + * + * Returns a function pointer for calling the given UnmanagedCallersOnly method from native code. + * The function pointer will use the calling convention specified on the UnmanagedCallersOnly + * attribute (or the default platform calling convention if omitted). + * + * Unlike \c mono_method_get_unmanaged_thunk, minimal marshaling is done to the method parameters in + * the wrapper. See + * https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.unmanagedcallersonlyattribute?view=net-6.0 + * The method must be static and only use blittable argument types. There is no exception out-argument. + * + * + */ +void* +mono_method_get_unmanaged_callers_only_ftnptr (MonoMethod *method, MonoError *error) +{ + MONO_EXTERNAL_ONLY_GC_UNSAFE (gpointer, mono_method_get_unmanaged_wrapper_ftnptr_internal (method, TRUE, error)); +} diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 1c86818363bf7a..13b679f78e892c 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -6045,11 +6045,19 @@ ves_icall_System_Environment_get_TickCount64 (void) gpointer ves_icall_RuntimeMethodHandle_GetFunctionPointer (MonoMethod *method, MonoError *error) +{ + return mono_method_get_unmanaged_wrapper_ftnptr_internal (method, FALSE, error); +} + +void* +mono_method_get_unmanaged_wrapper_ftnptr_internal (MonoMethod *method, gboolean only_unmanaged_callers_only, MonoError *error) { /* WISH: we should do this in managed */ if (G_UNLIKELY (mono_method_has_unmanaged_callers_only_attribute (method))) { method = mono_marshal_get_managed_wrapper (method, NULL, (MonoGCHandle)0, error); return_val_if_nok (error, NULL); + } else { + g_assert (!only_unmanaged_callers_only); } return mono_get_runtime_callbacks ()->get_ftnptr (method, error); } diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 3d0ea67230940e..f52ebd2e73b4e2 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -2137,4 +2137,7 @@ int mono_string_instance_is_interned (MonoString *str); #endif +gpointer +mono_method_get_unmanaged_wrapper_ftnptr_internal (MonoMethod *method, gboolean only_unmanaged_callers_only, MonoError *error); + #endif /* __MONO_OBJECT_INTERNALS_H__ */ diff --git a/src/native/public/mono/metadata/details/mono-private-unstable-functions.h b/src/native/public/mono/metadata/details/mono-private-unstable-functions.h index e515072680d1e1..0eb931ce1bb7fe 100644 --- a/src/native/public/mono/metadata/details/mono-private-unstable-functions.h +++ b/src/native/public/mono/metadata/details/mono-private-unstable-functions.h @@ -26,3 +26,6 @@ MONO_API_FUNCTION(MONO_RT_EXTERNAL_ONLY MonoAssemblyLoadContextGCHandle, mono_al MONO_API_FUNCTION(void, mono_register_bundled_satellite_assemblies, (const MonoBundledSatelliteAssembly **assemblies)) MONO_API_FUNCTION(MonoBundledSatelliteAssembly *, mono_create_new_bundled_satellite_assembly, (const char *name, const char *culture, const unsigned char *data, unsigned int size)) + + +MONO_API_FUNCTION(MONO_RT_EXTERNAL_ONLY void*, mono_method_get_unmanaged_callers_only_ftnptr, (MonoMethod *method, MonoError *error))