#include <mono/utils/mono-mmap.h>
#include "mono/utils/mono-compiler.h"
#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-digest.h>
#include "mini.h"
+#include "seq-points.h"
#include "version.h"
#ifndef DISABLE_AOT
-#ifdef TARGET_WIN32
-#define SHARED_EXT ".dll"
-#elif ((defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__)) || defined(__MACH__)) && !defined(__linux__)
-#define SHARED_EXT ".dylib"
-#elif defined(__APPLE__) && defined(TARGET_X86) && !defined(__native_client_codegen__)
-#define SHARED_EXT ".dylib"
-#else
-#define SHARED_EXT ".so"
+#ifdef TARGET_OSX
+#define ENABLE_AOT_CACHE
#endif
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
/*
* Whenever to AOT compile loaded assemblies on demand and store them in
- * a cache under $HOME/.mono/aot-cache.
+ * a cache.
*/
-static gboolean use_aot_cache = FALSE;
+static gboolean enable_aot_cache = FALSE;
-/*
- * Whenever to spawn a new process to AOT a file or do it in-process. Only relevant if
- * use_aot_cache is TRUE.
- */
-static gboolean spawn_compiler = TRUE;
+static gboolean mscorlib_aot_loaded;
/* For debugging */
static gint32 mono_last_aot_method = -1;
assembly = mono_assembly_load (&amodule->image_names [index], amodule->assembly->basedir, &status);
if (!assembly) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is unusable because dependency %s is not found.\n", amodule->aot_name, amodule->image_names [index].name);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: module %s is unusable because dependency %s is not found.\n", amodule->aot_name, amodule->image_names [index].name);
amodule->out_of_date = TRUE;
if (set_error) {
}
if (strcmp (assembly->image->guid, amodule->image_guids [index])) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is unusable (GUID of dependent assembly %s doesn't match (expected '%s', got '%s').\n", amodule->aot_name, amodule->image_names [index].name, amodule->image_guids [index], assembly->image->guid);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: module %s is unusable (GUID of dependent assembly %s doesn't match (expected '%s', got '%s').\n", amodule->aot_name, amodule->image_names [index].name, amodule->image_guids [index], assembly->image->guid);
amodule->out_of_date = TRUE;
return NULL;
}
static MonoClass*
decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
{
+ MonoError error;
MonoImage *image;
MonoClass *klass = NULL, *eklass;
guint32 token, rank, idx;
image = load_image (module, 0, TRUE);
if (!image)
return NULL;
- klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + idx);
+ klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF + idx, &error);
+ g_assert (mono_error_ok (&error));
break;
case MONO_AOT_TYPEREF_TYPEDEF_INDEX_IMAGE:
idx = decode_value (p, &p);
image = load_image (module, decode_value (p, &p), TRUE);
if (!image)
return NULL;
- klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + idx);
+ klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF + idx, &error);
+ g_assert (mono_error_ok (&error));
break;
case MONO_AOT_TYPEREF_TYPESPEC_TOKEN:
token = decode_value (p, &p);
image = module->assembly->image;
if (!image)
return NULL;
- klass = mono_class_get (image, token);
+ klass = mono_class_get_checked (image, token, &error);
+ g_assert (mono_error_ok (&error));
break;
case MONO_AOT_TYPEREF_GINST: {
MonoClass *gclass;
return decode_resolve_method_ref_with_target (module, NULL, buf, endbuf);
}
+#ifdef ENABLE_AOT_CACHE
+
+/* AOT CACHE */
+
+/*
+ * FIXME:
+ * - Add options for controlling the cache size
+ * - Handle full cache by deleting old assemblies lru style
+ * - Maybe add a threshold after an assembly is AOT compiled
+ * - Add options for enabling this for specific main assemblies
+ */
+
+/* The cache directory */
+static char *cache_dir;
+
+/* The number of assemblies AOTed in this run */
+static int cache_count;
+
+/* Whenever to AOT in-process */
+static gboolean in_process;
+
static void
-create_cache_structure (void)
+collect_assemblies (gpointer data, gpointer user_data)
{
- const char *home;
- char *tmp;
- int err;
+ MonoAssembly *ass = data;
+ GSList **l = user_data;
- home = g_get_home_dir ();
- if (!home)
- return;
+ *l = g_slist_prepend (*l, ass);
+}
- tmp = g_build_filename (home, ".mono", NULL);
- if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
-#ifdef HOST_WIN32
- err = mkdir (tmp);
-#else
- err = mkdir (tmp, 0777);
-#endif
- if (err) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
- g_free (tmp);
- return;
- }
+#define SHA1_DIGEST_LENGTH 20
+
+/*
+ * get_aot_config_hash:
+ *
+ * Return a hash for all the version information an AOT module depends on.
+ */
+static G_GNUC_UNUSED char*
+get_aot_config_hash (MonoAssembly *assembly)
+{
+ char *build_info;
+ GSList *l, *assembly_list = NULL;
+ GString *s;
+ int i;
+ guint8 digest [SHA1_DIGEST_LENGTH];
+ char *digest_str;
+
+ build_info = mono_get_runtime_build_info ();
+
+ s = g_string_new (build_info);
+
+ mono_assembly_foreach (collect_assemblies, &assembly_list);
+
+ /*
+ * The assembly list includes the current assembly as well, no need
+ * to add it.
+ */
+ for (l = assembly_list; l; l = l->next) {
+ MonoAssembly *ass = l->data;
+
+ g_string_append (s, "_");
+ g_string_append (s, ass->aname.name);
+ g_string_append (s, "_");
+ g_string_append (s, ass->image->guid);
}
- g_free (tmp);
- tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
- if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
-#ifdef HOST_WIN32
- err = mkdir (tmp);
-#else
- err = mkdir (tmp, 0777);
-#endif
- if (err) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
- g_free (tmp);
- return;
- }
+
+ for (i = 0; i < s->len; ++i) {
+ if (!isalnum (s->str [i]) && s->str [i] != '-')
+ s->str [i] = '_';
}
- g_free (tmp);
+
+ mono_sha1_get_digest ((guint8*)s->str, s->len, digest);
+
+ digest_str = g_malloc0 ((SHA1_DIGEST_LENGTH * 2) + 1);
+ for (i = 0; i < SHA1_DIGEST_LENGTH; ++i)
+ sprintf (digest_str + (i * 2), "%02x", digest [i]);
+
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: file dependencies: %s, hash %s", s->str, digest_str);
+
+ g_string_free (s, TRUE);
+
+ return digest_str;
+}
+
+static void
+aot_cache_init (void)
+{
+ if (mono_aot_only)
+ return;
+ enable_aot_cache = TRUE;
+ in_process = TRUE;
}
/*
- * load_aot_module_from_cache:
- *
- * Experimental code to AOT compile loaded assemblies on demand.
+ * aot_cache_load_module:
*
- * FIXME:
- * - Add environment variable MONO_AOT_CACHE_OPTIONS
- * - Add options for controlling the cache size
- * - Handle full cache by deleting old assemblies lru style
- * - Add options for excluding assemblies during development
- * - Maybe add a threshold after an assembly is AOT compiled
- * - invoking a new mono process is a security risk
- * - recompile the AOT module if one of its dependencies changes
+ * Load the AOT image corresponding to ASSEMBLY from the aot cache, AOTing it if neccessary.
*/
static MonoDl*
-load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
+aot_cache_load_module (MonoAssembly *assembly, char **aot_name)
{
- char *fname, *cmd, *tmp2, *aot_options;
+ MonoAotCacheConfig *config;
+ GSList *l;
+ char *fname, *tmp2, *aot_options, *failure_fname;
const char *home;
MonoDl *module;
gboolean res;
- gchar *out, *err;
gint exit_status;
+ char *hash;
+ int pid;
+ gboolean enabled;
+ FILE *failure_file;
*aot_name = NULL;
if (image_is_dynamic (assembly->image))
return NULL;
- create_cache_structure ();
+ /* Check in the list of assemblies enabled for aot caching */
+ config = mono_get_aot_cache_config ();
+
+ enabled = FALSE;
+ if (config->apps) {
+ MonoDomain *domain = mono_domain_get ();
+ MonoAssembly *entry_assembly = domain->entry_assembly;
- home = g_get_home_dir ();
+ // FIXME: This cannot be used for mscorlib during startup, since entry_assembly is not set yet
+ for (l = config->apps; l; l = l->next) {
+ char *n = l->data;
- tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
- fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
+ if ((entry_assembly && !strcmp (entry_assembly->aname.name, n)) || (!entry_assembly && !strcmp (assembly->aname.name, n)))
+ break;
+ }
+ if (l)
+ enabled = TRUE;
+ }
+
+ if (!enabled) {
+ for (l = config->assemblies; l; l = l->next) {
+ char *n = l->data;
+
+ if (!strcmp (assembly->aname.name, n))
+ break;
+ }
+ if (l)
+ enabled = TRUE;
+ }
+ if (!enabled)
+ return NULL;
+
+ if (!cache_dir) {
+ home = g_get_home_dir ();
+ if (!home)
+ return NULL;
+ cache_dir = g_strdup_printf ("%s/Library/Caches/mono/aot-cache", home);
+ if (!g_file_test (cache_dir, G_FILE_TEST_EXISTS|G_FILE_TEST_IS_DIR))
+ g_mkdir_with_parents (cache_dir, 0777);
+ }
+
+ /*
+ * The same assembly can be used in multiple configurations, i.e. multiple
+ * versions of the runtime, with multiple versions of dependent assemblies etc.
+ * To handle this, we compute a version string containing all this information, hash it,
+ * and use the hash as a filename suffix.
+ */
+ hash = get_aot_config_hash (assembly);
+
+ tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, hash, MONO_SOLIB_EXT);
+ fname = g_build_filename (cache_dir, tmp2, NULL);
*aot_name = fname;
g_free (tmp2);
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: loading from cache: '%s'.", fname);
module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
- if (!module) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
+ if (module) {
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: found in cache: '%s'.", fname);
+ return module;
+ }
- mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
+ if (!strcmp (assembly->aname.name, "mscorlib") && !mscorlib_aot_loaded)
+ /*
+ * Can't AOT this during startup, so we AOT it when called later from
+ * mono_aot_get_method ().
+ */
+ return NULL;
- aot_options = g_strdup_printf ("outfile=%s", fname);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: not found.");
- if (spawn_compiler) {
- /* FIXME: security */
- /* FIXME: Has to pass the assembly loading path to the child process */
- cmd = g_strdup_printf ("mono -O=all --aot=%s %s", aot_options, assembly->image->name);
+ /* Only AOT one assembly per run to avoid slowing down execution too much */
+ if (cache_count > 0)
+ return NULL;
+ cache_count ++;
+
+ /* Check for previous failure */
+ failure_fname = g_strdup_printf ("%s.failure", fname);
+ failure_file = fopen (failure_fname, "r");
+ if (failure_file) {
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: assembly '%s' previously failed to compile '%s' ('%s')... ", assembly->image->name, fname, failure_fname);
+ g_free (failure_fname);
+ return NULL;
+ } else {
+ g_free (failure_fname);
+ fclose (failure_file);
+ }
- res = g_spawn_command_line_sync (cmd, &out, &err, &exit_status, NULL);
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compiling assembly '%s', logfile: '%s.log'... ", assembly->image->name, fname);
-#if !defined(HOST_WIN32) && !defined(__ppc__) && !defined(__ppc64__) && !defined(__powerpc__)
- if (res) {
- if (!WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) == 0))
- mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed: %s.", err);
- else
- mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
- g_free (out);
- g_free (err);
- }
-#endif
- g_free (cmd);
+ /*
+ * We need to invoke the AOT compiler here. There are multiple approaches:
+ * - spawn a new runtime process. This can be hard when running with mkbundle, and
+ * its hard to make the new process load the same set of assemblies.
+ * - doing it in-process. This exposes the current process to bugs/leaks/side effects of
+ * the AOT compiler.
+ * - fork a new process and do the work there.
+ */
+ if (in_process) {
+ aot_options = g_strdup_printf ("outfile=%s,internal-logfile=%s.log%s%s", fname, fname, config->aot_options ? "," : "", config->aot_options ? config->aot_options : "");
+ /* Maybe due this in another thread ? */
+ res = mono_compile_assembly (assembly, mono_parse_default_optimizations (NULL), aot_options);
+ if (res) {
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compilation failed.");
+ failure_fname = g_strdup_printf ("%s.failure", fname);
+ failure_file = fopen (failure_fname, "a+");
+ fclose (failure_file);
+ g_free (failure_fname);
} else {
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compilation succeeded.");
+ }
+ } else {
+ /*
+ * - Avoid waiting for the aot process to finish ?
+ * (less overhead, but multiple processes could aot the same assembly at the same time)
+ */
+ pid = fork ();
+ if (pid == 0) {
+ FILE *logfile;
+ char *logfile_name;
+
+ /* Child */
+
+ logfile_name = g_strdup_printf ("%s/aot.log", cache_dir);
+ logfile = fopen (logfile_name, "a+");
+ g_free (logfile_name);
+
+ dup2 (fileno (logfile), 1);
+ dup2 (fileno (logfile), 2);
+
+ aot_options = g_strdup_printf ("outfile=%s", fname);
res = mono_compile_assembly (assembly, mono_parse_default_optimizations (NULL), aot_options);
if (!res) {
- mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
+ exit (1);
} else {
- mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
+ exit (0);
}
+ } else {
+ /* Parent */
+ waitpid (pid, &exit_status, 0);
+ if (!WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) == 0))
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: failed.");
+ else
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: succeeded.");
}
-
- module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
-
- g_free (aot_options);
}
+ module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
+
return module;
}
+#else
+
+static void
+aot_cache_init (void)
+{
+}
+
+static MonoDl*
+aot_cache_load_module (MonoAssembly *assembly, char **aot_name)
+{
+ return NULL;
+}
+
+#endif
+
static void
find_symbol (MonoDl *module, gpointer *globals, const char *name, gpointer *value)
{
info = NULL;
mono_aot_unlock ();
+ sofile = NULL;
+
if (info) {
/* Statically linked AOT module */
- sofile = NULL;
aot_name = g_strdup_printf ("%s", assembly->aname.name);
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "Found statically linked AOT module '%s'.\n", aot_name);
globals = info->globals;
} else {
- if (use_aot_cache)
- sofile = load_aot_module_from_cache (assembly, &aot_name);
- else {
+ if (enable_aot_cache)
+ sofile = aot_cache_load_module (assembly, &aot_name);
+ if (!sofile) {
char *err;
- aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
+ aot_name = g_strdup_printf ("%s%s", assembly->image->name, MONO_SOLIB_EXT);
sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
if (!sofile) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err);
g_free (err);
+
+ aot_name = g_strdup_printf ("%s/mono/aot-cache/%s/%s%s", mono_assembly_getrootdir(), ARCHITECTURE, g_path_get_basename (assembly->image->name), MONO_SOLIB_EXT);
+ sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
+ if (!sofile) {
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err);
+ g_free (err);
+ }
+
}
}
}
fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode: %s.\n", aot_name, msg);
exit (1);
} else {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is unusable: %s.\n", aot_name, msg);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: module %s is unusable: %s.\n", aot_name, msg);
}
g_free (msg);
g_free (aot_name);
}
if (amodule->out_of_date) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Module %s is unusable because a dependency is out-of-date.\n", assembly->image->name);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: Module %s is unusable because a dependency is out-of-date.\n", assembly->image->name);
if (mono_aot_only) {
fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode because a dependency cannot be found or it is out of date.\n", aot_name);
exit (1);
}
}
else
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: loaded AOT Module for %s.\n", assembly->image->name);
}
/*
if (g_getenv ("MONO_LASTAOT"))
mono_last_aot_method = atoi (g_getenv ("MONO_LASTAOT"));
- if (g_getenv ("MONO_AOT_CACHE"))
- use_aot_cache = TRUE;
+ aot_cache_init ();
}
void
name_space2 = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
if (!strcmp (name, name2) && !strcmp (name_space, name_space2)) {
+ MonoError error;
amodule_unlock (amodule);
- *klass = mono_class_get (image, token);
+ *klass = mono_class_get_checked (image, token, &error);
+ if (!mono_error_ok (&error))
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
/* Add to cache */
if (*klass) {
decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
MonoMethod *method, guint8 *code,
MonoJitExceptionInfo *clauses, int num_clauses,
- int extra_size, GSList **nesting,
+ MonoJitInfoFlags flags,
+ GSList **nesting,
int *this_reg, int *this_offset)
{
guint8 *p;
* allocate a new JI.
*/
jinfo =
- mono_domain_alloc0_lock_free (domain, MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * (ei_len + nested_len)) + extra_size);
+ mono_domain_alloc0_lock_free (domain, mono_jit_info_size (flags, ei_len + nested_len, 0));
+ mono_jit_info_init (jinfo, method, code, code_len, flags, ei_len + nested_len, 0);
- jinfo->code_size = code_len;
jinfo->unwind_info = mono_cache_unwind_info (info.unw_info, info.unw_info_len);
- jinfo->d.method = method;
- jinfo->code_start = code;
- jinfo->domain_neutral = 0;
/* This signals that unwind_info points to a normal cached unwind info */
jinfo->from_aot = 0;
- jinfo->num_clauses = ei_len + nested_len;
+ jinfo->from_llvm = 1;
for (i = 0; i < ei_len; ++i) {
/*
- * orig_jinfo contains the original IL exception info saved by the AOT
+ * clauses contains the original IL exception info saved by the AOT
* compiler, we have to combine that with the information produced by LLVM
*/
/* The type_info entries contain IL clause indexes */
{
int i, buf_len, num_clauses, len;
MonoJitInfo *jinfo;
- guint unwind_info, flags;
+ MonoJitInfoFlags flags = JIT_INFO_NONE;
+ guint unwind_info, eflags;
gboolean has_generic_jit_info, has_dwarf_unwind_info, has_clauses, has_seq_points, has_try_block_holes, has_arch_eh_jit_info;
gboolean from_llvm, has_gc_map;
guint8 *p;
async = mono_thread_info_is_async_context ();
p = ex_info;
- flags = decode_value (p, &p);
- has_generic_jit_info = (flags & 1) != 0;
- has_dwarf_unwind_info = (flags & 2) != 0;
- has_clauses = (flags & 4) != 0;
- has_seq_points = (flags & 8) != 0;
- from_llvm = (flags & 16) != 0;
- has_try_block_holes = (flags & 32) != 0;
- has_gc_map = (flags & 64) != 0;
- has_arch_eh_jit_info = (flags & 128) != 0;
+ eflags = decode_value (p, &p);
+ has_generic_jit_info = (eflags & 1) != 0;
+ has_dwarf_unwind_info = (eflags & 2) != 0;
+ has_clauses = (eflags & 4) != 0;
+ has_seq_points = (eflags & 8) != 0;
+ from_llvm = (eflags & 16) != 0;
+ has_try_block_holes = (eflags & 32) != 0;
+ has_gc_map = (eflags & 64) != 0;
+ has_arch_eh_jit_info = (eflags & 128) != 0;
if (has_dwarf_unwind_info) {
unwind_info = decode_value (p, &p);
} else {
unwind_info = decode_value (p, &p);
}
- if (has_generic_jit_info)
+ if (has_generic_jit_info) {
+ flags |= JIT_INFO_HAS_GENERIC_JIT_INFO;
generic_info_size = sizeof (MonoGenericJitInfo);
- else
+ } else {
generic_info_size = 0;
+ }
if (has_try_block_holes) {
num_holes = decode_value (p, &p);
+ flags |= JIT_INFO_HAS_TRY_BLOCK_HOLES;
try_holes_info_size = sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
} else {
num_holes = try_holes_info_size = 0;
}
+
+ if (has_arch_eh_jit_info) {
+ flags |= JIT_INFO_HAS_ARCH_EH_INFO;
+ arch_eh_jit_info_size = sizeof (MonoArchEHJitInfo);
+ /* Overwrite the original code_len which includes alignment padding */
+ code_len = decode_value (p, &p);
+ } else {
+ arch_eh_jit_info_size = 0;
+ }
+
/* Exception table */
if (has_clauses)
num_clauses = decode_value (p, &p);
else
num_clauses = 0;
- if (has_arch_eh_jit_info)
- arch_eh_jit_info_size = sizeof (MonoArchEHJitInfo);
- else
- arch_eh_jit_info_size = 0;
if (from_llvm) {
MonoJitExceptionInfo *clauses;
}
}
- jinfo = decode_llvm_mono_eh_frame (amodule, domain, method, code, clauses, num_clauses, generic_info_size + try_holes_info_size + arch_eh_jit_info_size, nesting, &this_reg, &this_offset);
- jinfo->from_llvm = 1;
+ jinfo = decode_llvm_mono_eh_frame (amodule, domain, method, code, clauses, num_clauses, flags, nesting, &this_reg, &this_offset);
g_free (clauses);
for (i = 0; i < num_clauses; ++i)
g_slist_free (nesting [i]);
g_free (nesting);
} else {
- len = MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * num_clauses) + generic_info_size + try_holes_info_size + arch_eh_jit_info_size;
+ len = mono_jit_info_size (flags, num_clauses, num_holes);
jinfo = alloc0_jit_info_data (domain, len, async);
- jinfo->num_clauses = num_clauses;
+ mono_jit_info_init (jinfo, method, code, code_len, flags, num_clauses, num_holes);
for (i = 0; i < jinfo->num_clauses; ++i) {
MonoJitExceptionInfo *ei = &jinfo->clauses [i];
ei->handler_start = code + decode_value (p, &p);
}
- jinfo->code_size = code_len;
jinfo->unwind_info = unwind_info;
- jinfo->d.method = method;
- jinfo->code_start = code;
jinfo->domain_neutral = 0;
jinfo->from_aot = 1;
}
- /*
- * Set all the 'has' flags, the mono_jit_info_get () functions depends on this to
- * compute the addresses of data blocks.
- */
- if (has_generic_jit_info)
- jinfo->has_generic_jit_info = 1;
- if (has_arch_eh_jit_info)
- jinfo->has_arch_eh_info = 1;
- if (has_try_block_holes)
- jinfo->has_try_block_holes = 1;
-
if (has_try_block_holes) {
MonoTryBlockHoleTableJitInfo *table;
eh_info = mono_jit_info_get_arch_eh_info (jinfo);
eh_info->stack_size = decode_value (p, &p);
+ eh_info->epilog_size = decode_value (p, &p);
}
if (async) {
if (method && has_seq_points) {
MonoSeqPointInfo *seq_points;
- int il_offset, native_offset, last_il_offset, last_native_offset, j;
- int len = decode_value (p, &p);
-
- seq_points = g_malloc0 (sizeof (MonoSeqPointInfo) + (len - MONO_ZERO_LEN_ARRAY) * sizeof (SeqPoint));
- seq_points->len = len;
- last_il_offset = last_native_offset = 0;
- for (i = 0; i < len; ++i) {
- SeqPoint *sp = &seq_points->seq_points [i];
- il_offset = last_il_offset + decode_value (p, &p);
- native_offset = last_native_offset + decode_value (p, &p);
-
- sp->il_offset = il_offset;
- sp->native_offset = native_offset;
-
- sp->flags = decode_value (p, &p);
- sp->next_len = decode_value (p, &p);
- sp->next = g_new (int, sp->next_len);
- for (j = 0; j < sp->next_len; ++j)
- sp->next [j] = decode_value (p, &p);
-
- last_il_offset = il_offset;
- last_native_offset = native_offset;
- }
+ p += seq_point_info_read (&seq_points, p, FALSE);
mono_domain_lock (domain);
g_hash_table_insert (domain_jit_info (domain)->seq_points, method, seq_points);
mono_aot_unlock ();
}
- /* The upper 16 bits of ji->unwind_info might contain the epilog offset */
- p = amodule->unwind_info + (ji->unwind_info & 0xffff);
+ p = amodule->unwind_info + ji->unwind_info;
*unwind_info_len = decode_value (p, &p);
return p;
}
case MONO_PATCH_INFO_MONITOR_ENTER:
case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
- case MONO_PATCH_INFO_CASTCLASS_CACHE:
case MONO_PATCH_INFO_JIT_TLS_ID:
break;
+ case MONO_PATCH_INFO_CASTCLASS_CACHE:
+ ji->data.index = decode_value (p, &p);
+ break;
case MONO_PATCH_INFO_RGCTX_FETCH: {
gboolean res;
MonoJumpInfoRgctxEntry *entry;
got_offset = decode_value (p, &p);
- if (aot_module->got [got_offset]) {
- /* Already loaded */
- //printf ("HIT!\n");
- } else {
- shared_p = aot_module->blob + mono_aot_get_offset (aot_module->got_info_offsets, got_offset);
+ shared_p = aot_module->blob + mono_aot_get_offset (aot_module->got_info_offsets, got_offset);
- ji->type = decode_value (shared_p, &shared_p);
+ ji->type = decode_value (shared_p, &shared_p);
+ /* See load_method () for SFLDA */
+ if (aot_module->got [got_offset] && ji->type != MONO_PATCH_INFO_SFLDA) {
+ /* Already loaded */
+ } else {
res = decode_patch (aot_module, mp, ji, shared_p, &shared_p);
if (!res)
goto cleanup;
MonoJitInfo *jinfo = NULL;
guint8 *code, *info;
- if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
+ if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) {
+ if (mono_aot_only)
+ /* The caller cannot handle this */
+ g_assert_not_reached ();
return NULL;
+ }
if ((domain != mono_get_root_domain ()) && (!(amodule->info.opts & MONO_OPT_SHARED)))
/* Non shared AOT code can't be used in other appdomains */
if (!method)
method = mono_get_method (image, token, NULL);
full_name = mono_method_full_name (method, TRUE);
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.", full_name);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name);
g_free (full_name);
}
return NULL;
for (pindex = 0; pindex < n_patches; ++pindex) {
MonoJumpInfo *ji = &patches [pindex];
+ gpointer addr;
- if (!amodule->got [got_slots [pindex]]) {
- amodule->got [got_slots [pindex]] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
+ /*
+ * For SFLDA, we need to call resolve_patch_target () since the GOT slot could have
+ * been initialized by load_method () for a static cctor before the cctor has
+ * finished executing (#23242).
+ */
+ if (!amodule->got [got_slots [pindex]] || ji->type == MONO_PATCH_INFO_SFLDA) {
+ addr = mono_resolve_patch_target (method, domain, code, ji, TRUE);
if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
- amodule->got [got_slots [pindex]] = mono_create_ftnptr (domain, amodule->got [got_slots [pindex]]);
+ addr = mono_create_ftnptr (domain, addr);
+ mono_memory_barrier ();
+ amodule->got [got_slots [pindex]] = addr;
if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
register_jump_target_got_slot (domain, ji->data.method, &(amodule->got [got_slots [pindex]]));
}
if (!jinfo)
jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code);
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND method %s [%p - %p %p]", full_name, code, code + jinfo->code_size, info);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: FOUND method %s [%p - %p %p]", full_name, code, code + jinfo->code_size, info);
g_free (full_name);
}
MonoAotModule *amodule = klass->image->aot_module;
guint8 *code;
+ if (enable_aot_cache && !amodule && domain->entry_assembly && klass->image == mono_defaults.corlib) {
+ /* This cannot be AOTed during startup, so do it now */
+ if (!mscorlib_aot_loaded) {
+ mscorlib_aot_loaded = TRUE;
+ load_aot_module (klass->image->assembly, NULL);
+ amodule = klass->image->aot_module;
+ }
+ }
+
if (!amodule)
return NULL;
if (!code)
g_error ("Symbol '%s' not found in AOT file '%s'.\n", name, amodule->aot_name);
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND function '%s' in AOT file '%s'.", name, amodule->aot_name);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: FOUND function '%s' in AOT file '%s'.", name, amodule->aot_name);
/* Load info */
#include <mach/mach.h>
static TrampolinePage* trampoline_pages [MONO_AOT_TRAMP_NUM];
-/* these sizes are for ARM code, parametrize if porting to other architectures (see arch_emit_specific_trampoline_pages)
- * trampoline size is assumed to be 8 bytes below as well (8 is the minimum for 32 bit archs, since we need to store
- * two pointers for trampoline in the data page).
- * the minimum for the common code must be at least sizeof(TrampolinePage), since we store the page info at the
- * beginning of the data page.
- */
-static const int trampolines_pages_code_offsets [MONO_AOT_TRAMP_NUM] = {16, 16, 72, 16};
static unsigned char*
get_new_trampoline_from_page (int tramp_type)
page = (TrampolinePage*)addr;
page->next = trampoline_pages [tramp_type];
trampoline_pages [tramp_type] = page;
-#ifdef TARGET_ARM64
page->trampolines = (void*)(taddr + amodule->info.tramp_page_code_offsets [tramp_type]);
-#else
- page->trampolines = (void*)(taddr + trampolines_pages_code_offsets [tramp_type]);
-#endif
page->trampolines_end = (void*)(taddr + psize - 64);
code = page->trampolines;
page->trampolines += specific_trampoline_size;
make_unreadable = unreadable;
if (make_unreadable && !inited) {
- mono_counters_register ("AOT pagefaults", MONO_COUNTER_JIT | MONO_COUNTER_INT, &n_pagefaults);
+ mono_counters_register ("AOT: pagefaults", MONO_COUNTER_JIT | MONO_COUNTER_INT, &n_pagefaults);
}
}