/*
- * generic-sharing.c: Support functions for generic sharing.
+ * mini-generic-sharing.c: Support functions for generic sharing.
*
* Author:
* Mark Probst (mark.probst@gmail.com)
*
* Copyright 2007-2011 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>
memcpy_method [size] = m;
}
if (!domain_info->memcpy_addr [size]) {
- gpointer addr = mono_compile_method (memcpy_method [size]);
+ gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
mono_memory_barrier ();
domain_info->memcpy_addr [size] = (gpointer *)addr;
+ mono_error_assert_ok (error);
}
return domain_info->memcpy_addr [size];
} else {
bzero_method [size] = m;
}
if (!domain_info->bzero_addr [size]) {
- gpointer addr = mono_compile_method (bzero_method [size]);
+ gpointer addr = mono_compile_method_checked (bzero_method [size], error);
mono_memory_barrier ();
domain_info->bzero_addr [size] = (gpointer *)addr;
+ mono_error_assert_ok (error);
}
return domain_info->bzero_addr [size];
}
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
case MONO_TYPE_PTR:
- return &mono_defaults.int_class->byval_arg;
+ // FIXME: refs and intptr cannot be shared because
+ // they are treated differently when a method has a vret arg,
+ // see get_call_info ().
+ return &mono_defaults.object_class->byval_arg;
+ //return &mono_defaults.int_class->byval_arg;
case MONO_TYPE_GENERICINST: {
MonoError error;
MonoClass *klass;
int i;
if (!MONO_TYPE_ISSTRUCT (t))
- return &mono_defaults.int_class->byval_arg;
+ return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
klass = mono_class_from_mono_type (t);
orig_ctx = &klass->generic_class->context;
// FIXME:
if (stind_op == CEE_STOBJ)
mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
+ else if (stind_op == CEE_STIND_REF)
+ /* Avoid write barriers, the vret arg points to the stack */
+ mono_mb_emit_byte (mb, CEE_STIND_I);
else
mono_mb_emit_byte (mb, stind_op);
}
{
static gboolean inited = FALSE;
static int num_trampolines;
+ MonoError error;
gpointer res, info;
MonoDomain *domain = mono_domain_get ();
MonoJitDomainInfo *domain_info;
wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
else
wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
- res = mono_compile_method (wrapper);
+ res = mono_compile_method_checked (wrapper, &error);
+ mono_error_assert_ok (&error);
return res;
}
if (!tramp_addr) {
wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
- addr = mono_compile_method (wrapper);
+ addr = mono_compile_method_checked (wrapper, &error);
mono_memory_barrier ();
+ mono_error_assert_ok (&error);
tramp_addr = addr;
}
addr = tramp_addr;
if (!tramp_addr) {
wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
- addr = mono_compile_method (wrapper);
+ addr = mono_compile_method_checked (wrapper, &error);
mono_memory_barrier ();
+ mono_error_assert_ok (&error);
tramp_addr = addr;
}
addr = tramp_addr;
gpointer arg = NULL;
if (mono_llvm_only) {
- addr = mono_compile_method (m);
+ addr = mono_compile_method_checked (m, error);
+ return_val_if_nok (error, NULL);
addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
/* Returns an ftndesc */
return mini_create_llvmonly_ftndesc (domain, addr, arg);
} else {
- addr = mono_compile_method ((MonoMethod *)data);
+ addr = mono_compile_method_checked ((MonoMethod *)data, error);
+ return_val_if_nok (error, NULL);
return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
}
}
g_assert (mono_llvm_only);
- addr = mono_compile_method (m);
+ addr = mono_compile_method_checked (m, error);
+ return_val_if_nok (error, NULL);
MonoJitInfo *ji;
gboolean callee_gsharedvt;
method = info->klass->vtable [ioffset + slot];
method = mono_class_inflate_generic_method_checked (method, context, error);
- if (!mono_error_ok (error))
- return NULL;
- addr = mono_compile_method (method);
+ return_val_if_nok (error, NULL);
+ addr = mono_compile_method_checked (method, error);
+ return_val_if_nok (error, NULL);
return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
}
case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
}
#ifndef DISABLE_REMOTING
case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
- return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
+ return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
#endif
case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
return mono_domain_alloc0 (domain, sizeof (gpointer));
g_assert (method->is_inflated);
- if (!virtual_)
- addr = mono_compile_method (method);
- else
+ if (!virtual_) {
+ addr = mono_compile_method_checked (method, error);
+ return_val_if_nok (error, NULL);
+ } else
addr = NULL;
if (virtual_) {
return mrgctx;
}
-
-static gboolean
-generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
- gboolean allow_partial);
-
static gboolean
type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
{
if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
MonoGenericClass *gclass = type->data.generic_class;
- if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
+ if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
return FALSE;
- if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
+ if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
return FALSE;
if (mono_class_is_nullable (mono_class_from_mono_type (type)))
return FALSE;
return FALSE;
}
-static gboolean
-generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
+gboolean
+mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
gboolean allow_partial)
{
int i;
{
g_assert (context->class_inst || context->method_inst);
- if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
+ if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
return FALSE;
- if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
+ if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
return FALSE;
return TRUE;
/* Lazy class loading functions */
static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
-static GENERATE_TRY_GET_CLASS_WITH_CACHE (async_state_machine_attribute, System.Runtime.CompilerServices, AsyncStateMachineAttribute)
-
static G_GNUC_UNUSED gboolean
is_async_state_machine_class (MonoClass *klass)
}
static gboolean gshared_supported;
-static gboolean gsharedvt_supported;
void
mono_set_generic_sharing_supported (gboolean supported)
gshared_supported = supported;
}
-void
-mono_set_generic_sharing_vt_supported (gboolean supported)
-{
- gsharedvt_supported = supported;
-}
void
mono_set_partial_sharing_supported (gboolean supported)
if (all_vt || gsharedvt) {
type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
} else {
- /* These types match the ones in generic_inst_is_sharable () */
+ /* These types match the ones in mini_generic_inst_is_sharable () */
type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
}
}
return slot;
}
-#if defined(ENABLE_GSHAREDVT)
+static gboolean gsharedvt_supported;
+
+void
+mono_set_generic_sharing_vt_supported (gboolean supported)
+{
+ gsharedvt_supported = supported;
+}
+
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
-#include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
+/*
+ * mini_is_gsharedvt_type:
+ *
+ * Return whenever T references type arguments instantiated with gshared vtypes.
+ */
+gboolean
+mini_is_gsharedvt_type (MonoType *t)
+{
+ int i;
+ if (t->byref)
+ return FALSE;
+ if ((t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE)
+ return TRUE;
+ else if (t->type == MONO_TYPE_GENERICINST) {
+ MonoGenericClass *gclass = t->data.generic_class;
+ MonoGenericContext *context = &gclass->context;
+ MonoGenericInst *inst;
+
+ inst = context->class_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (mini_is_gsharedvt_type (inst->type_argv [i]))
+ return TRUE;
+ }
+ inst = context->method_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (mini_is_gsharedvt_type (inst->type_argv [i]))
+ return TRUE;
+ }
+
+ return FALSE;
+ } else {
+ return FALSE;
+ }
+}
+
+gboolean
+mini_is_gsharedvt_klass (MonoClass *klass)
+{
+ return mini_is_gsharedvt_type (&klass->byval_arg);
+}
+
+gboolean
+mini_is_gsharedvt_signature (MonoMethodSignature *sig)
+{
+ int i;
+
+ if (sig->ret && mini_is_gsharedvt_type (sig->ret))
+ return TRUE;
+ for (i = 0; i < sig->param_count; ++i) {
+ if (mini_is_gsharedvt_type (sig->params [i]))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * mini_is_gsharedvt_variable_type:
+ *
+ * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
+ */
+gboolean
+mini_is_gsharedvt_variable_type (MonoType *t)
+{
+ if (!mini_is_gsharedvt_type (t))
+ return FALSE;
+ if (t->type == MONO_TYPE_GENERICINST) {
+ MonoGenericClass *gclass = t->data.generic_class;
+ MonoGenericContext *context = &gclass->context;
+ MonoGenericInst *inst;
+ int i;
+
+ if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
+ return FALSE;
+
+ inst = context->class_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
+ return TRUE;
+ }
+ inst = context->method_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+is_variable_size (MonoType *t)
+{
+ int i;
+
+ if (t->byref)
+ return FALSE;
+
+ if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
+ MonoGenericParam *param = t->data.generic_param;
+
+ if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
+ return FALSE;
+ if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
+ return is_variable_size (param->gshared_constraint);
+ return TRUE;
+ }
+ if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
+ MonoGenericClass *gclass = t->data.generic_class;
+ MonoGenericContext *context = &gclass->context;
+ MonoGenericInst *inst;
+
+ inst = context->class_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (is_variable_size (inst->type_argv [i]))
+ return TRUE;
+ }
+ inst = context->method_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (is_variable_size (inst->type_argv [i]))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
+{
+ int i;
+ gboolean has_vt = FALSE;
+
+ for (i = 0; i < inst->type_argc; ++i) {
+ MonoType *type = inst->type_argv [i];
+
+ if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
+ } else {
+ has_vt = TRUE;
+ }
+ }
+
+ return has_vt;
+}
+
+gboolean
+mini_is_gsharedvt_sharable_method (MonoMethod *method)
+{
+ MonoMethodSignature *sig;
+
+ /*
+ * A method is gsharedvt if:
+ * - it has type parameters instantiated with vtypes
+ */
+ if (!gsharedvt_supported)
+ return FALSE;
+ if (method->is_inflated) {
+ MonoMethodInflated *inflated = (MonoMethodInflated*)method;
+ MonoGenericContext *context = &inflated->context;
+ MonoGenericInst *inst;
+
+ if (context->class_inst && context->method_inst) {
+ /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
+ gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
+ gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
+
+ if ((vt1 && vt2) ||
+ (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
+ (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
+ ;
+ else
+ return FALSE;
+ } else {
+ inst = context->class_inst;
+ if (inst && !mini_is_gsharedvt_sharable_inst (inst))
+ return FALSE;
+ inst = context->method_inst;
+ if (inst && !mini_is_gsharedvt_sharable_inst (inst))
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+
+ sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
+ if (!sig)
+ return FALSE;
+
+ /*
+ if (mini_is_gsharedvt_variable_signature (sig))
+ return FALSE;
+ */
+
+ //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
+
+ return TRUE;
+}
+
+/*
+ * mini_is_gsharedvt_variable_signature:
+ *
+ * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
+ * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
+ */
+gboolean
+mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
+{
+ int i;
+
+ if (sig->ret && is_variable_size (sig->ret))
+ return TRUE;
+ for (i = 0; i < sig->param_count; ++i) {
+ MonoType *t = sig->params [i];
+
+ if (is_variable_size (t))
+ return TRUE;
+ }
+ return FALSE;
+}
#else
gboolean
return FALSE;
}
-#endif /* !MONOTOUCH */
+#endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */