#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
}
-/*
- * arch_get_cie_program:
- *
- * Get the unwind bytecode for the DWARF CIE.
- */
-static GSList*
-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 = (MonoClass*)mono_marshal_method_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 (!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);
- 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);
+ 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);
+
+ 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';
+
+ desc = mono_method_desc_new (name, TRUE);
+
+ method = mono_method_desc_search_in_image (desc, acfg->image);
- 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));
+ 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);
}
else
name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
break;
- case MONO_WRAPPER_DELEGATE_INVOKE:
- case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
- case MONO_WRAPPER_DELEGATE_END_INVOKE:
- /* This is a hack to work around the fact that these wrappers get assigned to some random class */
- name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
- break;
default:
klass_desc = mono_type_full_name (&method->klass->byval_arg);
name = g_strdup_printf ("%s:%s (%s)", klass_desc, method->name, tmpsig);
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, 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);
return 0;
}
-
-/*
- * Support for emitting debug info for JITted code.
- *
- * This works as follows:
- * - the runtime writes out an xdb.s file containing DWARF debug info.
- * - the user calls a gdb macro
- * - the macro compiles and loads this shared library using add-symbol-file.
- *
- * This is based on the xdebug functionality in the Kaffe Java VM.
- *
- * We emit assembly code instead of using the ELF writer, so we can emit debug info
- * incrementally as each method is JITted, and the debugger doesn't have to call
- * into the runtime to emit the shared library, which would cause all kinds of
- * complications, like threading issues, and the fact that the ELF writer's
- * emit_writeout () function cannot be called more than once.
- * GDB 7.0 and later has a JIT interface.
- */
-
-#define USE_GDB_JIT_INTERFACE
-
-/* The recommended gdb macro is: */
-/*
- define xdb
- shell rm -f xdb.so && as --64 -o xdb.o xdb.s && ld -shared -o xdb.so xdb.o
- add-symbol-file xdb.so 0
- end
-*/
-
-/*
- * GDB JIT interface definitions.
- *
- * http://sources.redhat.com/gdb/onlinedocs/gdb_30.html
- */
-typedef enum
-{
- JIT_NOACTION = 0,
- JIT_REGISTER_FN,
- JIT_UNREGISTER_FN
-} jit_actions_t;
-
-struct jit_code_entry
-{
- struct jit_code_entry *next_entry;
- struct jit_code_entry *prev_entry;
- const char *symfile_addr;
- guint64 symfile_size;
-};
-
-struct jit_descriptor
-{
- guint32 version;
- /* This type should be jit_actions_t, but we use guint32
- to be explicit about the bitwidth. */
- guint32 action_flag;
- struct jit_code_entry *relevant_entry;
- struct jit_code_entry *first_entry;
-};
-
-
-#ifdef _MSC_VER
-#define MONO_NOINLINE __declspec (noinline)
-#else
-#define MONO_NOINLINE __attribute__((noinline))
-#endif
-
-/* GDB puts a breakpoint in this function. */
-void MONO_NOINLINE __jit_debug_register_code(void);
-
-#if defined(ENABLE_LLVM) && ((LLVM_MAJOR_VERSION == 2 && LLVM_MINOR_VERSION >= 7) || LLVM_MAJOR_VERSION > 2)
-/* LLVM already defines these */
-extern struct jit_descriptor __jit_debug_descriptor;
-#else
-
-/* Make sure to specify the version statically, because the
- debugger may check the version before we can set it. */
-struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
-
-void MONO_NOINLINE __jit_debug_register_code(void) { };
-#endif
-
-static MonoImageWriter *xdebug_w;
-static MonoDwarfWriter *xdebug_writer;
-static FILE *xdebug_fp, *il_file;
-static gboolean use_gdb_interface, save_symfiles;
-static int il_file_line_index;
-static GHashTable *xdebug_syms;
-
-void
-mono_xdebug_init (char *options)
-{
- MonoImageWriter *w;
- char **args, **ptr;
-
- args = g_strsplit (options, ",", -1);
- for (ptr = args; ptr && *ptr; ptr ++) {
- char *arg = *ptr;
-
- if (!strcmp (arg, "gdb"))
- use_gdb_interface = TRUE;
- if (!strcmp (arg, "save-symfiles"))
- save_symfiles = TRUE;
- }
-
- /* This file will contain the IL code for methods which don't have debug info */
- il_file = fopen ("xdb.il", "w");
-
- if (use_gdb_interface)
- return;
-
- unlink ("xdb.s");
- xdebug_fp = fopen ("xdb.s", "w");
-
- w = img_writer_create (xdebug_fp, FALSE);
-
- img_writer_emit_start (w);
-
- xdebug_writer = mono_dwarf_writer_create (w, il_file, 0, TRUE);
-
- /* Emit something so the file has a text segment */
- img_writer_emit_section_change (w, ".text", 0);
- img_writer_emit_string (w, "");
-
- mono_dwarf_writer_emit_base_info (xdebug_writer, arch_get_cie_program ());
-}
-
-static void
-xdebug_begin_emit (MonoImageWriter **out_w, MonoDwarfWriter **out_dw)
-{
- MonoImageWriter *w;
- MonoDwarfWriter *dw;
-
- w = img_writer_create (NULL, TRUE);
-
- img_writer_emit_start (w);
-
- /* This file will contain the IL code for methods which don't have debug info */
- if (!il_file)
- il_file = fopen ("xdb.il", "w");
-
- dw = mono_dwarf_writer_create (w, il_file, il_file_line_index, FALSE);
-
- mono_dwarf_writer_emit_base_info (dw, arch_get_cie_program ());
-
- *out_w = w;
- *out_dw = dw;
-}
-
-static void
-xdebug_end_emit (MonoImageWriter *w, MonoDwarfWriter *dw, MonoMethod *method)
-{
- guint8 *img;
- guint32 img_size;
- struct jit_code_entry *entry;
-
- il_file_line_index = mono_dwarf_writer_get_il_file_line_index (dw);
- mono_dwarf_writer_close (dw);
-
- img_writer_emit_writeout (w);
-
- img = img_writer_get_output (w, &img_size);
-
- img_writer_destroy (w);
-
- if (FALSE) {
- /* Save the symbol files to help debugging */
- FILE *fp;
- char *file_name;
- static int file_counter;
-
- file_counter ++;
- file_name = g_strdup_printf ("xdb-%d.o", file_counter);
- //printf ("%s -> %s\n", mono_method_full_name (method, TRUE), file_name);
-
- fp = fopen (file_name, "w");
- fwrite (img, img_size, 1, fp);
- fclose (fp);
- g_free (file_name);
- }
-
- /* Register the image with GDB */
-
- entry = g_malloc (sizeof (struct jit_code_entry));
-
- entry->symfile_addr = (const char*)img;
- entry->symfile_size = img_size;
-
- entry->next_entry = __jit_debug_descriptor.first_entry;
- if (__jit_debug_descriptor.first_entry)
- __jit_debug_descriptor.first_entry->prev_entry = entry;
- __jit_debug_descriptor.first_entry = entry;
-
- __jit_debug_descriptor.relevant_entry = entry;
- __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
-
- __jit_debug_register_code ();
-}
-
-/*
- * mono_xdebug_flush:
- *
- * This could be called from inside gdb to flush the debugging information not yet
- * registered with gdb.
- */
-void
-mono_xdebug_flush (void)
-{
- if (xdebug_w)
- xdebug_end_emit (xdebug_w, xdebug_writer, NULL);
-
- xdebug_begin_emit (&xdebug_w, &xdebug_writer);
-}
-
-static int xdebug_method_count;
-
-/*
- * mono_save_xdebug_info:
- *
- * Emit debugging info for METHOD into an assembly file which can be assembled
- * and loaded into gdb to provide debugging info for JITted code.
- * LOCKING: Acquires the loader lock.
- */
-void
-mono_save_xdebug_info (MonoCompile *cfg)
-{
- if (use_gdb_interface) {
- mono_loader_lock ();
-
- if (!xdebug_syms)
- xdebug_syms = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
- /*
- * gdb is not designed to handle 1000s of symbol files (one per method). So we
- * group them into groups of 100.
- */
- if ((xdebug_method_count % 100) == 0)
- mono_xdebug_flush ();
-
- xdebug_method_count ++;
-
- mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, 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 ()));
-
-#if 0
- /*
- * Emit a symbol for the code by emitting it at the beginning of the text
- * segment, and setting the text segment to have an absolute address.
- * This symbol can be used to set breakpoints in gdb.
- * FIXME: This doesn't work when multiple methods are emitted into the same file.
- */
- sym = get_debug_sym (cfg->jit_info->method, "", xdebug_syms);
- img_writer_emit_section_change (w, ".text", 0);
- if (!xdebug_text_addr) {
- xdebug_text_addr = cfg->jit_info->code_start;
- img_writer_set_section_addr (w, (gssize)xdebug_text_addr);
- }
- img_writer_emit_global_with_size (w, sym, cfg->jit_info->code_size, TRUE);
- img_writer_emit_label (w, sym);
- img_writer_emit_bytes (w, cfg->jit_info->code_start, cfg->jit_info->code_size);
- g_free (sym);
-#endif
-
- mono_loader_unlock ();
- } else {
- if (!xdebug_writer)
- return;
-
- mono_loader_lock ();
- mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, 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 ()));
- fflush (xdebug_fp);
- mono_loader_unlock ();
- }
-}
-
-/*
- * mono_save_trampoline_xdebug_info:
- *
- * Same as mono_save_xdebug_info, but for trampolines.
- * LOCKING: Acquires the loader lock.
- */
-void
-mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
-{
- if (use_gdb_interface) {
- MonoImageWriter *w;
- MonoDwarfWriter *dw;
-
- mono_loader_lock ();
-
- xdebug_begin_emit (&w, &dw);
-
- mono_dwarf_writer_emit_trampoline (dw, tramp_name, NULL, NULL, code, code_size, unwind_info);
-
- xdebug_end_emit (w, dw, NULL);
-
- mono_loader_unlock ();
- } else {
- if (!xdebug_writer)
- return;
-
- mono_loader_lock ();
- mono_dwarf_writer_emit_trampoline (xdebug_writer, tramp_name, NULL, NULL, code, code_size, unwind_info);
- fflush (xdebug_fp);
- mono_loader_unlock ();
- }
-}
#else
return 0;
}
-void
-mono_xdebug_init (char *options)
-{
-}
-
-void
-mono_save_xdebug_info (MonoCompile *cfg)
-{
-}
-
-void
-mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
-{
-}
-
#endif