using System.Runtime.InteropServices;
namespace Mono {
- internal class RuntimeStructs {
+ //
+ // Managed representations of mono runtime types
+ //
+ internal static class RuntimeStructs {
// class-internals.h MonoRemoteClass
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct RemoteClass {
internal IntPtr* data;
internal int len;
}
+
+ // handle.h HandleStackMark
+ struct HandleStackMark {
+ int size;
+ IntPtr chunk;
+ }
+
+ // mono-error.h MonoError
+ struct MonoError {
+ ushort error_code;
+ ushort hidden_0;
+ IntPtr hidden_1, hidden_2, hidden_3, hidden_4, hidden_5, hidden_6, hidden_7, hidden_8;
+ IntPtr hidden_11, hidden_12, hidden_13, hidden_14, hidden_15, hidden_16, hidden_17, hidden_18;
+ }
}
//Maps to metadata-internals.h:: MonoAssemblyName
#define TYPED_HANDLE_PAYLOAD_NAME(TYPE) TYPE ## HandlePayload
#define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
+
/*
* typedef struct {
* MonoObject *__obj;
*
* typedef MonoObjectHandlePayload* MonoObjectHandle;
*/
-#define TYPED_HANDLE_DECL(TYPE) typedef struct { TYPE *__obj; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE);
+#define TYPED_HANDLE_DECL(TYPE) typedef struct { TYPE *__obj; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE)
+#define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_STRUCT_OFFSET(TYPED_HANDLE_PAYLOAD_NAME (TYPE), __obj)
#define MONO_HANDLE_INIT ((void*) mono_null_value_handle)
#define NULL_HANDLE mono_null_value_handle
/* Baked typed handles we all want */
-TYPED_HANDLE_DECL (MonoString)
-TYPED_HANDLE_DECL (MonoArray)
-TYPED_HANDLE_DECL (MonoObject)
+TYPED_HANDLE_DECL (MonoString);
+TYPED_HANDLE_DECL (MonoArray);
+TYPED_HANDLE_DECL (MonoObject);
+
+#define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE)
/*
This is the constant for a handle that points nowhere.
* 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_MonoType_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)
#include <mono/metadata/runtime.h>
#include <mono/metadata/file-mmap.h>
#include <mono/metadata/seq-points-data.h>
+#include <mono/metadata/handle.h>
#include <mono/io-layer/io-layer.h>
#include <mono/utils/monobitset.h>
#include <mono/utils/mono-time.h>
ICALL_EXPORT MonoReflectionAssembly* ves_icall_System_Reflection_Assembly_GetCallingAssembly (void);
+TYPED_HANDLE_DECL (MonoReflectionType);
+
/* Lazy class loading functions */
static GENERATE_GET_CLASS_WITH_CACHE (system_version, System, Version)
static GENERATE_GET_CLASS_WITH_CACHE (assembly_name, System.Reflection, AssemblyName)
return result;
}
-ICALL_EXPORT MonoString *
-ves_icall_System_MonoType_getFullName (MonoReflectionType *object, gboolean full_name,
- gboolean assembly_qualified)
+ICALL_EXPORT MonoStringHandle
+ves_icall_System_RuntimeType_getFullName (MonoReflectionTypeHandle object, gboolean full_name,
+ gboolean assembly_qualified, MonoError *error)
{
- MonoDomain *domain = mono_object_domain (object);
+ MonoDomain *domain = mono_object_domain (MONO_HANDLE_RAW (object));
+ MonoType *type = MONO_HANDLE_RAW (object)->type;
MonoTypeNameFormat format;
- MonoString *res;
+ MonoStringHandle res;
gchar *name;
if (full_name)
else
format = MONO_TYPE_NAME_FORMAT_REFLECTION;
- name = mono_type_get_name_full (object->type, format);
+ name = mono_type_get_name_full (type, format);
if (!name)
- return NULL;
+ return NULL_HANDLE_STRING;
- if (full_name && (object->type->type == MONO_TYPE_VAR || object->type->type == MONO_TYPE_MVAR)) {
+ if (full_name && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
g_free (name);
- return NULL;
+ return NULL_HANDLE_STRING;
}
- res = mono_string_new (domain, name);
+ res = mono_string_new_handle (domain, name);
g_free (name);
return res;
#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, mono_bool *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)
MONO_API void*
mono_lookup_internal_call (MonoMethod *method);
+void*
+mono_lookup_internal_call_full (MonoMethod *method, mono_bool *uses_handles);
+
+
MONO_API const char*
mono_lookup_icall_symbol (MonoMethod *m);
#include "mono/metadata/remoting.h"
#include "mono/metadata/reflection-internals.h"
#include "mono/metadata/threadpool-ms.h"
+#include "mono/metadata/handle.h"
#include "mono/utils/mono-counters.h"
#include "mono/utils/mono-tls.h"
#include "mono/utils/mono-memory-model.h"
static void
mono_marshal_ftnptr_eh_callback (guint32 gchandle);
+static MonoThreadInfo*
+mono_icall_start (HandleStackMark *stackmark, MonoError *error);
+
+static void
+mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error);
+
/* Lazy class loading functions */
static GENERATE_GET_CLASS_WITH_CACHE (string_builder, System.Text, StringBuilder)
static GENERATE_GET_CLASS_WITH_CACHE (date_time, System, DateTime)
register_icall (mono_threads_exit_gc_safe_region_unbalanced, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE);
register_icall (mono_threads_attach_coop, "mono_threads_attach_coop", "ptr ptr ptr", TRUE);
register_icall (mono_threads_detach_coop, "mono_threads_detach_coop", "void ptr ptr", TRUE);
+ register_icall (mono_icall_start, "mono_icall_start", "ptr ptr ptr", TRUE);
+ register_icall (mono_icall_end, "mono_icall_end", "void ptr ptr ptr", TRUE);
+ register_icall (mono_handle_new, "mono_handle_new", "ptr ptr", TRUE);
mono_cominterop_init ();
mono_remoting_init ();
else
csig = mono_metadata_signature_dup_full (method->klass->image, sig);
+ //printf ("%s\n", mono_method_full_name (method, 1));
+
/* hack - string constructors returns a value */
if (method->string_ctor)
csig->ret = &mono_defaults.string_class->byval_arg;
#ifndef DISABLE_JIT
+ // FIXME:
+ MonoClass *handle_stack_mark_class;
+ MonoClass *error_class;
+ int thread_info_var = -1, stack_mark_var = -1, error_var = -1;
+ MonoMethodSignature *call_sig = csig;
+ gboolean uses_handles;
+ (void) mono_lookup_internal_call_full (method, &uses_handles);
+
+
+ /* If it uses handles and MonoError, it had better check exceptions */
+ g_assert (!uses_handles || check_exceptions);
+
+ if (uses_handles) {
+ MonoMethodSignature *ret;
+
+ /* Add a MonoError argument */
+ // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
+ ret = mono_metadata_signature_alloc (method->klass->image, csig->param_count + 1);
+
+ ret->param_count = csig->param_count + 1;
+ ret->ret = csig->ret;
+ for (int i = 0; i < csig->param_count; ++i) {
+ // FIXME: TODO implement handle wrapping for out and inout params.
+ g_assert (!mono_signature_param_is_out (csig, i));
+ ret->params [i] = csig->params [i];
+ }
+ ret->params [csig->param_count] = &mono_get_intptr_class ()->byval_arg;
+ call_sig = ret;
+ }
+
+ if (uses_handles) {
+ handle_stack_mark_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/HandleStackMark");
+ error_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
+
+ thread_info_var = mono_mb_add_local (mb, &mono_get_intptr_class ()->byval_arg);
+ stack_mark_var = mono_mb_add_local (mb, &handle_stack_mark_class->byval_arg);
+ error_var = mono_mb_add_local (mb, &error_class->byval_arg);
+
+ // FIXME: Change csig so it passes a handle not an objref
+ }
+
if (sig->hasthis) {
int pos;
pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
mono_mb_emit_exception (mb, "NullReferenceException", NULL);
mono_mb_patch_branch (mb, pos);
-
- mono_mb_emit_byte (mb, CEE_LDARG_0);
}
- for (i = 0; i < sig->param_count; i++)
- mono_mb_emit_ldarg (mb, i + sig->hasthis);
+ if (uses_handles) {
+ mono_mb_emit_ldloc_addr (mb, stack_mark_var);
+ mono_mb_emit_ldloc_addr (mb, error_var);
+ mono_mb_emit_icall (mb, mono_icall_start);
+ mono_mb_emit_stloc (mb, thread_info_var);
+
+ if (sig->hasthis) {
+ mono_mb_emit_byte (mb, CEE_LDARG_0);
+ mono_mb_emit_icall (mb, mono_handle_new);
+ }
+ for (i = 0; i < sig->param_count; i++) {
+ mono_mb_emit_ldarg (mb, i + sig->hasthis);
+ if (MONO_TYPE_IS_REFERENCE (sig->params [i])) {
+ mono_mb_emit_icall (mb, mono_handle_new);
+ }
+ }
+ mono_mb_emit_ldloc_addr (mb, error_var);
+ } else {
+ if (sig->hasthis)
+ mono_mb_emit_byte (mb, CEE_LDARG_0);
+ for (i = 0; i < sig->param_count; i++)
+ mono_mb_emit_ldarg (mb, i + sig->hasthis);
+ }
if (aot) {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
- mono_mb_emit_calli (mb, csig);
+ mono_mb_emit_calli (mb, call_sig);
} else {
g_assert (piinfo->addr);
- mono_mb_emit_native_call (mb, csig, piinfo->addr);
+ mono_mb_emit_native_call (mb, call_sig, piinfo->addr);
+ }
+
+ if (uses_handles) {
+ if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
+ // if (ret != NULL_HANDLE) {
+ // ret = MONO_HANDLE_RAW(ret)
+ // }
+ mono_mb_emit_byte (mb, CEE_DUP);
+ int pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
+ mono_mb_emit_ldflda (mb, MONO_HANDLE_PAYLOAD_OFFSET (MonoObject));
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ mono_mb_patch_branch (mb, pos);
+ }
+ mono_mb_emit_ldloc (mb, thread_info_var);
+ mono_mb_emit_ldloc_addr (mb, stack_mark_var);
+ mono_mb_emit_ldloc_addr (mb, error_var);
+ mono_mb_emit_icall (mb, mono_icall_end);
}
+
if (check_exceptions)
emit_thread_interrupt_checkpoint (mb);
mono_mb_emit_byte (mb, CEE_RET);
{
ftnptr_eh_callback = callback;
}
+
+static MonoThreadInfo*
+mono_icall_start (HandleStackMark *stackmark, MonoError *error)
+{
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ mono_stack_mark_init (info, stackmark);
+ mono_error_init (error);
+ return info;
+}
+
+static void
+mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error)
+{
+ mono_stack_mark_pop (info, stackmark);
+ mono_error_set_pending_exception (error);
+}