[runtime] Add HANDLES() macro to icall-def.h
authorAleksey Kliger <aleksey@xamarin.com>
Wed, 27 Jul 2016 22:50:13 +0000 (18:50 -0400)
committerAleksey Kliger <aleksey@xamarin.com>
Mon, 8 Aug 2016 16:50:14 +0000 (12:50 -0400)
The HANDLES() macro can be wrapped around an ICALL() to signal that
the icall should use the coop handles machinery from handles.h

mono/metadata/icall-def.h
mono/metadata/icall.c
mono/metadata/loader.h

index 5c00a1489fadda7eda5a547f542fa833b564c78e..82fc1734c29102d1e84d8d806a8e0c800e430b18 100644 (file)
  * you need to insert a method in the middle, don't bother renaming all the symbols.
  * Remember to change also the first_icall_id argument in the ICALL_TYPE 
  * declaration if you add a new icall at the beginning of a type's icall list.
+ *
+ *
+ * *** (Experimental) Cooperative GC support via Handles and MonoError ***
+ * An icall can use the coop GC handles infrastructure from handles.h to avoid some
+ * boilerplate when manipulating managed objects from runtime code and to use MonoError for
+ * threading exceptions out to managed callerrs:
+ *
+ * HANDLES(ICALL(icallid, methodname, cfuncptr))
+ *
+ * An icall with a HANDLES() declaration wrapped around it will have a generated wrapper
+ * that:
+ *   (1) Updates the coop handle stack on entry and exit
+ *   (2) Call the cfuncptr with a new signature:
+ *     (a) All managed object reference in arguments will be wrapped in a handle
+ *         (ie, MonoString* becomes MonoStringHandle)
+ *     (b) the same for the return value (MonoObject* return becomes MonoObjectHandle)
+ *     (c) An additional final argument is added of type MonoError*
+ *     example:    class object {
+ *                     [MethodImplOptions(InternalCall)]
+ *                     String some_icall (object[] x);
+ *                 }
+ *     should be implemented as:
+ *        MonoStringHandle some_icall (MonoObjectHandle this_handle, MonoArrayHandle x_handle, MonoError *error);
+ *   (3) The wrapper will automatically call mono_error_set_pending_exception (error) and raise the resulting exception.
+ * Note:  valuetypes use the same calling convention as normal.
+ * Limitations: "out" and "ref" arguments are not supported yet. 
  */
 
 #ifndef DISABLE_PROCESS_HANDLING
@@ -767,7 +793,7 @@ ICALL(RT_28, "IsTypeExportedToWindowsRuntime", ves_icall_System_RuntimeType_IsTy
 ICALL(RT_29, "IsWindowsRuntimeObjectType", ves_icall_System_RuntimeType_IsWindowsRuntimeObjectType)
 ICALL(RT_17, "MakeGenericType", ves_icall_RuntimeType_MakeGenericType)
 ICALL(RT_18, "MakePointerType", ves_icall_RuntimeType_MakePointerType)
-ICALL(RT_19, "getFullName", ves_icall_System_RuntimeType_getFullName)
+HANDLES(ICALL(RT_19, "getFullName", ves_icall_System_RuntimeType_getFullName))
 ICALL(RT_21, "get_DeclaringMethod", ves_icall_RuntimeType_get_DeclaringMethod)
 ICALL(RT_22, "get_DeclaringType", ves_icall_RuntimeType_get_DeclaringType)
 ICALL(RT_23, "get_Name", ves_icall_RuntimeType_get_Name)
index f317a11b100b8ab272db9ab2d93017a058dc0f09..bcabf3773dd55080b9aa3340d201a6294e41c130 100644 (file)
@@ -8222,6 +8222,7 @@ ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint3
 
 #define ICALL_TYPE(id,name,first)
 #define ICALL(id,name,func) Icall_ ## id,
+#define HANDLES(inner) inner
 
 enum {
 #include "metadata/icall-def.h"
@@ -8232,6 +8233,8 @@ enum {
 #undef ICALL
 #define ICALL_TYPE(id,name,first) Icall_type_ ## id,
 #define ICALL(id,name,func)
+#undef HANDLES
+#define HANDLES(inner) inner
 enum {
 #include "metadata/icall-def.h"
        Icall_type_num
@@ -8241,6 +8244,8 @@ enum {
 #undef ICALL
 #define ICALL_TYPE(id,name,firstic) {(Icall_ ## firstic)},
 #define ICALL(id,name,func)
+#undef HANDLES
+#define HANDLES(inner) inner
 typedef struct {
        guint16 first_icall;
 } IcallTypeDesc;
@@ -8253,6 +8258,8 @@ icall_type_descs [] = {
 
 #define icall_desc_num_icalls(desc) ((desc) [1].first_icall - (desc) [0].first_icall)
 
+#undef HANDLES
+#define HANDLES(inner) inner
 #undef ICALL_TYPE
 #define ICALL_TYPE(id,name,first)
 #undef ICALL
@@ -8324,6 +8331,8 @@ icall_names [] = {
 
 #endif /* !HAVE_ARRAY_ELEM_INIT */
 
+#undef HANDLES
+#define HANDLES(inner) inner
 #undef ICALL_TYPE
 #undef ICALL
 #define ICALL_TYPE(id,name,first)
@@ -8335,6 +8344,8 @@ icall_functions [] = {
 };
 
 #ifdef ENABLE_ICALL_SYMBOL_MAP
+#undef HANDLES
+#define HANDLES(inner) inner
 #undef ICALL_TYPE
 #undef ICALL
 #define ICALL_TYPE(id,name,first)
@@ -8346,6 +8357,19 @@ icall_symbols [] = {
 };
 #endif
 
+#undef ICALL_TYPE
+#undef ICALL
+#define ICALL_TYPE(id,name,first)
+#define ICALL(id,name,func) 0,
+#undef HANDLES
+#define HANDLES(inner) 1,
+static const guchar
+icall_uses_handles [] = {
+#include "metadata/icall-def.h"
+#undef ICALL
+#undef HANDLES
+};
+
 #endif /* DISABLE_ICALL_TABLES */
 
 static mono_mutex_t icall_mutex;
@@ -8466,13 +8490,31 @@ compare_method_imap (const void *key, const void *elem)
        return strcmp (key, method_name);
 }
 
-static gpointer
-find_method_icall (const IcallTypeDesc *imap, const char *name)
+static gsize
+find_slot_icall (const IcallTypeDesc *imap, const char *name)
 {
        const guint16 *nameslot = (const guint16 *)mono_binary_search (name, icall_names_idx + imap->first_icall, icall_desc_num_icalls (imap), sizeof (icall_names_idx [0]), compare_method_imap);
        if (!nameslot)
+               return -1;
+       return (nameslot - &icall_names_idx [0]);
+}
+
+static gboolean
+find_uses_handles_icall (const IcallTypeDesc *imap, const char *name)
+{
+       gsize slotnum = find_slot_icall (imap, name);
+       if (slotnum == -1)
+               return FALSE;
+       return (gboolean)icall_uses_handles [slotnum];
+}
+
+static gpointer
+find_method_icall (const IcallTypeDesc *imap, const char *name)
+{
+       gsize slotnum = find_slot_icall (imap, name);
+       if (slotnum == -1)
                return NULL;
-       return (gpointer)icall_functions [(nameslot - &icall_names_idx [0])];
+       return (gpointer)icall_functions [slotnum];
 }
 
 static int
@@ -8500,13 +8542,31 @@ compare_method_imap (const void *key, const void *elem)
        return strcmp (key, *method_name);
 }
 
-static gpointer
-find_method_icall (const IcallTypeDesc *imap, const char *name)
+static gsize
+find_slot_icall (const IcallTypeDesc *imap, const char *name)
 {
        const char **nameslot = mono_binary_search (name, icall_names + imap->first_icall, icall_desc_num_icalls (imap), sizeof (icall_names [0]), compare_method_imap);
        if (!nameslot)
+               return -1;
+       return nameslot - icall_names;
+}
+
+static gpointer
+find_method_icall (const IcallTypeDesc *imap, const char *name)
+{
+       gsize slotnum = find_slot_icall (imap, name);
+       if (slotnum == -1)
                return NULL;
-       return (gpointer)icall_functions [(nameslot - icall_names)];
+       return (gpointer)icall_functions [slotnum];
+}
+
+static gboolean
+find_uses_handles_icall (const IcallTypeDesc *imap, const char *name)
+{
+       gsize slotnum = find_slot_icall (imap, name);
+       if (slotnum == -1)
+               return FALSE;
+       return (gboolean)icall_uses_handles [slotnum];
 }
 
 static int
@@ -8558,8 +8618,19 @@ no_icall_table (void)
 }
 #endif
 
+/**
+ * mono_lookup_internal_call_full:
+ * @method: the method to look up
+ * @uses_handles: out argument if method needs handles around managed objects.
+ *
+ * Returns a pointer to the icall code for the given method.  If
+ * uses_handles is not NULL, it will be set to TRUE if the method
+ * needs managed objects wrapped using the infrastructure in handle.h
+ *
+ * If the method is not found, warns and returns NULL.
+ */
 gpointer
-mono_lookup_internal_call (MonoMethod *method)
+mono_lookup_internal_call_full (MonoMethod *method, gboolean *uses_handles)
 {
        char *sigstart;
        char *tmpsig;
@@ -8620,6 +8691,8 @@ mono_lookup_internal_call (MonoMethod *method)
 
        res = g_hash_table_lookup (icall_hash, mname);
        if (res) {
+               if (uses_handles)
+                       *uses_handles = FALSE;
                mono_icall_unlock ();;
                return res;
        }
@@ -8627,6 +8700,8 @@ mono_lookup_internal_call (MonoMethod *method)
        *sigstart = 0;
        res = g_hash_table_lookup (icall_hash, mname);
        if (res) {
+               if (uses_handles)
+                       *uses_handles = FALSE;
                mono_icall_unlock ();
                return res;
        }
@@ -8647,6 +8722,8 @@ mono_lookup_internal_call (MonoMethod *method)
        }
        res = find_method_icall (imap, sigstart - mlen);
        if (res) {
+               if (uses_handles)
+                       *uses_handles = find_uses_handles_icall (imap, sigstart - mlen);
                mono_icall_unlock ();
                return res;
        }
@@ -8654,6 +8731,8 @@ mono_lookup_internal_call (MonoMethod *method)
        *sigstart = '(';
        res = find_method_icall (imap, sigstart - mlen);
        if (res) {
+               if (uses_handles)
+                       *uses_handles = find_uses_handles_icall (imap, sigstart - mlen);
                mono_icall_unlock ();
                return res;
        }
@@ -8672,6 +8751,12 @@ mono_lookup_internal_call (MonoMethod *method)
 #endif
 }
 
+gpointer
+mono_lookup_internal_call (MonoMethod *method)
+{
+       return mono_lookup_internal_call_full (method, NULL);
+}
+
 #ifdef ENABLE_ICALL_SYMBOL_MAP
 static int
 func_cmp (gconstpointer key, gconstpointer p)
index 774c9b8a47fbe13024a3db9799635992107af351..86f8fc0c9c3e61a5acbe29509d1b2c388a82e0b1 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _MONO_METADATA_LOADER_H_
 #define _MONO_METADATA_LOADER_H_ 1
 
+#include <glib.h>
 #include <mono/metadata/metadata.h>
 #include <mono/metadata/image.h>
 #include <mono/utils/mono-error.h>
@@ -60,6 +61,10 @@ mono_add_internal_call     (const char *name, const void* method);
 MONO_API void*
 mono_lookup_internal_call (MonoMethod *method);
 
+void*
+mono_lookup_internal_call_full (MonoMethod *method, gboolean *uses_handles);
+
+
 MONO_API const char*
 mono_lookup_icall_symbol (MonoMethod *m);