register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE);
register_icall (ves_icall_marshal_alloc, "ves_icall_marshal_alloc", "ptr ptr", FALSE);
register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE);
- register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", FALSE);
- register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", FALSE);
+ register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", TRUE);
+ register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", TRUE);
register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE);
register_icall (mono_string_utf8_to_builder2, "mono_string_utf8_to_builder2", "object ptr", FALSE);
register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE);
int i = 0;
MonoClass *klass;
+ MonoError error;
#endif
if (!array)
return NULL;
#ifndef DISABLE_COM
-
+ error_init (&error);
klass = array->obj.vtable->klass;
switch (klass->element_class->byval_arg.type) {
break;
case MONO_TYPE_CLASS:
nativeArraySize = array->max_length;
- nativeArray = (void **)malloc(sizeof(gpointer) * nativeArraySize);
- for(i = 0; i < nativeArraySize; ++i)
- nativeArray[i] = ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal(((MonoObject **)array->vector)[i]);
+ nativeArray = (void **)g_malloc (sizeof(gpointer) * nativeArraySize);
+ for(i = 0; i < nativeArraySize; ++i) {
+ nativeArray[i] = mono_cominterop_get_com_interface (((MonoObject **)array->vector)[i], klass->element_class, &error);
+ if (mono_error_set_pending_exception (&error))
+ break;
+ }
return nativeArray;
case MONO_TYPE_U1:
case MONO_TYPE_BOOLEAN:
{
#ifndef DISABLE_COM
MonoClass *klass;
- int i = 0;
if (!array)
return;
return;
klass = array->obj.vtable->klass;
- if (klass->element_class->byval_arg.type == MONO_TYPE_CLASS) {
- for(i = 0; i < array->max_length; ++i)
- mono_marshal_free_ccw (mono_array_get (array, MonoObject*, i));
+ if (klass->element_class->byval_arg.type == MONO_TYPE_CLASS)
g_free (nativeArray);
- }
#endif
}
* its \p method argument.
*/
MonoMethod *
-mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_)
+mono_marshal_get_runtime_invoke_full (MonoMethod *method, gboolean virtual_, gboolean need_direct_wrapper)
{
MonoMethodSignature *sig, *csig, *callsig;
MonoMethodBuilder *mb;
static MonoMethodSignature *finalize_signature = NULL;
char *name;
const char *param_names [16];
- gboolean need_direct_wrapper = FALSE;
WrapperInfo *info;
g_assert (method);
finalize_signature->hasthis = 1;
}
- if (virtual_)
- need_direct_wrapper = TRUE;
-
/*
* Use a separate cache indexed by methods to speed things up and to avoid the
* boundless mempool growth caused by the signature_dup stuff below.
if (res)
return res;
- if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
- (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
- /*
- * Array Get/Set/Address methods. The JIT implements them using inline code
- * so we need to create an invoke wrapper which calls the method directly.
- */
- need_direct_wrapper = TRUE;
- }
-
if (method->string_ctor) {
callsig = lookup_string_ctor_signature (mono_method_signature (method));
if (!callsig)
callsig = add_string_ctor_signature (method);
- /* Can't share this as we push a string as this */
- need_direct_wrapper = TRUE;
} else {
if (method_is_dynamic (method))
callsig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
csig->call_convention = MONO_CALL_C;
#endif
- name = mono_signature_to_name (callsig, virtual_ ? "runtime_invoke_virtual" : "runtime_invoke");
+ name = mono_signature_to_name (callsig, virtual_ ? "runtime_invoke_virtual" : (need_direct_wrapper ? "runtime_invoke_direct" : "runtime_invoke"));
mb = mono_mb_new (target_klass, name, MONO_WRAPPER_RUNTIME_INVOKE);
g_free (name);
return res;
}
+MonoMethod *
+mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_)
+{
+ gboolean need_direct_wrapper = FALSE;
+
+ if (virtual_)
+ need_direct_wrapper = TRUE;
+
+ if (method->dynamic)
+ need_direct_wrapper = TRUE;
+
+ if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
+ /*
+ * Array Get/Set/Address methods. The JIT implements them using inline code
+ * so we need to create an invoke wrapper which calls the method directly.
+ */
+ need_direct_wrapper = TRUE;
+ }
+
+ if (method->string_ctor) {
+ /* Can't share this as we push a string as this */
+ need_direct_wrapper = TRUE;
+ }
+
+ return mono_marshal_get_runtime_invoke_full (method, virtual_, need_direct_wrapper);
+}
+
/*
* mono_marshal_get_runtime_invoke_dynamic:
*
int i, argnum, *tmp_locals;
int type, param_shift = 0;
int coop_gc_stack_dummy, coop_gc_var;
+#ifndef DISABLE_COM
+ int coop_cominterop_fnptr;
+#endif
memset (&m, 0, sizeof (m));
m.mb = mb;
mono_mb_add_local (mb, sig->ret);
}
- if (mono_threads_is_coop_enabled ()) {
+ if (mono_threads_is_blocking_transition_enabled ()) {
/* local 4, dummy local used to get a stack address for suspend funcs */
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);
+#ifndef DISABLE_COM
+ if (!func_param && MONO_CLASS_IS_IMPORT (mb->method->klass)) {
+ coop_cominterop_fnptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ }
+#endif
}
/*
}
// In coop mode need to register blocking state during native call
- if (mono_threads_is_coop_enabled ()) {
+ if (mono_threads_is_blocking_transition_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, CEE_POP); // Result not needed yet
}
+#ifndef DISABLE_COM
+ if (!func_param && MONO_CLASS_IS_IMPORT (mb->method->klass)) {
+ mono_mb_emit_cominterop_get_function_pointer (mb, &piinfo->method);
+ mono_mb_emit_stloc (mb, coop_cominterop_fnptr);
+ }
+#endif
+
mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
mono_mb_emit_icall (mb, mono_threads_enter_gc_safe_region_unbalanced);
mono_mb_emit_stloc (mb, coop_gc_var);
mono_mb_emit_calli (mb, csig);
} else if (MONO_CLASS_IS_IMPORT (mb->method->klass)) {
#ifndef DISABLE_COM
- mono_mb_emit_cominterop_call (mb, csig, &piinfo->method);
+ if (!mono_threads_is_blocking_transition_enabled ()) {
+ mono_mb_emit_cominterop_call (mb, csig, &piinfo->method);
+ } else {
+ mono_mb_emit_ldloc (mb, coop_cominterop_fnptr);
+ mono_mb_emit_cominterop_call_function_pointer (mb, csig);
+ }
#else
g_assert_not_reached ();
#endif
}
/* Unblock before converting the result, since that can involve calls into the runtime */
- if (mono_threads_is_coop_enabled ()) {
+ if (mono_threads_is_blocking_transition_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_exit_gc_safe_region_unbalanced);
/* try { */
clause_catch->try_offset = clause_finally->try_offset = mono_mb_get_label (mb);
- if (!mono_threads_is_coop_enabled ()) {
+ if (!mono_threads_is_blocking_transition_enabled ()) {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
} else {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_byte (mb, CEE_MONO_LDDOMAIN);
mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
+ /*
+ * This icall is special cased in the JIT so it works in native-to-managed wrappers in unattached threads.
+ * Keep this in sync with the CEE_JIT_ICALL code in the JIT.
+ */
mono_mb_emit_icall (mb, mono_threads_attach_coop);
mono_mb_emit_stloc (mb, attach_cookie_local);
}
clause_finally->try_len = mono_mb_get_label (mb) - clause_finally->try_offset;
clause_finally->handler_offset = mono_mb_get_label (mb);
- if (!mono_threads_is_coop_enabled ()) {
+ if (!mono_threads_is_blocking_transition_enabled ()) {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
} else {
void
mono_marshal_set_last_error (void)
{
+ /* This icall is called just after a P/Invoke call before the P/Invoke
+ * wrapper transitions the runtime back to running mode. */
+ MONO_REQ_GC_SAFE_MODE;
#ifdef WIN32
mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (GetLastError ()));
#else
mono_marshal_set_last_error_windows (int error)
{
#ifdef WIN32
+ /* This icall is called just after a P/Invoke call before the P/Invoke
+ * wrapper transitions the runtime back to running mode. */
+ MONO_REQ_GC_SAFE_MODE;
mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (error));
#endif
}
layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
- /* The mempool is protected by the loader lock */
info = (MonoMarshalType *)mono_image_alloc0 (klass->image, MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count);
info->num_fields = count;
info->min_align = min_align;
/* Update the class's blittable info, if the layouts don't match */
- if (info->native_size != mono_class_value_size (klass, NULL))
+ if (info->native_size != mono_class_value_size (klass, NULL)) {
+ mono_loader_lock ();
klass->blittable = FALSE;
+ mono_loader_unlock ();
+ }
/* If this is an array type, ensure that we have element info */
if (klass->rank && !mono_marshal_is_loading_type_info (klass->element_class)) {
mono_gchandle_free (gchandle);
- mono_raise_exception (exc);
+ mono_reraise_exception (exc);
}
/*