/*
* mini.c: The new Mono code generator.
*
- * Author:
+ * Authors:
* Paolo Molaro (lupus@ximian.com)
* Dietmar Maurer (dietmar@ximian.com)
*
- * (C) 2002 Ximian, Inc.
+ * Copyright 2002-2003 Ximian, Inc.
+ * Coprygith 2003-2010 Novell, Inc.
*/
+#define MONO_LLVM_IN_MINI 1
#include <config.h>
#include <signal.h>
#ifdef HAVE_ALLOCA_H
#include <mono/metadata/verify-internals.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/attach.h>
+#include <mono/metadata/runtime.h>
#include <mono/utils/mono-math.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/dtrace.h>
#include "mini.h"
+#include "mini-llvm.h"
#include "tasklets.h"
#include <string.h>
#include <ctype.h>
MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
MonoMethodSignature *helper_sig_domain_get = NULL;
MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
+MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
/*
* This flag controls whenever the runtime uses LLVM compiled code.
* Enabling this causes different/slower code paths to be used, which is why it
- * defaults to FALSE if ENABLE_LLVM is not defined, i.e. the runtime is only capable of
- * running AOT code compiled by LLVM.
+ * defaults to FALSE.
* Changes when this flag is set include:
* - a per method vtable trampoline is used to handle virtual calls, instead of only
* one trampoline.
* - fast generic virtual calls are not supported.
*/
-#ifdef ENABLE_LLVM
+#if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
gboolean mono_use_llvm = TRUE;
#else
gboolean mono_use_llvm = FALSE;
{
return mono_jump_info_token_new2 (mp, image, token, NULL);
}
+
+/*
+ * mono_tramp_info_create:
+ *
+ * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
+ * of NAME, JI, and UNWIND_OPS.
+ */
+MonoTrampInfo*
+mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
+{
+ MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
+
+ info->name = (char*)name;
+ info->code = code;
+ info->code_size = code_size;
+ info->ji = ji;
+ info->unwind_ops = unwind_ops;
+
+ return info;
+}
+
+void
+mono_tramp_info_free (MonoTrampInfo *info)
+{
+ g_free (info->name);
+
+ // FIXME: ji + unwind_ops
+}
#define MONO_INIT_VARINFO(vi,id) do { \
(vi)->range.first_use.pos.bid = 0xffff; \
helper_sig_domain_get = mono_create_icall_signature ("ptr");
helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
+ helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
#else
case MONO_TYPE_I8:
#endif
-#ifdef HAVE_SGEN_GC
- slot_info = &scalar_stack_slots [MONO_TYPE_I];
- break;
-#else
+ if (cfg->disable_ref_noref_stack_slot_share) {
+ slot_info = &scalar_stack_slots [MONO_TYPE_I];
+ break;
+ }
/* Fall through */
-#endif
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
#else
case MONO_TYPE_I8:
#endif
-#ifdef HAVE_SGEN_GC
- slot_info = &scalar_stack_slots [MONO_TYPE_I];
- break;
-#else
+ if (cfg->disable_ref_noref_stack_slot_share) {
+ slot_info = &scalar_stack_slots [MONO_TYPE_I];
+ break;
+ }
/* Fall through */
-#endif
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
void
mono_destroy_compile (MonoCompile *cfg)
{
+ GSList *l;
+
if (cfg->header)
mono_metadata_free_mh (cfg->header);
//mono_mempool_stats (cfg->mempool);
g_hash_table_destroy (cfg->spvars);
if (cfg->exvars)
g_hash_table_destroy (cfg->exvars);
- mono_mempool_destroy (cfg->mempool);
+ for (l = cfg->headers_to_free; l; l = l->next)
+ mono_metadata_free_mh (l->data);
g_list_free (cfg->ldstr_list);
g_hash_table_destroy (cfg->token_info_hash);
if (cfg->abs_patches)
g_hash_table_destroy (cfg->abs_patches);
+ mono_mempool_destroy (cfg->mempool);
g_free (cfg->varinfo);
g_free (cfg->vars);
mini_method_get_context (method_to_compile)->method_inst ||
method_to_compile->klass->valuetype) {
inst = cfg->rgctx_var;
- g_assert (inst->opcode == OP_REGOFFSET);
+ if (!COMPILE_LLVM (cfg))
+ g_assert (inst->opcode == OP_REGOFFSET);
} else {
inst = cfg->args [0];
}
- if (inst->opcode == OP_REGVAR) {
+ if (COMPILE_LLVM (cfg)) {
+ g_assert (cfg->llvm_this_reg != -1);
+ gi->this_in_reg = 0;
+ gi->this_reg = cfg->llvm_this_reg;
+ gi->this_offset = cfg->llvm_this_offset;
+ } else if (inst->opcode == OP_REGVAR) {
gi->this_in_reg = 1;
gi->this_reg = inst->dreg;
} else {
ei->data.handler_end = cfg->native_code + end_offset;
}
}
+ }
- if (G_UNLIKELY (cfg->verbose_level >= 4)) {
- for (i = 0; i < jinfo->num_clauses; i++) {
- MonoJitExceptionInfo *ei = &jinfo->clauses [i];
- int start = (guint8*)ei->try_start - cfg->native_code;
- int end = (guint8*)ei->try_end - cfg->native_code;
- int handler = (guint8*)ei->handler_start - cfg->native_code;
+ if (G_UNLIKELY (cfg->verbose_level >= 4)) {
+ int i;
+ for (i = 0; i < jinfo->num_clauses; i++) {
+ MonoJitExceptionInfo *ei = &jinfo->clauses [i];
+ int start = (guint8*)ei->try_start - cfg->native_code;
+ int end = (guint8*)ei->try_end - cfg->native_code;
+ int handler = (guint8*)ei->handler_start - cfg->native_code;
- printf ("JitInfo EH clause %d flags %x try %x-%x handler %x\n", i, ei->flags, start, end, handler);
- }
+ printf ("JitInfo EH clause %d flags %x try %x-%x handler %x\n", i, ei->flags, start, end, handler);
}
-
}
/*
mono_stats.generics_unsharable_methods++;
}
- try_llvm = TRUE;
-
-#ifndef ENABLE_LLVM
- try_llvm = FALSE;
-#endif
+ try_llvm = mono_use_llvm;
restart_compile:
if (try_generic_shared) {
}
cfg->method_to_register = method_to_register;
- if (cfg->compile_llvm) {
- /* No way to obtain the location info for 'this' */
- if (try_generic_shared) {
- cfg->exception_message = g_strdup ("gshared");
- cfg->disable_llvm = TRUE;
- }
-
- if (cfg->method->save_lmf) {
- cfg->exception_message = g_strdup ("lmf");
- cfg->disable_llvm = TRUE;
- }
-
- /* FIXME: */
- if (cfg->method->dynamic) {
- cfg->exception_message = g_strdup ("dynamic.");
- cfg->disable_llvm = TRUE;
- }
- }
-
mono_error_init (&err);
sig = mono_method_signature_checked (cfg->method, &err);
if (!sig) {
return cfg;
}
- if (FALSE && header->clauses) {
- /*
- * Cannot be enabled until LLVM supports implicit exceptions, or we use
- * explicit checks, or we disable this for methods which might throw implicit
- * exceptions inside clauses.
- */
- cfg->exception_message = g_strdup ("clauses");
- cfg->disable_llvm = TRUE;
- }
-
#ifdef ENABLE_LLVM
{
static gboolean inited;
mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_without_llvm);
inited = TRUE;
}
-
+
/*
* Check for methods which cannot be compiled by LLVM early, to avoid
* the extra compilation pass.
*/
- if (COMPILE_LLVM (cfg) && cfg->disable_llvm) {
- if (cfg->verbose_level >= 1) {
- //nm = mono_method_full_name (cfg->method, TRUE);
- printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
- //g_free (nm);
+ if (COMPILE_LLVM (cfg)) {
+ mono_llvm_check_method_supported (cfg);
+ if (cfg->disable_llvm) {
+ if (cfg->verbose_level >= 1) {
+ //nm = mono_method_full_name (cfg->method, TRUE);
+ printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
+ //g_free (nm);
+ }
+ InterlockedIncrement (&methods_without_llvm);
+ mono_destroy_compile (cfg);
+ try_llvm = FALSE;
+ goto restart_compile;
}
- InterlockedIncrement (&methods_without_llvm);
- mono_destroy_compile (cfg);
- try_llvm = FALSE;
- goto restart_compile;
}
}
#endif
cfg->compute_precise_live_ranges = TRUE;
}
- mini_gc_init_gc_map (cfg);
+ mini_gc_init_cfg (cfg);
if (COMPILE_LLVM (cfg)) {
cfg->opt |= MONO_OPT_ABCREM;
mono_decompose_array_access_opts (cfg);
if (cfg->got_var) {
+#ifndef MONO_ARCH_GOT_REG
GList *regs;
+#endif
+ int got_reg;
g_assert (cfg->got_var_allocated);
* branches problem. Testcase: mcs crash in
* System.MonoCustomAttrs:GetCustomAttributes.
*/
+#ifdef MONO_ARCH_GOT_REG
+ got_reg = MONO_ARCH_GOT_REG;
+#else
regs = mono_arch_get_global_int_regs (cfg);
g_assert (regs);
+ got_reg = GPOINTER_TO_INT (regs->data);
+ g_list_free (regs);
+#endif
cfg->got_var->opcode = OP_REGVAR;
- cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
+ cfg->got_var->dreg = got_reg;
cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
-
- g_list_free (regs);
}
/*
}
if ((cfg->opt & MONO_OPT_LINEARS) && !cfg->globalra) {
- GList *vars, *regs;
+ GList *vars, *regs, *l;
/* fixme: maybe we can avoid to compute livenesss here if already computed ? */
cfg->comp_done &= ~MONO_COMP_LIVENESS;
if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
regs = mono_arch_get_global_int_regs (cfg);
- if (cfg->got_var)
- regs = g_list_delete_link (regs, regs);
+ /* Remove the reg reserved for holding the GOT address */
+ if (cfg->got_var) {
+ for (l = regs; l; l = l->next) {
+ if (GPOINTER_TO_UINT (l->data) == cfg->got_var->dreg) {
+ regs = g_list_delete_link (regs, l);
+ break;
+ }
+ }
+ }
mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
}
}
vtable = mono_class_vtable (target_domain, method->klass);
if (!vtable) {
- MonoException *exc;
- exc = mono_class_get_exception_for_failure (method->klass);
- g_assert (exc);
- mono_raise_exception (exc);
+ ex = mono_class_get_exception_for_failure (method->klass);
+ g_assert (ex);
+ *jit_ex = ex;
+ return NULL;
}
if (prof_options & MONO_PROFILE_JIT_COMPILATION) {
- if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
- /* The profiler doesn't know about wrappers, so pass the original icall method */
- mono_profiler_method_end_jit (mono_marshal_method_from_wrapper (method), jinfo, MONO_PROFILE_OK);
- else
+ if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+ if (mono_marshal_method_from_wrapper (method)) {
+ /* Native func wrappers have no method */
+ /* The profiler doesn't know about wrappers, so pass the original icall method */
+ mono_profiler_method_end_jit (mono_marshal_method_from_wrapper (method), jinfo, MONO_PROFILE_OK);
+ }
+ } else {
mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
+ }
}
- mono_runtime_class_init (vtable);
+ ex = mono_runtime_class_init_full (vtable, FALSE);
+ if (ex) {
+ *jit_ex = ex;
+ return NULL;
+ }
return code;
}
* We need this here because mono_marshal_get_runtime_invoke can place
* the helper method in System.Object and not the target class.
*/
- mono_runtime_class_init (info->vtable);
+ if (exc) {
+ *exc = (MonoObject*)mono_runtime_class_init_full (info->vtable, FALSE);
+ if (*exc)
+ return NULL;
+ } else {
+ mono_runtime_class_init (info->vtable);
+ }
+
+ /* The wrappers expect this to be initialized to NULL */
+ if (exc)
+ *exc = NULL;
#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
if (info->dyn_call_info) {
return mono_get_addr_from_ftnptr (addr);
}
-#ifdef MONO_ARCH_HAVE_IMT
-static G_GNUC_UNUSED gpointer
-mini_get_imt_trampoline (void)
-{
- static gpointer tramp = NULL;
- if (!tramp)
- tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
- return tramp;
-}
-#endif
+static gpointer *vtable_trampolines;
+static int vtable_trampolines_size;
gpointer
mini_get_vtable_trampoline (int slot_index)
{
- static gpointer tramp = NULL;
+ int index = slot_index + MONO_IMT_SIZE;
+
+ g_assert (slot_index >= - MONO_IMT_SIZE);
+ if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
+ mono_jit_lock ();
+ if (!vtable_trampolines || index >= vtable_trampolines_size) {
+ int new_size;
+ gpointer new_table;
+
+ new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
+ while (new_size <= index)
+ new_size *= 2;
+ new_table = g_new0 (gpointer, new_size);
+
+ if (vtable_trampolines)
+ memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
+ mono_memory_barrier ();
+ vtable_trampolines = new_table;
+ vtable_trampolines_size = new_size;
+ }
+ mono_jit_unlock ();
+ }
- if (!tramp)
- tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
- return tramp;
+ if (!vtable_trampolines [index])
+ vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
+ return vtable_trampolines [index];
+}
+
+static gpointer
+mini_get_imt_trampoline (int slot_index)
+{
+ return mini_get_vtable_trampoline (slot_index - MONO_IMT_SIZE);
}
static void
#ifdef MONO_ARCH_HAVE_IMT
if (mono_use_imt) {
- if (!mono_use_llvm) {
- /* LLVM needs a per-method vtable trampoline */
- callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
- }
+ callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
+ callbacks.get_imt_trampoline = mini_get_imt_trampoline;
}
#endif
}
#ifdef ENABLE_LLVM
- mono_llvm_init ();
+ if (!mono_llvm_load (NULL)) {
+ mono_use_llvm = FALSE;
+ fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
+ }
+ if (mono_use_llvm)
+ mono_llvm_init ();
#endif
mono_trampolines_init ();
#ifdef JIT_TRAMPOLINES_WORK
mono_install_compile_method (mono_jit_compile_method);
mono_install_free_method (mono_jit_free_method);
-#ifdef MONO_ARCH_LLVM_SUPPORTED
- if (mono_use_llvm)
- /* The runtime currently only uses this for filling out vtables */
- mono_install_trampoline (mono_create_llvm_vcall_trampoline);
- else
- mono_install_trampoline (mono_create_jit_trampoline);
-#else
mono_install_trampoline (mono_create_jit_trampoline);
-#endif
mono_install_jump_trampoline (mono_create_jump_trampoline);
mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
mono_install_delegate_trampoline (mono_create_delegate_trampoline);
mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
else
mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
- if (!mono_use_llvm) {
- /*
- * The imt code in mono_magic_trampoline () can't handle LLVM code. By disabling
- * this, we force iface calls to go through the llvm vcall trampoline.
- */
- mono_install_imt_trampoline (mini_get_imt_trampoline ());
- }
}
#endif
register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
-#ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
- register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE);
-#endif
#if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception",
"void ptr", TRUE);
register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
+ register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
+
+#ifdef HAVE_WRITE_BARRIERS
+ register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
+#endif
+
#endif
mono_generic_sharing_init ();
g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
g_print ("Hazardous pointers: %ld\n", mono_stats.hazardous_pointer_count);
-#ifdef HAVE_SGEN_GC
g_print ("Minor GC collections: %ld\n", mono_stats.minor_gc_count);
-#endif
g_print ("Major GC collections: %ld\n", mono_stats.major_gc_count);
-#ifdef HAVE_SGEN_GC
g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
-#endif
g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
g_print ("\nDecl security check : %ld\n", mono_jit_stats.cas_declsec_check);
cominterop_release_all_rcws ();
#endif
+ mono_runtime_shutdown ();
+
#ifndef MONO_CROSS_COMPILE
/*
* mono_runtime_cleanup() and mono_domain_finalize () need to
mono_debugger_cleanup ();
#ifdef ENABLE_LLVM
- mono_llvm_cleanup ();
+ if (mono_use_llvm)
+ mono_llvm_cleanup ();
#endif
mono_trampolines_cleanup ();