* 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>
gboolean use_trampolines_page;
gboolean no_instances;
gboolean gnu_asm;
+ gboolean llvm;
int nthreads;
int ntrampolines;
int nrgctx_trampolines;
char *mtriple;
char *llvm_path;
char *instances_logfile_path;
+ char *logfile;
} MonoAotOptions;
typedef struct MonoAotStats {
MonoAotStats stats;
int method_index;
char *static_linking_symbol;
- CRITICAL_SECTION mutex;
+ mono_mutex_t mutex;
gboolean use_bin_writer;
gboolean gas_line_numbers;
MonoImageWriter *w;
int objc_selector_index, objc_selector_index_2;
GPtrArray *objc_selectors;
GHashTable *objc_selector_to_index;
+ FILE *logfile;
FILE *instances_logfile;
} MonoAotCompile;
gboolean jit_used, llvm_used;
} MonoPltEntry;
-#define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
-#define mono_acfg_unlock(acfg) LeaveCriticalSection (&((acfg)->mutex))
+#define mono_acfg_lock(acfg) mono_mutex_lock (&((acfg)->mutex))
+#define mono_acfg_unlock(acfg) mono_mutex_unlock (&((acfg)->mutex))
/* This points to the current acfg in LLVM mode */
static MonoAotCompile *llvm_acfg;
static char*
get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cache);
+static void
+aot_printf (MonoAotCompile *acfg, const gchar *format, ...)
+{
+ FILE *output;
+ va_list args;
+
+ if (acfg->logfile)
+ output = acfg->logfile;
+ else
+ output = stdout;
+
+ va_start (args, format);
+ vfprintf (output, format, args);
+ va_end (args);
+}
+
+static void
+aot_printerrf (MonoAotCompile *acfg, const gchar *format, ...)
+{
+ FILE *output;
+ va_list args;
+
+ if (acfg->logfile)
+ output = acfg->logfile;
+ else
+ output = stderr;
+
+ va_start (args, format);
+ vfprintf (output, format, args);
+ va_end (args);
+}
+
/* Wrappers around the image writer functions */
static inline void
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
if (!acfg->typespec_classes) {
acfg->typespec_classes = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoClass*) * len);
for (i = 0; i < len; ++i) {
- acfg->typespec_classes [i] = mono_class_get_full (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL);
+ MonoError error;
+ acfg->typespec_classes [i] = mono_class_get_and_inflate_typespec_checked (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME error handling */
}
}
for (i = 0; i < len; ++i) {
case MONO_WRAPPER_LDFLDA:
case MONO_WRAPPER_STFLD:
case MONO_WRAPPER_ISINST: {
- MonoClass *proxy_class = mono_marshal_get_wrapper_info (method);
- encode_klass_ref (acfg, proxy_class, p, &p);
+ WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+ g_assert (info);
+ encode_klass_ref (acfg, info->d.proxy.klass, p, &p);
break;
}
case MONO_WRAPPER_LDFLD_REMOTE:
method = mini_get_shared_method (method);
if (acfg->aot_opts.log_generics)
- printf ("%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
+ aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
add_method_full (acfg, method, TRUE, depth);
}
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
/* delegate-invoke wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+ MonoError error;
MonoClass *klass;
MonoCustomAttrInfo *cattr;
token = MONO_TOKEN_TYPE_DEF | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
/* array access wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
+ MonoError error;
MonoClass *klass;
token = MONO_TOKEN_TYPE_SPEC | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
/* StructureToPtr/PtrToStructure wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+ MonoError error;
MonoClass *klass;
token = MONO_TOKEN_TYPE_DEF | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
for (i = 0; i < inst->type_argc; ++i) {
MonoType *t = inst->type_argv [i];
- if (t->type == MONO_TYPE_VALUETYPE)
+ if (MONO_TYPE_ISSTRUCT (t) || t->type == MONO_TYPE_VALUETYPE)
return TRUE;
}
return FALSE;
return;
if (acfg->aot_opts.log_generics)
- printf ("%*sAdding generic instance %s [%s].\n", depth, "", mono_type_full_name (&klass->byval_arg), ref);
+ aot_printf (acfg, "%*sAdding generic instance %s [%s].\n", depth, "", mono_type_full_name (&klass->byval_arg), ref);
g_hash_table_insert (acfg->ginst_hash, klass, klass);
method = mono_marshal_get_delegate_invoke (method, NULL);
if (acfg->aot_opts.log_generics)
- printf ("%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
+ aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
add_method (acfg, method);
}
}
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
+ MonoError error;
MonoClass *klass;
token = MONO_TOKEN_TYPE_SPEC | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass || klass->rank) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
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);
} else {
encode_value (0, p, &p);
}
+ encode_value (patch_info->data.del_tramp->virtual, p, &p);
break;
case MONO_PATCH_INFO_FIELD:
case MONO_PATCH_INFO_SFLDA:
encoded = mono_unwind_ops_encode (cfg->unwind_ops, &encoded_len);
unwind_desc = get_unwind_info_offset (acfg, encoded, encoded_len);
- g_assert (unwind_desc < 0xffff);
- if (cfg->has_unwind_info_for_epilog) {
- /*
- * The lower 16 bits identify the unwind descriptor, the upper 16 bits contain the offset of
- * the start of the epilog from the end of the method.
- */
- g_assert (cfg->code_size - cfg->epilog_begin < 0xffff);
- encode_value (((cfg->code_size - cfg->epilog_begin) << 16) | unwind_desc, p, &p);
- g_free (encoded);
- } else {
- encode_value (unwind_desc, p, &p);
- }
+ encode_value (unwind_desc, p, &p);
} else {
encode_value (jinfo->unwind_info, p, &p);
}
eh_info = mono_jit_info_get_arch_eh_info (jinfo);
encode_value (eh_info->stack_size, p, &p);
+ encode_value (eh_info->epilog_size, p, &p);
}
if (jinfo->has_generic_jit_info) {
static guint32
emit_klass_info (MonoAotCompile *acfg, guint32 token)
{
- MonoClass *klass = mono_class_get (acfg->image, token);
+ MonoError error;
+ MonoClass *klass = mono_class_get_checked (acfg->image, token, &error);
guint8 *p, *buf;
int i, buf_size, res;
gboolean no_special_static, cant_encode;
gpointer iter = NULL;
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
buf_size = 16;
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;
opts->instances_logfile_path = g_strdup (arg + strlen ("log-instances="));
} else if (str_begins_with (arg, "log-instances")) {
opts->log_instances = TRUE;
+ } else if (str_begins_with (arg, "internal-logfile=")) {
+ opts->logfile = g_strdup (arg + strlen ("internal-logfile="));
} else if (str_begins_with (arg, "mtriple=")) {
opts->mtriple = g_strdup (arg + strlen ("mtriple="));
} else if (str_begins_with (arg, "llvm-path=")) {
opts->llvm_path = g_strdup (arg + strlen ("llvm-path="));
+ } else if (!strcmp (arg, "llvm")) {
+ opts->llvm = TRUE;
} else if (str_begins_with (arg, "readonly-value=")) {
add_readonly_value (opts, arg + strlen ("readonly-value="));
} else if (str_begins_with (arg, "info")) {
{
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);
gboolean skip;
int index, depth;
MonoMethod *wrapped;
+ JitFlags flags;
if (acfg->aot_opts.metadata_only)
return;
* the runtime will not see AOT methods during AOT compilation,so it
* does not need to support them by creating a fake GOT etc.
*/
- cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), acfg->aot_opts.full_aot ? (JIT_FLAG_AOT|JIT_FLAG_FULL_AOT) : (JIT_FLAG_AOT), 0);
+ flags = JIT_FLAG_AOT;
+ if (acfg->aot_opts.full_aot)
+ flags |= JIT_FLAG_FULL_AOT;
+ if (acfg->llvm)
+ flags |= JIT_FLAG_LLVM;
+ cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0);
mono_loader_clear_error ();
if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
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)
{
* Emit the LLVM code into an LLVM bytecode file, and compile it using the LLVM
* tools.
*/
-static void
+static gboolean
emit_llvm_file (MonoAotCompile *acfg)
{
char *command, *opts, *tempbc;
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);
/*
opts = g_strdup ("-targetlibinfo -no-aa -basicaa -notti -instcombine -simplifycfg -sroa -domtree -early-cse -lazy-value-info -correlated-propagation -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop-idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt -sccp -instcombine -lazy-value-info -correlated-propagation -domtree -memdep -adce -simplifycfg -instcombine -strip-dead-prototypes -domtree -verify");
#if 1
command = g_strdup_printf ("%sopt -f %s -o \"%s.opt.bc\" \"%s.bc\"", acfg->aot_opts.llvm_path, opts, acfg->tmpbasename, acfg->tmpbasename);
- printf ("Executing opt: %s\n", command);
- if (system (command) != 0) {
- exit (1);
- }
+ aot_printf (acfg, "Executing opt: %s\n", command);
+ if (system (command) != 0)
+ return FALSE;
#endif
g_free (opts);
command = g_strdup_printf ("%sllc %s -disable-gnu-eh-frame -enable-mono-eh-frame -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname, acfg->tmpbasename);
- printf ("Executing llc: %s\n", command);
+ aot_printf (acfg, "Executing llc: %s\n", command);
- if (system (command) != 0) {
- exit (1);
- }
+ if (system (command) != 0)
+ return FALSE;
+ return TRUE;
}
#endif
for (i = 0; i < table_size; ++i)
g_ptr_array_add (table, NULL);
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+ MonoError error;
token = MONO_TOKEN_TYPE_DEF | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
#endif
}
-static void
+static gboolean
collect_methods (MonoAotCompile *acfg)
{
int mindex, i;
method = mono_get_method (acfg->image, token, NULL);
if (!method) {
- printf ("Failed to load method 0x%x from '%s'.\n", token, image->name);
- printf ("Run with MONO_LOG_LEVEL=debug for more information.\n");
- exit (1);
+ aot_printerrf (acfg, "Failed to load method 0x%x from '%s'.\n", token, image->name);
+ aot_printerrf (acfg, "Run with MONO_LOG_LEVEL=debug for more information.\n");
+ return FALSE;
}
/* Load all methods eagerly to skip the slower lazy loading code */
if (acfg->aot_opts.full_aot)
add_wrappers (acfg);
+ return TRUE;
}
static void
#endif
if (acfg->aot_opts.asm_only) {
- printf ("Output file: '%s'.\n", acfg->tmpfname);
+ aot_printf (acfg, "Output file: '%s'.\n", acfg->tmpfname);
if (acfg->aot_opts.static_link)
- printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol);
+ aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol);
return 0;
}
objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
}
command = g_strdup_printf ("%s%s %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", objfile, acfg->tmpfname);
- printf ("Executing the native assembler: %s\n", command);
+ aot_printf (acfg, "Executing the native assembler: %s\n", command);
if (system (command) != 0) {
g_free (command);
g_free (objfile);
g_free (command);
if (acfg->aot_opts.static_link) {
- printf ("Output file: '%s'.\n", objfile);
- printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol);
+ aot_printf (acfg, "Output file: '%s'.\n", objfile);
+ aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol);
g_free (objfile);
return 0;
}
#else
command = g_strdup_printf ("%sld %s -shared -o %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
#endif
- printf ("Executing the native linker: %s\n", command);
+ aot_printf (acfg, "Executing the native linker: %s\n", command);
if (system (command) != 0) {
g_free (tmp_outfile_name);
g_free (outfile_name);
* happens a lot in emit_and_reloc_code (), so we need to get rid of them.
*/
command = g_strdup_printf ("%sstrip --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
- printf ("Stripping the binary: %s\n", command);
+ aot_printf (acfg, "Stripping the binary: %s\n", command);
if (system (command) != 0) {
g_free (tmp_outfile_name);
g_free (outfile_name);
#if defined(TARGET_MACH)
command = g_strdup_printf ("dsymutil %s", outfile_name);
- printf ("Executing dsymutil: %s\n", command);
+ aot_printf (acfg, "Executing dsymutil: %s\n", command);
if (system (command) != 0) {
return 1;
}
g_free (objfile);
if (acfg->aot_opts.save_temps)
- printf ("Retained input file.\n");
+ aot_printf (acfg, "Retained input file.\n");
else
unlink (acfg->tmpfname);
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 ();
acfg->klass_blob_hash = g_hash_table_new (NULL, NULL);
acfg->method_blob_hash = g_hash_table_new (NULL, NULL);
acfg->plt_entry_debug_sym_cache = g_hash_table_new (g_str_hash, g_str_equal);
- InitializeCriticalSection (&acfg->mutex);
+ mono_mutex_init_recursive (&acfg->mutex);
return acfg;
}
TV_DECLARE (atv);
TV_DECLARE (btv);
-#if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED) || !defined(ENABLE_GSHAREDVT)
- if (opts & MONO_OPT_GSHAREDVT) {
- fprintf (stderr, "-O=gsharedvt not supported on this platform.\n");
- exit (1);
- }
-#endif
-
- printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
-
acfg = acfg_create (ass, opts);
memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts));
mono_aot_parse_options (aot_options, &acfg->aot_opts);
+ if (acfg->aot_opts.logfile) {
+ acfg->logfile = fopen (acfg->aot_opts.logfile, "a+");
+ }
+
if (acfg->aot_opts.static_link)
acfg->aot_opts.autoreg = TRUE;
//acfg->aot_opts.print_skipped_methods = TRUE;
+#if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED) || !defined(ENABLE_GSHAREDVT)
+ if (opts & MONO_OPT_GSHAREDVT) {
+ aot_printerrf (acfg, "-O=gsharedvt not supported on this platform.\n");
+ return 1;
+ }
+#endif
+
+ aot_printf (acfg, "Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
+
#ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
if (acfg->aot_opts.full_aot) {
- printf ("--aot=full is not supported on this platform.\n");
+ aot_printerrf (acfg, "--aot=full is not supported on this platform.\n");
return 1;
}
#endif
if (acfg->aot_opts.direct_pinvoke && !acfg->aot_opts.static_link) {
- fprintf (stderr, "The 'direct-pinvoke' AOT option also requires the 'static' AOT option.\n");
- exit (1);
+ aot_printerrf (acfg, "The 'direct-pinvoke' AOT option also requires the 'static' AOT option.\n");
+ return 1;
}
if (acfg->aot_opts.static_link)
opt->gen_seq_points = TRUE;
if (!mono_debug_enabled ()) {
- fprintf (stderr, "The soft-debug AOT option requires the --debug option.\n");
+ aot_printerrf (acfg, "The soft-debug AOT option requires the --debug option.\n");
return 1;
}
acfg->flags |= MONO_AOT_FILE_FLAG_DEBUG;
}
- if (mono_use_llvm) {
+ if (mono_use_llvm || acfg->aot_opts.llvm) {
acfg->llvm = TRUE;
acfg->aot_opts.asm_writer = TRUE;
acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
if (acfg->aot_opts.soft_debug) {
- fprintf (stderr, "The 'soft-debug' option is not supported when compiling with LLVM.\n");
- exit (1);
+ 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)
if (acfg->aot_opts.instances_logfile_path) {
acfg->instances_logfile = fopen (acfg->aot_opts.instances_logfile_path, "w");
if (!acfg->instances_logfile) {
- fprintf (stderr, "Unable to create logfile: '%s'.\n", acfg->aot_opts.instances_logfile_path);
- exit (1);
+ aot_printerrf (acfg, "Unable to create logfile: '%s'.\n", acfg->aot_opts.instances_logfile_path);
+ return 1;
}
}
mono_set_partial_sharing_supported (TRUE);
*/
- collect_methods (acfg);
+ res = collect_methods (acfg);
+ if (!res)
+ return 1;
acfg->cfgs_size = acfg->methods->len + 32;
acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size);
#ifdef ENABLE_LLVM
if (acfg->llvm) {
+ gboolean res;
+
if (acfg->aot_opts.asm_only) {
if (acfg->aot_opts.outfile) {
acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
}
- emit_llvm_file (acfg);
+ res = emit_llvm_file (acfg);
+ if (!res)
+ return 1;
}
#endif
acfg->fp = fopen (tmp_outfile_name, "w");
if (!acfg->fp) {
- printf ("Unable to create temporary file '%s': %s\n", tmp_outfile_name, strerror (errno));
+ aot_printf (acfg, "Unable to create temporary file '%s': %s\n", tmp_outfile_name, strerror (errno));
return 1;
}
}
}
if (acfg->fp == 0) {
- fprintf (stderr, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));
+ aot_printerrf (acfg, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));
return 1;
}
acfg->w = img_writer_create (acfg->fp, FALSE);
if (!acfg->aot_opts.nodebug || acfg->aot_opts.dwarf_debug) {
if (acfg->aot_opts.dwarf_debug && !mono_debug_enabled ()) {
- fprintf (stderr, "The dwarf AOT option requires the --debug option.\n");
+ aot_printerrf (acfg, "The dwarf AOT option requires the --debug option.\n");
return 1;
}
acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE, !acfg->gas_line_numbers);
all_sizes = acfg->stats.code_size + acfg->stats.info_size + acfg->stats.ex_info_size + acfg->stats.unwind_info_size + acfg->stats.class_info_size + acfg->stats.got_info_size + acfg->stats.offsets_size + acfg->stats.plt_size;
- printf ("Code: %d(%d%%) Info: %d(%d%%) Ex Info: %d(%d%%) Unwind Info: %d(%d%%) Class Info: %d(%d%%) PLT: %d(%d%%) GOT Info: %d(%d%%) Offsets: %d(%d%%) GOT: %d\n",
+ aot_printf (acfg, "Code: %d(%d%%) Info: %d(%d%%) Ex Info: %d(%d%%) Unwind Info: %d(%d%%) Class Info: %d(%d%%) PLT: %d(%d%%) GOT Info: %d(%d%%) Offsets: %d(%d%%) GOT: %d\n",
acfg->stats.code_size, acfg->stats.code_size * 100 / all_sizes,
acfg->stats.info_size, acfg->stats.info_size * 100 / all_sizes,
acfg->stats.ex_info_size, acfg->stats.ex_info_size * 100 / all_sizes,
acfg->stats.got_info_size, acfg->stats.got_info_size * 100 / all_sizes,
acfg->stats.offsets_size, acfg->stats.offsets_size * 100 / all_sizes,
(int)(acfg->got_offset * sizeof (gpointer)));
- printf ("Compiled: %d/%d (%d%%)%s, No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n",
+ aot_printf (acfg, "Compiled: %d/%d (%d%%)%s, No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n",
acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100,
llvm_stats_msg,
acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100,
acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
if (acfg->stats.genericcount)
- printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
+ aot_printf (acfg, "%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
if (acfg->stats.abscount)
- printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
+ aot_printf (acfg, "%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
if (acfg->stats.lmfcount)
- printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
+ aot_printf (acfg, "%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
if (acfg->stats.ocount)
- printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
+ aot_printf (acfg, "%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
TV_GETTIME (atv);
res = img_writer_emit_writeout (acfg->w);
int err = rename (tmp_outfile_name, outfile_name);
if (err) {
- printf ("Unable to rename '%s' to '%s': %s\n", tmp_outfile_name, outfile_name, strerror (errno));
+ aot_printf (acfg, "Unable to rename '%s' to '%s': %s\n", tmp_outfile_name, outfile_name, strerror (errno));
return 1;
}
} else {
if (acfg->aot_opts.stats) {
int i;
- printf ("GOT slot distribution:\n");
+ aot_printf (acfg, "GOT slot distribution:\n");
for (i = 0; i < MONO_PATCH_INFO_NONE; ++i)
if (acfg->stats.got_slot_types [i])
- printf ("\t%s: %d (%d)\n", get_patch_name (i), acfg->stats.got_slot_types [i], acfg->stats.got_slot_info_sizes [i]);
+ aot_printf (acfg, "\t%s: %d (%d)\n", get_patch_name (i), acfg->stats.got_slot_types [i], acfg->stats.got_slot_info_sizes [i]);
}
- printf ("JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
+ aot_printf (acfg, "JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
acfg_free (acfg);