#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/assembly.h>
+#include <mono/metadata/marshal.h>
#include <mono/os/gc_wrapper.h>
#include "mini.h"
static CRITICAL_SECTION aot_mutex;
+static guint32 mono_aot_verbose = 0;
+
+/*
+ * Disabling this will make a copy of the loaded code and use the copy instead
+ * of the original. This will place the caller and the callee close to each
+ * other in memory, possibly improving cache behavior. Since the original
+ * code is in copy-on-write memory, this will not increase the memory usage
+ * of the runtime.
+ */
+static gboolean use_loaded_code = FALSE;
+
+/* For debugging */
+static gint32 mono_last_aot_method = -1;
+
static MonoClass *
decode_class_info (MonoAotModule *module, gpointer *data)
{
char *aot_version = NULL;
char *opt_flags = NULL;
- if (mono_no_aot)
- return;
-
aot_name = g_strdup_printf ("%s.so", assembly->image->name);
assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
- printf ("AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
+ if (mono_aot_verbose > 0)
+ printf ("AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
usable = FALSE;
}
else
if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
- printf ("AOT module %s is out of date.\n", aot_name);
+ if (mono_aot_verbose > 0)
+ printf ("AOT module %s is out of date.\n", aot_name);
usable = FALSE;
}
for (i = 0; i < table_len; ++i) {
info->image_table [i] = mono_image_loaded_by_guid (table);
if (!info->image_table [i]) {
- printf ("AOT module %s is out of date.\n", aot_name);
- g_free (info->methods);
+ if (mono_aot_verbose > 0)
+ printf ("AOT module %s is out of date.\n", aot_name);
+ mono_g_hash_table_destroy (info->methods);
g_free (info->image_table);
+#ifndef HAVE_BOEHM_GC
g_free (info);
+#endif
g_free (aot_name);
g_module_close (assembly->aot_module);
assembly->aot_module = NULL;
mono_g_hash_table_insert (aot_modules, assembly, info);
LeaveCriticalSection (&aot_mutex);
- printf ("Loaded AOT Module for %s.\n", assembly->image->name);
+ if (mono_aot_verbose > 0)
+ printf ("Loaded AOT Module for %s.\n", assembly->image->name);
}
void
aot_modules = mono_g_hash_table_new (NULL, NULL);
mono_install_assembly_load_hook (load_aot_module, NULL);
+
+ if (getenv ("MONO_LASTAOT"))
+ mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
}
static MonoJitInfo *
MonoAssembly *ass = klass->image->assembly;
MonoJumpInfo *patch_info = NULL;
GModule *module = ass->aot_module;
- char *method_label, *info_label;
+ char method_label [256];
+ char info_label [256];
guint8 *code = NULL;
gpointer *info;
guint code_len, used_int_regs, used_strings;
if (!method->token)
return NULL;
+ if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
+ return NULL;
+
+ if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+ (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
+ (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
+ return NULL;
+
aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass);
g_assert (klass->inited);
code = mono_mempool_alloc (domain->code_mp, minfo->info->code_size);
memcpy (code, minfo->info->code_start, minfo->info->code_size);
- //printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + code_len);
+ if (mono_aot_verbose > 1)
+ printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + minfo->info->code_size);
/* Do this outside the lock to avoid deadlocks */
LeaveCriticalSection (&aot_mutex);
- mono_arch_patch_code (method, domain, code, minfo->patch_info);
+ mono_arch_patch_code (method, domain, code, minfo->patch_info, TRUE);
EnterCriticalSection (&aot_mutex);
/* Relocate jinfo */
guint32 w;
w = aot_module->methods_present_table [index / 32];
if (! (w & (1 << (index % 32)))) {
- //printf ("NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
+ if (mono_aot_verbose > 1)
+ printf ("NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
return NULL;
}
}
- method_label = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
-
- if (!g_module_symbol (module, method_label, (gpointer *)&code)) {
- g_free (method_label);
+ sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
+ if (!g_module_symbol (module, method_label, (gpointer *)&code))
return NULL;
- }
- info_label = g_strdup_printf ("%s_p", method_label);
- if (!g_module_symbol (module, info_label, (gpointer *)&info)) {
- g_free (method_label);
- g_free (info_label);
+ sprintf (info_label, "%s_p", method_label);
+ if (!g_module_symbol (module, info_label, (gpointer *)&info))
return NULL;
- }
- {
- static int count = 0;
-
- count ++;
-
- if (getenv ("MONO_LASTAOT")) {
- if (count > atoi(getenv ("MONO_LASTAOT"))) {
+ if (mono_last_aot_method != -1) {
+ if (mono_jit_stats.methods_aot > mono_last_aot_method)
return NULL;
- }
- else
- if (count == atoi(getenv ("MONO_LASTAOT")))
- printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
- }
+ else
+ if (mono_jit_stats.methods_aot == mono_last_aot_method)
+ printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
}
#ifdef HAVE_BOEHM_GC
used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
info++;
- //printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
+ if (!use_loaded_code) {
+ guint8 *code2;
+ code2 = mono_mempool_alloc (domain->code_mp, code_len);
+ memcpy (code2, code, code_len);
+ code = code2;
+ }
+
+ if (mono_aot_verbose > 1)
+ printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
/* Exception table */
if (header->num_clauses) {
}
if (*info) {
- MonoMemPool *mp = mono_mempool_new ();
+ MonoMemPool *mp;
MonoImage *image;
guint8 *page_start;
gpointer *table;
int pages;
int i, err;
- guint32 last_offset;
+ guint32 last_offset, buf_len;
+
+ if (aot_module->opts & MONO_OPT_SHARED)
+ mp = mono_mempool_new ();
+ else
+ mp = domain->mp;
last_offset = 0;
while (*info) {
MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
+ gpointer *data;
+
guint8 b1, b2;
b1 = *(guint8*)info;
last_offset = ji->ip.i;
//printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
- gpointer *data = *((gpointer **)info);
+ data = *((gpointer **)info);
switch (ji->type) {
case MONO_PATCH_INFO_CLASS:
+ case MONO_PATCH_INFO_IID:
ji->data.klass = decode_class_info (aot_module, data);
g_assert (ji->data.klass);
mono_class_init (ji->data.klass);
break;
case MONO_PATCH_INFO_VTABLE:
+ case MONO_PATCH_INFO_CLASS_INIT:
ji->data.klass = decode_class_info (aot_module, data);
g_assert (ji->data.klass);
mono_class_init (ji->data.klass);
break;
case MONO_PATCH_INFO_IMAGE:
- ji->data.image = aot_module->image_table [(guint32)data [0]];
+ ji->data.image = aot_module->image_table [(guint32)data];
g_assert (ji->data.image);
break;
case MONO_PATCH_INFO_METHOD:
- case MONO_PATCH_INFO_METHODCONST: {
+ case MONO_PATCH_INFO_METHODCONST:
+ case MONO_PATCH_INFO_METHOD_JUMP: {
guint32 image_index, token;
image_index = (guint32)data >> 24;
break;
}
+ case MONO_PATCH_INFO_WRAPPER: {
+ guint32 image_index, token;
+ guint32 wrapper_type;
+
+ wrapper_type = (guint32)data[0];
+ image_index = (guint32)data[1] >> 24;
+ token = MONO_TOKEN_METHOD_DEF | ((guint32)data[1] & 0xffffff);
+
+ image = aot_module->image_table [image_index];
+ ji->data.method = mono_get_method (image, token, NULL);
+ g_assert (ji->data.method);
+ mono_class_init (ji->data.method->klass);
+
+ g_assert (wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
+ ji->type = MONO_PATCH_INFO_METHOD;
+ ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
+ break;
+ }
case MONO_PATCH_INFO_FIELD:
- case MONO_PATCH_INFO_SFLDA:
- image = aot_module->image_table [(guint32)data [1]];
- g_assert (image);
- ji->data.field = mono_field_from_token (image, (guint32)data [0], NULL);
- mono_class_init (ji->data.field->parent);
- g_assert (ji->data.field);
+ case MONO_PATCH_INFO_SFLDA: {
+ MonoClass *klass = decode_class_info (aot_module, data [1]);
+ mono_class_init (klass);
+ ji->data.field = mono_class_get_field (klass, (guint32)data [0]);
break;
+ }
case MONO_PATCH_INFO_INTERNAL_METHOD:
ji->data.name = aot_module->icall_table [(guint32)data];
g_assert (ji->data.name);
case MONO_PATCH_INFO_LDSTR:
case MONO_PATCH_INFO_LDTOKEN:
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
- ji->data.target = *data;
+ image = aot_module->image_table [(int)data [0]];
+ ji->data.token = mono_jump_info_token_new (mp, image, (int)data [1]);
break;
case MONO_PATCH_INFO_EXC_NAME:
ji->data.klass = decode_class_info (aot_module, data);
patch_info = ji;
}
-#ifndef PLATFORM_WIN32
+ info = (gpointer)((guint8*)info + 4);
+ buf_len = *(guint32*)info;
+ info = (gpointer)((guint8*)info + 4);
+ mono_debug_add_aot_method (domain, method, code, (guint8*)info, buf_len);
+
+ if (use_loaded_code) {
/* disable write protection */
- page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
- pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
- err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
- g_assert (err == 0);
+#ifndef PLATFORM_WIN32
+ page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
+ pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
+ err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
+ g_assert (err == 0);
#else
- {
- DWORD oldp;
- g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
- }
+ {
+ DWORD oldp;
+ g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
+ }
#endif
+ }
/* Do this outside the lock to avoid deadlocks */
LeaveCriticalSection (&aot_mutex);
- mono_arch_patch_code (method, domain, code, patch_info);
+ mono_arch_patch_code (method, domain, code, patch_info, TRUE);
EnterCriticalSection (&aot_mutex);
if (aot_module->opts & MONO_OPT_SHARED)
- /* No need to cache this */
+ /* No need to cache patches */
mono_mempool_destroy (mp);
else
minfo->patch_info = patch_info;
}
- g_free (info_label);
- g_free (method_label);
-
mono_jit_stats.methods_aot++;
{
}
}
-gpointer
+MonoJitInfo*
mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
{
MonoJitInfo *info;
/* Do this outside the lock */
if (info) {
mono_jit_info_table_add (domain, info);
- return info->code_start;
+ return info;
}
else
return NULL;
cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info)
{
MonoClassField *field = patch_info->data.field;
- char *l1;
+ char *l1, *l2;
guint token;
if ((l1 = g_hash_table_lookup (cfg->ref_hash, field)))
return l1;
+ l2 = cond_emit_klass_label (cfg, field->parent);
fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer));
token = mono_get_field_token (field);
+ g_assert (token);
l1 = g_strdup_printf ("klass_p_%08x_%p", token, field);
fprintf (cfg->fp, "%s:\n", l1);
fprintf (cfg->fp, "\t.long 0x%08x\n", token);
- g_assert (token);
- emit_image_index (cfg, field->parent->image);
+ fprintf (cfg->fp, "\t.long %s\n", l2);
g_hash_table_insert (cfg->ref_hash, field, l1);
break;
}
case MONO_PATCH_INFO_METHODCONST:
- case MONO_PATCH_INFO_METHOD: {
+ case MONO_PATCH_INFO_METHOD:
+ case MONO_PATCH_INFO_METHOD_JUMP: {
/*
* The majority of patches are for methods, so we emit
* them inline instead of defining a label for them to
j++;
break;
}
+ case MONO_PATCH_INFO_WRAPPER: {
+ MonoMethod *m;
+ guint32 image_index;
+ guint32 token;
+
+ m = mono_marshal_method_from_wrapper (patch_info->data.method);
+ image_index = get_image_index (acfg, m->klass->image);
+ token = m->token;
+ g_assert (image_index < 256);
+ g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
+
+ fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
+ fprintf (tmpfp, "%s_p_%d:\n", mname, j);
+ fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
+ fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token)));
+ j++;
+ break;
+ }
case MONO_PATCH_INFO_FIELD:
patch_info->data.name = cond_emit_field_label (acfg, patch_info);
j++;
break;
case MONO_PATCH_INFO_CLASS:
+ case MONO_PATCH_INFO_IID:
patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
j++;
break;
j++;
break;
case MONO_PATCH_INFO_VTABLE:
+ case MONO_PATCH_INFO_CLASS_INIT:
patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
j++;
break;
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
fprintf (tmpfp, "\t.align 8\n");
fprintf (tmpfp, "%s_p_%d:\n", mname, j);
- fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token);
+ fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image));
+ fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token);
j++;
break;
default:
if (j) {
guint32 last_offset;
last_offset = 0;
+
j = 0;
for (pindex = 0; pindex < patches->len; ++pindex) {
guint32 offset;
switch (patch_info->type) {
case MONO_PATCH_INFO_METHODCONST:
case MONO_PATCH_INFO_METHOD:
+ case MONO_PATCH_INFO_METHOD_JUMP:
case MONO_PATCH_INFO_CLASS:
+ case MONO_PATCH_INFO_IID:
case MONO_PATCH_INFO_FIELD:
case MONO_PATCH_INFO_INTERNAL_METHOD:
case MONO_PATCH_INFO_IMAGE:
case MONO_PATCH_INFO_VTABLE:
+ case MONO_PATCH_INFO_CLASS_INIT:
case MONO_PATCH_INFO_SFLDA:
case MONO_PATCH_INFO_EXC_NAME:
fprintf (tmpfp, "\t.long %s\n", patch_info->data.name);
case MONO_PATCH_INFO_LDSTR:
case MONO_PATCH_INFO_LDTOKEN:
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+ case MONO_PATCH_INFO_WRAPPER:
fprintf (tmpfp, "\t.long %s_p_%d\n", mname, j);
j++;
break;
/* NULL terminated array */
fprintf (tmpfp, "\t.long 0\n");
+ {
+ guint8 *buf;
+ guint32 buf_len;
+
+ mono_debug_serialize_debug_info (cfg, &buf, &buf_len);
+
+ fprintf (tmpfp, "\t.long %d\n", buf_len);
+
+ for (i = 0; i < buf_len; ++i)
+ fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]);
+
+ if (buf_len > 0)
+ g_free (buf);
+ }
+
/* fixme: save the rest of the required infos */
g_free (mname);
char *com, *tmpfname, *opts_str;
FILE *tmpfp;
int i;
- guint8 *mname, *symbol;
+ guint8 *symbol;
int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
GHashTable *ref_hash;
MonoAotCompile *acfg;
gboolean *emitted;
- printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
+ printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
tmpfp = fdopen (i, "w+");
//printf ("START: %s\n", mono_method_full_name (method, TRUE));
//mono_compile_method (method);
- cfg = mini_method_compile (method, opts, mono_root_domain, 0);
+ cfg = mini_method_compile (method, opts, mono_root_domain, FALSE, 0);
g_assert (cfg);
if (cfg->disable_aot) {
+ printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
ocount++;
continue;
}
continue;
}
+ /* remoting-invoke-with-check wrappers are very common */
+ for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
+ if ((patch_info->type == MONO_PATCH_INFO_METHOD) &&
+ ((patch_info->data.method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
+ patch_info->type = MONO_PATCH_INFO_WRAPPER;
+ }
+
skip = FALSE;
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
patch_info->type == MONO_PATCH_INFO_METHODCONST) &&
patch_info->data.method->wrapper_type) {
/* unable to handle this */
- //printf ("Skip (wrapper call): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
+ //printf ("Skip (wrapper call): %s %d -> %s\n", mono_method_full_name (method, TRUE), patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
skip = TRUE;
break;
}
emitted [i] = TRUE;
emit_method (acfg, cfg);
- g_free (mname);
mono_destroy_compile (cfg);
ccount++;
system (com);
g_free (com);*/
- printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount);
- printf ("%d methods contain absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount);
- printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount);
- printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount);
- printf ("%d methods have other problems (%d%%)\n", ocount, (ocount*100)/mcount);
+ printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
+ printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
+ printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
+ printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
+ printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
unlink (tmpfname);
return 0;