#include <windows.h>
#endif
+#include <errno.h>
+#include <sys/stat.h>
#include <limits.h> /* for PAGESIZE */
#ifndef PAGESIZE
#define PAGESIZE 4096
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/utils/mono-logger.h>
-#include <mono/os/gc_wrapper.h>
#include "mini.h"
+#ifndef DISABLE_AOT
+
#ifdef PLATFORM_WIN32
#define SHARED_EXT ".dll"
#elif defined(__ppc__) && defined(__MACH__)
#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
-typedef struct MonoAotMethod {
- MonoJitInfo *info;
- MonoJumpInfo *patch_info;
- MonoDomain *domain;
-} MonoAotMethod;
-
typedef struct MonoAotModule {
+ char *aot_name;
/* Optimization flags used to compile the module */
guint32 opts;
- /* Maps MonoMethods to MonoAotMethodInfos */
- MonoGHashTable *methods;
+ /* Pointer to the Global Offset Table */
+ gpointer *got;
+ guint32 got_size;
char **icall_table;
+ MonoAssemblyName *image_names;
+ char **image_guids;
MonoImage **image_table;
- guint32* methods_present_table;
+ gboolean out_of_date;
+ guint8 *code;
+ guint32 *code_offsets;
+ guint8 *method_infos;
+ guint32 *method_info_offsets;
+ guint8 *class_infos;
+ guint32 *class_info_offsets;
} MonoAotModule;
+typedef struct MonoAotOptions {
+ char *outfile;
+ gboolean save_temps;
+ gboolean write_symbols;
+} MonoAotOptions;
+
typedef struct MonoAotCompile {
+ MonoImage *image;
FILE *fp;
- GHashTable *ref_hash;
GHashTable *icall_hash;
GPtrArray *icall_table;
GHashTable *image_hash;
GPtrArray *image_table;
+ guint32 got_offset;
+ guint32 *method_got_offsets;
+ MonoAotOptions aot_opts;
} MonoAotCompile;
-static MonoGHashTable *aot_modules;
+static GHashTable *aot_modules;
static CRITICAL_SECTION aot_mutex;
* code is in copy-on-write memory, this will not increase the memory usage
* of the runtime.
*/
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+static gboolean use_loaded_code = TRUE;
+#else
static gboolean use_loaded_code = FALSE;
+#endif
+
+/*
+ * Whenever to AOT compile loaded assemblies on demand and store them in
+ * a cache under $HOME/.mono/aot-cache.
+ */
+static gboolean use_aot_cache = FALSE;
/* For debugging */
static gint32 mono_last_aot_method = -1;
static MonoJitInfo*
mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info);
-static MonoClass *
-decode_class_info (MonoAotModule *module, guint32 *data)
+static gboolean
+is_got_patch (MonoJumpInfoType patch_type)
+{
+#ifdef __x86_64__
+ return TRUE;
+#elif defined(__i386__)
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+/*****************************************************/
+/* AOT RUNTIME */
+/*****************************************************/
+
+static MonoImage *
+load_image (MonoAotModule *module, int index)
+{
+ MonoAssembly *assembly;
+ MonoImageOpenStatus status;
+
+ if (module->image_table [index])
+ return module->image_table [index];
+ if (module->out_of_date)
+ return NULL;
+
+ assembly = mono_assembly_load (&module->image_names [index], NULL, &status);
+ if (!assembly) {
+ module->out_of_date = TRUE;
+ return NULL;
+ }
+
+ if (strcmp (assembly->image->guid, module->image_guids [index])) {
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date (Older than dependency %s).\n", module->aot_name, module->image_names [index].name);
+ module->out_of_date = TRUE;
+ return NULL;
+ }
+
+ module->image_table [index] = assembly->image;
+ return assembly->image;
+}
+
+
+static inline gint32
+decode_value (char *_ptr, char **rptr)
+{
+ unsigned char *ptr = (unsigned char *) _ptr;
+ unsigned char b = *ptr;
+ gint32 len;
+
+ if ((b & 0x80) == 0){
+ len = b;
+ ++ptr;
+ } else if ((b & 0x40) == 0){
+ len = ((b & 0x3f) << 8 | ptr [1]);
+ ptr += 2;
+ } else if (b != 0xff) {
+ len = ((b & 0x1f) << 24) |
+ (ptr [1] << 16) |
+ (ptr [2] << 8) |
+ ptr [3];
+ ptr += 4;
+ }
+ else {
+ len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
+ ptr += 5;
+ }
+ if (rptr)
+ *rptr = ptr;
+
+ //printf ("DECODE: %d.\n", len);
+ return len;
+}
+
+static MonoClass*
+decode_klass_info (MonoAotModule *module, char *buf, char **endbuf)
{
MonoImage *image;
MonoClass *klass;
-
- image = module->image_table [data [1]];
- g_assert (image);
+ guint32 token, rank, image_index;
- if (data [0]) {
- return mono_class_get (image, data [0]);
+ image_index = decode_value (buf, &buf);
+ image = load_image (module, image_index);
+ if (!image)
+ return NULL;
+ token = decode_value (buf, &buf);
+ if (mono_metadata_token_code (token) == 0) {
+ klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token);
} else {
- /* the pointer is dword aligned */
- klass = decode_class_info (module, *(guint32**)(ALIGN_PTR_TO (&data[3], sizeof (gpointer))));
- return mono_array_class_get (klass, data [2]);
+ token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf);
+ rank = decode_value (buf, &buf);
+ klass = mono_class_get (image, token);
+ g_assert (klass);
+ klass = mono_array_class_get (klass, rank);
}
+ g_assert (klass);
+ mono_class_init (klass);
- return NULL;
+ *endbuf = buf;
+ return klass;
+}
+
+static MonoClassField*
+decode_field_info (MonoAotModule *module, char *buf, char **endbuf)
+{
+ MonoClass *klass = decode_klass_info (module, buf, &buf);
+ guint32 token;
+
+ if (!klass)
+ return NULL;
+
+ token = MONO_TOKEN_FIELD_DEF + decode_value (buf, &buf);
+
+ *endbuf = buf;
+
+ return mono_class_get_field (klass, token);
+}
+
+static inline MonoImage*
+decode_method_ref (MonoAotModule *module, guint32 *token, char *buf, char **endbuf)
+{
+ guint32 image_index, value;
+ MonoImage *image;
+
+ value = decode_value (buf, &buf);
+ *endbuf = buf;
+ image_index = value >> 24;
+ *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
+
+ image = load_image (module, image_index);
+ if (!image)
+ return NULL;
+ else
+ return image;
+}
+
+G_GNUC_UNUSED
+static void
+make_writable (guint8* addr, guint32 len)
+{
+#ifndef PLATFORM_WIN32
+ guint8 *page_start;
+ int pages, err;
+
+ page_start = (char *) (((gssize) (addr)) & ~ (PAGESIZE - 1));
+ pages = (addr + 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 (addr, len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
+ }
+#endif
+}
+
+static void
+create_cache_structure (void)
+{
+ const char *home;
+ char *tmp;
+ int err;
+
+ home = g_get_home_dir ();
+ if (!home)
+ return;
+
+ 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 PLATFORM_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;
+ }
+ }
+ 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 PLATFORM_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;
+ }
+ }
+ g_free (tmp);
+}
+
+/*
+ * load_aot_module_from_cache:
+ *
+ * Experimental code to AOT compile loaded assemblies on demand.
+ *
+ * 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
+ */
+static GModule*
+load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
+{
+ char *fname, *cmd, *tmp2;
+ const char *home;
+ GModule *module;
+ gboolean res;
+ gchar *out, *err;
+
+ *aot_name = NULL;
+
+ if (assembly->image->dynamic)
+ return NULL;
+
+ create_cache_structure ();
+
+ home = g_get_home_dir ();
+
+ 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);
+ *aot_name = fname;
+ g_free (tmp2);
+
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
+ module = g_module_open (fname, G_MODULE_BIND_LAZY);
+
+ if (!module) {
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
+
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
+
+ /* FIXME: security */
+ cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
+
+ res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
+ g_free (cmd);
+ if (!res) {
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
+ return NULL;
+ }
+
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
+
+ module = g_module_open (fname, G_MODULE_BIND_LAZY);
+ }
+
+ return module;
}
static void
char *aot_version = NULL;
char *opt_flags = NULL;
- aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ gpointer *got_addr = NULL;
+ gpointer *got = NULL;
+ guint32 *got_size_ptr = NULL;
+#endif
+
+ if (mono_compile_aot)
+ return;
+
+ if (use_aot_cache)
+ assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
+ else {
+ aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
+
+ assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
- assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
+ if (!assembly->aot_module) {
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
+ }
+ }
if (!assembly->aot_module) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Failed to load AOT module %s: %s\n", aot_name, g_module_error ());
g_free (aot_name);
return;
}
g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
usable = FALSE;
}
- else
+ else {
if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Module %s is out of date.\n", aot_name);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
usable = FALSE;
}
+ }
if (!usable) {
g_free (aot_name);
return;
}
- /*
- * It seems that MonoGHashTables are in the GC heap, so structures
- * containing them must be in the GC heap as well :(
- */
-#ifdef HAVE_BOEHM_GC
- info = GC_MALLOC (sizeof (MonoAotModule));
-#else
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
+ g_assert (got_addr);
+ got = (gpointer*)*got_addr;
+ g_assert (got);
+ g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
+ g_assert (got_size_ptr);
+#endif
+
info = g_new0 (MonoAotModule, 1);
+ info->aot_name = aot_name;
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ info->got = got;
+ info->got_size = *got_size_ptr;
#endif
- info->methods = mono_g_hash_table_new (NULL, NULL);
sscanf (opt_flags, "%d", &info->opts);
/* Read image table */
table_len = *(guint32*)table;
table += sizeof (guint32);
info->image_table = g_new0 (MonoImage*, table_len);
+ info->image_names = g_new0 (MonoAssemblyName, table_len);
+ info->image_guids = g_new0 (char*, table_len);
for (i = 0; i < table_len; ++i) {
- info->image_table [i] = mono_image_loaded_by_guid (table);
- if (!info->image_table [i]) {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "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;
- return;
- }
+ MonoAssemblyName *aname = &(info->image_names [i]);
+
+ aname->name = g_strdup (table);
+ table += strlen (table) + 1;
+ info->image_guids [i] = g_strdup (table);
table += strlen (table) + 1;
+ if (table [0] != 0)
+ aname->culture = g_strdup (table);
+ table += strlen (table) + 1;
+ memcpy (aname->public_key_token, table, strlen (table) + 1);
+ table += strlen (table) + 1;
+
+ table = ALIGN_PTR_TO (table, 8);
+ aname->flags = *(guint32*)table;
+ table += 4;
+ aname->major = *(guint32*)table;
+ table += 4;
+ aname->minor = *(guint32*)table;
+ table += 4;
+ aname->build = *(guint32*)table;
+ table += 4;
+ aname->revision = *(guint32*)table;
+ table += 4;
}
}
}
}
- /* Read methods present table */
- g_module_symbol (assembly->aot_module, "mono_methods_present_table", (gpointer *)&info->methods_present_table);
- g_assert (info->methods_present_table);
+ /* Read method and method_info tables */
+ g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
+ g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
+ g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
+ g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos);
+ g_module_symbol (assembly->aot_module, "class_infos", (gpointer*)&info->class_infos);
+ g_module_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets);
EnterCriticalSection (&aot_mutex);
- mono_g_hash_table_insert (aot_modules, assembly, info);
+ g_hash_table_insert (aot_modules, assembly, info);
LeaveCriticalSection (&aot_mutex);
- 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);
}
void
mono_aot_init (void)
{
InitializeCriticalSection (&aot_mutex);
-
- aot_modules = mono_g_hash_table_new (NULL, NULL);
+ aot_modules = 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"));
+ if (getenv ("MONO_AOT_CACHE"))
+ use_aot_cache = TRUE;
+}
+
+static gboolean
+decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, char *buf, char **endbuf)
+{
+ guint32 flags;
+
+ info->vtable_size = decode_value (buf, &buf);
+ flags = decode_value (buf, &buf);
+ info->ghcimpl = (flags >> 0) & 0x1;
+ info->has_finalize = (flags >> 1) & 0x1;
+ info->has_cctor = (flags >> 2) & 0x1;
+ if (info->has_cctor) {
+ MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, buf, &buf);
+ if (!cctor_image)
+ return FALSE;
+ }
+ if (info->has_finalize) {
+ info->finalize_image = decode_method_ref (module, &info->finalize_token, buf, &buf);
+ if (!info->finalize_image)
+ return FALSE;
+ }
+
+ *endbuf = buf;
+
+ return TRUE;
+}
+
+gboolean
+mono_aot_init_vtable (MonoVTable *vtable)
+{
+ int i;
+ MonoAotModule *aot_module;
+ MonoClass *klass = vtable->klass;
+ guint8 *info;
+ MonoCachedClassInfo class_info;
+ char *p;
+ gboolean err;
+
+ if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module)
+ return FALSE;
+
+ EnterCriticalSection (&aot_mutex);
+
+ aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
+ if (!aot_module) {
+ LeaveCriticalSection (&aot_mutex);
+ return FALSE;
+ }
+
+ info = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
+ p = (char*)info;
+
+ err = decode_cached_class_info (aot_module, &class_info, p, &p);
+ if (!err) {
+ LeaveCriticalSection (&aot_mutex);
+ return FALSE;
+ }
+
+ //printf ("VT0: %s.%s %d\n", klass->name_space, klass->name, vtable_size);
+ for (i = 0; i < class_info.vtable_size; ++i) {
+ guint32 image_index, token, value;
+ MonoImage *image;
+ MonoMethod *m;
+
+ vtable->vtable [i] = 0;
+
+ value = decode_value (p, &p);
+ if (!value)
+ continue;
+
+ image_index = value >> 24;
+ token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
+
+ image = load_image (aot_module, image_index);
+ if (!image) {
+ LeaveCriticalSection (&aot_mutex);
+ return FALSE;
+ }
+
+#ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
+ vtable->vtable [i] = mono_create_jit_trampoline_from_token (image, token);
+#else
+ m = mono_get_method (image, token, NULL);
+ g_assert (m);
+
+ //printf ("M: %d %p %s\n", i, &(vtable->vtable [i]), mono_method_full_name (m, TRUE));
+ vtable->vtable [i] = mono_create_jit_trampoline (m);
+#endif
+ }
+
+ LeaveCriticalSection (&aot_mutex);
+
+ return TRUE;
+}
+
+gboolean
+mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
+{
+ MonoAotModule *aot_module;
+ char *p;
+ gboolean err;
+
+ if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module)
+ return FALSE;
+
+ EnterCriticalSection (&aot_mutex);
+
+ aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
+ if (!aot_module) {
+ LeaveCriticalSection (&aot_mutex);
+ return FALSE;
+ }
+
+ p = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
+
+ err = decode_cached_class_info (aot_module, res, p, &p);
+ if (!err) {
+ LeaveCriticalSection (&aot_mutex);
+ return FALSE;
+ }
+
+ LeaveCriticalSection (&aot_mutex);
+
+ return TRUE;
}
static MonoJitInfo *
MonoClass *klass = method->klass;
MonoAssembly *ass = klass->image->assembly;
GModule *module = ass->aot_module;
- char method_label [256];
- char info_label [256];
guint8 *code = NULL;
guint8 *info;
MonoAotModule *aot_module;
- MonoAotMethod *minfo;
- MonoJitInfo *jinfo;
- MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
- int i;
if (!module)
return NULL;
(method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
(method->flags & METHOD_ATTRIBUTE_ABSTRACT))
return NULL;
-
- aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass);
+
+ aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
g_assert (klass->inited);
- minfo = mono_g_hash_table_lookup (aot_module->methods, method);
- /* Can't use code from non-root domains since they can be unloaded */
- if (minfo && (minfo->domain == mono_get_root_domain ())) {
- /* This method was already loaded in another appdomain */
-
- /* Duplicate jinfo */
- jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
- memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
- if (jinfo->clauses) {
- jinfo->clauses =
- mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
- memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
- }
-
- if (aot_module->opts & MONO_OPT_SHARED)
- /* Use the same method in the new appdomain */
- ;
- else if (!minfo->patch_info)
- /* Use the same method in the new appdomain */
- ;
- else {
- /* Create a copy of the original method and apply relocations */
-
- code = mono_code_manager_reserve (domain->code_mp, minfo->info->code_size);
- memcpy (code, minfo->info->code_start, minfo->info->code_size);
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT 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, TRUE);
- EnterCriticalSection (&aot_mutex);
- mono_arch_flush_icache (code, minfo->info->code_size);
-
- /* Relocate jinfo */
- jinfo->code_start = code;
- if (jinfo->clauses) {
- for (i = 0; i < header->num_clauses; ++i) {
- MonoJitExceptionInfo *ei = &jinfo->clauses [i];
- gint32 offset = code - (guint8*)minfo->info->code_start;
-
- if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
- ei->data.filter = (guint8*)ei->data.filter + offset;
- ei->try_start = (guint8*)ei->try_start + offset;
- ei->try_end = (guint8*)ei->try_end + offset;
- ei->handler_start = (guint8*)ei->handler_start + offset;
- }
- }
- }
+ if ((domain != mono_get_root_domain ()) && (!(aot_module->opts & MONO_OPT_SHARED)))
+ /* Non shared AOT code can't be used in other appdomains */
+ return NULL;
- return jinfo;
- }
+ if (aot_module->out_of_date)
+ return NULL;
- /* Do a fast check to see whenever the method exists */
- {
- guint32 index = mono_metadata_token_index (method->token) - 1;
- guint32 w;
- w = aot_module->methods_present_table [index / 32];
- if (! (w & (1 << (index % 32)))) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
- return NULL;
+ if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
+ if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
+ char *full_name = mono_method_full_name (method, TRUE);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
+ g_free (full_name);
}
- }
-
- sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
-
- if (!g_module_symbol (module, method_label, (gpointer *)&code))
return NULL;
+ }
- sprintf (info_label, "%s_p", method_label);
-
- if (!g_module_symbol (module, info_label, (gpointer *)&info))
- return NULL;
+ code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
+ info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
if (mono_last_aot_method != -1) {
if (mono_jit_stats.methods_aot > mono_last_aot_method)
MonoClass *klass = method->klass;
MonoJumpInfo *patch_info = NULL;
guint code_len, used_int_regs, used_strings;
- MonoAotMethod *minfo;
MonoJitInfo *jinfo;
- MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
+ MonoMemPool *mp;
GPtrArray *patches;
- int i, pindex;
-
-#ifdef HAVE_BOEHM_GC
- minfo = GC_MALLOC (sizeof (MonoAotMethod));
-#else
- minfo = g_new0 (MonoAotMethod, 1);
-#endif
-
- minfo->domain = domain;
- jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
+ int i, pindex, got_index;
+ gboolean non_got_patches, keep_patches = TRUE;
+ gboolean has_clauses;
+ char *p;
- code_len = *(guint32*)info;
- info += 4;
- used_int_regs = *(guint32*)info;
- info += 4;
+ p = (char*)info;
+ code_len = decode_value (p, &p);
+ used_int_regs = decode_value (p, &p);
if (!use_loaded_code) {
guint8 *code2;
code = code2;
}
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
+ if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
+ char *full_name = mono_method_full_name (method, TRUE);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name, code, code + code_len, info);
+ g_free (full_name);
+ }
/* Exception table */
- if (header->num_clauses) {
- jinfo->clauses =
- mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
+ has_clauses = decode_value (p, &p);
+ if (has_clauses) {
+ MonoMethodHeader *header = mono_method_get_header (method);
+ jinfo =
+ mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses));
jinfo->num_clauses = header->num_clauses;
- jinfo->exvar_offset = *(guint32*)info;
- info += 4;
-
for (i = 0; i < header->num_clauses; ++i) {
MonoExceptionClause *ec = &header->clauses [i];
MonoJitExceptionInfo *ei = &jinfo->clauses [i];
ei->flags = ec->flags;
+ ei->exvar_offset = decode_value (p, &p);
+
if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
- ei->data.filter = code + *(guint32*)info;
+ ei->data.filter = code + decode_value (p, &p);
else
- ei->data.token = *(guint32*)info;
- info += 4;
- ei->try_start = code + *(guint32*)info;
- info += 4;
- ei->try_end = code + *(guint32*)info;
- info += 4;
- ei->handler_start = code + *(guint32*)info;
- info += 4;
+ ei->data.catch_class = ec->data.catch_class;
+
+ ei->try_start = code + decode_value (p, &p);
+ ei->try_end = code + decode_value (p, &p);
+ ei->handler_start = code + decode_value (p, &p);
}
}
+ else
+ jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
- if (aot_module->opts & MONO_OPT_SHARED) {
- used_strings = *(guint32*)info;
- info += 4;
- }
+ if (aot_module->opts & MONO_OPT_SHARED)
+ used_strings = decode_value (p, &p);
else
used_strings = 0;
for (i = 0; i < used_strings; i++) {
- guint token = *(guint32*)info;
- info += 4;
+ guint token = decode_value (p, &p);
mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
}
- if (*info) {
- MonoMemPool *mp;
+ if (aot_module->opts & MONO_OPT_SHARED)
+ keep_patches = FALSE;
+
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ got_index = decode_value (p, &p);
+ keep_patches = FALSE;
+#endif
+
+ if (*p) {
MonoImage *image;
- guint8 *page_start;
gpointer *table;
- int pages;
- int i, err;
+ int i;
guint32 last_offset, buf_len;
- guint32 *data;
- if (aot_module->opts & MONO_OPT_SHARED)
- mp = mono_mempool_new ();
- else
+ if (keep_patches)
mp = domain->mp;
+ else
+ mp = mono_mempool_new ();
/* First load the type + offset table */
last_offset = 0;
patches = g_ptr_array_new ();
- while (*info) {
+ while (*p) {
MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
+#if defined(MONO_ARCH_HAVE_PIC_AOT)
+ ji->type = *p;
+ p ++;
+#else
guint8 b1, b2;
- b1 = *(guint8*)info;
- b2 = *((guint8*)info + 1);
-
- info += 2;
+ b1 = *(guint8*)p;
+ b2 = *((guint8*)p + 1);
+ p += 2;
ji->type = b1 >> 2;
- if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
- info = ALIGN_PTR_TO (info, 4);
- ji->ip.i = *(guint32*)info;
- info += 4;
- }
+ if (((b1 & (1 + 2)) == 3) && (b2 == 255))
+ ji->ip.i = decode_value (p, &p);
else
ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
ji->ip.i += last_offset;
last_offset = ji->ip.i;
+#endif
//printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
ji->next = patch_info;
g_ptr_array_add (patches, ji);
}
- info ++;
- info = ALIGN_PTR_TO (info, sizeof (gpointer));
+ /* Null terminated array */
+ p ++;
/* Then load the other data */
for (pindex = 0; pindex < patches->len; ++pindex) {
MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
-
- data = *((guint32 **)info);
- info += sizeof (gpointer);
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);
+ ji->data.klass = decode_klass_info (aot_module, p, &p);
+ if (!ji->data.klass)
+ goto cleanup;
break;
case MONO_PATCH_INFO_IMAGE:
- ji->data.image = aot_module->image_table [(guint32)data];
- g_assert (ji->data.image);
+ ji->data.image = load_image (aot_module, decode_value (p, &p));
+ if (!ji->data.image)
+ goto cleanup;
break;
case MONO_PATCH_INFO_METHOD:
case MONO_PATCH_INFO_METHODCONST:
case MONO_PATCH_INFO_METHOD_JUMP: {
- guint32 image_index, token;
+ guint32 image_index, token, value;
- image_index = (guint32)data >> 24;
- token = MONO_TOKEN_METHOD_DEF | ((guint32)data & 0xffffff);
+ value = decode_value (p, &p);
+ image_index = value >> 24;
+ token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
- image = aot_module->image_table [image_index];
+ image = load_image (aot_module, image_index);
+ if (!image)
+ goto cleanup;
ji->data.method = mono_get_method (image, token, NULL);
g_assert (ji->data.method);
mono_class_init (ji->data.method->klass);
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);
+ wrapper_type = decode_value (p, &p);
- 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);
+ switch (wrapper_type) {
+ case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
+ guint32 image_index, token, value;
+
+ value = decode_value (p, &p);
+ image_index = value >> 24;
+ token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
- 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);
+ image = load_image (aot_module, image_index);
+ if (!image)
+ goto cleanup;
+ ji->data.method = mono_get_method (image, token, NULL);
+ g_assert (ji->data.method);
+ mono_class_init (ji->data.method->klass);
+
+ ji->type = MONO_PATCH_INFO_METHOD;
+ ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
+ break;
+ }
+ case MONO_WRAPPER_PROXY_ISINST: {
+ MonoClass *klass = decode_klass_info (aot_module, p, &p);
+ if (!klass)
+ goto cleanup;
+ ji->type = MONO_PATCH_INFO_METHOD;
+ ji->data.method = mono_marshal_get_proxy_cancast (klass);
+ break;
+ }
+ case MONO_WRAPPER_LDFLD:
+ case MONO_WRAPPER_STFLD:
+ case MONO_WRAPPER_LDFLD_REMOTE:
+ case MONO_WRAPPER_STFLD_REMOTE:
+ case MONO_WRAPPER_ISINST: {
+ MonoClass *klass = decode_klass_info (aot_module, p, &p);
+ if (!klass)
+ goto cleanup;
+ ji->type = MONO_PATCH_INFO_METHOD;
+ if (wrapper_type == MONO_WRAPPER_LDFLD)
+ ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
+ else if (wrapper_type == MONO_WRAPPER_STFLD)
+ ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
+ else if (wrapper_type == MONO_WRAPPER_LDFLD_REMOTE)
+ ji->data.method = mono_marshal_get_ldfld_remote_wrapper (klass);
+ else
+ ji->data.method = mono_marshal_get_isinst (klass);
+ break;
+ }
+ case MONO_WRAPPER_STELEMREF:
+ ji->type = MONO_PATCH_INFO_METHOD;
+ ji->data.method = mono_marshal_get_stelemref ();
+ break;
+ default:
+ g_assert_not_reached ();
+ }
break;
}
case MONO_PATCH_INFO_FIELD:
- case MONO_PATCH_INFO_SFLDA: {
- /* The pointer is dword aligned */
- gpointer class_ptr = *(gpointer*)(ALIGN_PTR_TO (&data[1], sizeof (gpointer)));
- MonoClass *klass = decode_class_info (aot_module, class_ptr);
- mono_class_init (klass);
- ji->data.field = mono_class_get_field (klass, data [0]);
+ case MONO_PATCH_INFO_SFLDA:
+ ji->data.field = decode_field_info (aot_module, p, &p);
+ if (!ji->data.field)
+ goto cleanup;
break;
- }
case MONO_PATCH_INFO_INTERNAL_METHOD:
- ji->data.name = aot_module->icall_table [(guint32)data];
+ ji->data.name = aot_module->icall_table [decode_value (p, &p)];
g_assert (ji->data.name);
- //printf ("A: %s.\n", ji->data.name);
break;
case MONO_PATCH_INFO_SWITCH:
- ji->table_size = data [0];
- table = g_new (gpointer, ji->table_size);
- ji->data.target = table;
- for (i = 0; i < ji->table_size; i++) {
- table [i] = data [i + 1];
- }
+ ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
+ ji->data.table->table_size = decode_value (p, &p);
+ table = g_new (gpointer, ji->data.table->table_size);
+ ji->data.table->table = (MonoBasicBlock**)table;
+ for (i = 0; i < ji->data.table->table_size; i++)
+ table [i] = (gpointer)(gssize)decode_value (p, &p);
+ break;
+ case MONO_PATCH_INFO_R4: {
+ guint32 val;
+
+ ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
+ val = decode_value (p, &p);
+ *(float*)ji->data.target = *(float*)&val;
break;
- case MONO_PATCH_INFO_R4:
- case MONO_PATCH_INFO_R8:
- ji->data.target = data;
+ }
+ case MONO_PATCH_INFO_R8: {
+ guint32 val [2];
+
+ ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
+
+ val [0] = decode_value (p, &p);
+ val [1] = decode_value (p, &p);
+ *(double*)ji->data.target = *(double*)val;
break;
+ }
case MONO_PATCH_INFO_LDSTR:
+ image = load_image (aot_module, decode_value (p, &p));
+ if (!image)
+ goto cleanup;
+ ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
+ break;
+ case MONO_PATCH_INFO_DECLSEC:
case MONO_PATCH_INFO_LDTOKEN:
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
- image = aot_module->image_table [data [0]];
- ji->data.token = mono_jump_info_token_new (mp, image, data [1]);
+ image = load_image (aot_module, decode_value (p, &p));
+ if (!image)
+ goto cleanup;
+ ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
break;
case MONO_PATCH_INFO_EXC_NAME:
- ji->data.klass = decode_class_info (aot_module, data);
- g_assert (ji->data.klass);
- mono_class_init (ji->data.klass);
+ ji->data.klass = decode_klass_info (aot_module, p, &p);
+ if (!ji->data.klass)
+ goto cleanup;
ji->data.name = ji->data.klass->name;
break;
case MONO_PATCH_INFO_METHOD_REL:
- ji->data.offset = data [0];
+ ji->data.offset = decode_value (p, &p);
break;
default:
g_warning ("unhandled type %d", ji->type);
}
}
- g_ptr_array_free (patches, TRUE);
+ buf_len = decode_value (p, &p);
+ mono_debug_add_aot_method (domain, method, code, p, buf_len);
- buf_len = *(guint32*)info;
- info += 4;
- mono_debug_add_aot_method (domain, method, code, info, buf_len);
+#if MONO_ARCH_HAVE_PIC_AOT
+ mono_arch_flush_icache (code, code_len);
- if (use_loaded_code) {
- /* disable write protection */
-#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);
+ if (non_got_patches)
+ make_writable (code, code_len);
+
+ /* Do this outside the lock to avoid deadlocks */
+ LeaveCriticalSection (&aot_mutex);
+ non_got_patches = FALSE;
+ for (pindex = 0; pindex < patches->len; ++pindex) {
+ MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
+
+ if (is_got_patch (ji->type)) {
+ aot_module->got [got_index] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
+ got_index ++;
+ ji->type = MONO_PATCH_INFO_NONE;
}
-#endif
+ else
+ non_got_patches = TRUE;
}
+ if (non_got_patches) {
+ make_writable (code, code_len);
+ mono_arch_patch_code (method, domain, code, patch_info, TRUE);
+ }
+ EnterCriticalSection (&aot_mutex);
+#else
+ if (use_loaded_code)
+ /* disable write protection */
+ make_writable (code, code_len);
/* Do this outside the lock to avoid deadlocks */
LeaveCriticalSection (&aot_mutex);
mono_arch_patch_code (method, domain, code, patch_info, TRUE);
EnterCriticalSection (&aot_mutex);
- if (aot_module->opts & MONO_OPT_SHARED)
- /* No need to cache patches */
+#endif
+ g_ptr_array_free (patches, TRUE);
+
+ if (!keep_patches)
mono_mempool_destroy (mp);
- else
- minfo->patch_info = patch_info;
}
mono_jit_stats.methods_aot++;
jinfo->used_regs = used_int_regs;
jinfo->method = method;
jinfo->code_start = code;
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ jinfo->domain_neutral = 0;
+#else
jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
-
- minfo->info = jinfo;
- mono_g_hash_table_insert (aot_module->methods, method, minfo);
+#endif
return jinfo;
}
+
+ cleanup:
+ g_ptr_array_free (patches, TRUE);
+
+ /* FIXME: The space in domain->mp is wasted */
+ if (aot_module->opts & MONO_OPT_SHARED)
+ /* No need to cache patches */
+ mono_mempool_destroy (mp);
+
+ return NULL;
}
MonoJitInfo*
return NULL;
}
+gboolean
+mono_aot_is_got_entry (guint8 *code, guint8 *addr)
+{
+ MonoJitInfo *ji;
+ MonoAssembly *ass;
+ MonoAotModule *aot_module;
+
+ ji = mono_jit_info_table_find (mono_domain_get (), code);
+ if (!ji)
+ return FALSE;
+
+ ass = ji->method->klass->image->assembly;
+
+ if (!aot_modules)
+ return FALSE;
+ aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
+ if (!aot_module || !aot_module->got)
+ return FALSE;
+
+ return ((addr >= (guint8*)(aot_module->got)) && (addr < (guint8*)(aot_module->got + aot_module->got_size)));
+}
+
+/*****************************************************/
+/* AOT COMPILER */
+/*****************************************************/
+
static void
emit_section_change (FILE *fp, const char *section_name, int subsection_index)
{
}
static void
-emit_global (FILE *fp, const char *name)
+emit_symbol_type (FILE *fp, const char *name, gboolean func)
+{
+ const char *stype;
+
+ if (func)
+ stype = "function";
+ else
+ stype = "object";
+
+#if defined(sparc)
+ fprintf (fp, "\t.type %s,#%s\n", name, stype);
+#elif !(defined(__ppc__) && defined(__MACH__))
+ fprintf (fp, "\t.type %s,@%s\n", name, stype);
+#elif defined(__x86_64__) || defined(__i386__)
+ fprintf (fp, "\t.type %s,@%s\n", name, stype);
+#endif
+}
+
+static void
+emit_global (FILE *fp, const char *name, gboolean func)
{
#if defined(__ppc__) && defined(__MACH__)
// mach-o always uses a '_' prefix.
- fprintf (fp, ".globl _%s\n", name);
+ fprintf (fp, "\t.globl _%s\n", name);
#else
- fprintf (fp, ".globl %s\n", name);
+ fprintf (fp, "\t.globl %s\n", name);
#endif
+
+ emit_symbol_type (fp, name, func);
}
static void
#endif
}
-#if 0
static void
-write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
+emit_string_symbol (FILE *fp, const char *name, const char *value)
{
- int i;
-
emit_section_change (fp, ".text", 1);
+ emit_global(fp, name, FALSE);
+ emit_label(fp, name);
+ fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
+}
- fprintf (fp, ".globl %s\n", name);
- fprintf (fp, "\t.align %d\n", align);
- fprintf (fp, "\t.type %s,#object\n", name);
- fprintf (fp, "\t.size %s,%d\n", name, size);
- fprintf (fp, "%s:\n", name);
- for (i = 0; i < size; i++) {
- fprintf (fp, ".byte %d\n", buf [i]);
- }
-
+#if defined(__ppc__) && defined(__MACH__)
+static int
+ilog2(register int value)
+{
+ int count = -1;
+ while (value & ~0xf) count += 4, value >>= 4;
+ while (value) count++, value >>= 1;
+ return count;
}
#endif
-static void
-write_string_symbol (FILE *fp, const char *name, const char *value)
+static void
+emit_alignment(FILE *fp, int size)
{
- emit_section_change (fp, ".text", 1);
- emit_global(fp, name);
- emit_label(fp, name);
- fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
+#if defined(__ppc__) && defined(__MACH__)
+ // the mach-o assembler specifies alignments as powers of 2.
+ fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
+#elif defined(__powerpc__)
+ /* ignore on linux/ppc */
+#else
+ fprintf (fp, "\t.align %d\n", size);
+#endif
+}
+
+G_GNUC_UNUSED static void
+emit_pointer (FILE *fp, const char *target)
+{
+ emit_alignment (fp, sizeof (gpointer));
+#if defined(__x86_64__)
+ fprintf (fp, "\t.quad %s\n", target);
+#elif defined(sparc) && SIZEOF_VOID_P == 8
+ fprintf (fp, "\t.xword %s\n", target);
+#else
+ fprintf (fp, "\t.long %s\n", target);
+#endif
}
static guint32
return 0;
}
+static inline void
+encode_value (gint32 value, char *buf, char **endbuf)
+{
+ char *p = buf;
+
+ //printf ("ENCODE: %d 0x%x.\n", value, value);
+
+ /*
+ * Same encoding as the one used in the metadata, extended to handle values
+ * greater than 0x1fffffff.
+ */
+ if ((value >= 0) && (value <= 127))
+ *p++ = value;
+ else if ((value >= 0) && (value <= 16383)) {
+ p [0] = 0x80 | (value >> 8);
+ p [1] = value & 0xff;
+ p += 2;
+ } else if ((value >= 0) && (value <= 0x1fffffff)) {
+ p [0] = (value >> 24) | 0xc0;
+ p [1] = (value >> 16) & 0xff;
+ p [2] = (value >> 8) & 0xff;
+ p [3] = value & 0xff;
+ p += 4;
+ }
+ else {
+ p [0] = 0xff;
+ p [1] = (value >> 24) & 0xff;
+ p [2] = (value >> 16) & 0xff;
+ p [3] = (value >> 8) & 0xff;
+ p [4] = value & 0xff;
+ p += 5;
+ }
+ if (endbuf)
+ *endbuf = p;
+}
+
static guint32
get_image_index (MonoAotCompile *cfg, MonoImage *image)
{
}
static void
-emit_image_index (MonoAotCompile *cfg, MonoImage *image)
-{
- guint32 image_index;
-
- image_index = get_image_index (cfg, image);
-
- fprintf (cfg->fp, "\t.long %d\n", image_index);
-}
-
-#if defined(__ppc__) && defined(__MACH__)
-static int
-ilog2(register int value)
-{
- int count = -1;
- while (value & ~0xf) count += 4, value >>= 4;
- while (value) count++, value >>= 1;
- return count;
-}
-#endif
-
-static void emit_alignment(FILE *fp, int size)
-{
-#if defined(__ppc__) && defined(__MACH__)
- // the mach-o assembler specifies alignments as powers of 2.
- fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
-#elif defined(__powerpc__)
- /* ignore on linux/ppc */
-#else
- fprintf (fp, "\t.align %d\n", size);
-#endif
-}
-
-static void
-emit_pointer (FILE *fp, const char *target)
+encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, char *buf, char **endbuf)
{
- emit_alignment (fp, sizeof (gpointer));
-#if defined(sparc) && SIZEOF_VOID_P == 8
- fprintf (fp, "\t.xword %s\n", target);
-#else
- fprintf (fp, "\t.long %s\n", target);
-#endif
-}
-
-static char *
-cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass)
-{
- char *l1, *el = NULL;
-
- if ((l1 = g_hash_table_lookup (cfg->ref_hash, klass)))
- return l1;
-
+ encode_value (get_image_index (cfg, klass->image), buf, &buf);
if (!klass->type_token) {
+ /* Array class */
g_assert (klass->rank > 0);
- el = cond_emit_klass_label (cfg, klass->element_class);
+ g_assert (klass->element_class->type_token);
+ encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
+ g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
+ encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
+ encode_value (klass->rank, buf, &buf);
}
-
- emit_alignment(cfg->fp, sizeof (gpointer));
-
- l1 = g_strdup_printf ("klass_p_%08x_%p", klass->type_token, klass);
- fprintf (cfg->fp, "%s:\n", l1);
- fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token);
- emit_image_index (cfg, klass->image);
-
- if (el) {
- fprintf (cfg->fp, "\t.long %d\n", klass->rank);
- emit_pointer (cfg->fp, el);
+ else {
+ g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
+ encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
}
+ *endbuf = buf;
+}
- g_hash_table_insert (cfg->ref_hash, klass, l1);
+static void
+encode_field_info (MonoAotCompile *cfg, MonoClassField *field, char *buf, char **endbuf)
+{
+ guint32 token = mono_get_field_token (field);
- return l1;
+ encode_klass_info (cfg, field->parent, buf, &buf);
+ g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
+ encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
+ *endbuf = buf;
}
-static char *
-cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info)
+static void
+encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, char *buf, char **endbuf)
{
- MonoClassField *field = patch_info->data.field;
- 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);
- emit_alignment(cfg->fp, 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);
- emit_pointer (cfg->fp, l2);
-
- g_hash_table_insert (cfg->ref_hash, field, l1);
+ guint32 image_index = get_image_index (acfg, method->klass->image);
+ guint32 token = method->token;
+ g_assert (image_index < 256);
+ g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
- return l1;
+ encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
+ *endbuf = buf;
}
static gint
}
static void
-emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
+emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
{
MonoMethod *method;
- GList *l;
FILE *tmpfp;
- int i, j, k, pindex;
+ int i, j, pindex, byte_index;
guint8 *code, *mname, *mname_p;
int func_alignment = 16;
GPtrArray *patches;
MonoJumpInfo *patch_info;
MonoMethodHeader *header;
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ gboolean skip;
+#endif
tmpfp = acfg->fp;
method = cfg->method;
code = cfg->native_code;
- header = ((MonoMethodNormal*)method)->header;
+ header = mono_method_get_header (method);
- emit_section_change (tmpfp, ".text", 0);
- mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
+ /* Make the labels local */
+ mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
mname_p = g_strdup_printf ("%s_p", mname);
+
emit_alignment(tmpfp, func_alignment);
- emit_global(tmpfp, mname);
-#if defined(sparc)
- fprintf (tmpfp, "\t.type %s,#function\n", mname);
-#elif !(defined(__ppc__) && defined(__MACH__))
- fprintf (tmpfp, "\t.type %s,@function\n", mname);
-#endif
emit_label(tmpfp, mname);
+ if (acfg->aot_opts.write_symbols)
+ emit_global (tmpfp, mname, TRUE);
- for (i = 0; i < cfg->code_len; i++)
- fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]);
+ if (cfg->verbose_level > 0)
+ g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), mname);
- emit_section_change (tmpfp, ".text", 1);
+ /* Sort relocations */
+ patches = g_ptr_array_new ();
+ for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
+ g_ptr_array_add (patches, patch_info);
+ g_ptr_array_sort (patches, compare_patches);
+
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ acfg->method_got_offsets [mono_metadata_token_index (method->token)] = acfg->got_offset;
+ byte_index = 0;
+ for (i = 0; i < cfg->code_len; i++) {
+ patch_info = NULL;
+ for (pindex = 0; pindex < patches->len; ++pindex) {
+ patch_info = g_ptr_array_index (patches, pindex);
+ if (patch_info->ip.i == i)
+ break;
+ }
+
+ skip = FALSE;
+ if (patch_info && (pindex < patches->len)) {
+ switch (patch_info->type) {
+ case MONO_PATCH_INFO_LABEL:
+ case MONO_PATCH_INFO_BB:
+ case MONO_PATCH_INFO_NONE:
+ break;
+ case MONO_PATCH_INFO_GOT_OFFSET: {
+ guint32 offset = mono_arch_get_patch_offset (code + i);
+ fprintf (tmpfp, "\n.byte ");
+ for (j = 0; j < offset; ++j)
+ fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
+ fprintf (tmpfp, "\n.int got - . + %d", offset);
+
+ i += offset + 4 - 1;
+ skip = TRUE;
+ break;
+ }
+ default:
+ if (!is_got_patch (patch_info->type))
+ break;
+
+ fprintf (tmpfp, "\n.byte ");
+ for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
+ fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
+#ifdef __x86_64__
+ fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((acfg->got_offset * sizeof (gpointer)) - 4));
+#elif defined(__i386__)
+ fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer))));
+#endif
+ acfg->got_offset ++;
+
+ i += mono_arch_get_patch_offset (code + i) + 4 - 1;
+ skip = TRUE;
+ }
+ }
+
+ if (!skip) {
+ if (byte_index == 0)
+ fprintf (tmpfp, "\n.byte ");
+ fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
+ byte_index = (byte_index + 1) % 32;
+ }
+ else
+ byte_index = 0;
+ }
+#else
+ for (i = 0; i < cfg->code_len; i++) {
+ fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
+ }
+#endif
+ fprintf (tmpfp, "\n");
+}
+
+static void
+emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
+{
+ MonoMethod *method;
+ GList *l;
+ FILE *tmpfp;
+ int i, j, k, pindex, buf_size;
+ guint32 debug_info_size;
+ guint8 *code, *mname, *mname_p;
+ GPtrArray *patches;
+ MonoJumpInfo *patch_info;
+ MonoMethodHeader *header;
+ guint32 last_offset;
+ char *p, *buf;
+ guint8 *debug_info;
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ guint32 first_got_offset;
+#endif
+
+ tmpfp = acfg->fp;
+ method = cfg->method;
+ code = cfg->native_code;
+ header = mono_method_get_header (method);
+
+ /* Make the labels local */
+ mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
+ mname_p = g_strdup_printf ("%s_p", mname);
/* Sort relocations */
patches = g_ptr_array_new ();
g_ptr_array_add (patches, patch_info);
g_ptr_array_sort (patches, compare_patches);
- /* Emit out of line info for relocations */
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
+#endif
+
+ /**********************/
+ /* Encode method info */
+ /**********************/
+
+ buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
+ p = buf = g_malloc (buf_size);
+
+ encode_value (cfg->code_len, p, &p);
+ encode_value (cfg->used_int_regs, p, &p);
+
+ /* Exception table */
+ encode_value (header->num_clauses ? 1 : 0, p, &p);
+ if (header->num_clauses) {
+ MonoJitInfo *jinfo = cfg->jit_info;
+
+ for (k = 0; k < header->num_clauses; ++k) {
+ MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+
+ encode_value (ei->exvar_offset, p, &p);
+
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+ encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+
+ encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
+ encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
+ encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+ }
+ }
+
+ /* String table */
+ if (cfg->opt & MONO_OPT_SHARED) {
+ encode_value (g_list_length (cfg->ldstr_list), p, &p);
+ for (l = cfg->ldstr_list; l; l = l->next) {
+ encode_value ((long)l->data, p, &p);
+ }
+ }
+ else
+ /* Used only in shared mode */
+ g_assert (!cfg->ldstr_list);
+
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ encode_value (first_got_offset, p, &p);
+#endif
+
+ /* First emit the type+position table */
+ last_offset = 0;
j = 0;
+ for (pindex = 0; pindex < patches->len; ++pindex) {
+ guint32 offset;
+ patch_info = g_ptr_array_index (patches, pindex);
+
+ if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
+ (patch_info->type == MONO_PATCH_INFO_BB) ||
+ (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
+ (patch_info->type == MONO_PATCH_INFO_NONE))
+ /* Nothing to do */
+ continue;
+
+ j ++;
+ //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
+ offset = patch_info->ip.i - last_offset;
+ last_offset = patch_info->ip.i;
+
+#if defined(MONO_ARCH_HAVE_PIC_AOT)
+ /* Only the type is needed */
+ *p = patch_info->type;
+ p++;
+#else
+ /* Encode type+position compactly */
+ g_assert (patch_info->type < 64);
+ if (offset < 1024 - 1) {
+ *p = (patch_info->type << 2) + (offset >> 8);
+ p++;
+ *p = offset & ((1 << 8) - 1);
+ p ++;
+ }
+ else {
+ *p = (patch_info->type << 2) + 3;
+ p ++;
+ *p = 255;
+ p ++;
+ encode_value (offset, p, &p);
+ }
+#endif
+ }
+
+ /*
+ * 0 is PATCH_INFO_BB, which can't be in the file.
+ */
+ /* NULL terminated array */
+ *p = 0;
+ p ++;
+
+ /* Then emit the other info */
for (pindex = 0; pindex < patches->len; ++pindex) {
patch_info = g_ptr_array_index (patches, pindex);
+
switch (patch_info->type) {
case MONO_PATCH_INFO_LABEL:
case MONO_PATCH_INFO_BB:
- /* relative jumps are no problem, there is no need to handle then here */
+ case MONO_PATCH_INFO_GOT_OFFSET:
+ case MONO_PATCH_INFO_NONE:
+ break;
+ case MONO_PATCH_INFO_IMAGE:
+ encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
+ break;
+ case MONO_PATCH_INFO_METHOD_REL:
+ encode_value ((gint)patch_info->data.offset, p, &p);
break;
case MONO_PATCH_INFO_SWITCH: {
- gpointer *table = (gpointer *)patch_info->data.target;
+ gpointer *table = (gpointer *)patch_info->data.table->table;
int k;
- emit_alignment(tmpfp, sizeof (gpointer));
- fprintf (tmpfp, "%s_p_%d:\n", mname, j);
- fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
-
- for (k = 0; k < patch_info->table_size; k++) {
- fprintf (tmpfp, "\t.long %d\n", (int)table [k]);
- }
- j++;
+ encode_value (patch_info->data.table->table_size, p, &p);
+ for (k = 0; k < patch_info->data.table->table_size; k++)
+ encode_value ((int)(gssize)table [k], p, &p);
break;
}
+ case MONO_PATCH_INFO_METHODCONST:
+ case MONO_PATCH_INFO_METHOD:
+ case MONO_PATCH_INFO_METHOD_JUMP:
+ encode_method_ref (acfg, patch_info->data.method, p, &p);
+ break;
case MONO_PATCH_INFO_INTERNAL_METHOD: {
guint32 icall_index;
- icall_index = (guint32)g_hash_table_lookup (acfg->icall_hash, patch_info->data.name);
+ icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
if (!icall_index) {
icall_index = g_hash_table_size (acfg->icall_hash) + 1;
g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
GUINT_TO_POINTER (icall_index));
g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
}
- patch_info->data.name = g_strdup_printf ("%d", icall_index - 1);
- j++;
+ encode_value (icall_index - 1, p, &p);
break;
}
- case MONO_PATCH_INFO_METHODCONST:
- 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
- * decrease the number of relocations.
+ case MONO_PATCH_INFO_LDSTR: {
+ guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
+ guint32 token = patch_info->data.token->token;
+ g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
+ /*
+ * An optimization would be to emit shared code for ldstr
+ * statements followed by a throw.
*/
- guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
- guint32 token = patch_info->data.method->token;
- g_assert (image_index < 256);
- g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
-
- patch_info->data.name =
- g_strdup_printf ("%d", (image_index << 24) + (mono_metadata_token_index (token)));
- 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);
-
- emit_alignment(tmpfp, 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++;
+ encode_value (image_index, p, &p);
+ encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
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;
- case MONO_PATCH_INFO_IMAGE:
- patch_info->data.name = g_strdup_printf ("%d", get_image_index (acfg, patch_info->data.image));
- j++;
+ case MONO_PATCH_INFO_DECLSEC:
+ case MONO_PATCH_INFO_LDTOKEN:
+ case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+ encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
+ encode_value (patch_info->data.token->token, p, &p);
break;
case MONO_PATCH_INFO_EXC_NAME: {
MonoClass *ex_class;
-
+
ex_class =
mono_class_from_name (mono_defaults.exception_class->image,
"System", patch_info->data.target);
g_assert (ex_class);
- patch_info->data.name = cond_emit_klass_label (acfg, ex_class);
- j++;
+ encode_klass_info (acfg, ex_class, p, &p);
break;
}
case MONO_PATCH_INFO_R4:
- emit_alignment(tmpfp, 8);
- fprintf (tmpfp, "%s_p_%d:\n", mname, j);
- fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
- j++;
+ encode_value (*((guint32 *)patch_info->data.target), p, &p);
break;
case MONO_PATCH_INFO_R8:
- emit_alignment(tmpfp, 8);
- fprintf (tmpfp, "%s_p_%d:\n", mname, j);
- fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
- fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1));
- j++;
- break;
- case MONO_PATCH_INFO_METHOD_REL:
- emit_alignment(tmpfp, sizeof (gpointer));
- fprintf (tmpfp, "%s_p_%d:\n", mname, j);
- fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.offset);
- j++;
+ encode_value (*((guint32 *)patch_info->data.target), p, &p);
+ encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
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++;
+ case MONO_PATCH_INFO_CLASS:
+ case MONO_PATCH_INFO_IID:
+ encode_klass_info (acfg, patch_info->data.klass, p, &p);
break;
+ case MONO_PATCH_INFO_FIELD:
case MONO_PATCH_INFO_SFLDA:
- patch_info->data.name = cond_emit_field_label (acfg, patch_info);
- j++;
+ encode_field_info (acfg, patch_info->data.field, p, &p);
break;
- case MONO_PATCH_INFO_LDSTR:
- case MONO_PATCH_INFO_LDTOKEN:
- case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
- emit_alignment(tmpfp, 8);
- fprintf (tmpfp, "%s_p_%d:\n", mname, j);
- 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++;
+ case MONO_PATCH_INFO_WRAPPER: {
+ encode_value (patch_info->data.method->wrapper_type, p, &p);
+
+ switch (patch_info->data.method->wrapper_type) {
+ case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
+ 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);
+
+ encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
+ break;
+ }
+ case MONO_WRAPPER_PROXY_ISINST:
+ case MONO_WRAPPER_LDFLD:
+ case MONO_WRAPPER_STFLD:
+ case MONO_WRAPPER_LDFLD_REMOTE:
+ case MONO_WRAPPER_STFLD_REMOTE:
+ case MONO_WRAPPER_ISINST: {
+ MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
+ encode_klass_info (acfg, proxy_class, p, &p);
+ break;
+ }
+ case MONO_WRAPPER_STELEMREF:
+ break;
+ default:
+ g_assert_not_reached ();
+ }
break;
+ }
default:
g_warning ("unable to handle jump info %d", patch_info->type);
g_assert_not_reached ();
}
}
- emit_global (tmpfp, mname_p);
- emit_alignment (tmpfp, sizeof (gpointer));
- emit_label (tmpfp, mname_p);
-
- fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
- fprintf (tmpfp, "\t.long %ld\n", (long)cfg->used_int_regs);
-
- /* Exception table */
- if (header->num_clauses) {
- MonoJitInfo *jinfo = cfg->jit_info;
-
- fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset);
+ mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
- for (k = 0; k < header->num_clauses; ++k) {
- MonoJitExceptionInfo *ei = &jinfo->clauses [k];
-
- if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
- fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->data.filter - code);
- else
- /* fixme: tokens are not global */
- fprintf (tmpfp, "\t.long %d\n", ei->data.token);
-
- fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_start - code);
- fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_end - code);
- fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->handler_start - code);
- }
+ encode_value (debug_info_size, p, &p);
+ if (debug_info_size) {
+ memcpy (p, debug_info, debug_info_size);
+ p += debug_info_size;
+ g_free (debug_info);
}
- /* String table */
- if (cfg->opt & MONO_OPT_SHARED) {
- fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
- for (l = cfg->ldstr_list; l; l = l->next) {
- fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data);
- }
- }
- else
- /* Used only in shared mode */
- g_assert (!cfg->ldstr_list);
+ /* Emit method info */
- //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname);
-
- if (j) {
- guint32 last_offset;
- last_offset = 0;
-
- j = 0;
+ emit_label (tmpfp, mname_p);
- /* First emit the type+position table */
- for (pindex = 0; pindex < patches->len; ++pindex) {
- guint32 offset;
- patch_info = g_ptr_array_index (patches, pindex);
+ g_assert (p - buf < buf_size);
+ for (i = 0; i < p - buf; ++i) {
+ if ((i % 32) == 0)
+ fprintf (tmpfp, "\n.byte ");
+ fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
+ }
+ fprintf (tmpfp, "\n");
+ g_free (buf);
- if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
- (patch_info->type == MONO_PATCH_INFO_BB))
- /* Nothing to do */
- continue;
+ g_free (mname);
+ g_free (mname_p);
+}
- //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
- offset = patch_info->ip.i - last_offset;
- last_offset = patch_info->ip.i;
+static void
+emit_klass_info (MonoAotCompile *acfg, guint32 token)
+{
+ MonoClass *klass = mono_class_get (acfg->image, token);
+ char *p, *buf;
+ int i, buf_size;
+ char *label;
+ FILE *tmpfp = acfg->fp;
- /* Encode type+position compactly */
- g_assert (patch_info->type < 64);
- if (offset < 1024 - 1) {
- fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + (offset >> 8));
- fprintf (tmpfp, "\t.byte %d\n", offset & ((1 << 8) - 1));
- }
- else {
- fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3);
- fprintf (tmpfp, "\t.byte %d\n", 255);
- emit_alignment(tmpfp, 4);
- fprintf (tmpfp, "\t.long %d\n", offset);
- }
- }
+ buf_size = 10240;
+ p = buf = g_malloc (buf_size);
- /*
- * 0 is PATCH_INFO_BB, which can't be in the file.
- */
- /* NULL terminated array */
- fprintf (tmpfp, "\t.byte 0\n");
+ g_assert (klass);
- emit_alignment (tmpfp, sizeof (gpointer));
+ mono_class_init (klass);
- /* Then emit the other info */
- for (pindex = 0; pindex < patches->len; ++pindex) {
- patch_info = g_ptr_array_index (patches, pindex);
+ /*
+ * Emit all the information which is required for creating vtables so
+ * the runtime does not need to create the MonoMethod structures which
+ * take up a lot of space.
+ */
- if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
- (patch_info->type == MONO_PATCH_INFO_BB))
- /* Nothing to do */
- continue;
+ if (!MONO_CLASS_IS_INTERFACE (klass)) {
+ encode_value (klass->vtable_size, p, &p);
+ encode_value ((klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
+ if (klass->has_cctor)
+ encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
+ if (klass->has_finalize)
+ encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
- 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:
- emit_pointer (tmpfp, patch_info->data.name);
- j++;
- break;
- case MONO_PATCH_INFO_SWITCH:
- case MONO_PATCH_INFO_R4:
- case MONO_PATCH_INFO_R8:
- case MONO_PATCH_INFO_METHOD_REL:
- case MONO_PATCH_INFO_LDSTR:
- case MONO_PATCH_INFO_LDTOKEN:
- case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
- case MONO_PATCH_INFO_WRAPPER: {
- char buf [256];
- sprintf (buf, "%s_p_%d", mname, j);
- emit_pointer (tmpfp, buf);
- j++;
- break;
- }
- case MONO_PATCH_INFO_LABEL:
- case MONO_PATCH_INFO_BB:
- break;
- default:
- g_warning ("unable to handle jump info %d", patch_info->type);
- g_assert_not_reached ();
- }
+ for (i = 0; i < klass->vtable_size; ++i) {
+ MonoMethod *cm = klass->vtable [i];
+ if (cm)
+ encode_method_ref (acfg, cm, p, &p);
+ else
+ encode_value (0, p, &p);
}
}
- {
- guint8 *buf;
- guint32 buf_len;
+ /* Emit the info */
+ label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
+ emit_label (tmpfp, label);
- 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);
+ g_assert (p - buf < buf_size);
+ for (i = 0; i < p - buf; ++i) {
+ if ((i % 32) == 0)
+ fprintf (tmpfp, "\n.byte ");
+ fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
}
+ fprintf (tmpfp, "\n");
+ g_free (buf);
+}
- /* fixme: save the rest of the required infos */
+static gboolean
+str_begins_with (const char *str1, const char *str2)
+{
+ int len = strlen (str2);
+ return strncmp (str1, str2, len) == 0;
+}
- g_free (mname);
- g_free (mname_p);
+static void
+mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
+{
+ gchar **args, **ptr;
+
+ memset (opts, 0, sizeof (*opts));
+
+ args = g_strsplit (aot_options ? aot_options : "", ",", -1);
+ for (ptr = args; ptr && *ptr; ptr ++) {
+ const char *arg = *ptr;
+
+ if (str_begins_with (arg, "outfile=")) {
+ opts->outfile = g_strdup (arg + strlen ("outfile="));
+ } else if (str_begins_with (arg, "save-temps")) {
+ opts->save_temps = TRUE;
+ } else if (str_begins_with (arg, "write-symbols")) {
+ opts->write_symbols = TRUE;
+ } else {
+ fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
+ exit (1);
+ }
+ }
}
int
-mono_compile_assembly (MonoAssembly *ass, guint32 opts)
+mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
{
MonoCompile *cfg;
MonoImage *image = ass->image;
int i;
guint8 *symbol;
int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
- GHashTable *ref_hash;
MonoAotCompile *acfg;
- gboolean *emitted;
+ MonoCompile **cfgs;
+ char *outfile_name, *tmp_outfile_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+");
- g_assert (tmpfp);
-
- ref_hash = g_hash_table_new (NULL, NULL);
-
acfg = g_new0 (MonoAotCompile, 1);
- acfg->fp = tmpfp;
- acfg->ref_hash = ref_hash;
acfg->icall_hash = g_hash_table_new (NULL, NULL);
acfg->icall_table = g_ptr_array_new ();
acfg->image_hash = g_hash_table_new (NULL, NULL);
acfg->image_table = g_ptr_array_new ();
+ acfg->image = image;
+
+ mono_aot_parse_options (aot_options, &acfg->aot_opts);
+
+ i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
+ tmpfp = fdopen (i, "w+");
+ acfg->fp = tmpfp;
+ g_assert (tmpfp);
- write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
+ emit_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
- write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
+ emit_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
opts_str = g_strdup_printf ("%d", opts);
- write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
+ emit_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
g_free (opts_str);
- emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows);
+ symbol = g_strdup_printf ("methods");
+ emit_section_change (tmpfp, ".text", 0);
+ emit_global (tmpfp, symbol, FALSE);
+ emit_alignment (tmpfp, 8);
+ emit_label (tmpfp, symbol);
+
+ symbol = g_strdup_printf ("method_infos");
+ emit_section_change (tmpfp, ".text", 1);
+ emit_global (tmpfp, symbol, FALSE);
+ emit_alignment (tmpfp, 8);
+ emit_label (tmpfp, symbol);
+
+ cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
+ acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
MonoJumpInfo *patch_info;
//printf ("START: %s\n", mono_method_full_name (method, TRUE));
//mono_compile_method (method);
- cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, 0);
+ /*
+ * Since these methods are the only ones which are compiled with
+ * AOT support, and they are not used by runtime startup/shutdown code,
+ * 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, opts, mono_get_root_domain (), FALSE, TRUE, 0);
g_assert (cfg);
if (cfg->disable_aot) {
- printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
+ //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
ocount++;
continue;
}
continue;
}
- /* remoting-invoke-with-check wrappers are very common */
+ /* some 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;
+ if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
+ switch (patch_info->data.method->wrapper_type) {
+ case MONO_WRAPPER_PROXY_ISINST:
+ patch_info->type = MONO_PATCH_INFO_WRAPPER;
+ }
+ }
+
+ if (patch_info->type == MONO_PATCH_INFO_METHOD) {
+ switch (patch_info->data.method->wrapper_type) {
+ case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+ case MONO_WRAPPER_STFLD:
+ case MONO_WRAPPER_LDFLD:
+ case MONO_WRAPPER_LDFLD_REMOTE:
+ case MONO_WRAPPER_STFLD_REMOTE:
+ case MONO_WRAPPER_STELEMREF:
+ case MONO_WRAPPER_ISINST:
+ case MONO_WRAPPER_PROXY_ISINST:
+ patch_info->type = MONO_PATCH_INFO_WRAPPER;
+ break;
+ }
+ }
}
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 -> %s\n", mono_method_full_name (method, TRUE), patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
- skip = TRUE;
+ switch (patch_info->type) {
+ case MONO_PATCH_INFO_METHOD:
+ case MONO_PATCH_INFO_METHODCONST:
+ if (patch_info->data.method->wrapper_type) {
+ /* unable to handle this */
+ //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;
+ }
+ if (!patch_info->data.method->token)
+ /*
+ * The method is part of a constructed type like Int[,].Set (). It doesn't
+ * have a token, and we can't make one, since the parent type is part of
+ * assembly which contains the element type, and not the assembly which
+ * referenced this type.
+ */
+ skip = TRUE;
+ break;
+ case MONO_PATCH_INFO_VTABLE:
+ case MONO_PATCH_INFO_CLASS_INIT:
+ case MONO_PATCH_INFO_CLASS:
+ case MONO_PATCH_INFO_IID:
+ if (!patch_info->data.klass->type_token)
+ if (!patch_info->data.klass->element_class->type_token)
+ skip = TRUE;
+ break;
+ default:
break;
}
}
if (skip) {
wrappercount++;
+ mono_destroy_compile (cfg);
continue;
}
//printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
- emitted [i] = TRUE;
- emit_method (acfg, cfg);
-
- mono_destroy_compile (cfg);
+ cfgs [i] = cfg;
ccount++;
}
+ /* Emit code */
+ emit_section_change (tmpfp, ".text", 0);
+ for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+ if (cfgs [i])
+ emit_method_code (acfg, cfgs [i]);
+ }
+
+ /* Emit method info */
+ emit_section_change (tmpfp, ".text", 1);
+ for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+ if (cfgs [i])
+ emit_method_info (acfg, cfgs [i]);
+ }
+
+ /* Emit class info */
+
+ symbol = g_strdup_printf ("class_infos");
+ emit_section_change (tmpfp, ".text", 1);
+ emit_global (tmpfp, symbol, FALSE);
+ emit_alignment (tmpfp, 8);
+ emit_label (tmpfp, symbol);
+
+ for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
+ emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
+
+ symbol = g_strdup_printf ("class_info_offsets");
+ emit_section_change (tmpfp, ".text", 1);
+ emit_global (tmpfp, symbol, FALSE);
+ emit_alignment (tmpfp, 8);
+ emit_label(tmpfp, symbol);
+
+ for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+ const char *sep;
+ if ((i % 32) == 0) {
+ fprintf (tmpfp, "\n.long ");
+ sep = "";
+ }
+ else
+ sep = ",";
+
+ symbol = g_strdup_printf (".LK_I_%x", i);
+ fprintf (tmpfp, "%s%s - class_infos", sep, symbol);
+ }
+ fprintf (tmpfp, "\n");
+
/*
* The icall and image tables are small but referenced in a lot of places.
- * So we emit them at once, and reference their elements by an index
- * instead of an assembly label to cut back on the number of relocations.
+ * So we emit them at once, and reference their elements by an index.
*/
/* Emit icall table */
symbol = g_strdup_printf ("mono_icall_table");
emit_section_change (tmpfp, ".text", 1);
- emit_global(tmpfp, symbol);
+ emit_global(tmpfp, symbol, FALSE);
emit_alignment(tmpfp, 8);
emit_label(tmpfp, symbol);
fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
symbol = g_strdup_printf ("mono_image_table");
emit_section_change (tmpfp, ".text", 1);
- emit_global(tmpfp, symbol);
+ emit_global(tmpfp, symbol, FALSE);
emit_alignment(tmpfp, 8);
emit_label(tmpfp, symbol);
fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
- for (i = 0; i < acfg->image_table->len; i++)
- fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid);
+ for (i = 0; i < acfg->image_table->len; i++) {
+ MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
+ MonoAssemblyName *aname = &image->assembly->aname;
+
+ /* FIXME: Support multi-module assemblies */
+ g_assert (image->assembly->image == image);
+
+ fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
+ fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
+ fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
+ fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
+
+ emit_alignment (tmpfp, 8);
+ fprintf (tmpfp, ".long %d\n", aname->flags);
+ fprintf (tmpfp, ".long %d\n", aname->major);
+ fprintf (tmpfp, ".long %d\n", aname->minor);
+ fprintf (tmpfp, ".long %d\n", aname->build);
+ fprintf (tmpfp, ".long %d\n", aname->revision);
+ }
- /*
- * g_module_symbol takes a lot of time for failed lookups, so we emit
- * a table which contains one bit for each method. This bit specifies
- * whenever the method is emitted or not.
- */
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ /* Emit GOT */
- symbol = g_strdup_printf ("mono_methods_present_table");
+ /* Don't make GOT global so accesses to it don't need relocations */
+ symbol = g_strdup_printf ("got");
+#ifdef __x86_64__
+ emit_section_change (tmpfp, ".bss", 1);
+#else
+ emit_section_change (tmpfp, ".data", 1);
+#endif
+ emit_alignment (tmpfp, 8);
+ emit_label(tmpfp, symbol);
+ if (acfg->got_offset > 0)
+ fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
+
+ symbol = g_strdup_printf ("got_addr");
+ emit_section_change (tmpfp, ".data", 1);
+ emit_global (tmpfp, symbol, FALSE);
+ emit_alignment (tmpfp, 8);
+ emit_label(tmpfp, symbol);
+ emit_pointer (tmpfp, "got");
+
+ symbol = g_strdup_printf ("got_size");
+ emit_section_change (tmpfp, ".data", 1);
+ emit_global (tmpfp, symbol, FALSE);
+ emit_alignment (tmpfp, 8);
+ emit_label(tmpfp, symbol);
+ fprintf (tmpfp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
+#endif
+
+ symbol = g_strdup_printf ("method_offsets");
emit_section_change (tmpfp, ".text", 1);
- emit_global(tmpfp, symbol);
- emit_alignment(tmpfp, 8);
+ emit_global (tmpfp, symbol, FALSE);
+ emit_alignment (tmpfp, 8);
emit_label(tmpfp, symbol);
- {
- guint32 k, nrows;
- guint32 w;
-
- nrows = image->tables [MONO_TABLE_METHOD].rows;
- for (i = 0; i < nrows / 32 + 1; ++i) {
- w = 0;
- for (k = 0; k < 32; ++k) {
- if (emitted [(i * 32) + k])
- w += (1 << k);
- }
- //printf ("EMITTED [%d] = %d.\n", i, b);
- fprintf (tmpfp, "\t.long %d\n", w);
+
+ for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+ const char *sep;
+ if ((i % 32) == 0) {
+ fprintf (tmpfp, "\n.long ");
+ sep = "";
+ }
+ else
+ sep = ",";
+ if (cfgs [i]) {
+ symbol = g_strdup_printf (".Lm_%x", i + 1);
+ fprintf (tmpfp, "%s%s-methods", sep, symbol);
+ }
+ else
+ fprintf (tmpfp, "%s0xffffffff", sep);
+ }
+ fprintf (tmpfp, "\n");
+
+ symbol = g_strdup_printf ("method_info_offsets");
+ emit_section_change (tmpfp, ".text", 1);
+ emit_global (tmpfp, symbol, FALSE);
+ emit_alignment (tmpfp, 8);
+ emit_label(tmpfp, symbol);
+
+ for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+ const char *sep;
+ if ((i % 32) == 0) {
+ fprintf (tmpfp, "\n.long ");
+ sep = "";
+ }
+ else
+ sep = ",";
+ if (cfgs [i]) {
+ symbol = g_strdup_printf (".Lm_%x_p", i + 1);
+ fprintf (tmpfp, "%s%s - method_infos", sep, symbol);
}
+ else
+ fprintf (tmpfp, "%s0", sep);
}
+ fprintf (tmpfp, "\n");
fclose (tmpfp);
-#if defined(sparc) && SIZEOF_VOID_P == 8
+#if defined(__x86_64__)
+ com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
+#elif defined(sparc) && SIZEOF_VOID_P == 8
com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
#else
com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
}
g_free (com);
+
+ if (acfg->aot_opts.outfile)
+ outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+ else
+ outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
+
+ tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
+
#if defined(sparc)
- com = g_strdup_printf ("ld -shared -G -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
+ com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
#elif defined(__ppc__) && defined(__MACH__)
- com = g_strdup_printf ("gcc -dynamiclib -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
+ com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
#else
- com = g_strdup_printf ("ld -shared -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
+ com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
#endif
printf ("Executing the native linker: %s\n", com);
if (system (com) != 0) {
+ g_free (tmp_outfile_name);
+ g_free (outfile_name);
g_free (com);
return 1;
}
system (com);
g_free (com);*/
+ rename (tmp_outfile_name, outfile_name);
+
+ g_free (tmp_outfile_name);
+ g_free (outfile_name);
+
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);
- //printf ("Retained input file.\n");
- unlink (tmpfname);
+ if (acfg->aot_opts.save_temps)
+ printf ("Retained input file.\n");
+ else
+ unlink (tmpfname);
return 0;
}
+#else
+/* AOT disabled */
+
+void
+mono_aot_init (void)
+{
+}
+
+MonoJitInfo*
+mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
+{
+ return NULL;
+}
+
+gboolean
+mono_aot_is_got_entry (guint8 *code, guint8 *addr)
+{
+ return FALSE;
+}
+
+int
+mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
+{
+ return 0;
+}
+#endif