#include "mini-gc.h"
#include "debugger-agent.h"
+#ifdef MONO_ARCH_LLVM_SUPPORTED
+#ifdef ENABLE_LLVM
+#include "mini-llvm-cpp.h"
+#endif
+#endif
+
static guint32 default_opt = 0;
static gboolean default_opt_set = FALSE;
gboolean mono_compile_aot = FALSE;
/* If this is set, no code is generated dynamically, everything is taken from AOT files */
gboolean mono_aot_only = FALSE;
+/* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
+gboolean mono_llvm_only = FALSE;
MonoAotMode mono_aot_mode = MONO_AOT_MODE_NONE;
const char *mono_build_date;
{
#ifndef DISABLE_JIT
mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_throw);
+#else
+ MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
+
+ g_assert (!sig->hasthis);
+ g_assert (sig->param_count < 3);
+
+ /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
+ mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
#endif
}
mono_register_jit_icall_full (func, name, sig, avoid_wrapper, FALSE, avoid_wrapper ? name : NULL);
}
+static void
+register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
+{
+ MonoMethodSignature *sig;
+
+ if (sigstr)
+ sig = mono_create_icall_signature (sigstr);
+ else
+ sig = NULL;
+
+ mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
+}
+
static void
register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
{
memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
break;
case MONO_PATCH_INFO_RGCTX_FETCH:
+ case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
case MONO_PATCH_INFO_SIGNATURE:
case MONO_PATCH_INFO_TLS_OFFSET:
case MONO_PATCH_INFO_METHOD_CODE_SLOT:
+ case MONO_PATCH_INFO_AOT_JIT_INFO:
return (ji->type << 8) | (gssize)ji->data.target;
case MONO_PATCH_INFO_GSHAREDVT_CALL:
return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
- case MONO_PATCH_INFO_RGCTX_FETCH: {
+ case MONO_PATCH_INFO_RGCTX_FETCH:
+ case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
case MONO_PATCH_INFO_JIT_TLS_ID:
case MONO_PATCH_INFO_GOT_OFFSET:
case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
+ case MONO_PATCH_INFO_AOT_MODULE:
return (ji->type << 8);
case MONO_PATCH_INFO_CASTCLASS_CACHE:
return (ji->type << 8) | (ji->data.index);
/* Hash on the selector name */
return g_str_hash (ji->data.target);
case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
- return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->virtual;
+ return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
case MONO_PATCH_INFO_LDSTR_LIT:
return g_str_hash (ji->data.target);
case MONO_PATCH_INFO_VIRT_METHOD: {
break;
case MONO_PATCH_INFO_INTERNAL_METHOD:
return g_str_equal (ji1->data.name, ji2->data.name);
- case MONO_PATCH_INFO_RGCTX_FETCH: {
+ case MONO_PATCH_INFO_RGCTX_FETCH:
+ case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
case MONO_PATCH_INFO_GSHAREDVT_METHOD:
return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
- return ji1->data.del_tramp->klass == ji2->data.del_tramp->klass && ji1->data.del_tramp->method == ji2->data.del_tramp->method && ji1->data.del_tramp->virtual == ji2->data.del_tramp->virtual;
+ return ji1->data.del_tramp->klass == ji2->data.del_tramp->klass && ji1->data.del_tramp->method == ji2->data.del_tramp->method && ji1->data.del_tramp->is_virtual == ji2->data.del_tramp->is_virtual;
case MONO_PATCH_INFO_CASTCLASS_CACHE:
return ji1->data.index == ji2->data.index;
case MONO_PATCH_INFO_VIRT_METHOD:
case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
#if defined(__native_client_codegen__)
target = (gpointer)&__nacl_thread_suspension_needed;
-#elif defined (USE_COOP_GC)
- target = (gpointer)&mono_polling_required;
#else
- g_error ("Unsuported patch target");
+ g_assert (mono_threads_is_coop_enabled ());
+ target = (gpointer)&mono_polling_required;
#endif
break;
case MONO_PATCH_INFO_SWITCH: {
case MONO_PATCH_INFO_IMAGE:
case MONO_PATCH_INFO_FIELD:
case MONO_PATCH_INFO_SIGNATURE:
+ case MONO_PATCH_INFO_AOT_MODULE:
target = patch_info->data.target;
break;
case MONO_PATCH_INFO_IID:
case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
- if (del_tramp->virtual)
+ if (del_tramp->is_virtual)
target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
else
target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
break;
}
+ case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
+ int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
+
+ target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
+ break;
+ }
case MONO_PATCH_INFO_BB_OVF:
case MONO_PATCH_INFO_EXC_OVF:
case MONO_PATCH_INFO_GOT_OFFSET:
if ((code = mono_aot_get_method (domain, method))) {
MonoVTable *vtable;
- vtable = mono_class_vtable (domain, method->klass);
- g_assert (vtable);
- mono_runtime_class_init (vtable);
+ /*
+ * In llvm-only mode, method might be a shared method, so we can't initialize its class.
+ * This is not a problem, since it will be initialized when the method is first
+ * called by init_method ().
+ */
+ if (!mono_llvm_only) {
+ vtable = mono_class_vtable (domain, method->klass);
+ g_assert (vtable);
+ mono_runtime_class_init (vtable);
+ }
}
}
#endif
if (!code)
code = mono_jit_compile_method_inner (method, target_domain, opt, ex);
+
+ if (!code && mono_llvm_only) {
+ printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
+ g_assert_not_reached ();
+ }
+
if (!code)
return NULL;
MonoVTable *vtable;
MonoDynCallInfo *dyn_call_info;
MonoClass *ret_box_class;
+ gboolean needs_rgctx;
} RuntimeInvokeInfo;
/**
}
info = g_new0 (RuntimeInvokeInfo, 1);
+ info->needs_rgctx = mono_llvm_only && mono_method_needs_static_rgctx_invoke (method, TRUE);
- invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE, info->needs_rgctx);
info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
g_assert (info->vtable);
MonoMethod *wrapper;
wrapper = mono_marshal_get_array_accessor_wrapper (method);
- invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
+ invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE, FALSE);
callee = wrapper;
} else {
callee = NULL;
* possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
*/
#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
- if (mono_aot_only || debug_options.dyn_runtime_invoke) {
+ if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
MonoType *ret_type;
MonoMethodSignature *sig = mono_method_signature (method);
gboolean supported = TRUE;
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];
int i, pindex;
guint8 buf [256];
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 = g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
+ args = g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * 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
- return runtime_invoke (obj, params, exc, info->compiled_method);
+ if (info->needs_rgctx) {
+ MonoMethodSignature *sig = mono_method_signature (method);
+ gpointer rgctx;
+ gpointer *args;
+ int i, pindex;
+
+ args = 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 (obj, args, exc, info->compiled_method);
+ } else {
+ return runtime_invoke (obj, params, exc, info->compiled_method);
+ }
}
MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
}
#endif
+static void
+no_imt_trampoline (void)
+{
+ g_assert_not_reached ();
+}
+
+static void
+no_vcall_trampoline (void)
+{
+ g_assert_not_reached ();
+}
+
static gpointer *vtable_trampolines;
static int vtable_trampolines_size;
{
int index = slot_index + MONO_IMT_SIZE;
+ if (mono_llvm_only) {
+ /* Not used */
+ if (slot_index < 0)
+ /* The vtable/imt construction code in object.c depends on this being non-NULL */
+ return no_imt_trampoline;
+ else
+ return no_vcall_trampoline;
+ }
+
g_assert (slot_index >= - MONO_IMT_SIZE);
if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
mono_jit_lock ();
register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
+ register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
+ register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
+ register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
+ register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
+ register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
+ register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
+ register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", FALSE);
+#if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
+ register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
+
+ // FIXME: This is broken
+ register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
+#endif
+
register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
#if defined(__native_client__) || defined(__native_client_codegen__)
register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
#endif
-#if defined(USE_COOP_GC)
- register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
-#endif
+
+ if (mono_threads_is_coop_enabled ())
+ register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
#ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", TRUE);
#endif
#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
- if (ARCH_EMULATE_MUL_DIV || mono_arch_is_soft_float ()) {
- register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
- }
+ register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
#endif
register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
}
#endif
+ register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
#ifdef COMPRESSED_INTERFACE_BITMAP
register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
+ register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
+ register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
+ register_icall (mono_aot_init_gshared_method_rgctx, "mono_aot_init_gshared_method_rgctx", "void ptr int ptr", TRUE);
+
+ register_icall_no_wrapper (mono_resolve_iface_call, "mono_resolve_iface_call", "ptr object int ptr ptr");
+ register_icall_no_wrapper (mono_resolve_vcall, "mono_resolve_vcall", "ptr object int ptr");
+ register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE);
+ register_icall (mono_init_delegate_virtual, "mono_init_delegate_virtual", "void object object ptr", TRUE);
+ register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
+
#ifdef TARGET_IOS
register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
#endif
}
mono_compile_method (method);
if (strcmp (method->name, "Finalize") == 0) {
- invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
mono_compile_method (invoke);
}
#ifndef DISABLE_REMOTING