* 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 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);
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;
static void
parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piinfo)
{
+ MonoError error;
MonoCustomAttrInfo *cinfo;
MonoReflectionUnmanagedFunctionPointerAttribute *attr;
* The pinvoke attributes are stored in a real custom attribute so we have to
* construct it.
*/
- cinfo = mono_custom_attrs_from_class (klass);
+ cinfo = mono_custom_attrs_from_class_checked (klass, &error);
+ if (!mono_error_ok (&error)) {
+ g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error));
+ mono_error_cleanup (&error);
+ }
if (cinfo && !mono_runtime_get_no_exec ()) {
- MonoError error;
attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_try_get_unmanaged_function_pointer_attribute_class (), &error);
if (attr) {
piinfo->piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
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);
}
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);
}
}
}
static MonoAsyncResult *
mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
{
+ MonoError error;
MonoMulticastDelegate *mcast_delegate;
MonoClass *klass;
MonoMethod *method;
msg->call_type = CallType_BeginInvoke;
exc = NULL;
- mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+ mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
if (exc)
mono_set_pending_exception ((MonoException *) exc);
return ares;
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_message_init (domain, msg, delegate->method_info, NULL);
msg->call_type = CallType_EndInvoke;
MONO_OBJECT_SETREF (msg, async_result, ares);
- res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+ res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
} else
#endif
{
if (callvirt) {
subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL;
if (target_method->is_inflated) {
+ MonoError error;
MonoType *target_type;
g_assert (method->signature->hasthis);
- target_type = mono_class_inflate_generic_type (method->signature->params [0],
- mono_method_get_context (method));
+ target_type = mono_class_inflate_generic_type_checked (method->signature->params [0],
+ mono_method_get_context (method), &error);
+ mono_error_assert_ok (&error); /* FIXME don't swallow the error */
target_class = mono_class_from_mono_type (target_type);
} else {
target_class = target_method->klass;
*conv_arg_type = &mono_defaults.int_class->byval_arg;
return conv_arg;
#else
+ MonoError error;
MonoType *mtype;
MonoClass *mklass;
static MonoClass *ICustomMarshaler = NULL;
}
if (spec->data.custom_data.image)
- mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, spec->data.custom_data.image);
+ mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, spec->data.custom_data.image, &error);
else
- mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
+ mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, m->image, &error);
g_assert (mtype != NULL);
+ mono_error_assert_ok (&error);
mklass = mono_class_from_mono_type (mtype);
g_assert (mklass != NULL);
}
/* load pointer to returned value type */
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+ g_assert (m->vtaddr_var);
+ mono_mb_emit_ldloc (mb, m->vtaddr_var);
/* store the address of the source into local variable 0 */
mono_mb_emit_stloc (mb, 0);
/* set dst_ptr */
}
/* load pointer to returned value type */
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+ g_assert (m->vtaddr_var);
+ mono_mb_emit_ldloc (mb, m->vtaddr_var);
/* store the address of the source into local variable 0 */
mono_mb_emit_stloc (mb, 0);
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 {
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_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;
}
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;
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;
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;
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);
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);
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);
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
/* dest */
mono_mb_emit_ldloc (mb, dest_ptr);
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);
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
/* dest */
mono_mb_emit_ldloc (mb, dest);
EmitMarshalContext m;
MonoMethodSignature *csig;
MonoClass *klass;
+ MonoExceptionClause *clause;
int i, argnum, *tmp_locals;
int type, param_shift = 0;
static MonoMethodSignature *get_last_error_sig = NULL;
- int coop_gc_stack_dummy, coop_gc_var;
+ int coop_gc_stack_dummy, coop_gc_var, coop_unblocked_var;
+ int leave_pos;
memset (&m, 0, sizeof (m));
m.mb = mb;
mono_mb_emit_icon (mb, 0);
mono_mb_emit_stloc (mb, 2);
- if (!MONO_TYPE_IS_VOID(sig->ret)) {
+ if (!MONO_TYPE_IS_VOID (sig->ret)) {
/* allocate local 3 to store the return value */
mono_mb_add_local (mb, sig->ret);
}
coop_gc_stack_dummy = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
/* local 5, the local to be used when calling the suspend funcs */
coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ coop_unblocked_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
+ clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
}
+ if (MONO_TYPE_ISSTRUCT (sig->ret))
+ m.vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
/* Return type custom marshaling */
/*
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);
+ mono_mb_emit_icall (mb, mono_threads_prepare_blocking);
+ mono_mb_emit_stloc (mb, coop_gc_var);
+ }
+
/* push all arguments */
if (sig->hasthis)
emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
}
- if (mono_threads_is_coop_enabled ()) {
- mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
- mono_mb_emit_icall (mb, mono_threads_prepare_blocking);
- mono_mb_emit_stloc (mb, coop_gc_var);
- }
-
/* call the native method */
if (func_param) {
mono_mb_emit_byte (mb, CEE_LDARG_0);
#endif
}
+ if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ MonoClass *klass = mono_class_from_mono_type (sig->ret);
+ mono_class_init (klass);
+ if (!(((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable)) {
+ /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+ mono_mb_emit_stloc (mb, m.vtaddr_var);
+ }
+ }
+
+ /* Unblock before converting the result, since that can involve calls into the runtime */
if (mono_threads_is_coop_enabled ()) {
mono_mb_emit_ldloc (mb, coop_gc_var);
mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
mono_mb_emit_icall (mb, mono_threads_finish_blocking);
+ mono_mb_emit_icon (mb, 1);
+ mono_mb_emit_stloc (mb, coop_unblocked_var);
}
/* convert the result */
if (spec && spec->native == MONO_NATIVE_CUSTOM) {
emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
} else {
-
handle_enum:
switch (type) {
case MONO_TYPE_VOID:
mono_mb_emit_stloc (mb, 3);
}
+ if (mono_threads_is_coop_enabled ()) {
+ int pos;
+
+ leave_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+ clause->try_len = mono_mb_get_label (mb) - clause->try_offset;
+ clause->handler_offset = mono_mb_get_label (mb);
+
+ mono_mb_emit_ldloc (mb, coop_unblocked_var);
+ mono_mb_emit_icon (mb, 1);
+ pos = mono_mb_emit_branch (mb, CEE_BEQ);
+
+ mono_mb_emit_ldloc (mb, coop_gc_var);
+ mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
+ mono_mb_emit_icall (mb, mono_threads_finish_blocking);
+
+ mono_mb_patch_branch (mb, pos);
+
+ mono_mb_emit_byte (mb, CEE_ENDFINALLY);
+
+ clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
+
+ mono_mb_patch_branch (mb, leave_pos);
+ }
+
/*
* Need to call this after converting the result since MONO_VTADDR needs
* to be adjacent to the call instruction.
mono_mb_emit_ldloc (mb, 3);
mono_mb_emit_byte (mb, CEE_RET);
+
+ if (mono_threads_is_coop_enabled ()) {
+ mono_mb_set_clauses (mb, 1, clause);
+ }
}
#endif /* DISABLE_JIT */
mono_mb_add_local (mb, sig->ret);
}
+ if (MONO_TYPE_ISSTRUCT (sig->ret))
+ m->vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
/*
* try {
* mono_jit_attach ();
/* ret = method (...) */
mono_mb_emit_managed_call (mb, method, NULL);
+ if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ MonoClass *klass = mono_class_from_mono_type (sig->ret);
+ mono_class_init (klass);
+ if (!(((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable)) {
+ /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+ mono_mb_emit_stloc (mb, m->vtaddr_var);
+ }
+ }
+
if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
} else if (!sig->ret->byref) {
MonoMethod *
mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle)
{
+ MonoError error;
MonoMethodSignature *sig, *csig, *invoke_sig;
MonoMethodBuilder *mb;
MonoMethod *res, *invoke;
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
* contents of the attribute without constructing it, as that might not be
* possible when running in cross-compiling mode.
*/
- cinfo = mono_custom_attrs_from_class (delegate_klass);
+ cinfo = mono_custom_attrs_from_class_checked (delegate_klass, &error);
+ mono_error_assert_ok (&error);
attr = NULL;
if (cinfo) {
for (i = 0; i < cinfo->num_attrs; ++i) {
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)
/*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));