gboolean write_symbols;
gboolean metadata_only;
gboolean bind_to_runtime_version;
- gboolean full_aot;
+ MonoAotMode mode;
gboolean no_dlsym;
gboolean static_link;
gboolean asm_only;
gboolean autoreg;
char *mtriple;
char *llvm_path;
+ char *temp_path;
char *instances_logfile_path;
char *logfile;
gboolean dump_json;
case MONO_PATCH_INFO_ICALL_ADDR:
case MONO_PATCH_INFO_CLASS_INIT:
case MONO_PATCH_INFO_RGCTX_FETCH:
- case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
case MONO_PATCH_INFO_MONITOR_ENTER:
case MONO_PATCH_INFO_MONITOR_ENTER_V4:
case MONO_PATCH_INFO_MONITOR_EXIT:
g_ptr_array_add (acfg->extra_methods, method);
}
+static gboolean
+prefer_gsharedvt_method (MonoAotCompile *acfg, MonoMethod *method)
+{
+ /* One instantiation with valuetypes is generated for each async method */
+ if (method->klass->image == mono_defaults.corlib && (!strcmp (method->klass->name, "AsyncMethodBuilderCore") || !strcmp (method->klass->name, "AsyncVoidMethodBuilder")))
+ return TRUE;
+ else
+ return FALSE;
+}
+
static guint32
get_method_index (MonoAotCompile *acfg, MonoMethod *method)
{
{
if (mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE))
method = mini_get_shared_method (method);
+ else if ((acfg->opts & MONO_OPT_GSHAREDVT) && prefer_gsharedvt_method (acfg, method) && mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE))
+ /* Use the gsharedvt version */
+ return;
if (acfg->aot_opts.log_generics)
aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
/* Managed Allocators */
nallocators = mono_gc_get_managed_allocator_types ();
for (i = 0; i < nallocators; ++i) {
- m = mono_gc_get_managed_allocator_by_type (i);
+ m = mono_gc_get_managed_allocator_by_type (i, TRUE);
+ if (m)
+ add_method (acfg, m);
+ }
+ for (i = 0; i < nallocators; ++i) {
+ m = mono_gc_get_managed_allocator_by_type (i, FALSE);
if (m)
add_method (acfg, m);
}
for (j = 0; j < cattr->num_attrs; ++j)
if (cattr->attrs [j].ctor && (!strcmp (cattr->attrs [j].ctor->klass->name, "MonoNativeFunctionWrapperAttribute") || !strcmp (cattr->attrs [j].ctor->klass->name, "UnmanagedFunctionPointerAttribute")))
break;
- if (j < cattr->num_attrs)
- add_method (acfg, mono_marshal_get_native_func_wrapper_aot (klass));
+ if (j < cattr->num_attrs) {
+ MonoMethod *invoke;
+ MonoMethod *wrapper;
+ MonoMethod *del_invoke;
+
+ /* Add wrappers needed by mono_ftnptr_to_delegate () */
+ invoke = mono_get_delegate_invoke (klass);
+ wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
+ del_invoke = mono_marshal_get_delegate_invoke_internal (invoke, FALSE, TRUE, wrapper);
+ add_method (acfg, wrapper);
+ add_method (acfg, del_invoke);
+ }
}
} else if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->generic_container) {
MonoError error;
return FALSE;
}
+static
+gboolean mono_aot_mode_is_full (MonoAotOptions *opts)
+{
+ return opts->mode == MONO_AOT_MODE_FULL;
+}
+
static void add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, const char *ref);
static void
add_generic_class (MonoAotCompile *acfg, MonoClass *klass, gboolean force, const char *ref)
{
/* This might lead to a huge code blowup so only do it if neccesary */
- if (!acfg->aot_opts.full_aot && !force)
+ if (!mono_aot_mode_is_full (&acfg->aot_opts) && !force)
return;
add_generic_class_with_depth (acfg, klass, 0, ref);
memcpy (name2, prefix, strlen (prefix));
j = strlen (prefix);
for (i = 0; i < len; ++i) {
- if (isalnum (name1 [i])) {
+ if (i == 0 && name1 [0] >= '0' && name1 [0] <= '9') {
+ name2 [j ++] = '_';
+ } else if (isalnum (name1 [i])) {
name2 [j ++] = name1 [i];
} else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
i += 2;
encode_patch (acfg, entry->data, p, &p);
break;
}
- case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
case MONO_PATCH_INFO_MONITOR_ENTER:
case MONO_PATCH_INFO_MONITOR_ENTER_V4:
case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
debug_sym = g_strdup_printf ("%s_jit_icall_native_%s", prefix, ji->data.name);
break;
- case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
- debug_sym = g_strdup_printf ("%s_generic_class_init", prefix);
- break;
default:
break;
}
int tramp_type;
#endif
- if (!acfg->aot_opts.full_aot)
+ if (!mono_aot_mode_is_full (&acfg->aot_opts))
return;
g_assert (acfg->image->assembly);
emit_trampoline (acfg, acfg->got_offset, info);
#endif
- mono_arch_create_generic_class_init_trampoline (&info, TRUE);
- emit_trampoline (acfg, acfg->got_offset, info);
-
/* Emit the exception related code pieces */
mono_arch_get_restore_context (&info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
readonly_values = rdv;
}
+static gchar *
+clean_path (gchar * path)
+{
+ if (!path)
+ return NULL;
+
+ if (g_str_has_suffix (path, G_DIR_SEPARATOR_S))
+ return path;
+
+ gchar *clean = g_strconcat (path, G_DIR_SEPARATOR_S, NULL);
+ g_free (path);
+
+ return clean;
+}
+
static void
mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
{
opts->outfile = g_strdup (arg + strlen ("outfile="));
} else if (str_begins_with (arg, "llvm-outfile=")) {
opts->llvm_outfile = g_strdup (arg + strlen ("llvm-outfile="));
+ } else if (str_begins_with (arg, "temp-path=")) {
+ opts->temp_path = clean_path (g_strdup (arg + strlen ("temp-path=")));
} else if (str_begins_with (arg, "save-temps")) {
opts->save_temps = TRUE;
} else if (str_begins_with (arg, "keep-temps")) {
} else if (str_begins_with (arg, "bind-to-runtime-version")) {
opts->bind_to_runtime_version = TRUE;
} else if (str_begins_with (arg, "full")) {
- opts->full_aot = TRUE;
+ opts->mode = MONO_AOT_MODE_FULL;
+ } else if (str_begins_with (arg, "hybrid")) {
+ opts->mode = MONO_AOT_MODE_HYBRID;
} else if (str_begins_with (arg, "threads=")) {
opts->nthreads = atoi (arg + strlen ("threads="));
} else if (str_begins_with (arg, "static")) {
} 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="));
- if (!g_str_has_suffix (opts->llvm_path, G_DIR_SEPARATOR_S)) {
- gchar *old = opts->llvm_path;
- opts->llvm_path = g_strconcat (opts->llvm_path, G_DIR_SEPARATOR_S, NULL);
- g_free (old);
- }
+ opts->llvm_path = clean_path (g_strdup (arg + strlen ("llvm-path=")));
} else if (!strcmp (arg, "llvm")) {
opts->llvm = TRUE;
} else if (str_begins_with (arg, "readonly-value=")) {
printf ("Supported options for --aot:\n");
printf (" outfile=\n");
printf (" llvm-outfile=\n");
+ printf (" llvm-path=\n");
+ printf (" temp-path=\n");
printf (" save-temps\n");
printf (" keep-temps\n");
printf (" write-symbols\n");
* does not need to support them by creating a fake GOT etc.
*/
flags = JIT_FLAG_AOT;
- if (acfg->aot_opts.full_aot)
+ if (mono_aot_mode_is_full (&acfg->aot_opts))
flags |= JIT_FLAG_FULL_AOT;
if (acfg->llvm)
flags |= JIT_FLAG_LLVM;
mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) &&
!method_has_type_vars (m)) {
if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
- if (acfg->aot_opts.full_aot)
+ if (mono_aot_mode_is_full (&acfg->aot_opts))
add_extra_method_with_depth (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE), depth + 1);
} else {
add_extra_method_with_depth (acfg, m, depth + 1);
method = cfg->orig_method;
/* Emit unbox trampoline */
- if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+ if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
sprintf (symbol, "ut_%d", get_method_index (acfg, method));
emit_section_change (acfg, ".text", 0);
method = cfg->orig_method;
- if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+ if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
index = get_method_index (acfg, method);
emit_int32 (acfg, index);
method = cfg->orig_method;
- if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+ if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
#ifdef MONO_ARCH_AOT_SUPPORTED
int call_size;
emit_pointer (acfg, NULL);
emit_pointer (acfg, NULL);
}
- if (acfg->thumb_mixed) {
- emit_pointer (acfg, "thumb_end");
- } else {
- emit_pointer (acfg, NULL);
- }
if (acfg->aot_opts.static_link) {
emit_pointer (acfg, "globals");
} else {
/* Load all methods eagerly to skip the slower lazy loading code */
mono_class_setup_methods (method->klass);
- if (acfg->aot_opts.full_aot && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+ if (mono_aot_mode_is_full (&acfg->aot_opts) && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
/* Compile the wrapper instead */
/* We do this here instead of add_wrappers () because it is easy to do it here */
MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc, TRUE);
add_generic_instances (acfg);
- if (acfg->aot_opts.full_aot)
+ if (mono_aot_mode_is_full (&acfg->aot_opts))
add_wrappers (acfg);
return TRUE;
}
#define LD_NAME "gcc -shared --dll"
#elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
#define LD_NAME "clang -m32 -dynamiclib"
-#elif defined(TARGET_ARM)
+#elif defined(TARGET_ARM) && !defined(TARGET_ANDROID)
#define LD_NAME "gcc --shared"
#endif
* gas generates 'mapping symbols' each time code and data is mixed, which
* 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);
+ command = g_strdup_printf ("\"%sstrip\" --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
aot_printf (acfg, "Stripping the binary: %s\n", command);
if (execute_system (command) != 0) {
g_free (tmp_outfile_name);
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) {
+ if (mono_aot_mode_is_full (&acfg->aot_opts)) {
aot_printerrf (acfg, "--aot=full is not supported on this platform.\n");
return 1;
}
* Emit all LLVM code into a separate assembly/object file and link with it
* normally.
*/
- if (!acfg->aot_opts.asm_only)
+ if (!acfg->aot_opts.asm_only) {
acfg->llvm_owriter = TRUE;
+ } else if (acfg->aot_opts.llvm_outfile) {
+ int len = strlen (acfg->aot_opts.llvm_outfile);
+
+ if (len >= 2 && acfg->aot_opts.llvm_outfile [len - 2] == '.' && acfg->aot_opts.llvm_outfile [len - 1] == 'o')
+ acfg->llvm_owriter = TRUE;
+ }
}
- if (acfg->aot_opts.full_aot)
+ if (mono_aot_mode_is_full (&acfg->aot_opts))
acfg->flags |= MONO_AOT_FILE_FLAG_FULL_AOT;
if (acfg->aot_opts.instances_logfile_path) {
load_profile_files (acfg);
- acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0;
+ acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ntrampolines : 0;
#ifdef MONO_ARCH_GSHARED_SUPPORTED
- acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? acfg->aot_opts.nrgctx_trampolines : 0;
+ acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.nrgctx_trampolines : 0;
#endif
- acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
+ acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.nimt_trampolines : 0;
#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
if (acfg->opts & MONO_OPT_GSHAREDVT)
- acfg->num_trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = acfg->aot_opts.full_aot ? acfg->aot_opts.ngsharedvt_arg_trampolines : 0;
+ acfg->num_trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ngsharedvt_arg_trampolines : 0;
#endif
acfg->temp_prefix = mono_img_writer_get_temp_label_prefix (NULL);
arch_init (acfg);
+ if (acfg->llvm && acfg->thumb_mixed)
+ acfg->flags |= MONO_AOT_FILE_FLAG_LLVM_THUMB;
+
acfg->assembly_name_sym = g_strdup (acfg->image->assembly->aname.name);
/* Get rid of characters which cannot occur in symbols */
for (p = acfg->assembly_name_sym; *p; ++p) {
acfg->method_index = 1;
- if (acfg->aot_opts.full_aot)
+ if (mono_aot_mode_is_full (&acfg->aot_opts))
mono_set_partial_sharing_supported (TRUE);
res = collect_methods (acfg);
}
g_assert (acfg->aot_opts.llvm_outfile);
acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
+ if (acfg->llvm_owriter)
+ acfg->llvm_ofile = g_strdup (acfg->aot_opts.llvm_outfile);
+ else
+ acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
} else {
acfg->tmpbasename = g_strdup_printf ("%s", "temp");
acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
if (acfg->dwarf)
mono_dwarf_writer_emit_base_info (acfg->dwarf, g_path_get_basename (acfg->image->name), mono_unwind_get_cie_program ());
- if (acfg->thumb_mixed) {
- char symbol [256];
- /*
- * This global symbol marks the end of THUMB code, and the beginning of ARM
- * code generated by our JIT.
- */
- sprintf (symbol, "thumb_end");
- emit_section_change (acfg, ".text", 0);
- emit_alignment_code (acfg, 8);
- emit_label (acfg, symbol);
- emit_zero_bytes (acfg, 16);
-
- fprintf (acfg->fp, ".arm\n");
- }
-
emit_code (acfg);
emit_info (acfg);