#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/threads-types.h>
-#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-logger-internal.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-time.h>
#include <mono/utils/mono-mmap.h>
int nthreads;
int ntrampolines;
int nrgctx_trampolines;
+ int nimt_trampolines;
gboolean print_skipped_methods;
gboolean stats;
char *tool_prefix;
GHashTable *unwind_info_offsets;
GPtrArray *unwind_ops;
guint32 unwind_info_offset;
+ char *got_symbol_base;
char *got_symbol;
char *plt_symbol;
GHashTable *method_label_hash;
const char *temp_prefix;
+ const char *llvm_label_prefix;
guint32 label_generator;
gboolean llvm;
MonoAotFileFlags flags;
#define PPC_LDX_OP "lwzx"
#endif
+//#define TARGET_ARM
+
+#ifdef TARGET_ARM
+#define LLVM_LABEL_PREFIX "_"
+#else
+#define LLVM_LABEL_PREFIX ""
+#endif
+
+#ifdef TARGET_ARM
+/* iphone */
+#define LLC_TARGET_ARGS "-march=arm -mattr=+v6 -mtriple=arm-apple-darwin"
+/* ELF */
+//#define LLC_TARGET_ARGS "-march=arm -mtriple=arm-linux-gnueabi -soft-float"
+#else
+#define LLC_TARGET_ARGS ""
+#endif
+
/*
* arch_emit_direct_call:
*
#endif
}
-/*
- * mono_arch_get_cie_program:
- *
- * Get the unwind bytecode for the DWARF CIE.
- */
-GSList*
-mono_arch_get_cie_program (void)
-{
-#ifdef TARGET_AMD64
- GSList *l = NULL;
-
- mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, AMD64_RSP, 8);
- mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, AMD64_RIP, -8);
-
- return l;
-#elif defined(TARGET_POWERPC)
- GSList *l = NULL;
-
- mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
-
- return l;
-#else
- return NULL;
-#endif
-}
-
/* END OF ARCH SPECIFIC CODE */
static guint32
case MONO_WRAPPER_LDFLDA:
case MONO_WRAPPER_STFLD:
case MONO_WRAPPER_ISINST: {
- MonoClass *proxy_class = mono_marshal_wrapper_info_from_wrapper (method);
+ MonoClass *proxy_class = mono_marshal_get_wrapper_info (method);
encode_klass_ref (acfg, proxy_class, p, &p);
break;
}
case MONO_WRAPPER_STFLD_REMOTE:
break;
case MONO_WRAPPER_ALLOC: {
- int alloc_type = mono_gc_get_managed_allocator_type (method);
- g_assert (alloc_type != -1);
- encode_value (alloc_type, p, &p);
+ AllocatorWrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+ g_assert (info->alloc_type != -1);
+ encode_value (info->alloc_type, p, &p);
break;
}
+ case MONO_WRAPPER_WRITE_BARRIER:
+ break;
case MONO_WRAPPER_STELEMREF:
break;
case MONO_WRAPPER_UNKNOWN:
}
case MONO_WRAPPER_MANAGED_TO_MANAGED:
if (!strcmp (method->name, "ElementAddr")) {
- ElementAddrWrapperInfo *info = mono_marshal_wrapper_info_from_wrapper (method);
+ ElementAddrWrapperInfo *info = mono_marshal_get_wrapper_info (method);
g_assert (info);
encode_value (MONO_AOT_WRAPPER_ELEMENT_ADDR, p, &p);
if (got_offset)
return got_offset - 1;
- g_assert (!acfg->final_got_size);
-
got_offset = acfg->got_offset;
acfg->got_offset ++;
+ if (acfg->final_got_size)
+ g_assert (got_offset < acfg->final_got_size);
+
acfg->stats.got_slots ++;
acfg->stats.got_slot_types [ji->type] ++;
case MONO_TYPE_STRING:
break;
case MONO_TYPE_VALUETYPE:
- if (!mono_class_from_mono_type (field->type)->enumtype && can_marshal_struct (mono_class_from_mono_type (field->type)))
+ if (!mono_class_from_mono_type (field->type)->enumtype && !can_marshal_struct (mono_class_from_mono_type (field->type)))
can_marshal = FALSE;
break;
default:
add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
}
}
+
+ /* native-to-managed wrappers */
+ for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+ MonoMethod *method;
+ guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+ MonoCustomAttrInfo *cattr;
+ int j;
+
+ method = mono_get_method (acfg->image, token, NULL);
+
+ /*
+ * Only generate native-to-managed wrappers for methods which have an
+ * attribute named MonoPInvokeCallbackAttribute. We search for the attribute by
+ * name to avoid defining a new assembly to contain it.
+ */
+ cattr = mono_custom_attrs_from_method (method);
+
+ if (cattr) {
+ for (j = 0; j < cattr->num_attrs; ++j)
+ if (cattr->attrs [j].ctor && !strcmp (cattr->attrs [j].ctor->klass->name, "MonoPInvokeCallbackAttribute"))
+ break;
+ if (j < cattr->num_attrs) {
+ MonoCustomAttrEntry *e = &cattr->attrs [j];
+ MonoMethodSignature *sig = mono_method_signature (e->ctor);
+ const char *p = (const char*)e->data;
+ int slen;
+ char *n;
+ MonoType *t;
+ MonoClass *klass;
+
+ g_assert (method->flags & METHOD_ATTRIBUTE_STATIC);
+
+ g_assert (sig->param_count == 1);
+ g_assert (sig->params [0]->type == MONO_TYPE_CLASS && !strcmp (mono_class_from_mono_type (sig->params [0])->name, "Type"));
+
+ /*
+ * Decode the cattr manually since we can't create objects
+ * during aot compilation.
+ */
+
+ /* Skip prolog */
+ p += 2;
+
+ /* From load_cattr_value () in reflection.c */
+ slen = mono_metadata_decode_value (p, &p);
+ n = g_memdup (p, slen + 1);
+ n [slen] = 0;
+ t = mono_reflection_type_from_name (n, acfg->image);
+ g_assert (t);
+ g_free (n);
+
+ klass = mono_class_from_mono_type (t);
+ g_assert (klass->parent == mono_defaults.multicastdelegate_class);
+
+ add_method (acfg, mono_marshal_get_managed_wrapper (method, klass, NULL));
+ }
+ }
+
+ if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
+ add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
+ }
+ }
/* StructureToPtr/PtrToStructure wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
iter = NULL;
while ((method = mono_class_get_methods (klass, &iter))) {
- if (mono_method_is_generic_sharable_impl (method, FALSE))
+ if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
/* Already added */
continue;
token = MONO_TOKEN_METHOD_SPEC | (i + 1);
method = mono_get_method (acfg->image, token, NULL);
- context = mono_method_get_context (method);
- if (context && ((context->class_inst && context->class_inst->is_open) ||
- (context->method_inst && context->method_inst->is_open)))
+ if (method->klass->image != acfg->image)
continue;
- if (method->klass->image != acfg->image)
+ context = mono_method_get_context (method);
+
+ if (context && ((context->class_inst && context->class_inst->is_open)))
continue;
- if (mono_method_is_generic_sharable_impl (method, FALSE))
- /* Already added */
+ /*
+ * For open methods, create an instantiation which can be passed to the JIT.
+ * FIXME: Handle class_inst as well.
+ */
+ if (context && context->method_inst && context->method_inst->is_open) {
+ MonoGenericContext shared_context;
+ MonoGenericInst *inst;
+ MonoType **type_argv;
+ int i;
+ MonoMethod *declaring_method;
+ gboolean supported = TRUE;
+
+ /* Check that the context doesn't contain open constructed types */
+ if (context->class_inst) {
+ inst = context->class_inst;
+ for (i = 0; i < inst->type_argc; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+ continue;
+ if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+ supported = FALSE;
+ }
+ }
+ if (context->method_inst) {
+ inst = context->method_inst;
+ for (i = 0; i < inst->type_argc; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+ continue;
+ if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+ supported = FALSE;
+ }
+ }
+
+ if (!supported)
+ continue;
+
+ memset (&shared_context, 0, sizeof (MonoGenericContext));
+
+ inst = context->class_inst;
+ if (inst) {
+ type_argv = g_new0 (MonoType*, inst->type_argc);
+ for (i = 0; i < inst->type_argc; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+ type_argv [i] = &mono_defaults.object_class->byval_arg;
+ else
+ type_argv [i] = inst->type_argv [i];
+ }
+
+ shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+ g_free (type_argv);
+ }
+
+ inst = context->method_inst;
+ if (inst) {
+ type_argv = g_new0 (MonoType*, inst->type_argc);
+ for (i = 0; i < inst->type_argc; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+ type_argv [i] = &mono_defaults.object_class->byval_arg;
+ else
+ type_argv [i] = inst->type_argv [i];
+ }
+
+ shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+ g_free (type_argv);
+ }
+
+ if (method->is_generic || method->klass->generic_container)
+ declaring_method = method;
+ else
+ declaring_method = mono_method_get_declaring_generic_method (method);
+
+ method = mono_class_inflate_generic_method (declaring_method, &shared_context);
+ }
+
+ /*
+ * If the method is fully sharable, it was already added in place of its
+ * generic definition.
+ */
+ if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
continue;
+ /*
+ * FIXME: Partially shared methods are not shared here, so we end up with
+ * many identical methods.
+ */
add_extra_method (acfg, method);
}
MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
//printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
direct_call = TRUE;
- sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
+ sprintf (direct_call_target, callee_cfg->asm_symbol);
patch_info->type = MONO_PATCH_INFO_NONE;
acfg->stats.direct_calls ++;
}
if (plt_offset != -1) {
/* This patch has a PLT entry, so we must emit a call to the PLT entry */
direct_call = TRUE;
- sprintf (direct_call_target, "%sp_%d", acfg->temp_prefix, plt_offset);
+ sprintf (direct_call_target, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, plt_offset);
/* Nullify the patch */
patch_info->type = MONO_PATCH_INFO_NONE;
method_index = get_method_index (acfg, method);
- /* Emit unbox trampoline */
- if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
- char call_target [256];
-
- if (!method->wrapper_type && !method->is_inflated) {
- g_assert (method->token);
- sprintf (symbol, "ut_%d", mono_metadata_token_index (method->token) - 1);
- } else {
- sprintf (symbol, "ut_e_%d", get_method_index (acfg, method));
- }
-
- emit_section_change (acfg, ".text", 0);
- emit_global (acfg, symbol, TRUE);
- emit_label (acfg, symbol);
-
- sprintf (call_target, "%sm_%x", acfg->temp_prefix, method_index);
-
- arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
- }
-
/* Make the labels local */
- sprintf (symbol, "%sm_%x", acfg->temp_prefix, method_index);
+ sprintf (symbol, "%s", cfg->asm_symbol);
emit_section_change (acfg, ".text", 0);
emit_alignment (acfg, func_alignment);
}
/* Exception table */
- if (jinfo->num_clauses)
- encode_value (jinfo->num_clauses, p, &p);
+ if (cfg->compile_llvm) {
+ /* The assembly might be CIL stripped so emit the data ourselves */
+ if (header->num_clauses)
+ encode_value (header->num_clauses, p, &p);
- for (k = 0; k < jinfo->num_clauses; ++k) {
- MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+ for (k = 0; k < header->num_clauses; ++k) {
+ MonoExceptionClause *clause;
- encode_value (ei->flags, p, &p);
- encode_value (ei->exvar_offset, p, &p);
+ clause = &header->clauses [k];
- if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
- encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
- else {
- if (ei->data.catch_class) {
+ encode_value (clause->flags, p, &p);
+ if (clause->data.catch_class) {
encode_value (1, p, &p);
- encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+ encode_klass_ref (acfg, clause->data.catch_class, p, &p);
} else {
encode_value (0, p, &p);
}
}
+ } else {
+ if (jinfo->num_clauses)
+ encode_value (jinfo->num_clauses, p, &p);
+
+ for (k = 0; k < jinfo->num_clauses; ++k) {
+ MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+
+ encode_value (ei->flags, p, &p);
+ encode_value (ei->exvar_offset, p, &p);
- encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
- encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
- encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
+ encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+ else {
+ if (ei->data.catch_class) {
+ encode_value (1, p, &p);
+ encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+ } else {
+ encode_value (0, p, &p);
+ }
+ }
+
+ encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
+ encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
+ encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+ }
}
if (jinfo->has_generic_jit_info) {
char *debug_sym = NULL;
MonoJumpInfo *ji;
- sprintf (label, "%sp_%d", acfg->temp_prefix, i);
+ sprintf (label, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, i);
if (acfg->llvm) {
/*
ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer) {
MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, ji->data.method);
- fprintf (acfg->fp, "\n.set %s, .Lm_%x\n", label, get_method_index (acfg, callee_cfg->orig_method));
+ fprintf (acfg->fp, "\n.set %s, %s\n", label, callee_cfg->asm_symbol);
continue;
}
}
g_assert (acfg->image->assembly);
- /* Currently, we only emit most trampolines into the mscorlib AOT image. */
+ /* Currently, we emit most trampolines into the mscorlib AOT image. */
if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
#ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
/*
opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
} else if (str_begins_with (arg, "nrgctx-trampolines=")) {
opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines="));
+ } else if (str_begins_with (arg, "nimt-trampolines=")) {
+ opts->nimt_trampolines = atoi (arg + strlen ("nimt-trampolines="));
} else if (str_begins_with (arg, "autoreg")) {
opts->autoreg = TRUE;
} else if (str_begins_with (arg, "tool-prefix=")) {
case MONO_WRAPPER_ALLOC:
case MONO_WRAPPER_REMOTING_INVOKE:
case MONO_WRAPPER_UNKNOWN:
+ case MONO_WRAPPER_WRITE_BARRIER:
break;
case MONO_WRAPPER_MANAGED_TO_MANAGED:
if (!strcmp (method->name, "ElementAddr"))
file_index = 0;
while (TRUE) {
- tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
+ tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%d", g_get_home_dir (), acfg->image->assembly_name, file_index);
if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) {
g_free (tmp);
file_index ++;
res = fscanf (infile, "%32s\n", ver);
- if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
+ if ((res != 1) || strcmp (ver, "#VER:2") != 0) {
printf ("Profile file has wrong version or invalid.\n");
fclose (infile);
continue;
}
while (TRUE) {
- res = fscanf (infile, "%d\n", &token);
- if (res < 1)
+ char name [1024];
+ MonoMethodDesc *desc;
+ MonoMethod *method;
+
+ if (fgets (name, 1023, infile) == NULL)
break;
- method_index = mono_metadata_token_index (token) - 1;
+ /* Kill the newline */
+ if (strlen (name) > 0)
+ name [strlen (name) - 1] = '\0';
- if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
- acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+ desc = mono_method_desc_new (name, TRUE);
+
+ method = mono_method_desc_search_in_image (desc, acfg->image);
+
+ if (method && mono_method_get_token (method)) {
+ token = mono_method_get_token (method);
+ method_index = mono_metadata_token_index (token) - 1;
+
+ if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index))) {
+ acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+ }
+ } else {
+ //printf ("No method found matching '%s'.\n", name);
+ }
}
fclose (infile);
}
{
guint32 method_index = get_method_index (llvm_acfg, cfg->orig_method);
- /* LLVM converts these to .Lm_%x */
return g_strdup_printf ("m_%x", method_index);
}
offset = get_plt_offset (llvm_acfg, ji);
- return g_strdup_printf (".Lp_%d", offset);
+ return g_strdup_printf ("%sp_%d", llvm_acfg->temp_prefix, offset);
}
MonoJumpInfo*
char *command, *opts;
int i;
MonoJumpInfo *patch_info;
+ char *llc_target_args;
/*
* When using LLVM, we let llvm emit the got since the LLVM IL needs to refer
}
}
}
+
acfg->final_got_size = acfg->got_offset + acfg->plt_offset;
+ if (acfg->aot_opts.full_aot) {
+ int ntype;
+
+ /*
+ * Need to add the got entries used by the trampolines.
+ * This is only a conservative approximation.
+ */
+ if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
+ /* For the generic + rgctx trampolines */
+ acfg->final_got_size += 200;
+ /* For the specific trampolines */
+ for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype)
+ acfg->final_got_size += acfg->num_trampolines [ntype] * 2;
+ }
+ }
+
+
mono_llvm_emit_aot_module ("temp.bc", acfg->final_got_size);
/*
* a lot of time, and doesn't seem to save much space.
* The following optimizations cannot be enabled:
* - 'tailcallelim'
+ * The opt list below was produced by taking the output of:
+ * llvm-as < /dev/null | opt -O2 -disable-output -debug-pass=Arguments
+ * then removing tailcallelim + the global opts, and adding a second gvn.
*/
opts = g_strdup ("-instcombine -simplifycfg");
+ opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -basiccg -prune-eh -inline -functionattrs -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -jump-threading -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loopsimplify -domfrontier -loopsimplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loopsimplify -lcssa -iv-users -indvars -loop-deletion -loopsimplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -jump-threading -domtree -memdep -dse -adce -gvn -simplifycfg -preverify -domtree -verify");
#if 1
command = g_strdup_printf ("opt -f %s -o temp.opt.bc temp.bc", opts);
printf ("Executing opt: %s\n", command);
#endif
g_free (opts);
- //command = g_strdup_printf ("llc -march=arm -mtriple=arm-linux-gnueabi -f -relocation-model=pic -unwind-tables temp.bc");
- command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables -o temp.s temp.opt.bc");
+ llc_target_args = g_strdup (LLC_TARGET_ARGS);
+
+ command = g_strdup_printf ("llc %s -f -relocation-model=pic -unwind-tables -o %s temp.opt.bc", llc_target_args, acfg->tmpfname);
+ g_free (llc_target_args);
+
printf ("Executing llc: %s\n", command);
if (system (command) != 0) {
{
int i;
char symbol [256];
+ char end_symbol [256];
GList *l;
#if defined(TARGET_POWERPC64)
emit_pointer (acfg, acfg->got_symbol);
#endif
- if (!acfg->llvm) {
- sprintf (symbol, "methods");
- emit_section_change (acfg, ".text", 0);
- emit_global (acfg, symbol, TRUE);
- emit_alignment (acfg, 8);
+ /*
+ * This global symbol is used to compute the address of each method using the
+ * code_offsets array. It is also used to compute the memory ranges occupied by
+ * AOT code, so it must be equal to the address of the first emitted method.
+ */
+ sprintf (symbol, "methods");
+ emit_section_change (acfg, ".text", 0);
+ emit_global (acfg, symbol, TRUE);
+ emit_alignment (acfg, 8);
+ if (acfg->llvm) {
+ for (i = 0; i < acfg->nmethods; ++i) {
+ if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm) {
+ fprintf (acfg->fp, "\n.set methods, %s\n", acfg->cfgs [i]->asm_symbol);
+ break;
+ }
+ }
+ if (i == acfg->nmethods)
+ /* No LLVM compiled methods */
+ emit_label (acfg, symbol);
+ } else {
emit_label (acfg, symbol);
}
emit_zero_bytes (acfg, 16);
for (l = acfg->method_order; l != NULL; l = l->next) {
+ MonoCompile *cfg;
+ MonoMethod *method;
+
i = GPOINTER_TO_UINT (l->data);
- if (acfg->cfgs [i]) {
- if (acfg->cfgs [i]->compile_llvm)
- acfg->stats.llvm_count ++;
- else
- emit_method_code (acfg, acfg->cfgs [i]);
+ cfg = acfg->cfgs [i];
+
+ if (!cfg)
+ continue;
+
+ method = cfg->orig_method;
+
+ /* Emit unbox trampoline */
+ if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+ char call_target [256];
+
+ if (!method->wrapper_type && !method->is_inflated) {
+ g_assert (method->token);
+ sprintf (symbol, "ut_%d", mono_metadata_token_index (method->token) - 1);
+ } else {
+ sprintf (symbol, "ut_e_%d", get_method_index (acfg, method));
+ }
+
+ emit_section_change (acfg, ".text", 0);
+ emit_global (acfg, symbol, TRUE);
+ emit_label (acfg, symbol);
+
+ sprintf (call_target, "%s", cfg->asm_symbol);
+
+ arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
}
+
+ if (cfg->compile_llvm)
+ acfg->stats.llvm_count ++;
+ else
+ emit_method_code (acfg, cfg);
}
sprintf (symbol, "methods_end");
acfg->stats.offsets_size += acfg->nmethods * 4;
+ sprintf (end_symbol, "methods");
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
- sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
- emit_symbol_diff (acfg, symbol, "methods", 0);
+ emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
} else {
emit_int32 (acfg, 0xffffffff);
}
nmethods ++;
+ method = cfg->method_to_register;
+
name = NULL;
if (method->wrapper_type) {
/*
if (cfg->compile_llvm)
continue;
- sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
+ sprintf (symbol, "%s", cfg->asm_symbol);
sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, symbol, symbol2, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
{
MonoImage *image = ass->image;
- int res;
+ int i, res;
MonoAotCompile *acfg;
char *outfile_name, *tmp_outfile_name, *p;
TV_DECLARE (atv);
acfg->aot_opts.write_symbols = TRUE;
acfg->aot_opts.ntrampolines = 1024;
acfg->aot_opts.nrgctx_trampolines = 1024;
+ acfg->aot_opts.nimt_trampolines = 128;
mono_aot_parse_options (aot_options, &acfg->aot_opts);
#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? acfg->aot_opts.nrgctx_trampolines : 0;
#endif
- acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? 128 : 0;
+ acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
- acfg->got_symbol = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
+ acfg->got_symbol_base = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
acfg->plt_symbol = g_strdup_printf ("mono_aot_%s_plt", acfg->image->assembly->aname.name);
/* Get rid of characters which cannot occur in symbols */
- for (p = acfg->got_symbol; *p; ++p) {
+ for (p = acfg->got_symbol_base; *p; ++p) {
if (!(isalnum (*p) || *p == '_'))
*p = '_';
}
*p = '_';
}
+ acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
+
acfg->method_index = 1;
collect_methods (acfg);
#ifdef ENABLE_LLVM
llvm_acfg = acfg;
- mono_llvm_create_aot_module (acfg->got_symbol);
+ mono_llvm_create_aot_module (acfg->got_symbol_base);
#endif
/* GOT offset 0 is reserved for the address of the current assembly */
TV_GETTIME (atv);
#ifdef ENABLE_LLVM
+ if (acfg->llvm) {
+ if (acfg->aot_opts.asm_only) {
+ if (acfg->aot_opts.outfile)
+ acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+ else
+ acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
+ } else {
+ acfg->tmpfname = g_strdup ("temp.s");
+ }
+ }
+
emit_llvm_file (acfg);
#endif
if (acfg->llvm) {
/* Append to the .s file created by llvm */
/* FIXME: Use multiple files instead */
- acfg->tmpfname = g_strdup ("temp.s");
- acfg->fp = fopen (acfg->tmpfname, "a");
+ acfg->fp = fopen (acfg->tmpfname, "a+");
} else {
if (acfg->aot_opts.asm_only) {
if (acfg->aot_opts.outfile)
outfile_name = NULL;
}
- acfg->temp_prefix = img_writer_get_temp_label_prefix (acfg->w);
+ /*
+ * The prefix LLVM likes to put in front of symbol names on darwin.
+ * The mach-os specs require this for globals, but LLVM puts them in front of all
+ * symbols. We need to handle this, since we need to refer to LLVM generated
+ * symbols.
+ */
+ acfg->llvm_label_prefix = "";
+ if (acfg->llvm)
+ acfg->llvm_label_prefix = LLVM_LABEL_PREFIX;
+
+ acfg->got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->got_symbol_base);
+
+ /* Compute symbols for methods */
+ for (i = 0; i < acfg->nmethods; ++i) {
+ if (acfg->cfgs [i]) {
+ MonoCompile *cfg = acfg->cfgs [i];
+ int method_index = get_method_index (acfg, cfg->orig_method);
+
+ cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, LLVM_LABEL_PREFIX, method_index);
+ }
+ }
if (!acfg->aot_opts.nodebug)
acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE);
img_writer_emit_start (acfg->w);
if (acfg->dwarf)
- mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_arch_get_cie_program ());
+ mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_unwind_get_cie_program ());
emit_code (acfg);
acfg->stats.gen_time = TV_ELAPSED (atv, btv);
if (acfg->llvm)
- g_assert (acfg->got_offset == acfg->final_got_size);
+ g_assert (acfg->got_offset <= acfg->final_got_size);
printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT: %d Offsets: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.unwind_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, (int)(acfg->got_offset * sizeof (gpointer)), acfg->stats.offsets_size);