* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
static gboolean use_aot_wrappers;
+static MonoFtnPtrEHCallback ftnptr_eh_callback;
+
static void
delegate_hash_table_add (MonoDelegate *d);
void
mono_free_lparray (MonoArray *array, gpointer* nativeArray);
+static gint32
+mono_marshal_has_ftnptr_eh_callback (void);
+
+static void
+mono_marshal_ftnptr_eh_callback (guint32 gchandle);
+
/* 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)
}
static void
-register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
+register_icall (gpointer func, const char *name, const char *sigstr, gboolean no_wrapper)
{
MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
- mono_register_jit_icall (func, name, sig, save);
+ mono_register_jit_icall (func, name, sig, no_wrapper);
}
MonoMethodSignature*
mono_native_tls_alloc (&load_type_info_tls_id, NULL);
}
+static MonoObject*
+mono_object_isinst_icall (MonoObject *obj, MonoClass *klass)
+{
+ MonoError error;
+ MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
void
mono_marshal_init (void)
{
register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
register_icall (g_free, "g_free", "void ptr", FALSE);
- register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
+ register_icall (mono_object_isinst_icall, "mono_object_isinst_icall", "object object ptr", FALSE);
register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
+ register_icall (mono_gchandle_new, "mono_gchandle_new", "uint32 object bool", TRUE);
register_icall (mono_marshal_isinst_with_cache, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE);
+ register_icall (mono_marshal_has_ftnptr_eh_callback, "mono_marshal_has_ftnptr_eh_callback", "int32", TRUE);
+ register_icall (mono_marshal_ftnptr_eh_callback, "mono_marshal_ftnptr_eh_callback", "void uint32", TRUE);
mono_cominterop_init ();
mono_remoting_init ();
if (delegate->method_is_virtual)
method = mono_object_get_virtual_method (delegate->target, method);
- if (mono_method_signature (method)->pinvoke) {
+ if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
const char *exc_class, *exc_arg;
gpointer ftnptr;
if (use_aot_wrappers) {
wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
- this_obj = mono_value_box (mono_domain_get (), mono_defaults.int_class, &ftn);
+ this_obj = mono_value_box_checked (mono_domain_get (), mono_defaults.int_class, &ftn, &error);
+ if (!is_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
} else {
memset (&piinfo, 0, sizeof (piinfo));
parse_unmanaged_function_pointer_attr (klass, &piinfo);
}
}
+/* This is a JIT icall, it sets the pending exception and returns NULL on error */
static MonoString *
mono_string_from_byvalstr (const char *data, int max_len)
{
+ MonoError error;
MonoDomain *domain = mono_domain_get ();
int len = 0;
while (len < max_len - 1 && data [len])
len++;
- return mono_string_new_len (domain, data, len);
+ MonoString *result = mono_string_new_len_checked (domain, data, len, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
/* This is a JIT icall, it sets the pending exception and return NULL on error */
*((gunichar2 *) dst + len) = 0;
}
+/* this is an icall, it sets the pending exception and returns NULL on error */
static MonoString*
mono_string_new_len_wrapper (const char *text, guint length)
{
- return mono_string_new_len (mono_domain_get (), text, length);
+ MonoError error;
+ MonoString *result = mono_string_new_len_checked (mono_domain_get (), text, length, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
#ifndef DISABLE_JIT
mono_type_to_stind (MonoType *type)
{
if (type->byref)
- return CEE_STIND_I;
+ return MONO_TYPE_IS_REFERENCE (type) ? CEE_STIND_REF : CEE_STIND_I;
+
handle_enum:
switch (type->type) {
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
mono_mb_emit_op (mb, CEE_NEWARR, eklass);
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
if (eklass->blittable) {
/* copy the elements */
}
static gpointer
-conv_to_icall (MonoMarshalConv conv)
+conv_to_icall (MonoMarshalConv conv, int *ind_store_type)
{
+ int dummy;
+ if (!ind_store_type)
+ ind_store_type = &dummy;
+ *ind_store_type = CEE_STIND_I;
switch (conv) {
case MONO_MARSHAL_CONV_STR_LPWSTR:
return mono_marshal_string_to_utf16;
case MONO_MARSHAL_CONV_LPWSTR_STR:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_from_utf16;
case MONO_MARSHAL_CONV_LPTSTR_STR:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_new_wrapper;
case MONO_MARSHAL_CONV_LPSTR_STR:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_new_wrapper;
case MONO_MARSHAL_CONV_STR_LPTSTR:
#ifdef TARGET_WIN32
case MONO_MARSHAL_CONV_STR_BSTR:
return mono_string_to_bstr;
case MONO_MARSHAL_CONV_BSTR_STR:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_from_bstr;
case MONO_MARSHAL_CONV_STR_TBSTR:
case MONO_MARSHAL_CONV_STR_ANSIBSTR:
case MONO_MARSHAL_CONV_DEL_FTN:
return mono_delegate_to_ftnptr;
case MONO_MARSHAL_CONV_FTN_DEL:
+ *ind_store_type = CEE_STIND_REF;
return mono_ftnptr_to_delegate;
case MONO_MARSHAL_CONV_LPSTR_SB:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_utf8_to_builder;
case MONO_MARSHAL_CONV_LPTSTR_SB:
+ *ind_store_type = CEE_STIND_REF;
#ifdef TARGET_WIN32
return mono_string_utf16_to_builder;
#else
return mono_string_utf8_to_builder;
#endif
case MONO_MARSHAL_CONV_LPWSTR_SB:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_utf16_to_builder;
case MONO_MARSHAL_FREE_ARRAY:
return mono_marshal_free_array;
emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
{
int pos;
+ int stind_op;
switch (conv) {
case MONO_MARSHAL_CONV_BOOL_I4:
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
break;
}
case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
break;
case MONO_MARSHAL_CONV_STR_BYVALSTR:
case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */
mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
break;
}
case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
}
default: {
- char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
- MonoException *exc = mono_get_exception_not_implemented (msg);
- g_warning ("%s", msg);
- g_free (msg);
- mono_raise_exception (exc);
+ g_error ("marshalling conversion %d not implemented", conv);
}
}
}
case MONO_MARSHAL_CONV_NONE: {
int t;
- if (ftype->byref || ftype->type == MONO_TYPE_I ||
- ftype->type == MONO_TYPE_U) {
+ //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
+ g_assert (!ftype->byref);
+ if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) {
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_I);
method = mono_get_delegate_invoke (klass);
g_assert (method);
- return mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params);
+ MonoAsyncResult *result = mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
#ifndef DISABLE_JIT
case MONO_NATIVE_BSTR:
return MONO_MARSHAL_CONV_STR_BSTR;
default:
- return (MonoMarshalConv)-1;
+ return MONO_MARSHAL_CONV_INVALID;
}
}
return MONO_MARSHAL_CONV_SB_LPTSTR;
break;
default:
- return (MonoMarshalConv)-1;
+ return MONO_MARSHAL_CONV_INVALID;
}
}
case MONO_NATIVE_BSTR:
return MONO_MARSHAL_CONV_BSTR_STR;
default:
- return (MonoMarshalConv)-1;
+ return MONO_MARSHAL_CONV_INVALID;
}
}
return MONO_MARSHAL_CONV_LPTSTR_SB;
break;
default:
- return (MonoMarshalConv)-1;
+ return MONO_MARSHAL_CONV_INVALID;
}
}
mono_set_pending_exception ((MonoException*)exc);
}
- mono_method_return_message_restore (method, params, out_args);
+ mono_method_return_message_restore (method, params, out_args, &error);
+ mono_error_set_pending_exception (&error);
return res;
}
mono_mb_emit_ldarg (mb, argnum);
}
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
} else {
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, conv_arg);
}
case MARSHAL_ACTION_CONV_OUT:
conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
mono_mb_emit_icall (mb, mono_string_new_len_wrapper);
mono_mb_emit_byte (mb, CEE_STIND_REF);
} else if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
+ int stind_op;
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_REF);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
need_free = TRUE;
}
mono_mb_emit_stloc (mb, 0);
conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
}
mono_mb_emit_ldloc (mb, 0);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, 3);
/* free the string */
}
conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
mono_mb_emit_ldarg (mb, argnum);
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, conv_arg);
break;
case MARSHAL_ACTION_MANAGED_CONV_OUT:
if (t->byref) {
if (conv_arg) {
+ int stind_op;
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
}
}
break;
case MARSHAL_ACTION_MANAGED_CONV_RESULT:
- if (conv_to_icall (conv) == mono_marshal_string_to_utf16)
+ if (conv_to_icall (conv, NULL) == mono_marshal_string_to_utf16)
/* We need to make a copy so the caller is able to free it */
mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
else
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, 3);
break;
mono_mb_emit_stloc (mb, conv_arg);
} else {
mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
mono_mb_emit_stloc (mb, conv_arg);
}
} else if (klass == mono_defaults.stringbuilder_class) {
if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))
break;
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, conv_arg);
} else if (klass->blittable) {
mono_mb_emit_byte (mb, CEE_LDNULL);
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
}
if (need_free) {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
mono_mb_emit_byte (mb, CEE_STIND_REF);
}
break;
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
mono_mb_emit_ldloc (mb, 0);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
mono_mb_emit_stloc (mb, 3);
} else {
/* set src */
mono_mb_emit_ldarg (mb, argnum);
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
mono_mb_emit_stloc (mb, conv_arg);
break;
}
case MARSHAL_ACTION_MANAGED_CONV_OUT:
if (klass->delegate) {
if (t->byref) {
+ int stind_op;
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
break;
}
}
case MARSHAL_ACTION_MANAGED_CONV_RESULT:
if (klass->delegate) {
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
mono_mb_emit_stloc (mb, 3);
break;
}
mono_mb_emit_ldarg (mb, argnum);
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL));
mono_mb_emit_stloc (mb, conv_arg);
} else {
MonoClass *eklass;
conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
}
else
- conv = (MonoMarshalConv)-1;
+ conv = MONO_MARSHAL_CONV_INVALID;
- if (is_string && conv == -1) {
+ if (is_string && conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
/* Emit marshalling code */
if (is_string) {
+ int stind_op;
mono_mb_emit_ldloc (mb, dest_ptr);
mono_mb_emit_ldloc (mb, src_var);
mono_mb_emit_ldloc (mb, index_var);
mono_mb_emit_byte (mb, CEE_LDELEM_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
} else {
/* set the src_ptr */
mono_mb_emit_ldloc (mb, src_var);
mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
mono_mb_emit_op (mb, CEE_NEWARR, klass->element_class);
/* Store into argument */
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
}
}
gboolean need_free2;
MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
- g_assert (conv != -1);
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
/* dest */
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, src_ptr);
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
if (need_free) {
/* src */
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_REF);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL));
}
break;
conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
}
else
- conv = (MonoMarshalConv)-1;
+ conv = MONO_MARSHAL_CONV_INVALID;
mono_marshal_load_type_info (eklass);
/* Emit marshalling code */
if (is_string) {
- g_assert (conv != -1);
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
mono_mb_emit_ldloc (mb, conv_arg);
mono_mb_emit_ldloc (mb, index_var);
mono_mb_emit_ldloc (mb, src_ptr);
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_byte (mb, CEE_STELEM_REF);
}
else {
conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
}
else
- conv = (MonoMarshalConv)-1;
+ conv = MONO_MARSHAL_CONV_INVALID;
mono_marshal_load_type_info (eklass);
/* Emit marshalling code */
if (is_string) {
- g_assert (conv != -1);
+ int stind_op;
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
/* dest */
mono_mb_emit_ldloc (mb, dest_ptr);
mono_mb_emit_byte (mb, CEE_LDELEM_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
}
else {
char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
MonoClass *eklass;
guint32 label1, label2, label3;
int index_var, src, dest, esize;
- MonoMarshalConv conv = (MonoMarshalConv)-1;
+ MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID;
gboolean is_string = FALSE;
g_assert (!t->byref);
/* Emit marshalling code */
if (is_string) {
- g_assert (conv != -1);
+ int stind_op;
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
/* dest */
mono_mb_emit_ldloc (mb, dest);
mono_mb_emit_byte (mb, CEE_LDELEM_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
}
else {
char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
-#ifndef DISABLE_COM
+#if !defined(DISABLE_COM) && !defined(DISABLE_JIT)
if (spec && spec->native == MONO_NATIVE_STRUCT)
return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+#endif
+#if !defined(DISABLE_COM)
if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
spec->native == MONO_NATIVE_IDISPATCH ||
spec->native == MONO_NATIVE_INTERFACE))
tmp_locals [i] = emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
}
+ // In coop mode need to register blocking state during native call
if (mono_threads_is_coop_enabled ()) {
+ // Perform an extra, early lookup of the function address, so any exceptions
+ // potentially resulting from the lookup occur before entering blocking mode.
+ if (!func_param && !MONO_CLASS_IS_IMPORT (mb->method->klass) && aot) {
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
+ mono_mb_emit_byte (mb, CEE_POP); // Result not needed yet
+ }
+
clause->try_offset = mono_mb_get_label (mb);
mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
}
#else
MonoMethodSignature *sig, *csig;
- MonoExceptionClause *clause;
- int i, *tmp_locals;
- int leave_pos;
+ MonoExceptionClause *clauses, *clause_finally, *clause_catch;
+ int i, *tmp_locals, ex_local, e_local;
+ int leave_try_pos, leave_catch_pos, ex_m1_pos, rethrow_pos;
gboolean closed = FALSE;
sig = m->sig;
if (MONO_TYPE_ISSTRUCT (sig->ret))
m->vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ ex_local = mono_mb_add_local (mb, &mono_defaults.uint32_class->byval_arg);
+ e_local = mono_mb_add_local (mb, &mono_defaults.exception_class->byval_arg);
+
/*
+ * guint32 ex = -1;
* try {
* mono_jit_attach ();
*
* <interrupt check>
*
* ret = method (...);
+ * } catch (Exception e) {
+ * if (!mono_marshal_has_ftnptr_eh_callback ())
+ * throw e;
+ * ex = mono_gchandle_new (e, false);
* } finally {
* mono_jit_detach ();
* }
+ * if (ex != -1)
+ * mono_marshal_ftnptr_eh_callback (ex);
*
* return ret;
*/
- if (mono_threads_is_coop_enabled ()) {
- clause = g_new0 (MonoExceptionClause, 1);
- clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
- }
+ clauses = g_new0 (MonoExceptionClause, 2);
+
+ clause_catch = &clauses [0];
+ clause_catch->flags = MONO_EXCEPTION_CLAUSE_NONE;
+ clause_catch->data.catch_class = mono_defaults.exception_class;
+
+ clause_finally = &clauses [1];
+ clause_finally->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
mono_mb_emit_icon (mb, 0);
mono_mb_emit_stloc (mb, 2);
- if (mono_threads_is_coop_enabled ()) {
- /* try { */
- clause->try_offset = mono_mb_get_label (mb);
- }
+ mono_mb_emit_icon (mb, -1);
+ mono_mb_emit_byte (mb, CEE_CONV_U4);
+ mono_mb_emit_stloc (mb, ex_local);
+
+ /* try { */
+ clause_catch->try_offset = clause_finally->try_offset = mono_mb_get_label (mb);
/*
* Might need to attach the thread to the JIT or change the
}
}
- if (mono_threads_is_coop_enabled ()) {
- leave_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
+ leave_try_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
- /* } finally { */
- clause->try_len = mono_mb_get_label (mb) - clause->try_offset;
- clause->handler_offset = mono_mb_get_label (mb);
- }
+ /* } catch (Exception e) { */
+ clause_catch->try_len = mono_mb_get_label (mb) - clause_catch->try_offset;
+ clause_catch->handler_offset = mono_mb_get_label (mb);
+
+ mono_mb_emit_stloc (mb, e_local);
+
+ /* if (!mono_marshal_has_ftnptr_eh_callback ()) { */
+ mono_mb_emit_icall (mb, mono_marshal_has_ftnptr_eh_callback);
+ rethrow_pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
+
+ /* throw e; */
+ mono_mb_emit_ldloc (mb, e_local);
+ mono_mb_emit_byte (mb, CEE_THROW);
+
+ /* } [endif] */
+ mono_mb_patch_branch (mb, rethrow_pos);
+
+ /* ex = mono_gchandle_new (e, false); */
+ mono_mb_emit_ldloc (mb, e_local);
+ mono_mb_emit_icon (mb, 0);
+ mono_mb_emit_icall (mb, mono_gchandle_new);
+ mono_mb_emit_stloc (mb, ex_local);
+
+ leave_catch_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+ /* } [endcatch] */
+ clause_catch->handler_len = mono_mb_get_pos (mb) - clause_catch->handler_offset;
+
+ /* } finally { */
+ clause_finally->try_len = mono_mb_get_label (mb) - clause_finally->try_offset;
+ clause_finally->handler_offset = mono_mb_get_label (mb);
/*
* Also does the RUNNING -> (BLOCKING|RUNNING) thread state transition
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
- if (mono_threads_is_coop_enabled ()) {
- mono_mb_emit_byte (mb, CEE_ENDFINALLY);
+ mono_mb_emit_byte (mb, CEE_ENDFINALLY);
- /* } [endfinally] */
- clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
+ /* } [endfinally] */
+ clause_finally->handler_len = mono_mb_get_pos (mb) - clause_finally->handler_offset;
- mono_mb_patch_branch (mb, leave_pos);
- }
+ mono_mb_patch_branch (mb, leave_try_pos);
+ mono_mb_patch_branch (mb, leave_catch_pos);
+
+ /* if (ex != -1) */
+ mono_mb_emit_ldloc (mb, ex_local);
+ mono_mb_emit_icon (mb, -1);
+ mono_mb_emit_byte (mb, CEE_CONV_U4);
+ ex_m1_pos = mono_mb_emit_branch (mb, CEE_BEQ);
+
+ /* mono_marshal_ftnptr_eh_callback (ex) */
+ mono_mb_emit_ldloc (mb, ex_local);
+ mono_mb_emit_icall (mb, mono_marshal_ftnptr_eh_callback);
+
+ /* [ex == -1] */
+ mono_mb_patch_branch (mb, ex_m1_pos);
/* return ret; */
if (m->retobj_var) {
mono_mb_emit_byte (mb, CEE_RET);
}
- if (mono_threads_is_coop_enabled ()) {
- mono_mb_set_clauses (mb, 1, clause);
- }
+ mono_mb_set_clauses (mb, 2, clauses);
if (closed)
g_free (sig);
EmitMarshalContext m;
g_assert (method != NULL);
- g_assert (!mono_method_signature (method)->pinvoke);
+ g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
/*
* FIXME: Should cache the method+delegate type pair, since the same method
static MonoObject *
mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
{
- MonoObject *isinst = mono_object_isinst (obj, klass);
+ MonoError error;
+ MonoObject *isinst = mono_object_isinst_checked (obj, klass, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
#ifndef DISABLE_REMOTING
if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
// return obj
mono_mb_patch_branch (mb, positive_cache_hit_pos);
- mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_ldarg (mb, obj_arg_position);
mono_mb_emit_byte (mb, CEE_RET);
#endif
if (!enter_method) {
MonoMethodDesc *desc;
- desc = mono_method_desc_new ("Monitor:enter_with_atomic_var(object,bool&)", FALSE);
+ desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
g_assert (enter_method);
mono_method_desc_free (desc);
/*if (mono_object_isinst (value, aklass)) */
mono_mb_emit_ldarg (mb, 2);
mono_mb_emit_ldloc (mb, aklass);
- mono_mb_emit_icall (mb, mono_object_isinst);
+ mono_mb_emit_icall (mb, mono_object_isinst_icall);
b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
/* do_store: */
/*if (mono_object_isinst (value, aklass)) */
mono_mb_emit_ldarg (mb, 2);
mono_mb_emit_ldloc (mb, aklass);
- mono_mb_emit_icall (mb, mono_object_isinst);
+ mono_mb_emit_icall (mb, mono_object_isinst_icall);
b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
/* if (vklass->idepth < aklass->idepth) goto failue */
mono_mb_emit_ldarg (mb, 2);
mono_mb_emit_ldloc (mb, aklass);
- mono_mb_emit_icall (mb, mono_object_isinst);
+ mono_mb_emit_icall (mb, mono_object_isinst_icall);
b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
MonoString *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
{
- if (ptr == NULL) {
- mono_set_pending_exception (mono_get_exception_argument_null ("ptr"));
- return NULL;
- } else {
- return mono_string_new_len (mono_domain_get (), ptr, len);
- }
+ MonoError error;
+ MonoString *result = NULL;
+ mono_error_init (&error);
+ if (ptr == NULL)
+ mono_error_set_argument_null (&error, "ptr", "");
+ else
+ result = mono_string_new_len_checked (mono_domain_get (), ptr, len, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
MonoString *
if (marshal_mutex_initialized)
mono_marshal_unlock ();
}
+
+static gint32
+mono_marshal_has_ftnptr_eh_callback (void)
+{
+ return ftnptr_eh_callback != NULL;
+}
+
+static void
+mono_marshal_ftnptr_eh_callback (guint32 gchandle)
+{
+ g_assert (ftnptr_eh_callback);
+ ftnptr_eh_callback (gchandle);
+}
+
+/*
+ * mono_install_ftnptr_eh_callback:
+ *
+ * Install a callback that should be called when there is a managed exception
+ * in a native-to-managed wrapper. This is mainly used by iOS to convert a
+ * managed exception to a native exception, to properly unwind the native
+ * stack; this native exception will then be converted back to a managed
+ * exception in their managed-to-native wrapper.
+ */
+void
+mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
+{
+ ftnptr_eh_callback = callback;
+}