ICALL_SIG (5, (void, object, ptr, ptr, ptr)) \
ICALL_SIG (5, (void, ptr, int, int, object)) \
ICALL_SIG (5, (void, ptr, ptr, ptr, ptr)) \
+ICALL_SIG (5, (void, ptr, ptr, int, object)) \
+ICALL_SIG (5, (void, ptr, ptr, int, ptr)) \
ICALL_SIG (5, (ptr, ptr, ptr, ptr, ptr)) \
ICALL_SIG (6, (int, int, int, ptr, ptr, ptr)) \
ICALL_SIG (6, (int, ptr, int, int, ptr, object)) \
char *gen_msym_dir_path;
gboolean direct_pinvoke;
gboolean direct_icalls;
+ gboolean direct_extern_calls;
gboolean no_direct_calls;
gboolean use_trampolines_page;
gboolean no_instances;
}
/*
+ * method_is_externally_callable:
+ *
+ * Return whenever METHOD can be directly called from other AOT images
+ * without going through a PLT.
+ */
+static gboolean
+method_is_externally_callable (MonoAotCompile *acfg, MonoMethod *method)
+{
+ // FIXME: Unify
+ if (acfg->aot_opts.llvm_only) {
+ if (!acfg->aot_opts.static_link)
+ return FALSE;
+ if (method->wrapper_type == MONO_WRAPPER_ALLOC)
+ return TRUE;
+ if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
+ return TRUE;
+ if (method->string_ctor)
+ return FALSE;
+ if (method->wrapper_type)
+ return FALSE;
+ if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
+ return FALSE;
+ if (method->is_inflated)
+ return FALSE;
+ if (!((mono_class_get_flags (method->klass) & TYPE_ATTRIBUTE_PUBLIC) && (method->flags & METHOD_ATTRIBUTE_PUBLIC)))
+ return FALSE;
+ /* Can't enable this as the callee might fail llvm compilation */
+ //return TRUE;
+ return FALSE;
+ } else {
+ if (!acfg->aot_opts.direct_extern_calls)
+ return FALSE;
+ if (!acfg->llvm || acfg->aot_opts.llvm_disable_self_init)
+ return FALSE;
+ if (acfg->aot_opts.soft_debug || acfg->aot_opts.no_direct_calls)
+ return FALSE;
+ if (method->wrapper_type == MONO_WRAPPER_ALLOC)
+ return FALSE;
+ if (method->string_ctor)
+ return FALSE;
+ if (method->wrapper_type)
+ return FALSE;
+ if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
+ return FALSE;
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ return FALSE;
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)
+ return FALSE;
+ if (method->is_inflated)
+ return FALSE;
+ if (!((mono_class_get_flags (method->klass) & TYPE_ATTRIBUTE_PUBLIC) && (method->flags & METHOD_ATTRIBUTE_PUBLIC)))
+ return FALSE;
+ return TRUE;
+ }
+}
+
+/*
* is_direct_callable:
*
* Return whenever the method identified by JI is directly callable without
if (direct_callable)
return TRUE;
}
+ } else if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (m_class_get_image (patch_info->data.method->klass) != acfg->image)) {
+ /* Cross assembly calls */
+ return method_is_externally_callable (acfg, patch_info->data.method);
} else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
if (acfg->aot_opts.direct_pinvoke)
return TRUE;
*/
direct_call = FALSE;
external_call = FALSE;
- if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (m_class_get_image (patch_info->data.method->klass) == acfg->image)) {
- if (!got_only && is_direct_callable (acfg, method, patch_info)) {
- MonoCompile *callee_cfg = (MonoCompile *)g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
+ if (patch_info->type == MONO_PATCH_INFO_METHOD) {
+ MonoMethod *cmethod = patch_info->data.method;
+ if (cmethod->wrapper_type == MONO_WRAPPER_OTHER && mono_marshal_get_wrapper_info (cmethod)->subtype == WRAPPER_SUBTYPE_AOT_INIT) {
+ WrapperInfo *info = mono_marshal_get_wrapper_info (cmethod);
+
+ /*
+ * This is a call from a JITted method to the init wrapper emitted by LLVM.
+ */
+ g_assert (acfg->aot_opts.llvm && acfg->aot_opts.direct_extern_calls);
+
+ const char *init_name = mono_marshal_get_aot_init_wrapper_name (info->d.aot_init.subtype);
+ char *symbol = g_strdup_printf ("%s%s_%s", acfg->user_symbol_prefix, acfg->global_prefix, init_name);
+
+ direct_call = TRUE;
+ direct_call_target = symbol;
+ patch_info->type = MONO_PATCH_INFO_NONE;
+ } else if ((m_class_get_image (patch_info->data.method->klass) == acfg->image) && !got_only && is_direct_callable (acfg, method, patch_info)) {
+ MonoCompile *callee_cfg = (MonoCompile *)g_hash_table_lookup (acfg->method_to_cfg, cmethod);
// Don't compile inflated methods if we're doing dedup
- if (acfg->aot_opts.dedup && !mono_aot_can_dedup (patch_info->data.method)) {
- char *name = mono_aot_get_mangled_method_name (patch_info->data.method);
+ if (acfg->aot_opts.dedup && !mono_aot_can_dedup (cmethod)) {
+ char *name = mono_aot_get_mangled_method_name (cmethod);
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "DIRECT CALL: %s by %s", name, method ? mono_method_full_name (method, TRUE) : "");
g_free (name);
opts->direct_pinvoke = TRUE;
} else if (str_begins_with (arg, "direct-icalls")) {
opts->direct_icalls = TRUE;
+ } else if (str_begins_with (arg, "direct-extern-calls")) {
+ opts->direct_extern_calls = TRUE;
} else if (str_begins_with (arg, "no-direct-calls")) {
opts->no_direct_calls = TRUE;
} else if (str_begins_with (arg, "print-skipped")) {
flags = (JitFlags)(flags | JIT_FLAG_INTERP);
if (acfg->aot_opts.use_current_cpu)
flags = (JitFlags)(flags | JIT_FLAG_USE_CURRENT_CPU);
+ if (method_is_externally_callable (acfg, method))
+ flags = (JitFlags)(flags | JIT_FLAG_SELF_INIT);
jit_time_start = mono_time_track_start ();
cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0, index);
if (cfg->llvm_only)
acfg->stats.llvm_count ++;
+ if (acfg->llvm && !cfg->compile_llvm && method_is_externally_callable (acfg, cfg->method)) {
+ /*
+ * This is a JITted fallback method for a method which failed LLVM compilation, emit a global
+ * symbol for it with the same name the LLVM method would get.
+ */
+ char *name = mono_aot_get_mangled_method_name (cfg->method);
+ char *export_name = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, name);
+ g_hash_table_insert (acfg->export_names, cfg->method, export_name);
+ }
+
/*
* FIXME: Instead of this mess, allocate the patches from the aot mempool.
*/
return offset < llvm_acfg->nshared_got_entries;
}
+gboolean
+mono_aot_is_externally_callable (MonoMethod *cmethod)
+{
+ return method_is_externally_callable (llvm_acfg, cmethod);
+}
+
char*
mono_aot_get_method_name (MonoCompile *cfg)
{
case ':':
g_string_append (s, "_colon_");
break;
+ case '|':
+ g_string_append (s, "_verbar_");
+ break;
default:
g_string_append_c (s, c);
}
g_assert (objfile != NULL);
command = g_strdup_printf ("\"%s%s\" %s %s /OUT:%s %s %s", tool_prefix, LD_NAME,
acfg->aot_opts.nodebug ? LD_OPTIONS : LD_DEBUG_OPTIONS, ld_flags, wrap_path (tmp_outfile_name), wrap_path (objfile), wrap_path (llvm_ofile));
-#elif defined(LD_NAME)
- command = g_strdup_printf ("%s%s %s -o %s %s %s %s", tool_prefix, LD_NAME, LD_OPTIONS,
- wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
- wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
+#else
+ GString *str;
+
+ str = g_string_new ("");
+#if defined(LD_NAME)
+ g_string_append_printf (str, "%s%s %s", tool_prefix, LD_NAME, LD_OPTIONS);
#else
// Default (linux)
- if (acfg->aot_opts.tool_prefix) {
+ if (acfg->aot_opts.tool_prefix)
/* Cross compiling */
- command = g_strdup_printf ("\"%sld\" %s -shared -o %s %s %s %s", tool_prefix, LD_OPTIONS,
- wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
- wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
- } else {
- char *args = g_strdup_printf ("%s -shared -o %s %s %s %s", LD_OPTIONS,
- wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
- wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
+ g_string_append_printf (str, "\"%sld\" %s", tool_prefix, LD_OPTIONS);
+ else if (acfg->aot_opts.llvm_only)
+ g_string_append_printf (str, "%s", acfg->aot_opts.clangxx);
+ else
+ g_string_append_printf (str, "\"%sld\"", tool_prefix);
+ g_string_append_printf (str, " -shared");
+#endif
+ g_string_append_printf (str, " -o %s %s %s %s",
+ wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
+ wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
- if (acfg->aot_opts.llvm_only) {
- command = g_strdup_printf ("%s %s", acfg->aot_opts.clangxx, args);
- } else {
- command = g_strdup_printf ("\"%sld\" %s", tool_prefix, args);
- }
- g_free (args);
- }
+#if defined(TARGET_MACH)
+ g_string_append_printf (str, " -Wl,-install_name,%s%s", g_path_get_basename (acfg->image->name), MONO_SOLIB_EXT);
+#endif
+
+ command = g_string_free (str, FALSE);
#endif
aot_printf (acfg, "Executing the native linker: %s\n", command);
if (execute_system (command) != 0) {
* Allocate the first few GOT entries to information which is needed frequently, or it is needed
* during method initialization etc.
*/
-
ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
ji->type = MONO_PATCH_INFO_IMAGE;
ji->data.image = acfg->image;
mono_aot_parse_options (aot_options, &acfg->aot_opts);
+ if (acfg->aot_opts.direct_extern_calls && !(acfg->aot_opts.llvm && acfg->aot_opts.static_link)) {
+ aot_printerrf (acfg, "The 'direct-extern-calls' option requires the 'llvm' and 'static' options.\n");
+ return 1;
+ }
+
// start dedup
MonoAotState *astate = NULL;
gboolean is_dedup_dummy = FALSE;
return FALSE;
}
+gboolean
+mono_aot_is_externally_callable (MonoMethod *cmethod)
+{
+ return FALSE;
+}
+
int
mono_compile_deferred_assemblies (guint32 opts, const char *aot_options, gpointer **aot_state)
{
MONO_LLVM_INTERNAL char* mono_aot_get_method_name (MonoCompile *cfg);
MONO_LLVM_INTERNAL char* mono_aot_get_mangled_method_name (MonoMethod *method);
MONO_LLVM_INTERNAL gboolean mono_aot_is_direct_callable (MonoJumpInfo *patch_info);
+MONO_LLVM_INTERNAL gboolean mono_aot_is_externally_callable (MonoMethod *cmethod);
MONO_LLVM_INTERNAL void mono_aot_mark_unused_llvm_plt_entry(MonoJumpInfo *patch_info);
MONO_LLVM_INTERNAL char* mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data);
MONO_LLVM_INTERNAL char* mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data);
#include <mono/utils/mono-digest.h>
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/bsearch.h>
+#include <mono/utils/mono-tls-inline.h>
#include "mini.h"
#include "seq-points.h"
#include "aot-runtime.h"
#include "jit-icalls.h"
#include "mini-runtime.h"
-#include "mono/utils/mono-tls-inline.h"
+#include "llvmonly-runtime.h"
#ifndef DISABLE_AOT
#define ENABLE_AOT_CACHE
#endif
-/* Number of got entries shared between the JIT and LLVM GOT */
-#define N_COMMON_GOT_ENTRIES 10
-
#define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
typedef struct {
* Initialize the shared got entries for AMODULE.
*/
static void
-init_amodule_got (MonoAotModule *amodule)
+init_amodule_got (MonoAotModule *amodule, gboolean preinit)
{
MonoJumpInfo *ji;
MonoMemPool *mp;
return;
}
- amodule->got_initialized = GOT_INITIALIZING;
+ if (!preinit)
+ amodule->got_initialized = GOT_INITIALIZING;
mp = mono_mempool_new ();
npatches = amodule->info.nshared_got_entries;
for (i = 0; i < npatches; ++i) {
ji = &patches [i];
- if (ji->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR && !mono_gc_is_moving ()) {
+ if (amodule->shared_got [i]) {
+ } else if (ji->type == MONO_PATCH_INFO_AOT_MODULE) {
+ amodule->shared_got [i] = amodule;
+ } else if (preinit) {
+ /*
+ * This is called from init_amodule () during startup, so some things might not
+ * be setup. Initialize just the slots needed to make method initialization work.
+ */
+ if (ji->type == MONO_PATCH_INFO_JIT_ICALL_ID) {
+ if (ji->data.jit_icall_id == MONO_JIT_ICALL_mini_llvm_init_method)
+ amodule->shared_got [i] = (gpointer)mini_llvm_init_method;
+ }
+ } else if (ji->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR && !mono_gc_is_moving ()) {
amodule->shared_got [i] = NULL;
} else if (ji->type == MONO_PATCH_INFO_GC_NURSERY_START && !mono_gc_is_moving ()) {
amodule->shared_got [i] = NULL;
mono_mempool_destroy (mp);
- mono_memory_barrier ();
- amodule->got_initialized = GOT_INITIALIZED;
+ if (!preinit) {
+ mono_memory_barrier ();
+ amodule->got_initialized = GOT_INITIALIZED;
+ }
mono_loader_unlock ();
}
amodule->trampolines [MONO_AOT_TRAMP_FTNPTR_ARG] = (guint8 *)info->ftnptr_arg_trampolines;
amodule->trampolines [MONO_AOT_TRAMP_UNBOX_ARBITRARY] = (guint8 *)info->unbox_arbitrary_trampolines;
- if (mono_is_corlib_image (assembly->image))
+ if (mono_is_corlib_image (assembly->image) || !strcmp (assembly->aname.name, "mscorlib") || !strcmp (assembly->aname.name, "System.Private.CoreLib"))
mscorlib_aot_module = amodule;
/* Compute method addresses */
g_hash_table_insert (aot_modules, assembly, amodule);
mono_aot_unlock ();
+ init_amodule_got (amodule, TRUE);
+
+ if (info->flags & MONO_AOT_FILE_FLAG_WITH_LLVM)
+ /* Directly called methods might make calls through the PLT */
+ init_plt (amodule);
+
if (amodule->jit_code_start)
mono_jit_info_add_aot_module (assembly->image, amodule->jit_code_start, amodule->jit_code_end);
if (amodule->llvm_code_start)
error_init (error);
- init_amodule_got (amodule);
+ init_amodule_got (amodule, FALSE);
if (domain != mono_get_root_domain ())
/* Non shared AOT code can't be used in other appdomains */
MonoGenericContext *context;
MonoGenericContext ctx;
+ /* Might be needed if the method is externally called */
+ init_plt (amodule);
+ init_amodule_got (amodule, FALSE);
+
memset (&ctx, 0, sizeof (ctx));
error_init (error);
MonoAotModule *amodule;
image = mono_defaults.corlib;
- if (image)
+ if (image && image->aot_module)
amodule = image->aot_module;
else
amodule = mscorlib_aot_module;
#include "mini.h"
/* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION 171
+#define MONO_AOT_FILE_VERSION 172
#define MONO_AOT_TRAMP_PAGE_SIZE 16384
/* Called from generated code to initialize a method */
void
-mini_llvm_init_method (gpointer aot_module, guint32 method_index)
+mini_llvm_init_method (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index)
{
MonoAotModule *amodule = (MonoAotModule *)aot_module;
/* Same for gshared methods with a this pointer */
void
-mini_llvm_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this_obj)
+mini_llvm_init_gshared_method_this (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoObject *this_obj)
{
MonoAotModule *amodule = (MonoAotModule *)aot_module;
MonoClass *klass;
/* Same for gshared methods with an mrgctx arg */
void
-mini_llvm_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
+mini_llvm_init_gshared_method_mrgctx (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
{
MonoAotModule *amodule = (MonoAotModule *)aot_module;
/* Same for gshared methods with a vtable arg */
void
-mini_llvm_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable)
+mini_llvm_init_gshared_method_vtable (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoVTable *vtable)
{
MonoAotModule *amodule = (MonoAotModule *)aot_module;
MonoClass *klass;
#define __MONO_LLVMONLY_RUNTIME_H__
#include "mini-runtime.h"
+#include "aot-runtime.h"
gpointer mini_llvmonly_load_method (MonoMethod *method, gboolean caller_gsharedvt, gboolean need_unbox, gpointer *out_arg, MonoError *error);
MonoFtnDesc* mini_llvmonly_load_method_ftndesc (MonoMethod *method, gboolean caller_gsharedvt, gboolean need_unbox, MonoError *error);
G_EXTERN_C void mini_llvmonly_init_delegate (MonoDelegate *del);
G_EXTERN_C void mini_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method);
-G_EXTERN_C void mini_llvm_init_method (gpointer aot_module, guint32 method_index);
-G_EXTERN_C void mini_llvm_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this_ins);
-G_EXTERN_C void mini_llvm_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx);
-G_EXTERN_C void mini_llvm_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable);
+G_EXTERN_C void mini_llvm_init_method (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index);
+G_EXTERN_C void mini_llvm_init_gshared_method_this (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoObject *this_ins);
+G_EXTERN_C void mini_llvm_init_gshared_method_mrgctx (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx);
+G_EXTERN_C void mini_llvm_init_gshared_method_vtable (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoVTable *vtable);
G_EXTERN_C void mini_llvmonly_throw_nullref_exception (void);
mono_save_args (cfg, sig, inline_args);
}
+ if (cfg->method == method && cfg->self_init && cfg->compile_aot && !COMPILE_LLVM (cfg)) {
+ MonoMethod *wrapper;
+ MonoInst *args [2];
+ int idx;
+
+ /*
+ * Emit code to initialize this method by calling the init wrapper emitted by LLVM.
+ * This is not efficient right now, but its only used for the methods which fail
+ * LLVM compilation.
+ * FIXME: Optimize this
+ */
+ g_assert (!cfg->gshared);
+ wrapper = mono_marshal_get_aot_init_wrapper (AOT_INIT_METHOD);
+ /* Emit this into the entry bb so it comes before the GC safe point which depends on an inited GOT */
+ cfg->cbb = cfg->bb_entry;
+ idx = mono_aot_get_method_index (cfg->method);
+ EMIT_NEW_ICONST (cfg, args [0], idx);
+ /* Dummy */
+ EMIT_NEW_ICONST (cfg, args [1], 0);
+ mono_emit_method_call (cfg, wrapper, args, NULL);
+ }
+
/* FIRST CODE BLOCK */
NEW_BBLOCK (cfg, tblock);
tblock->cil_code = ip;
LLVMValueRef unbox_tramp_indexes;
LLVMValueRef unbox_trampolines;
LLVMValueRef gc_poll_cold_wrapper;
+ LLVMValueRef info_var;
+ LLVMTypeRef *info_var_eltypes;
int max_inited_idx, max_method_idx;
gboolean has_jitted_code;
gboolean static_link;
static void llvm_jit_finalize_method (EmitContext *ctx);
static void mono_llvm_nonnull_state_update (EmitContext *ctx, LLVMValueRef lcall, MonoMethod *call_method, LLVMValueRef *args, int num_params);
static void mono_llvm_propagate_nonnull_final (GHashTable *all_specializable, MonoLLVMModule *module);
+static void create_aot_info_var (MonoLLVMModule *module);
static inline void
set_failure (EmitContext *ctx, const char *message)
}
static G_GNUC_UNUSED LLVMTypeRef
+LLVMFunctionType4 (LLVMTypeRef ReturnType,
+ LLVMTypeRef ParamType1,
+ LLVMTypeRef ParamType2,
+ LLVMTypeRef ParamType3,
+ LLVMTypeRef ParamType4,
+ int IsVarArg)
+{
+ LLVMTypeRef param_types [4];
+
+ param_types [0] = ParamType1;
+ param_types [1] = ParamType2;
+ param_types [2] = ParamType3;
+ param_types [3] = ParamType4;
+
+ return LLVMFunctionType (ReturnType, param_types, 4, IsVarArg);
+}
+
+static G_GNUC_UNUSED LLVMTypeRef
LLVMFunctionType5 (LLVMTypeRef ReturnType,
LLVMTypeRef ParamType1,
LLVMTypeRef ParamType2,
LLVMTypeRef type;
} CallSite;
-static gboolean
-method_is_direct_callable (MonoMethod *method)
-{
- if (method->wrapper_type == MONO_WRAPPER_ALLOC)
- return TRUE;
- if (method->string_ctor)
- return FALSE;
- if (method->wrapper_type)
- return FALSE;
- if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
- return FALSE;
- /* Can't enable this as the callee might fail llvm compilation */
- /*
- if (!method->is_inflated && (mono_class_get_flags (method->klass) & TYPE_ATTRIBUTE_PUBLIC) && (method->flags & METHOD_ATTRIBUTE_PUBLIC))
- return TRUE;
- */
- return FALSE;
-}
-
static LLVMValueRef
get_callee_llvmonly (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gconstpointer data)
{
}
} else if (type == MONO_PATCH_INFO_METHOD) {
MonoMethod *method = (MonoMethod*)data;
- if (m_class_get_image (method->klass) != ctx->module->assembly->image && method_is_direct_callable (method))
+ if (m_class_get_image (method->klass) != ctx->module->assembly->image && mono_aot_is_externally_callable (method))
callee_name = mono_aot_get_mangled_method_name (method);
}
}
if (ctx->llvm_only)
return get_callee_llvmonly (ctx, llvm_sig, type, data);
+ callee_name = NULL;
+ /* Cross-assembly direct calls */
+ if (type == MONO_PATCH_INFO_METHOD) {
+ MonoMethod *cmethod = (MonoMethod*)data;
+
+ if (m_class_get_image (cmethod->klass) != ctx->module->assembly->image) {
+ MonoJumpInfo tmp_ji;
+
+ memset (&tmp_ji, 0, sizeof (MonoJumpInfo));
+ tmp_ji.type = type;
+ tmp_ji.data.target = data;
+ if (mono_aot_is_direct_callable (&tmp_ji)) {
+ /*
+ * This will add a reference to cmethod's image so it will
+ * be loaded when the current AOT image is loaded, so
+ * the GOT slots used by the init method code are initialized.
+ */
+ tmp_ji.type = MONO_PATCH_INFO_IMAGE;
+ tmp_ji.data.image = m_class_get_image (cmethod->klass);
+ ji = mono_aot_patch_info_dup (&tmp_ji);
+ mono_aot_get_got_offset (ji);
+
+ callee_name = mono_aot_get_mangled_method_name (cmethod);
+
+ callee = (LLVMValueRef)g_hash_table_lookup (ctx->module->direct_callables, callee_name);
+ if (!callee) {
+ callee = LLVMAddFunction (ctx->lmodule, callee_name, llvm_sig);
+
+ LLVMSetLinkage (callee, LLVMExternalLinkage);
+
+ g_hash_table_insert (ctx->module->direct_callables, callee_name, callee);
+ } else {
+ /* LLVMTypeRef's are uniqued */
+ if (LLVMGetElementType (LLVMTypeOf (callee)) != llvm_sig)
+ callee = LLVMConstBitCast (callee, LLVMPointerType (llvm_sig, 0));
+
+ g_free (callee_name);
+ }
+ return callee;
+ }
+ }
+ }
+
callee_name = mono_aot_get_plt_symbol (type, data);
if (!callee_name)
return NULL;
emit_init_icall_wrapper (MonoLLVMModule *module, MonoAotInitSubtype subtype)
{
LLVMModuleRef lmodule = module->lmodule;
- LLVMValueRef func, indexes [2], got_entry_addr, args [16], callee;
- LLVMBasicBlockRef entry_bb;
+ LLVMValueRef func, indexes [2], got_entry_addr, args [16], callee, inited_var, cmp;
+ LLVMBasicBlockRef entry_bb, inited_bb, notinited_bb;
LLVMBuilderRef builder;
LLVMTypeRef sig;
MonoJumpInfo *ji;
int got_offset;
const char *wrapper_name = mono_marshal_get_aot_init_wrapper_name (subtype);
- char *name = g_strdup_printf ("%s%s", module->global_prefix, wrapper_name);
+ char *name = g_strdup_printf ("%s_%s", module->global_prefix, wrapper_name);
MonoJitICallId icall_id = MONO_JIT_ICALL_ZeroIsReserved;
switch (subtype) {
case AOT_INIT_METHOD:
icall_id = MONO_JIT_ICALL_mini_llvm_init_method;
func = LLVMAddFunction (lmodule, name, LLVMFunctionType1 (LLVMVoidType (), LLVMInt32Type (), FALSE));
- sig = LLVMFunctionType2 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), FALSE);
+ sig = LLVMFunctionType3 (LLVMVoidType (), IntPtrType (), IntPtrType (), LLVMInt32Type (), FALSE);
break;
case AOT_INIT_METHOD_GSHARED_MRGCTX:
icall_id = MONO_JIT_ICALL_mini_llvm_init_gshared_method_mrgctx; // Deliberate fall-through
if (!icall_id)
icall_id = MONO_JIT_ICALL_mini_llvm_init_gshared_method_vtable;
func = LLVMAddFunction (lmodule, name, LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), IntPtrType (), FALSE));
- sig = LLVMFunctionType3 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), IntPtrType (), FALSE);
+ sig = LLVMFunctionType4 (LLVMVoidType (), IntPtrType (), IntPtrType (), LLVMInt32Type (), IntPtrType (), FALSE);
break;
case AOT_INIT_METHOD_GSHARED_THIS:
icall_id = MONO_JIT_ICALL_mini_llvm_init_gshared_method_this;
func = LLVMAddFunction (lmodule, name, LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), ObjRefType (), FALSE));
- sig = LLVMFunctionType3 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), ObjRefType (), FALSE);
+ sig = LLVMFunctionType4 (LLVMVoidType (), IntPtrType (), IntPtrType (), LLVMInt32Type (), ObjRefType (), FALSE);
break;
default:
g_assert_not_reached ();
set_cold_cconv (func);
entry_bb = LLVMAppendBasicBlock (func, "ENTRY");
+
builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, entry_bb);
+ /* Check for is_inited here as well, since this can be called from JITted code which might not check it */
+ indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ indexes [1] = LLVMGetParam (func, 0);
+ inited_var = LLVMBuildLoad (builder, LLVMBuildGEP (builder, module->inited_var, indexes, 2, ""), "is_inited");
+
+ cmp = LLVMBuildICmp (builder, LLVMIntEQ, inited_var, LLVMConstInt (LLVMTypeOf (inited_var), 0, FALSE), "");
+
+ inited_bb = LLVMAppendBasicBlock (func, "INITED");
+ notinited_bb = LLVMAppendBasicBlock (func, "NOT_INITED");
+
+ LLVMBuildCondBr (builder, cmp, notinited_bb, inited_bb);
+
+ LLVMPositionBuilderAtEnd (builder, notinited_bb);
+
/* get_aotconst */
ji = g_new0 (MonoJumpInfo, 1);
ji->type = MONO_PATCH_INFO_AOT_MODULE;
indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
indexes [1] = LLVMConstInt (LLVMInt32Type (), got_offset, FALSE);
got_entry_addr = LLVMBuildGEP (builder, module->got_var, indexes, 2, "");
- args [0] = LLVMBuildPtrToInt (builder, LLVMBuildLoad (builder, got_entry_addr, ""), IntPtrType (), "");
- args [1] = LLVMGetParam (func, 0);
+ args [0] = LLVMBuildPtrToInt (builder, module->info_var, IntPtrType (), "");
+ args [1] = LLVMBuildPtrToInt (builder, LLVMBuildLoad (builder, got_entry_addr, ""), IntPtrType (), "");
+ args [2] = LLVMGetParam (func, 0);
if (subtype)
- args [2] = LLVMGetParam (func, 1);
+ args [3] = LLVMGetParam (func, 1);
ji = g_new0 (MonoJumpInfo, 1);
ji->type = MONO_PATCH_INFO_JIT_ICALL_ID;
indexes [1] = LLVMGetParam (func, 0);
LLVMBuildStore (builder, LLVMConstInt (LLVMInt8Type (), 1, FALSE), LLVMBuildGEP (builder, module->inited_var, indexes, 2, ""));
+ LLVMBuildBr (builder, inited_bb);
+
+ LLVMPositionBuilderAtEnd (builder, inited_bb);
LLVMBuildRetVoid (builder);
LLVMVerifyFunction(func, LLVMAbortProcessAction);
g_free (ctx);
}
-static gboolean
-is_externally_callable (EmitContext *ctx, MonoMethod *method)
-{
- if (ctx->module->llvm_only && ctx->module->static_link && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || method_is_direct_callable (method)))
- return TRUE;
- return FALSE;
-}
-
/*
* mono_llvm_emit_method:
*
if (cfg->compile_aot) {
ctx->module = &aot_module;
- if (is_externally_callable (ctx, cfg->method))
+ if (mono_aot_is_externally_callable (cfg->method))
method_name = mono_aot_get_mangled_method_name (cfg->method);
else
method_name = mono_aot_get_method_name (cfg);
ctx->module->max_method_idx = MAX (ctx->module->max_method_idx, cfg->method_index);
const char *init_name = mono_marshal_get_aot_init_wrapper_name (info->d.aot_init.subtype);
- ctx->method_name = g_strdup_printf ("%s%s", ctx->module->global_prefix, init_name);
+ ctx->method_name = g_strdup_printf ("%s_%s", ctx->module->global_prefix, init_name);
ctx->cfg->asm_symbol = g_strdup (ctx->method_name);
if (!cfg->llvm_only && ctx->module->external_symbols) {
mono_llvm_add_func_attr_nv (method, "no-frame-pointer-elim", "true");
if (cfg->compile_aot) {
- if (is_externally_callable (ctx, cfg->method)) {
+ if (mono_aot_is_externally_callable (cfg->method)) {
LLVMSetLinkage (method, LLVMExternalLinkage);
} else {
LLVMSetLinkage (method, LLVMInternalLinkage);
module->inited_var = LLVMAddGlobal (aot_module.lmodule, inited_type, "mono_inited_tmp");
LLVMSetInitializer (module->inited_var, LLVMConstNull (inited_type));
+ create_aot_info_var (module);
emit_gc_safepoint_poll (module, module->lmodule, NULL);
g_free (s);
return v;
}
+#define FILE_INFO_NFIELDS (2 + MONO_AOT_FILE_INFO_NUM_SYMBOLS + 22 + 5)
static void
-emit_aot_file_info (MonoLLVMModule *module)
+create_aot_info_var (MonoLLVMModule *module)
{
LLVMTypeRef file_info_type;
- LLVMTypeRef *eltypes, eltype;
+ LLVMTypeRef *eltypes;
LLVMValueRef info_var;
- LLVMValueRef *fields;
int i, nfields, tindex;
- MonoAotFileInfo *info;
LLVMModuleRef lmodule = module->lmodule;
- info = &module->aot_info;
-
/* Create an LLVM type to represent MonoAotFileInfo */
- nfields = 2 + MONO_AOT_FILE_INFO_NUM_SYMBOLS + 22 + 5;
+ nfields = FILE_INFO_NFIELDS;
eltypes = g_new (LLVMTypeRef, nfields);
tindex = 0;
eltypes [tindex ++] = LLVMInt32Type ();
LLVMStructSetBody (file_info_type, eltypes, nfields, FALSE);
info_var = LLVMAddGlobal (lmodule, file_info_type, "mono_aot_file_info");
+
+ module->info_var = info_var;
+ module->info_var_eltypes = eltypes;
+}
+
+static void
+emit_aot_file_info (MonoLLVMModule *module)
+{
+ LLVMTypeRef *eltypes, eltype;
+ LLVMValueRef info_var;
+ LLVMValueRef *fields;
+ int i, nfields, tindex;
+ MonoAotFileInfo *info;
+ LLVMModuleRef lmodule = module->lmodule;
+
+ info = &module->aot_info;
+ info_var = module->info_var;
+ eltypes = module->info_var_eltypes;
+ nfields = FILE_INFO_NFIELDS;
+
if (module->static_link) {
LLVMSetVisibility (info_var, LLVMHiddenVisibility);
LLVMSetLinkage (info_var, LLVMInternalLinkage);
fields [tindex ++] = llvm_array_from_bytes (info->aotid, 16);
g_assert (tindex == nfields);
- LLVMSetInitializer (info_var, LLVMConstNamedStruct (file_info_type, fields, nfields));
+ LLVMSetInitializer (info_var, LLVMConstNamedStruct (LLVMGetElementType (LLVMTypeOf (info_var)), fields, nfields));
if (module->static_link) {
char *s, *p;
register_dyn_icall (mini_get_dbg_callbacks ()->user_break, mono_debugger_agent_user_break, mono_icall_sig_void, FALSE);
- register_icall (mini_llvm_init_method, mono_icall_sig_void_ptr_int, TRUE);
- register_icall (mini_llvm_init_gshared_method_this, mono_icall_sig_void_ptr_int_object, TRUE);
- register_icall (mini_llvm_init_gshared_method_mrgctx, mono_icall_sig_void_ptr_int_ptr, TRUE);
- register_icall (mini_llvm_init_gshared_method_vtable, mono_icall_sig_void_ptr_int_ptr, TRUE);
+ register_icall (mini_llvm_init_method, mono_icall_sig_void_ptr_ptr_int, TRUE);
+ register_icall (mini_llvm_init_gshared_method_this, mono_icall_sig_void_ptr_ptr_int_object, TRUE);
+ register_icall (mini_llvm_init_gshared_method_mrgctx, mono_icall_sig_void_ptr_ptr_int_ptr, TRUE);
+ register_icall (mini_llvm_init_gshared_method_vtable, mono_icall_sig_void_ptr_ptr_int_ptr, TRUE);
register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
} else if (bblock == cfg->bb_entry) {
mono_bblock_insert_after_ins (bblock, bblock->last_ins, poll_addr);
mono_bblock_insert_after_ins (bblock, poll_addr, ins);
-
} else {
mono_bblock_insert_before_ins (bblock, NULL, poll_addr);
mono_bblock_insert_after_ins (bblock, poll_addr, ins);
cfg->llvm_only = (flags & JIT_FLAG_LLVM_ONLY) != 0;
cfg->interp = (flags & JIT_FLAG_INTERP) != 0;
cfg->use_current_cpu = (flags & JIT_FLAG_USE_CURRENT_CPU) != 0;
+ cfg->self_init = (flags & JIT_FLAG_SELF_INIT) != 0;
cfg->backend = current_backend;
if (cfg->method->wrapper_type == MONO_WRAPPER_ALLOC) {
JIT_FLAG_INTERP = (1 << 9),
/* Allow AOT to use all current CPU instructions */
JIT_FLAG_USE_CURRENT_CPU = (1 << 10),
+ /* Generate code to self-init the method for AOT */
+ JIT_FLAG_SELF_INIT = (1 << 11)
} JitFlags;
/* Bit-fields in the MonoBasicBlock.region */
guint llvm_only : 1;
guint interp : 1;
guint use_current_cpu : 1;
+ guint self_init : 1;
guint domainvar_inited : 1;
guint8 uses_simd_intrinsics;
int r4_stack_type;