#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 */
- GHashTable *methods;
/* Pointer to the Global Offset Table */
gpointer *got;
guint32 got_size;
guint32 *code_offsets;
guint8 *method_infos;
guint32 *method_info_offsets;
+ guint8 *class_infos;
+ guint32 *class_info_offsets;
} MonoAotModule;
typedef struct MonoAotOptions {
} MonoAotOptions;
typedef struct MonoAotCompile {
+ MonoImage *image;
FILE *fp;
GHashTable *icall_hash;
GPtrArray *icall_table;
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)
info = g_new0 (MonoAotModule, 1);
info->aot_name = aot_name;
- info->methods = g_hash_table_new (NULL, NULL);
#ifdef MONO_ARCH_HAVE_PIC_AOT
info->got = got;
info->got_size = *got_size_ptr;
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);
g_hash_table_insert (aot_modules, assembly, info);
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 *
mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
guint8 *code = NULL;
guint8 *info;
MonoAotModule *aot_module;
- MonoAotMethod *minfo;
- MonoJitInfo *jinfo;
- MonoMethodHeader *header;
if (!module)
return NULL;
(method->flags & METHOD_ATTRIBUTE_ABSTRACT))
return NULL;
- header = mono_method_get_header (method);
-
aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
g_assert (klass->inited);
/* Non shared AOT code can't be used in other appdomains */
return NULL;
- minfo = 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);
- }
-
- return jinfo;
- }
-
if (aot_module->out_of_date)
return NULL;
if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
+ 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);
+ }
return NULL;
}
MonoClass *klass = method->klass;
MonoJumpInfo *patch_info = NULL;
guint code_len, used_int_regs, used_strings;
- MonoAotMethod *minfo;
MonoJitInfo *jinfo;
- MonoMethodHeader *header = mono_method_get_header (method);
MonoMemPool *mp;
GPtrArray *patches;
int i, pindex, got_index;
gboolean non_got_patches, keep_patches = TRUE;
+ gboolean has_clauses;
char *p;
- minfo = g_new0 (MonoAotMethod, 1);
-
- minfo->domain = domain;
- jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
-
p = (char*)info;
code_len = decode_value (p, &p);
used_int_regs = decode_value (p, &p);
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;
for (i = 0; i < header->num_clauses; ++i) {
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 = decode_value (p, &p);
}
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)
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_PATCH_INFO_INTERNAL_METHOD:
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->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
for (i = 0; i < ji->data.table->table_size; i++)
table [i] = (gpointer)(gssize)decode_value (p, &p);
break;
- case MONO_PATCH_INFO_R4:
- ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
+ 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_R8: {
- ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
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;
jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
#endif
- minfo->info = jinfo;
- g_hash_table_insert (aot_module->methods, method, minfo);
-
return jinfo;
}
*endbuf = buf;
}
+static void
+encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, char *buf, char **endbuf)
+{
+ 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);
+
+ encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
+ *endbuf = buf;
+}
+
static gint
compare_patches (gconstpointer a, gconstpointer b)
{
code = cfg->native_code;
header = mono_method_get_header (method);
- emit_section_change (tmpfp, ".text", 0);
-
/* Make the labels local */
mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
mname_p = g_strdup_printf ("%s_p", mname);
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;
}
case MONO_PATCH_INFO_METHODCONST:
case MONO_PATCH_INFO_METHOD:
- case MONO_PATCH_INFO_METHOD_JUMP: {
- 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);
-
- encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
+ 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;
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);
/* Emit method info */
- emit_section_change (tmpfp, ".text", 1);
emit_label (tmpfp, mname_p);
g_assert (p - buf < buf_size);
g_free (mname_p);
}
+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;
+
+ buf_size = 10240;
+ p = buf = g_malloc (buf_size);
+
+ g_assert (klass);
+
+ mono_class_init (klass);
+
+ /*
+ * 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 (!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);
+
+ 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);
+ }
+ }
+
+ /* Emit the info */
+ label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
+ emit_label (tmpfp, label);
+
+ 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);
+}
+
static gboolean
str_begins_with (const char *str1, const char *str2)
{
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);
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;
}
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:
}
/* 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.