return NULL;
}
+static guint32 bisect_opt = 0;
+static GHashTable *bisect_methods_hash = NULL;
+
+void
+mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
+{
+ FILE *file;
+ char method_name [2048];
+
+ bisect_opt = opt;
+ bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ g_assert (bisect_methods_hash);
+
+ file = fopen (method_list_filename, "r");
+ g_assert (file);
+
+ while (fgets (method_name, sizeof (method_name), file)) {
+ size_t len = strlen (method_name);
+ g_assert (len > 0);
+ g_assert (method_name [len - 1] == '\n');
+ method_name [len - 1] = 0;
+ g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
+ }
+ g_assert (feof (file));
+}
+
gboolean mono_do_single_method_regression = FALSE;
guint32 mono_single_method_regression_opt = 0;
MonoMethod *mono_current_single_method;
{
g_assert (method);
+ if (bisect_methods_hash) {
+ char *name = mono_method_full_name (method, TRUE);
+ void *res = g_hash_table_lookup (bisect_methods_hash, name);
+ g_free (name);
+ if (res)
+ return default_opt | bisect_opt;
+ }
if (!mono_do_single_method_regression)
return default_opt;
if (!mono_current_single_method) {
MonoVTable *vtable;
MonoDynCallInfo *dyn_call_info;
MonoClass *ret_box_class;
- gboolean needs_rgctx;
MonoMethodSignature *sig;
+ gboolean gsharedvt_invoke;
gpointer *wrapper_arg;
} RuntimeInvokeInfo;
-gboolean
-mini_gsharedvt_runtime_invoke_supported (MonoMethodSignature *sig)
-{
- gboolean supported = TRUE;
- int i;
-
- for (i = 0; i < sig->param_count; ++i) {
- MonoType *t = sig->params [i];
-
- if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
- supported = FALSE;
- }
-
- return supported;
-}
-
static RuntimeInvokeInfo*
-create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method)
+create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt)
{
MonoMethod *invoke;
RuntimeInvokeInfo *info;
info = g_new0 (RuntimeInvokeInfo, 1);
- info->needs_rgctx = mono_llvm_only && mono_method_needs_static_rgctx_invoke (method, TRUE);
info->compiled_method = compiled_method;
+ info->sig = mono_method_signature (method);
- invoke = mono_marshal_get_runtime_invoke (method, FALSE, info->needs_rgctx);
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE);
info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
g_assert (info->vtable);
if (method->string_ctor)
sig = mono_marshal_get_string_ctor_signature (method);
- g_assert (!info->needs_rgctx);
for (i = 0; i < sig->param_count; ++i) {
MonoType *t = sig->params [i];
if (!info->dyn_call_info) {
if (mono_llvm_only) {
- gboolean supported;
-
- supported = mini_gsharedvt_runtime_invoke_supported (sig);
-
- if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
- supported = FALSE;
-
#ifndef ENABLE_GSHAREDVT
- supported = FALSE;
+ g_assert_not_reached ();
#endif
-
- if (supported) {
+ if (!callee_gsharedvt) {
/* Invoke a gsharedvt out wrapper instead */
MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
+ info->gsharedvt_invoke = TRUE;
info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
info->wrapper_arg [0] = info->compiled_method;
info->wrapper_arg [1] = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
g_free (wrapper_sig);
info->compiled_method = mono_jit_compile_method (wrapper);
+ } else {
+ /* Gsharedvt methods can be invoked the same way */
+ /* The out wrapper has the same signature as the compiled gsharedvt method */
+ MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
+
+ info->gsharedvt_invoke = TRUE;
+ info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
+
+ invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
+ g_free (wrapper_sig);
}
}
info->runtime_invoke = mono_jit_compile_method (invoke);
return info;
}
+static MonoObject*
+mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc)
+{
+ MonoMethodSignature *sig = info->sig;
+ MonoDomain *domain = mono_domain_get ();
+ MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
+ gpointer *args;
+ gpointer retval_ptr;
+ guint8 retval [256];
+ gpointer *param_refs;
+ int i, pindex;
+
+ g_assert (info->gsharedvt_invoke);
+
+ /*
+ * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
+ * The advantage of this is the gsharedvt out wrappers have a reduced set of
+ * signatures, so we only have to generate runtime invoke wrappers for these
+ * signatures.
+ * This code also handles invocation of gsharedvt methods directly, no
+ * out wrappers are used in that case.
+ */
+ args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
+ param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
+ pindex = 0;
+ /*
+ * The runtime invoke wrappers expects pointers to primitive types, so have to
+ * use indirections.
+ */
+ if (sig->hasthis)
+ args [pindex ++] = &obj;
+ if (sig->ret->type != MONO_TYPE_VOID) {
+ retval_ptr = (gpointer)&retval;
+ args [pindex ++] = &retval_ptr;
+ }
+ for (i = 0; i < sig->param_count; ++i) {
+ MonoType *t = sig->params [i];
+
+ if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+ MonoClass *klass = mono_class_from_mono_type (t);
+ guint8 *nullable_buf;
+ int size;
+
+ size = mono_class_value_size (klass, NULL);
+ nullable_buf = g_alloca (size);
+ g_assert (nullable_buf);
+
+ /* The argument pointed to by params [i] is either a boxed vtype or null */
+ mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
+ params [i] = nullable_buf;
+ }
+
+ if (MONO_TYPE_IS_REFERENCE (t)) {
+ param_refs [i] = params [i];
+ params [i] = &(param_refs [i]);
+ }
+ args [pindex ++] = ¶ms [i];
+ }
+ /* The gsharedvt out wrapper has an extra argument which contains the method to call */
+ args [pindex ++] = &info->wrapper_arg;
+
+ runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
+
+ runtime_invoke (NULL, args, exc, info->compiled_method);
+
+ if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
+ return mono_value_box (domain, info->ret_box_class, retval);
+ else
+ return *(MonoObject**)retval;
+}
+
/**
* mono_jit_runtime_invoke:
* @method: the method to invoke
MonoDomain *domain = mono_domain_get ();
MonoJitDomainInfo *domain_info;
RuntimeInvokeInfo *info, *info2;
+ MonoJitInfo *ji = NULL;
+ gboolean callee_gsharedvt = FALSE;
if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
MonoMethod *wrapper;
wrapper = mono_marshal_get_array_accessor_wrapper (method);
- invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE, FALSE);
+ invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
callee = wrapper;
} else {
callee = NULL;
}
}
- compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
+ if (mono_llvm_only) {
+ ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
+ callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
+ }
+
+ if (!callee_gsharedvt)
+ compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
} else {
compiled_method = NULL;
}
- info = create_runtime_invoke_info (domain, method, compiled_method);
+ info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt);
mono_domain_lock (domain);
info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
int i, pindex;
guint8 buf [512];
guint8 retval [256];
- gpointer rgctx;
if (!dyn_runtime_invoke) {
invoke = mono_marshal_get_runtime_invoke_dynamic ();
}
/* Convert the arguments to the format expected by start_dyn_call () */
- args = (void **)g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
+ args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
pindex = 0;
if (sig->hasthis)
args [pindex ++] = &obj;
args [pindex ++] = params [i];
}
}
- if (info->needs_rgctx) {
- rgctx = mini_method_get_rgctx (method);
- args [pindex ++] = &rgctx;
- }
//printf ("M: %s\n", mono_method_full_name (method, TRUE));
}
#endif
- runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
-
- if (info->wrapper_arg) {
- MonoMethodSignature *sig = mono_method_signature (method);
- gpointer *args;
- gpointer retval_ptr;
- guint8 retval [256];
- gpointer *param_refs;
- int i, pindex;
-
- /*
- * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
- * The advantage of this is the gsharedvt out wrappers have a reduced set of
- * signatures, so we only have to generate runtime invoke wrappers for these
- * signatures.
- */
- args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
- param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
- pindex = 0;
- /*
- * The runtime invoke wrappers expects pointers to primitive types, so have to
- * use indirections.
- */
- if (sig->hasthis)
- args [pindex ++] = &obj;
- if (sig->ret->type != MONO_TYPE_VOID) {
- retval_ptr = (gpointer)&retval;
- args [pindex ++] = &retval_ptr;
- }
- for (i = 0; i < sig->param_count; ++i) {
- MonoType *t = sig->params [i];
-
- if (MONO_TYPE_IS_REFERENCE (t)) {
- param_refs [i] = params [i];
- params [i] = &(param_refs [i]);
- }
- args [pindex ++] = ¶ms [i];
- }
- /* The gsharedvt out wrapper has an extra argument which contains the method to call */
- args [pindex ++] = &info->wrapper_arg;
- runtime_invoke (NULL, args, exc, info->compiled_method);
-
- if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
- return mono_value_box (domain, info->ret_box_class, retval);
- else
- return *(MonoObject**)retval;
- }
+ if (mono_llvm_only)
+ return mono_llvmonly_runtime_invoke (method, info, obj, params, exc);
- // FIXME: Cache this
- if (info->needs_rgctx) {
- MonoMethodSignature *sig = mono_method_signature (method);
- gpointer rgctx;
- gpointer *args;
- int i, pindex;
+ runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
- args = (void **)g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
- pindex = 0;
- rgctx = mini_method_get_rgctx (method);
- for (i = 0; i < sig->param_count; ++i)
- args [pindex ++] = params [i];
- args [pindex ++] = &rgctx;
- return runtime_invoke ((MonoObject *)obj, args, exc, info->compiled_method);
- } else {
- return runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
- }
+ return runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
}
typedef struct {
return cache [idx];
}
+gboolean
+mini_parse_debug_option (const char *option)
+{
+ if (!strcmp (option, "handle-sigint"))
+ debug_options.handle_sigint = TRUE;
+ else if (!strcmp (option, "keep-delegates"))
+ debug_options.keep_delegates = TRUE;
+ else if (!strcmp (option, "reverse-pinvoke-exceptions"))
+ debug_options.reverse_pinvoke_exceptions = TRUE;
+ else if (!strcmp (option, "collect-pagefault-stats"))
+ debug_options.collect_pagefault_stats = TRUE;
+ else if (!strcmp (option, "break-on-unverified"))
+ debug_options.break_on_unverified = TRUE;
+ else if (!strcmp (option, "no-gdb-backtrace"))
+ debug_options.no_gdb_backtrace = TRUE;
+ else if (!strcmp (option, "suspend-on-sigsegv"))
+ debug_options.suspend_on_sigsegv = TRUE;
+ else if (!strcmp (option, "suspend-on-exception"))
+ debug_options.suspend_on_exception = TRUE;
+ else if (!strcmp (option, "suspend-on-unhandled"))
+ debug_options.suspend_on_unhandled = TRUE;
+ else if (!strcmp (option, "dont-free-domains"))
+ mono_dont_free_domains = TRUE;
+ else if (!strcmp (option, "dyn-runtime-invoke"))
+ debug_options.dyn_runtime_invoke = TRUE;
+ else if (!strcmp (option, "gdb"))
+ debug_options.gdb = TRUE;
+ else if (!strcmp (option, "explicit-null-checks"))
+ debug_options.explicit_null_checks = TRUE;
+ else if (!strcmp (option, "gen-seq-points"))
+ debug_options.gen_sdb_seq_points = TRUE;
+ else if (!strcmp (option, "gen-compact-seq-points"))
+ debug_options.gen_seq_points_compact_data = TRUE;
+ else if (!strcmp (option, "single-imm-size"))
+ debug_options.single_imm_size = TRUE;
+ else if (!strcmp (option, "init-stacks"))
+ debug_options.init_stacks = TRUE;
+ else if (!strcmp (option, "casts"))
+ debug_options.better_cast_details = TRUE;
+ else if (!strcmp (option, "soft-breakpoints"))
+ debug_options.soft_breakpoints = TRUE;
+ else if (!strcmp (option, "check-pinvoke-callconv"))
+ debug_options.check_pinvoke_callconv = TRUE;
+ else if (!strcmp (option, "arm-use-fallback-tls"))
+ debug_options.arm_use_fallback_tls = TRUE;
+ else if (!strcmp (option, "debug-domain-unload"))
+ mono_enable_debug_domain_unload (TRUE);
+ else if (!strcmp (option, "partial-sharing"))
+ mono_set_partial_sharing_supported (TRUE);
+ else if (!strcmp (option, "align-small-structs"))
+ mono_align_small_structs = TRUE;
+ else if (!strcmp (option, "native-debugger-break"))
+ debug_options.native_debugger_break = TRUE;
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
static void
mini_parse_debug_options (void)
{
for (ptr = args; ptr && *ptr; ptr++) {
const char *arg = *ptr;
- if (!strcmp (arg, "handle-sigint"))
- debug_options.handle_sigint = TRUE;
- else if (!strcmp (arg, "keep-delegates"))
- debug_options.keep_delegates = TRUE;
- else if (!strcmp (arg, "reverse-pinvoke-exceptions"))
- debug_options.reverse_pinvoke_exceptions = TRUE;
- else if (!strcmp (arg, "collect-pagefault-stats"))
- debug_options.collect_pagefault_stats = TRUE;
- else if (!strcmp (arg, "break-on-unverified"))
- debug_options.break_on_unverified = TRUE;
- else if (!strcmp (arg, "no-gdb-backtrace"))
- debug_options.no_gdb_backtrace = TRUE;
- else if (!strcmp (arg, "suspend-on-sigsegv"))
- debug_options.suspend_on_sigsegv = TRUE;
- else if (!strcmp (arg, "suspend-on-exception"))
- debug_options.suspend_on_exception = TRUE;
- else if (!strcmp (arg, "suspend-on-unhandled"))
- debug_options.suspend_on_unhandled = TRUE;
- else if (!strcmp (arg, "dont-free-domains"))
- mono_dont_free_domains = TRUE;
- else if (!strcmp (arg, "dyn-runtime-invoke"))
- debug_options.dyn_runtime_invoke = TRUE;
- else if (!strcmp (arg, "gdb"))
- debug_options.gdb = TRUE;
- else if (!strcmp (arg, "explicit-null-checks"))
- debug_options.explicit_null_checks = TRUE;
- else if (!strcmp (arg, "gen-seq-points"))
- debug_options.gen_sdb_seq_points = TRUE;
- else if (!strcmp (arg, "gen-compact-seq-points"))
- debug_options.gen_seq_points_compact_data = TRUE;
- else if (!strcmp (arg, "single-imm-size"))
- debug_options.single_imm_size = TRUE;
- else if (!strcmp (arg, "init-stacks"))
- debug_options.init_stacks = TRUE;
- else if (!strcmp (arg, "casts"))
- debug_options.better_cast_details = TRUE;
- else if (!strcmp (arg, "soft-breakpoints"))
- debug_options.soft_breakpoints = TRUE;
- else if (!strcmp (arg, "check-pinvoke-callconv"))
- debug_options.check_pinvoke_callconv = TRUE;
- else if (!strcmp (arg, "arm-use-fallback-tls"))
- debug_options.arm_use_fallback_tls = TRUE;
- else if (!strcmp (arg, "debug-domain-unload"))
- mono_enable_debug_domain_unload (TRUE);
- else if (!strcmp (arg, "partial-sharing"))
- mono_set_partial_sharing_supported (TRUE);
- else if (!strcmp (arg, "align-small-structs"))
- mono_align_small_structs = TRUE;
- else if (!strcmp (arg, "native-debugger-break"))
- debug_options.native_debugger_break = TRUE;
- else {
+ if (!mini_parse_debug_option (arg)) {
fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'gen-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'arm-use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
exit (1);
}
mono_compile_method (method);
if (strcmp (method->name, "Finalize") == 0) {
- invoke = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE);
mono_compile_method (invoke);
}
#ifndef DISABLE_REMOTING