* 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
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)
#define ICALL_TYPE(id,name,first)
#define ICALL(id,name,func) Icall_ ## id,
+#define HANDLES(inner) inner
enum {
#include "metadata/icall-def.h"
#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
#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;
#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
#endif /* !HAVE_ARRAY_ELEM_INIT */
+#undef HANDLES
+#define HANDLES(inner) inner
#undef ICALL_TYPE
#undef ICALL
#define ICALL_TYPE(id,name,first)
};
#ifdef ENABLE_ICALL_SYMBOL_MAP
+#undef HANDLES
+#define HANDLES(inner) inner
#undef ICALL_TYPE
#undef ICALL
#define ICALL_TYPE(id,name,first)
};
#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;
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
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
}
#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;
res = g_hash_table_lookup (icall_hash, mname);
if (res) {
+ if (uses_handles)
+ *uses_handles = FALSE;
mono_icall_unlock ();;
return res;
}
*sigstart = 0;
res = g_hash_table_lookup (icall_hash, mname);
if (res) {
+ if (uses_handles)
+ *uses_handles = FALSE;
mono_icall_unlock ();
return res;
}
}
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;
}
*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;
}
#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)