* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
*/
-/* Remaining AOT-only work:
- * - optimize the trampolines, generate more code in the arch files.
- * - make things more consistent with how elf works, for example, use ELF
- * relocations.
- * Remaining generics sharing work:
- * - optimize the size of the data which is encoded.
- * - optimize the runtime loading of data:
- * - the trampoline code calls mono_jit_info_table_find () to find the rgctx,
- * which loads the debugging+exception handling info for the method. This is a
- * huge waste of time and code, since the rgctx structure is currently empty.
- */
#include "config.h"
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <errno.h>
#include <sys/stat.h>
-
#include <mono/metadata/abi-details.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/class.h>
#include <mono/utils/mono-mmap.h>
#include "mini.h"
+#include "seq-points.h"
#include "image-writer.h"
#include "dwarfwriter.h"
#include "mini-gc.h"
#define TV_GETTIME(tv) tv = mono_100ns_ticks ()
#define TV_ELAPSED(start,end) (((end) - (start)) / 10)
-#ifdef TARGET_WIN32
-#define SHARED_EXT ".dll"
-#elif defined(__ppc__) && defined(TARGET_MACH)
-#define SHARED_EXT ".dylib"
-#elif defined(TARGET_MACH) && defined(TARGET_X86) && !defined(__native_client_codegen__)
-#define SHARED_EXT ".dylib"
-#elif defined(TARGET_MACH) && defined(TARGET_AMD64) && !defined(__native_client_codegen__)
-#define SHARED_EXT ".dylib"
-#else
-#define SHARED_EXT ".so"
-#endif
-
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
#define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
acfg->llvm_label_prefix = "";
acfg->user_symbol_prefix = "";
+#if defined(TARGET_X86)
+ g_string_append (acfg->llc_args, " -march=x86 -mattr=sse4.1");
+#endif
+
#if defined(TARGET_AMD64)
g_string_append (acfg->llc_args, " -march=x86-64 -mattr=sse4.1");
#endif
g_assert (code - buf == 8);
emit_bytes (acfg, buf, code - buf);
}
+
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_SPECIFIC] = 16;
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_STATIC_RGCTX] = 16;
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_IMT_THUNK] = 72;
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_GSHAREDVT_ARG] = 16;
#elif defined(TARGET_ARM64)
arm64_emit_specific_trampoline_pages (acfg);
#endif
code = buf;
/* Load the mscorlib got address */
- ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
+ ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
/* Load the parameter from the GOT */
ppc_load (code, ppc_r0, offset * sizeof (gpointer));
- ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
+ ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
/* Load and check key */
labels [1] = code;
- ppc_ldptr (code, ppc_r0, 0, ppc_r11);
+ ppc_ldptr (code, ppc_r0, 0, ppc_r12);
ppc_cmp (code, 0, sizeof (gpointer) == 8 ? 1 : 0, ppc_r0, MONO_ARCH_IMT_REG);
labels [2] = code;
ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
/* Loop footer */
- ppc_addi (code, ppc_r11, ppc_r11, 2 * sizeof (gpointer));
+ ppc_addi (code, ppc_r12, ppc_r12, 2 * sizeof (gpointer));
labels [4] = code;
ppc_b (code, 0);
mono_ppc_patch (labels [4], labels [1]);
/* Match */
mono_ppc_patch (labels [2], code);
- ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r11);
- /* r11 now contains the value of the vtable slot */
+ ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r12);
+ /* r12 now contains the value of the vtable slot */
/* this is not a function descriptor on ppc64 */
- ppc_ldptr (code, ppc_r11, 0, ppc_r11);
- ppc_mtctr (code, ppc_r11);
+ ppc_ldptr (code, ppc_r12, 0, ppc_r12);
+ ppc_mtctr (code, ppc_r12);
ppc_bcctr (code, PPC_BR_ALWAYS, 0);
/* Fail */
if (info && !has_nullable) {
/* Supported by the dynamic runtime-invoke wrapper */
skip = TRUE;
- g_free (info);
}
+ if (info)
+ mono_arch_dyn_call_free (info);
}
#endif
char *name1, *name2, *cached;
int i, j, len, count;
+ name1 = mono_method_full_name (method, TRUE);
+
#ifdef TARGET_MACH
// This is so that we don't accidentally create a local symbol (which starts with 'L')
- if (!prefix || !*prefix)
+ if ((!prefix || !*prefix) && name1 [0] == 'L')
prefix = "_";
#endif
- name1 = mono_method_full_name (method, TRUE);
len = strlen (name1);
name2 = malloc (strlen (prefix) + len + 16);
memcpy (name2, prefix, strlen (prefix));
case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
case MONO_PATCH_INFO_JIT_TLS_ID:
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
+ break;
case MONO_PATCH_INFO_CASTCLASS_CACHE:
+ encode_value (patch_info->data.index, p, &p);
break;
case MONO_PATCH_INFO_METHOD_REL:
encode_value ((gint)patch_info->data.offset, p, &p);
{
MonoMethod *method;
int i, k, buf_size, method_index;
- guint32 debug_info_size;
+ guint32 debug_info_size, seq_points_size;
guint8 *code;
MonoMethodHeader *header;
guint8 *p, *buf, *debug_info;
seq_points = cfg->seq_point_info;
- buf_size = header->num_clauses * 256 + debug_info_size + 2048 + (seq_points ? (seq_points->len * 128) : 0) + cfg->gc_map_size;
+ seq_points_size = (cfg->gen_seq_points)? seq_point_info_get_write_size (seq_points) : 0;
+
+ buf_size = header->num_clauses * 256 + debug_info_size + 2048 + seq_points_size + cfg->gc_map_size;
p = buf = g_malloc (buf_size);
use_unwind_ops = cfg->unwind_ops != NULL;
encode_value (table->num_holes, p, &p);
}
+ if (jinfo->has_arch_eh_info) {
+ /*
+ * In AOT mode, the code length is calculated from the address of the previous method,
+ * which could include alignment padding, so calculating the start of the epilog as
+ * code_len - epilog_size is correct any more. Save the real code len as a workaround.
+ */
+ encode_value (jinfo->code_size, p, &p);
+ }
+
/* Exception table */
if (cfg->compile_llvm) {
/*
}
}
- if (seq_points) {
- int il_offset, native_offset, last_il_offset, last_native_offset, j;
+ if (seq_points)
+ p += seq_point_info_write (seq_points, p);
- encode_value (seq_points->len, p, &p);
- last_il_offset = last_native_offset = 0;
- for (i = 0; i < seq_points->len; ++i) {
- SeqPoint *sp = &seq_points->seq_points [i];
- il_offset = sp->il_offset;
- native_offset = sp->native_offset;
- encode_value (il_offset - last_il_offset, p, &p);
- encode_value (native_offset - last_native_offset, p, &p);
- last_il_offset = il_offset;
- last_native_offset = native_offset;
-
- encode_value (sp->flags, p, &p);
- encode_value (sp->next_len, p, &p);
- for (j = 0; j < sp->next_len; ++j)
- encode_value (sp->next [j], p, &p);
- }
- }
-
g_assert (debug_info_size < buf_size);
encode_value (debug_info_size, p, &p);
plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
ji = plt_entry->ji;
- if (acfg->llvm) {
- /*
- * If the target is directly callable, alias the plt symbol to point to
- * the method code.
- * FIXME: Use this to simplify emit_and_reloc_code ().
- * FIXME: Avoid the got slot.
- * FIXME: Add support to the binary writer.
- */
- 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);
-
- if (callee_cfg) {
- if (acfg->thumb_mixed && !callee_cfg->compile_llvm) {
- /* LLVM calls the PLT entries using bl, so emit a stub */
- emit_set_thumb_mode (acfg);
- fprintf (acfg->fp, "\n.thumb_func\n");
- emit_label (acfg, plt_entry->llvm_symbol);
- fprintf (acfg->fp, "bx pc\n");
- fprintf (acfg->fp, "nop\n");
- emit_set_arm_mode (acfg);
- fprintf (acfg->fp, "b %s\n", callee_cfg->asm_symbol);
- } else {
- fprintf (acfg->fp, "\n.set %s, %s\n", plt_entry->llvm_symbol, callee_cfg->asm_symbol);
- }
- continue;
- }
- }
- }
-
debug_sym = plt_entry->debug_sym;
if (acfg->thumb_mixed && !plt_entry->jit_used)
/* Emit only a thumb version */
continue;
+ /* Skip plt entries not actually called */
+ if (!plt_entry->jit_used && !plt_entry->llvm_used)
+ continue;
+
if (acfg->llvm && !acfg->thumb_mixed)
emit_label (acfg, plt_entry->llvm_symbol);
plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
ji = plt_entry->ji;
- if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer)
- continue;
-
/* Skip plt entries not actually called by LLVM code */
if (!plt_entry->llvm_used)
continue;
{
MonoMethod *method = (MonoMethod*)key;
MonoJumpInfoToken *ji = (MonoJumpInfoToken*)value;
- MonoJumpInfoToken *new_ji = g_new0 (MonoJumpInfoToken, 1);
MonoAotCompile *acfg = user_data;
+ MonoJumpInfoToken *new_ji;
+ new_ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfoToken));
new_ji->image = ji->image;
new_ji->token = ji->token;
g_hash_table_insert (acfg->token_info_hash, method, new_ji);
mono_acfg_lock (acfg);
g_hash_table_foreach (cfg->token_info_hash, add_token_info_hash, acfg);
mono_acfg_unlock (acfg);
+ g_hash_table_destroy (cfg->token_info_hash);
+ cfg->token_info_hash = NULL;
/*
* Check for absolute addresses.
return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
}
+gboolean
+mono_aot_is_direct_callable (MonoJumpInfo *patch_info)
+{
+ return is_direct_callable (llvm_acfg, NULL, patch_info);
+}
+
+void
+mono_aot_mark_unused_llvm_plt_entry (MonoJumpInfo *patch_info)
+{
+ MonoPltEntry *plt_entry;
+
+ plt_entry = get_plt_entry (llvm_acfg, patch_info);
+ plt_entry->llvm_used = FALSE;
+}
+
char*
mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
{
tempbc = g_strdup_printf ("%s.bc", acfg->tmpbasename);
- mono_llvm_emit_aot_module (tempbc, acfg->final_got_size);
+ mono_llvm_emit_aot_module (tempbc, g_path_get_basename (acfg->image->name), acfg->final_got_size);
g_free (tempbc);
/*
if (acfg->aot_opts.outfile)
outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
else
- outfile_name = g_strdup_printf ("%s%s", acfg->image->name, SHARED_EXT);
+ outfile_name = g_strdup_printf ("%s%s", acfg->image->name, MONO_SOLIB_EXT);
tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
g_free (command);
- /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, SHARED_EXT);
+ /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, MONO_SOLIB_EXT);
printf ("Stripping the binary: %s\n", com);
system (com);
g_free (com);*/
acfg->patch_to_got_offset_by_type [i] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
acfg->got_patches = g_ptr_array_new ();
acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
- acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+ acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, NULL);
acfg->method_to_pinvoke_import = g_hash_table_new_full (NULL, NULL, NULL, g_free);
acfg->image_hash = g_hash_table_new (NULL, NULL);
acfg->image_table = g_ptr_array_new ();
MonoDebugOptions *opt = mini_get_debug_options ();
opt->mdb_optimizations = TRUE;
- opt->gen_seq_points = TRUE;
+ opt->gen_seq_points_debug_data = TRUE;
if (!mono_debug_enabled ()) {
aot_printerrf (acfg, "The soft-debug AOT option requires the --debug option.\n");
aot_printerrf (acfg, "The 'soft-debug' option is not supported when compiling with LLVM.\n");
return 1;
}
+
+ mini_llvm_init ();
}
if (acfg->aot_opts.full_aot)
res = emit_llvm_file (acfg);
if (!res)
- return FALSE;
+ return 1;
}
#endif
if (acfg->aot_opts.outfile)
outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
else
- outfile_name = g_strdup_printf ("%s%s", acfg->image->name, SHARED_EXT);
+ outfile_name = g_strdup_printf ("%s%s", acfg->image->name, MONO_SOLIB_EXT);
/*
* Can't use g_file_open_tmp () as it will be deleted at exit, and