From f2048bca67b6dfa03b2972c3e6539d9ef79bb8c9 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 1 Mar 2022 10:36:06 -0500 Subject: [PATCH] [monoapi] Add mono_method_get_unmanaged_callers_only_ftnptr Like `RuntimeMethodHandle.GetFunctionPointer`, but callable from native code --- src/mono/mono/metadata/external-only.c | 23 +++++++++++++++++++ src/mono/mono/metadata/icall.c | 13 +++++++++++ .../mono/metadata/mono-private-unstable.h | 3 +++ src/mono/mono/metadata/object-internals.h | 3 +++ 4 files changed, 42 insertions(+) diff --git a/src/mono/mono/metadata/external-only.c b/src/mono/mono/metadata/external-only.c index 19999e384c7763..08d629dbf2dfc1 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 "threads.h" +#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 e471252ea6195b..b1e2d737f2246e 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -6600,6 +6600,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/mono-private-unstable.h b/src/mono/mono/metadata/mono-private-unstable.h index 4618c8fe08bc92..72f0a912c5207b 100644 --- a/src/mono/mono/metadata/mono-private-unstable.h +++ b/src/mono/mono/metadata/mono-private-unstable.h @@ -42,4 +42,7 @@ mono_create_new_bundled_satellite_assembly (const char *name, const char *cultur typedef void * (*PInvokeOverrideFn) (const char *libraryName, const char *entrypointName); +MONO_API MONO_RT_EXTERNAL_ONLY void* +mono_method_get_unmanaged_callers_only_ftnptr (MonoMethod *method, MonoError *error); + #endif /*__MONO_METADATA_MONO_PRIVATE_UNSTABLE_H__*/ diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 8f47c92ee86cdf..d5c69bbf2877f9 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -2097,4 +2097,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__ */