} MonoAotOptions;
typedef struct MonoAotStats {
- int ccount, mcount, lmfcount, abscount, wrappercount, gcount, ocount;
+ int ccount, mcount, lmfcount, abscount, wrappercount, gcount, ocount, genericcount;
int code_size, info_size, ex_info_size, got_size, class_info_size, got_info_size, got_info_offsets_size;
int methods_without_got_slots, direct_calls, all_calls;
int got_slots;
enum {
EMIT_NONE,
EMIT_BYTE,
+ EMIT_WORD,
EMIT_LONG
};
#endif
} MonoAotCompile;
-/* Keep in synch with MonoJumpInfoType */
-static const char* patch_types [] = {
- "bb",
- "abs",
- "label",
- "method",
- "method_jump",
- "method_rel",
- "methodconst",
- "internal_method",
- "switch",
- "exc",
- "exc_name",
- "class",
- "image",
- "field",
- "vtable",
- "class_init",
- "sflda",
- "ldstr",
- "ldtoken",
- "type_from_handle",
- "r4",
- "r8",
- "ip",
- "iid",
- "adjusted_iid",
- "bb_ovf",
- "exc_ovf",
- "wrapper",
- "got_offset",
- "declsec",
- "none"
+#ifdef HAVE_ARRAY_ELEM_INIT
+#define MSGSTRFIELD(line) MSGSTRFIELD1(line)
+#define MSGSTRFIELD1(line) str##line
+static const struct msgstr_t {
+#define PATCH_INFO(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
+#include "patch-info.h"
+#undef PATCH_INFO
+} opstr = {
+#define PATCH_INFO(a,b) b,
+#include "patch-info.h"
+#undef PATCH_INFO
};
+static const gint16 opidx [] = {
+#define PATCH_INFO(a,b) [MONO_PATCH_INFO_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
+#include "patch-info.h"
+#undef PATCH_INFO
+};
+
+static const char*
+get_patch_name (int info)
+{
+ return (const char*)&opstr + opidx [info];
+}
+
+#else
+#define PATCH_INFO(a,b) b,
+static const char* const
+patch_types [MONO_PATCH_INFO_NUM + 1] = {
+#include "patch-info.h"
+ NULL
+};
+
+static const char*
+get_patch_name (int info)
+{
+ return patch_types [info];
+}
+
+#endif
static gboolean
is_got_patch (MonoJumpInfoType patch_type)
acfg->cur_section->cur_offset += sizeof (gpointer);
}
+static void
+emit_int16 (MonoAotCompile *acfg, int value)
+{
+ guint8 *data;
+ emit_ensure_buffer (acfg->cur_section, 2);
+ data = acfg->cur_section->data + acfg->cur_section->cur_offset;
+ acfg->cur_section->cur_offset += 2;
+ /* FIXME: little endian */
+ data [0] = value;
+ data [1] = value >> 8;
+}
+
static void
emit_int32 (MonoAotCompile *acfg, int value)
{
}
}
-static void
+static inline void
+emit_int16 (MonoAotCompile *acfg, int value)
+{
+ if (acfg->mode != EMIT_WORD) {
+ acfg->mode = EMIT_WORD;
+ acfg->col_count = 0;
+ }
+ if ((acfg->col_count++ % 8) == 0)
+ fprintf (acfg->fp, "\n\t.word ");
+ else
+ fprintf (acfg->fp, ", ");
+ fprintf (acfg->fp, "%d", value);
+}
+
+static inline void
emit_int32 (MonoAotCompile *acfg, int value)
{
if (acfg->mode != EMIT_LONG) {
encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
{
if (!klass->type_token) {
+ guint32 token;
+
/* Array class */
g_assert (klass->rank > 0);
- g_assert (klass->element_class->type_token);
encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
encode_value (get_image_index (cfg, klass->image), 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);
+ token = klass->element_class->type_token;
+ if (!token) {
+ /* <Type>[][] */
+ g_assert (klass->element_class->rank);
+ encode_value (0, buf, &buf);
+ encode_value (klass->element_class->rank, buf, &buf);
+ token = klass->element_class->element_class->type_token;
+ }
+ g_assert (mono_metadata_token_code (token) == MONO_TOKEN_TYPE_DEF);
+ encode_value (token - MONO_TOKEN_TYPE_DEF, buf, &buf);
encode_value (klass->rank, buf, &buf);
}
else {
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.
- */
encode_value (image_index, p, &p);
encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
break;
}
+ case MONO_PATCH_INFO_RVA:
case MONO_PATCH_INFO_DECLSEC:
case MONO_PATCH_INFO_LDTOKEN:
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
continue;
}
+ if ((patch_info->type == MONO_PATCH_INFO_METHOD) ||
+ (patch_info->type == MONO_PATCH_INFO_INTERNAL_METHOD) ||
+ (patch_info->type == MONO_PATCH_INFO_WRAPPER) ||
+ (patch_info->type == MONO_PATCH_INFO_CLASS_INIT)) {
+ /* Calls are made through the PLT */
+ patch_info->type = MONO_PATCH_INFO_NONE;
+ continue;
+ }
+
n_patches ++;
}
for (pindex = 0; pindex < patches->len; ++pindex) {
patch_info = g_ptr_array_index (patches, pindex);
if (patch_info->type != MONO_PATCH_INFO_NONE) {
- printf ("\t%s", patch_types [patch_info->type]);
+ printf ("\t%s", get_patch_name (patch_info->type));
if (patch_info->type == MONO_PATCH_INFO_VTABLE)
printf (": %s\n", patch_info->data.klass->name);
else
no_special_static = !mono_class_has_special_static_fields (klass);
- if (1) {
+ if (klass->generic_container) {
+ encode_value (-1, p, &p);
+ } else {
encode_value (klass->vtable_size, p, &p);
encode_value ((no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (klass->nested_classes ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
if (klass->has_cctor)
return;
}
+ if (mono_method_signature (method)->has_type_parameters || method->klass->generic_container) {
+ acfg->stats.genericcount ++;
+ return;
+ }
+
/*
* Since these methods are the only ones which are compiled with
* AOT support, and they are not used by runtime startup/shutdown code,
skip = FALSE;
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
- if (patch_info->type == MONO_PATCH_INFO_ABS) {
+ switch (patch_info->type) {
+ case MONO_PATCH_INFO_ABS:
/* unable to handle this */
//printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
skip = TRUE;
break;
+ default:
+ break;
}
}
return;
}
+ /*
+ * We can't currently handle instantinated generic types/methods
+ * since we save typedef/methoddef tokens, instead of typespec/methodref/methodspec
+ * tokens.
+ */
+ for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
+ switch (patch_info->type) {
+ case MONO_PATCH_INFO_METHOD:
+ case MONO_PATCH_INFO_METHODCONST:
+ /* Methods of instantinated generic types */
+ if (patch_info->data.method->klass->generic_class)
+ skip = TRUE;
+ /* Instantinated generic methods */
+ if (mono_method_signature (patch_info->data.method)->is_inflated)
+ skip = TRUE;
+ break;
+ case MONO_PATCH_INFO_VTABLE:
+ case MONO_PATCH_INFO_CLASS:
+ case MONO_PATCH_INFO_IID:
+ case MONO_PATCH_INFO_ADJUSTED_IID:
+ case MONO_PATCH_INFO_CLASS_INIT:
+ if (patch_info->data.klass->generic_class)
+ skip = TRUE;
+ break;
+ /* FIXME: Add more types of patches */
+ default:
+ break;
+ }
+ }
+
+ if (skip) {
+ acfg->stats.genericcount++;
+ mono_destroy_compile (cfg);
+ return;
+ }
+
skip = FALSE;
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
if (patch_info->type == MONO_PATCH_INFO_METHOD_JUMP) {
case MONO_PATCH_INFO_IID:
case MONO_PATCH_INFO_ADJUSTED_IID:
if (!patch_info->data.klass->type_token)
- if (!patch_info->data.klass->element_class->type_token)
+ if (!patch_info->data.klass->element_class->type_token && !(patch_info->data.klass->element_class->rank && patch_info->data.klass->element_class->element_class->type_token))
skip = TRUE;
break;
default:
res = fscanf (infile, "%32s\n", ver);
if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
printf ("Profile file has wrong version or invalid.\n");
+ fclose (infile);
continue;
}
if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
}
+ fclose (infile);
}
/* Add missing methods */
case MONO_PATCH_INFO_DECLSEC:
case MONO_PATCH_INFO_LDTOKEN:
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+ case MONO_PATCH_INFO_RVA:
get_shared_got_offset (acfg, ji);
break;
default:
emit_label (acfg, symbol);
/* FIXME: Optimize memory usage */
- emit_int32 (acfg, table_size);
+ g_assert (table_size < 65000);
+ emit_int16 (acfg, table_size);
+ g_assert (table->len < 65000);
for (i = 0; i < table->len; ++i) {
ClassNameTableEntry *entry = g_ptr_array_index (table, i);
if (entry == NULL) {
- emit_int32 (acfg, 0);
- emit_int32 (acfg, 0);
+ emit_int16 (acfg, 0);
+ emit_int16 (acfg, 0);
} else {
- emit_int32 (acfg, entry->token);
+ emit_int16 (acfg, mono_metadata_token_index (entry->token));
if (entry->next)
- emit_int32 (acfg, entry->next->index);
+ emit_int16 (acfg, entry->next->index);
else
- emit_int32 (acfg, 0);
+ emit_int16 (acfg, 0);
}
}
}
load_profile_files (acfg);
+#if 0
if (mono_defaults.generic_nullable_class) {
/*
* FIXME: Its hard to skip generic methods or methods which use generics.
printf ("Error: Can't AOT Net 2.0 assemblies.\n");
return 1;
}
+#endif
emit_start (acfg);
printf ("GOT slot distribution:\n");
for (i = 0; i < MONO_PATCH_INFO_NONE; ++i)
if (acfg->stats.got_slot_types [i])
- printf ("\t%s: %d\n", patch_types [i], acfg->stats.got_slot_types [i]);
+ printf ("\t%s: %d\n", get_patch_name (i), acfg->stats.got_slot_types [i]);
return 0;
}