[monoapi] Add mono_method_get_unmanaged_callers_only_ftnptr (#66007)
authorAleksey Kliger (λgeek) <alklig@microsoft.com>
Thu, 3 Mar 2022 15:38:37 +0000 (10:38 -0500)
committerGitHub <noreply@github.com>
Thu, 3 Mar 2022 15:38:37 +0000 (10:38 -0500)
Like `RuntimeMethodHandle.GetFunctionPointer`, but callable from native code

src/mono/mono/metadata/external-only.c
src/mono/mono/metadata/icall.c
src/mono/mono/metadata/object-internals.h
src/native/public/mono/metadata/details/mono-private-unstable-functions.h

index f936d7b..f4612de 100644 (file)
@@ -23,6 +23,7 @@
 #include "assembly-internals.h"
 #include "external-only.h"
 #include <mono/metadata/threads.h>
+#include <mono/metadata/mono-private-unstable.h>
 #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));
+}
index 1c86818..13b679f 100644 (file)
@@ -6046,10 +6046,18 @@ 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);
 }
index 3d0ea67..f52ebd2 100644 (file)
@@ -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__ */
index e515072..0eb931c 100644 (file)
@@ -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))