#define SHARED_EXT ".so"
#endif
-#if defined(sparc) || defined(__ppc__)
+#if defined(sparc) || defined(__ppc__) || defined(__MACH__)
#define AS_STRING_DIRECTIVE ".asciz"
#else
/* GNU as */
#define AS_STRING_DIRECTIVE ".string"
#endif
+
+// __MACH__
+// .byte generates 1 byte per expression.
+// .short generates 2 bytes per expression.
+// .long generates 4 bytes per expression.
+// .quad generates 8 bytes per expression.
+
#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
#define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
gboolean metadata_only;
gboolean bind_to_runtime_version;
gboolean full_aot;
+ gboolean no_dlsym;
+ gboolean static_link;
} MonoAotOptions;
typedef struct MonoAotStats {
GHashTable *method_indexes;
MonoCompile **cfgs;
GHashTable *patch_to_plt_offset;
- GHashTable **patch_to_plt_offset_wrapper;
GHashTable *plt_offset_to_patch;
GHashTable *patch_to_shared_got_offset;
GPtrArray *shared_patches;
GHashTable *method_to_cfg;
GHashTable *token_info_hash;
GPtrArray *image_table;
+ GPtrArray *globals;
GList *method_order;
/* Number of trampolines emitted into the AOT file */
guint32 num_aot_trampolines;
MonoMemPool *mempool;
MonoAotStats stats;
int method_index;
+ char *static_linking_symbol;
#ifdef USE_BIN_WRITER
BinSymbol *symbols;
BinSection *sections;
#endif
+static void
+emit_global (MonoAotCompile *acfg, const char *name, gboolean func);
+
static gboolean
is_got_patch (MonoJumpInfoType patch_type)
{
}
static void
-emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
+emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
{
BinSymbol *symbol = g_new0 (BinSymbol, 1);
symbol->name = g_strdup (name);
emit_pointer (MonoAotCompile *acfg, const char *target)
{
BinReloc *reloc;
+
+ if (!target)
+ // FIXME:
+ g_assert_not_reached ();
emit_alignment (acfg, sizeof (gpointer));
reloc = g_new0 (BinReloc, 1);
reloc->val1 = g_strdup (target);
emit_unset_mode (acfg);
#if defined(PLATFORM_WIN32)
fprintf (acfg->fp, ".section %s\n", section_name);
+#elif defined(__MACH__)
+ /* This needs to be made more precise on mach. */
+ fprintf (acfg->fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
#elif defined(sparc) || defined(__arm__)
/* For solaris as, GNU as should accept the same */
fprintf (acfg->fp, ".section \"%s\"\n", section_name);
-#elif defined(__ppc__) && defined(__MACH__)
- /* This needs to be made more precise on mach. */
- fprintf (acfg->fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
#else
fprintf (acfg->fp, "%s %d\n", section_name, subsection_index);
#endif
stype = "object";
emit_unset_mode (acfg);
-#if defined(sparc) || defined(__arm__)
+#if defined(__MACH__)
+
+#elif defined(sparc) || defined(__arm__)
fprintf (acfg->fp, "\t.type %s,#%s\n", name, stype);
#elif defined(PLATFORM_WIN32)
-#elif !(defined(__ppc__) && defined(__MACH__))
- fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
#elif defined(__x86_64__) || defined(__i386__)
fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
+#else
+ fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
#endif
}
static void
-emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
+emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
{
emit_unset_mode (acfg);
#if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
emit_unset_mode (acfg);
emit_alignment (acfg, sizeof (gpointer));
#if defined(__x86_64__)
- fprintf (acfg->fp, "\t.quad %s\n", target);
+ fprintf (acfg->fp, "\t.quad %s\n", target ? target : "0");
#elif defined(sparc) && SIZEOF_VOID_P == 8
- fprintf (acfg->fp, "\t.xword %s\n", target);
+ fprintf (acfg->fp, "\t.xword %s\n", target ? target : "0");
#else
- fprintf (acfg->fp, "\t.long %s\n", target);
+ fprintf (acfg->fp, "\t.long %s\n", target ? target : "0");
#endif
}
acfg->col_count = 0;
}
if ((acfg->col_count++ % 8) == 0)
-#if defined(__arm__)
+#if defined(__MACH__)
+ fprintf (acfg->fp, "\n\t.short ");
+#elif defined(__arm__)
/* FIXME: Use .hword on other archs as well */
fprintf (acfg->fp, "\n\t.hword ");
#else
emit_zero_bytes (MonoAotCompile *acfg, int num)
{
emit_unset_mode (acfg);
+#if defined(__MACH__)
+ fprintf (acfg->fp, "\t.space %d\n", num);
+#else
fprintf (acfg->fp, "\t.skip %d\n", num);
+#endif
}
static int
#else
#define AS_OPTIONS ""
#endif
- command = g_strdup_printf ("as %s %s -o %s.o", AS_OPTIONS, acfg->tmpfname, acfg->tmpfname);
+
+ if (acfg->aot_opts.static_link) {
+ if (acfg->aot_opts.outfile)
+ objfile = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+ else
+ objfile = g_strdup_printf ("%s.o", acfg->image->name);
+ } else {
+ objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
+ }
+ command = g_strdup_printf ("as %s %s -o %s", AS_OPTIONS, acfg->tmpfname, objfile);
printf ("Executing the native assembler: %s\n", command);
if (system (command) != 0) {
g_free (command);
+ g_free (objfile);
return 1;
}
g_free (command);
+ if (acfg->aot_opts.static_link) {
+ printf ("Output file: '%s'.\n", objfile);
+ printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol);
+ g_free (objfile);
+ return 0;
+ }
+
if (acfg->aot_opts.outfile)
outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
else
#elif defined(PLATFORM_WIN32)
command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, acfg->tmpfname);
#else
- command = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, acfg->tmpfname);
+ if (acfg->aot_opts.no_dlsym) {
+ /*
+ * Need to link using gcc so our ctor function gets called.
+ */
+ command = g_strdup_printf ("gcc -shared -o %s %s.o", outfile_name, acfg->tmpfname);
+ } else {
+ command = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, acfg->tmpfname);
+ }
#endif
printf ("Executing the native linker: %s\n", command);
if (system (command) != 0) {
g_free (tmp_outfile_name);
g_free (outfile_name);
g_free (command);
+ g_free (objfile);
return 1;
}
g_free (command);
- objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
unlink (objfile);
- g_free (objfile);
/*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, SHARED_EXT);
printf ("Stripping the binary: %s\n", com);
system (com);
g_free (tmp_outfile_name);
g_free (outfile_name);
+ g_free (objfile);
if (acfg->aot_opts.save_temps)
printf ("Retained input file.\n");
#endif /* ASM_WRITER */
+static void
+emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
+{
+ if (acfg->aot_opts.no_dlsym) {
+ g_ptr_array_add (acfg->globals, g_strdup (name));
+ } else {
+ emit_global_inner (acfg, name, func);
+ }
+}
+
static void
emit_byte (MonoAotCompile *acfg, guint8 val)
{
return 0;
}
+static void
+encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf);
+
+/*
+ * encode_klass_ref:
+ *
+ * Encode a reference to KLASS. We use our home-grown encoding instead of the
+ * standard metadata encoding.
+ */
static void
encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
{
+ guint8 *p = buf;
+
if (klass->generic_class) {
guint32 token;
g_assert (klass->type_token);
/* Find a typespec for a class if possible */
token = find_typespec_for_class (acfg, klass);
if (token) {
- encode_value (token, buf, &buf);
- encode_value (get_image_index (acfg, acfg->image), buf, &buf);
+ encode_value (token, p, &p);
+ encode_value (get_image_index (acfg, acfg->image), p, &p);
} else {
MonoClass *gclass = klass->generic_class->container_class;
MonoGenericInst *inst = klass->generic_class->context.class_inst;
/* Encode it ourselves */
/* Marker */
- encode_value (MONO_TOKEN_TYPE_SPEC, buf, &buf);
- encode_klass_ref (acfg, gclass, buf, &buf);
- encode_value (inst->type_argc, buf, &buf);
+ encode_value (MONO_TOKEN_TYPE_SPEC, p, &p);
+ encode_value (MONO_TYPE_GENERICINST, p, &p);
+ encode_klass_ref (acfg, gclass, p, &p);
+ encode_value (inst->type_argc, p, &p);
for (i = 0; i < inst->type_argc; ++i)
- encode_klass_ref (acfg, mono_class_from_mono_type (inst->type_argv [i]), buf, &buf);
+ encode_klass_ref (acfg, mono_class_from_mono_type (inst->type_argv [i]), p, &p);
}
} else if (klass->type_token) {
g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
- encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
- encode_value (get_image_index (acfg, klass->image), buf, &buf);
+ encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, p, &p);
+ encode_value (get_image_index (acfg, klass->image), p, &p);
+ } else if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR)) {
+ MonoGenericParam *param = klass->byval_arg.data.generic_param;
+
+ /* Marker */
+ encode_value (MONO_TOKEN_TYPE_SPEC, p, &p);
+ encode_value (klass->byval_arg.type, p, &p);
+
+ encode_value (param->num, p, &p);
+
+ g_assert (param->owner);
+ encode_value (param->owner->is_method, p, &p);
+ if (param->owner->is_method)
+ encode_method_ref (acfg, param->owner->owner.method, p, &p);
+ else
+ encode_klass_ref (acfg, param->owner->owner.klass, p, &p);
} else {
/* Array class */
g_assert (klass->rank > 0);
- encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
- encode_value (get_image_index (acfg, klass->image), buf, &buf);
- encode_value (klass->rank, buf, &buf);
- encode_klass_ref (acfg, klass->element_class, buf, &buf);
+ encode_value (MONO_TOKEN_TYPE_DEF, p, &p);
+ encode_value (get_image_index (acfg, klass->image), p, &p);
+ encode_value (klass->rank, p, &p);
+ encode_klass_ref (acfg, klass->element_class, p, &p);
}
- *endbuf = buf;
+ *endbuf = p;
}
static void
encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
{
guint32 token = mono_get_field_token (field);
+ guint8 *p = buf;
- encode_klass_ref (cfg, field->parent, buf, &buf);
+ encode_klass_ref (cfg, field->parent, p, &p);
g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
- encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
- *endbuf = buf;
+ encode_value (token - MONO_TOKEN_FIELD_DEF, p, &p);
+ *endbuf = p;
}
#if 0
}
#endif
+#define MAX_IMAGE_INDEX 250
+
static void
encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
{
guint32 image_index = get_image_index (acfg, method->klass->image);
guint32 token = method->token;
MonoJumpInfoToken *ji;
+ guint8 *p = buf;
- g_assert (image_index < 255);
+ g_assert (image_index < MAX_IMAGE_INDEX);
if (mono_method_signature (method)->is_inflated) {
/*
*/
/* Obtain the token from information recorded by the JIT */
ji = g_hash_table_lookup (acfg->token_info_hash, method);
- g_assert (ji);
- image_index = get_image_index (acfg, ji->image);
- g_assert (image_index < 255);
- token = ji->token;
+ if (!ji) {
+ MonoMethod *declaring;
- /* Marker */
- encode_value ((255 << 24), buf, &buf);
- encode_value (image_index, buf, &buf);
- encode_value (token, buf, &buf);
+ g_assert (method->is_inflated);
+ declaring = ((MonoMethodInflated*)method)->declaring;
+
+ /*
+ * This might be a non-generic method of a generic instance, which doesn't
+ * have a token since the reference is generated by the JIT like
+ * Nullable:Box/Unbox.
+ */
+
+ /* Marker */
+ encode_value ((254 << 24), p, &p);
+ /* Encode the klass */
+ encode_klass_ref (acfg, method->klass, p, &p);
+ /* Encode the method */
+ image_index = get_image_index (acfg, method->klass->image);
+ g_assert (image_index < MAX_IMAGE_INDEX);
+ g_assert (declaring->token);
+ token = declaring->token;
+ g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
+ encode_value (image_index, p, &p);
+ encode_value (token, p, &p);
+ } else {
+ image_index = get_image_index (acfg, ji->image);
+ g_assert (image_index < MAX_IMAGE_INDEX);
+ token = ji->token;
+
+ /* Marker */
+ encode_value ((255 << 24), p, &p);
+ encode_value (image_index, p, &p);
+ encode_value (token, p, &p);
+ }
} else if (token == 0) {
/* This might be a method of a constructed type like int[,].Set */
/* Obtain the token from information recorded by the JIT */
ji = g_hash_table_lookup (acfg->token_info_hash, method);
g_assert (ji);
image_index = get_image_index (acfg, ji->image);
- g_assert (image_index < 255);
+ g_assert (image_index < MAX_IMAGE_INDEX);
token = ji->token;
/* Marker */
- encode_value ((255 << 24), buf, &buf);
- encode_value (image_index, buf, &buf);
- encode_value (token, buf, &buf);
+ encode_value ((255 << 24), p, &p);
+ encode_value (image_index, p, &p);
+ encode_value (token, p, &p);
} else {
g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
- encode_value ((image_index << 24) | mono_metadata_token_index (token), buf, &buf);
+ encode_value ((image_index << 24) | mono_metadata_token_index (token), p, &p);
}
- *endbuf = buf;
+ *endbuf = p;
}
static gint
return 0;
}
-static int
-get_plt_index (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+/*
+ * is_plt_patch:
+ *
+ * Return whenever PATCH_INFO refers to a direct call, and thus requires a
+ * PLT entry.
+ */
+static inline gboolean
+is_plt_patch (MonoJumpInfo *patch_info)
{
- int res = -1;
- int idx;
- GHashTable *hash = acfg->patch_to_plt_offset;
-
switch (patch_info->type) {
case MONO_PATCH_INFO_METHOD:
case MONO_PATCH_INFO_WRAPPER:
case MONO_PATCH_INFO_INTERNAL_METHOD:
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
- case MONO_PATCH_INFO_CLASS_INIT: {
- MonoJumpInfo *new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
- gpointer patch_id = NULL;
+ case MONO_PATCH_INFO_CLASS_INIT:
+ case MONO_PATCH_INFO_RGCTX_FETCH:
+ case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
- /* First check for an existing patch */
- switch (patch_info->type) {
- case MONO_PATCH_INFO_METHOD:
- patch_id = patch_info->data.method;
- break;
- case MONO_PATCH_INFO_INTERNAL_METHOD:
- patch_id = (gpointer)patch_info->data.name;
- break;
- case MONO_PATCH_INFO_CLASS_INIT:
- patch_id = patch_info->data.klass;
- break;
- case MONO_PATCH_INFO_WRAPPER:
- hash = acfg->patch_to_plt_offset_wrapper [patch_info->data.method->wrapper_type];
- if (!hash) {
- acfg->patch_to_plt_offset_wrapper [patch_info->data.method->wrapper_type] = g_hash_table_new (NULL, NULL);
- hash = acfg->patch_to_plt_offset_wrapper [patch_info->data.method->wrapper_type];
- }
- patch_id = patch_info->data.method;
- break;
- case MONO_PATCH_INFO_JIT_ICALL_ADDR:
- /* Each addr should only occur once */
- break;
- default:
- g_assert_not_reached ();
- }
+/*
+ * is_shared_got_patch:
+ *
+ * Return whenever PATCH_INFO refers to a patch which needs a shared GOT
+ * entry.
+ * Keep it in sync with the version in aot-runtime.c.
+ */
+static inline gboolean
+is_shared_got_patch (MonoJumpInfo *patch_info)
+{
+ switch (patch_info->type) {
+ 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_FIELD:
+ case MONO_PATCH_INFO_SFLDA:
+ case MONO_PATCH_INFO_DECLSEC:
+ case MONO_PATCH_INFO_LDTOKEN:
+ case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+ case MONO_PATCH_INFO_RVA:
+ case MONO_PATCH_INFO_METHODCONST:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
- if (patch_id) {
- idx = GPOINTER_TO_UINT (g_hash_table_lookup (hash, patch_id));
- if (idx)
- res = idx;
- else
- g_hash_table_insert (hash, patch_id, GUINT_TO_POINTER (acfg->plt_offset));
- }
+static int
+get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+{
+ int res = -1;
+
+ if (is_plt_patch (patch_info)) {
+ int idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info));
+
+ if (idx) {
+ res = idx;
+ } else {
+ MonoJumpInfo *new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
- if (res == -1) {
res = acfg->plt_offset;
- g_hash_table_insert (acfg->plt_offset_to_patch, GUINT_TO_POINTER (acfg->plt_offset), new_ji);
+ g_hash_table_insert (acfg->plt_offset_to_patch, GUINT_TO_POINTER (res), new_ji);
+ g_hash_table_insert (acfg->patch_to_plt_offset, new_ji, GUINT_TO_POINTER (res));
acfg->plt_offset ++;
}
-
- /* Nullify the patch */
- patch_info->type = MONO_PATCH_INFO_NONE;
-
- return res;
- }
- default:
- return -1;
}
+
+ return res;
}
/**
add_method (acfg, mono_marshal_get_runtime_invoke (method));
}
- /* JIT icall wrappers */
- /* FIXME: locking */
- g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
+ if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
+ /* JIT icall wrappers */
+ /* FIXME: locking */
+ g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
+
+ /* Managed Allocators */
+ nallocators = mono_gc_get_managed_allocator_types ();
+ for (i = 0; i < nallocators; ++i) {
+ m = mono_gc_get_managed_allocator_by_type (i);
+ if (m)
+ add_method (acfg, m);
+ }
- /* Managed Allocators */
- nallocators = mono_gc_get_managed_allocator_types ();
- for (i = 0; i < nallocators; ++i) {
- m = mono_gc_get_managed_allocator_by_type (i);
- if (m)
- add_method (acfg, m);
+ /* stelemref */
+ add_method (acfg, mono_marshal_get_stelemref ());
}
- /* stelemref */
- add_method (acfg, mono_marshal_get_stelemref ());
-
/* remoting-invoke wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
MonoMethod *method;
break;
}
default: {
- int plt_index;
char *direct_call_target;
if (!is_got_patch (patch_info->type))
}
if (!got_only && !direct_call_target) {
- plt_index = get_plt_index (acfg, patch_info);
- if (plt_index != -1) {
+ int plt_offset = get_plt_offset (acfg, patch_info);
+ if (plt_offset != -1) {
/* This patch has a PLT entry, so we must emit a call to the PLT entry */
- direct_call_target = g_strdup_printf (".Lp_%d", plt_index);
+ direct_call_target = g_strdup_printf (".Lp_%d", plt_offset);
+
+ /* Nullify the patch */
+ patch_info->type = MONO_PATCH_INFO_NONE;
}
}
i += 4 - 1;
#endif
#endif
+
+ g_free (direct_call_target);
} else {
got_slot = get_got_offset (acfg, patch_info);
int func_alignment = 16;
MonoMethodHeader *header;
- method = cfg->method;
+ method = cfg->orig_method;
code = cfg->native_code;
header = mono_method_get_header (method);
if (cfg->verbose_level > 0)
g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
+ g_free (symbol);
acfg->stats.code_size += cfg->code_len;
/**
* encode_patch:
*
- * Encode PATCH_INFO into its disk representation. If SHARED is true, encode some types
- * of patches by allocating a GOT entry for them, and encode the GOT offset instead.
+ * Encode PATCH_INFO into its disk representation.
*/
static void
-encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint8 **endbuf, gboolean shared)
+encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint8 **endbuf)
{
guint8 *p = buf;
case MONO_PATCH_INFO_METHOD:
case MONO_PATCH_INFO_METHOD_JUMP:
case MONO_PATCH_INFO_ICALL_ADDR:
+ case MONO_PATCH_INFO_METHOD_RGCTX:
encode_method_ref (acfg, patch_info->data.method, p, &p);
break;
case MONO_PATCH_INFO_INTERNAL_METHOD:
case MONO_PATCH_INFO_DECLSEC:
case MONO_PATCH_INFO_LDTOKEN:
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
- if (shared) {
- guint32 offset = get_got_offset (acfg, patch_info);
- encode_value (offset, p, &p);
- } else {
- encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
- encode_value (patch_info->data.token->token, p, &p);
- }
+ 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;
case MONO_PATCH_INFO_CLASS:
case MONO_PATCH_INFO_IID:
case MONO_PATCH_INFO_ADJUSTED_IID:
- if (shared) {
- guint32 offset = get_got_offset (acfg, patch_info);
- encode_value (offset, p, &p);
- } else {
- encode_klass_ref (acfg, patch_info->data.klass, p, &p);
- }
+ encode_klass_ref (acfg, patch_info->data.klass, p, &p);
break;
case MONO_PATCH_INFO_CLASS_INIT:
case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
break;
case MONO_PATCH_INFO_FIELD:
case MONO_PATCH_INFO_SFLDA:
- if (shared) {
- guint32 offset = get_got_offset (acfg, patch_info);
- encode_value (offset, p, &p);
- } else {
- encode_field_info (acfg, patch_info->data.field, p, &p);
- }
+ encode_field_info (acfg, patch_info->data.field, p, &p);
break;
case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
break;
g_assert_not_reached ();
}
break;
+ case MONO_PATCH_INFO_RGCTX_FETCH: {
+ MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
+
+ encode_method_ref (acfg, entry->method, p, &p);
+ encode_value (entry->in_mrgctx, p, &p);
+ encode_value (entry->info_type, p, &p);
+ encode_value (entry->data->type, p, &p);
+ encode_patch (acfg, entry->data, p, &p);
+ break;
+ }
+ case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+ break;
default:
g_warning ("unable to handle jump info %d", patch_info->type);
g_assert_not_reached ();
for (pindex = 0; pindex < patches->len; ++pindex) {
patch_info = g_ptr_array_index (patches, pindex);
- encode_patch (acfg, patch_info, p, &p, TRUE);
+ if (is_shared_got_patch (patch_info)) {
+ guint32 offset = get_got_offset (acfg, patch_info);
+ encode_value (offset, p, &p);
+ } else {
+ encode_patch (acfg, patch_info, p, &p);
+ }
}
*endbuf = p;
guint8 *p, *buf;
guint32 first_got_offset;
- method = cfg->method;
+ method = cfg->orig_method;
code = cfg->native_code;
header = mono_method_get_header (method);
continue;
}
- if ((patch_info->type == MONO_PATCH_INFO_METHOD) ||
- (patch_info->type == MONO_PATCH_INFO_INTERNAL_METHOD) ||
- (patch_info->type == MONO_PATCH_INFO_JIT_ICALL_ADDR) ||
- (patch_info->type == MONO_PATCH_INFO_WRAPPER) ||
- (patch_info->type == MONO_PATCH_INFO_CLASS_INIT)) {
+ if (is_plt_patch (patch_info)) {
/* Calls are made through the PLT */
patch_info->type = MONO_PATCH_INFO_NONE;
continue;
/* Emit method info */
emit_label (acfg, symbol);
+ g_free (symbol);
g_assert (p - buf < buf_size);
emit_bytes (acfg, buf, p - buf);
g_free (buf);
-
- g_free (symbol);
}
static void
MonoMethodHeader *header;
guint8 *p, *buf, *debug_info;
- method = cfg->method;
+ method = cfg->orig_method;
code = cfg->native_code;
header = mono_method_get_header (method);
/* Emit info */
emit_label (acfg, symbol);
+ g_free (symbol);
g_assert (p - buf < buf_size);
emit_bytes (acfg, buf, p - buf);
g_free (buf);
-
- g_free (symbol);
}
static void
MonoClass *klass = mono_class_get (acfg->image, token);
guint8 *p, *buf;
int i, buf_size;
- char *label;
+ char *symbol;
gboolean no_special_static, cant_encode;
buf_size = 10240 + (klass->vtable_size * 16);
acfg->stats.class_info_size += p - buf;
/* Emit the info */
- label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
- emit_label (acfg, label);
+ symbol = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
+ emit_label (acfg, symbol);
+ g_free (symbol);
g_assert (p - buf < buf_size);
emit_bytes (acfg, buf, p - buf);
plt_info_offsets [i] = p - buf;
encode_value (patch_info->type, p, &p);
- encode_patch (acfg, patch_info, p, &p, FALSE);
+ encode_patch (acfg, patch_info, p, &p);
}
emit_line (acfg);
emit_global (acfg, symbol, TRUE);
emit_alignment (acfg, PAGESIZE);
emit_label (acfg, symbol);
+ g_free (symbol);
#if defined(USE_BIN_WRITER) && defined(__arm__)
/* FIXME: */
/* It is filled up during loading by the AOT loader. */
emit_zero_bytes (acfg, 16);
} else {
- /* Need to make sure this is 5 bytes long */
+ /* Need to make sure this is 9 bytes long */
emit_byte (acfg, '\xe9');
- label = g_strdup_printf (".Lpd_%d", i);
- emit_symbol_diff (acfg, label, ".", -4);
- g_free (label);
+ emit_symbol_diff (acfg, "plt", ".", -4);
+ emit_int32 (acfg, plt_info_offsets [i]);
}
#elif defined(__x86_64__)
/*
* point to .Lpd entries. ELF stores these in the GOT too, but we don't, since
* methods with GOT entries can't be called directly.
* We also emit the default PLT code here since the PLT code will not be patched.
- * An x86_64 plt entry is 16 bytes long, init_plt () depends on this.
+ * An x86_64 plt entry is 10 bytes long, init_plt () depends on this.
*/
/* jmpq *<offset>(%rip) */
emit_byte (acfg, '\xff');
emit_byte (acfg, '\x25');
emit_symbol_diff (acfg, "plt_jump_table", ".", (i * sizeof (gpointer)) -4);
- /* mov <plt info offset>, %eax */
- emit_byte (acfg, '\xb8');
+ /* Used by mono_aot_get_plt_info_offset */
emit_int32 (acfg, plt_info_offsets [i]);
- /* jmp .Lp_0 */
- emit_byte (acfg, '\xe9');
- emit_symbol_diff (acfg, ".Lp_0", ".", -4);
#elif defined(__arm__)
- /*
- * Emit an indirect call since branch displacements are limited to 24 bits on
- * ARM. Put the jump table entries inline since offsets are even smaller on
- * ARM.
- * FIXME:
+ /* FIXME:
* - optimize OP_AOTCONST implementation
* - optimize the PLT entries
* - optimize SWITCH AOT implementation
fprintf (acfg->fp, "\tldr pc, [ip, #0]\n");
emit_symbol_diff (acfg, "plt_jump_table", ".", 0);
/* Used by mono_aot_get_plt_info_offset */
+ #if defined(__MACH__)
+ fprintf (acfg->fp, "\n\t.long %d\n", plt_info_offsets [i]);
+ #else
fprintf (acfg->fp, "\n\t.word %d\n", plt_info_offsets [i]);
+ #endif
+
#else
g_assert_not_reached ();
#endif
}
+ g_free (plt_info_offsets);
+
symbol = g_strdup_printf ("plt_end");
emit_global (acfg, symbol, TRUE);
emit_label (acfg, symbol);
-
- /*
- * Emit the default targets for the PLT entries separately since these will not
- * be modified at runtime.
- */
- for (i = 1; i < acfg->plt_offset; ++i) {
- char *label;
-
- label = g_strdup_printf (".Lpd_%d", i);
- emit_label (acfg, label);
- g_free (label);
-
- /* Put the offset into the register expected by mono_aot_plt_trampoline */
-#if defined(__i386__)
- /* movl $const, %eax */
- emit_byte (acfg, '\xb8');
- emit_int32 (acfg, plt_info_offsets [i]);
- /* jmp .Lp_0 */
- emit_byte (acfg, '\xe9');
- emit_symbol_diff (acfg, ".Lp_0", ".", -4);
-#elif defined(__x86_64__)
- /* Emitted along with the PLT entries since they will not be patched */
-#elif defined(__arm__)
- /* Emitted along with the PLT entries since they will not be patched */
-#if 0
- /* This is 12 bytes long, init_plt () depends on this */
- emit_unset_mode (acfg);
- fprintf (acfg->fp, "\tldr ip, [pc, #0]\n");
- fprintf (acfg->fp, "\tb .Lp_0\n");
- fprintf (acfg->fp, "\t.word %d\n", plt_info_offsets [i]);
-#endif
-#else
- g_assert_not_reached ();
-#endif
- }
+ g_free (symbol);
/* Emit PLT info */
symbol = g_strdup_printf ("plt_info");
emit_global (acfg, symbol, FALSE);
emit_label (acfg, symbol);
+ g_free (symbol);
g_assert (p - buf < buf_size);
emit_bytes (acfg, buf, p - buf);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
emit_pointer (acfg, "plt_jump_table");
+ g_free (symbol);
symbol = g_strdup_printf ("plt_jump_table_size");
emit_section_change (acfg, ".data", 0);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
emit_symbol_diff (acfg, "plt_jump_table_end", "plt_jump_table", 0);
+ g_free (symbol);
/* Don't make this a global so accesses don't need relocations */
symbol = g_strdup_printf ("plt_jump_table");
emit_section_change (acfg, ".bss", 0);
emit_label (acfg, symbol);
+ g_free (symbol);
#if defined(__x86_64__) || defined(__arm__)
emit_zero_bytes (acfg, (int)(acfg->plt_offset * sizeof (gpointer)));
symbol = g_strdup_printf ("plt_jump_table_end");
emit_label (acfg, symbol);
+ g_free (symbol);
}
static void
g_assert (acfg->image->assembly);
- /* Currently, we only most trampolines into the mscorlib AOT image. */
+ /* Currently, we only emit most trampolines into the mscorlib AOT image. */
if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
#ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
/*
method = mono_get_method (acfg->image, token, NULL);
cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
- if (!cfg || !cfg->method->klass->valuetype || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ if (!cfg || !cfg->orig_method->klass->valuetype || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL))
continue;
symbol = g_strdup_printf ("unbox_trampoline_%d", i);
emit_global (acfg, symbol, TRUE);
emit_label (acfg, symbol);
- call_target = g_strdup_printf (".Lm_%x", get_method_index (acfg, cfg->method));
+ call_target = g_strdup_printf (".Lm_%x", get_method_index (acfg, cfg->orig_method));
#if defined(__x86_64__)
{
guint8 buf [32];
int this_reg;
- this_reg = mono_arch_get_this_arg_reg (mono_method_signature (cfg->method), cfg->generic_sharing_context, NULL);
+ this_reg = mono_arch_get_this_arg_reg (mono_method_signature (cfg->orig_method), cfg->generic_sharing_context, NULL);
code = buf;
amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
code = buf;
- if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret))
+ if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->orig_method)->ret))
this_pos = 1;
ARM_ADD_REG_IMM8 (code, this_pos, this_pos, sizeof (MonoObject));
opts->bind_to_runtime_version = TRUE;
} else if (str_begins_with (arg, "full")) {
opts->full_aot = TRUE;
+ /*
+ * The no-dlsym option is only useful on the iphone, and even there,
+ * do to other limitations of the dynamic linker, it doesn't seem to
+ * work. So disable it for now so we don't have to support it.
+ */
+ /*
+ } else if (str_begins_with (arg, "no-dlsym")) {
+ opts->no_dlsym = TRUE;
+ */
+ } else if (str_begins_with (arg, "static")) {
+ opts->static_link = TRUE;
+ opts->no_dlsym = TRUE;
} else {
fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
exit (1);
}
}
+
+ g_strfreev (args);
}
static void
//acfg->opts &= ~MONO_OPT_GSHARED;
// FIXME: GSHARED is on by default
+#if 1
if (TRUE || !(acfg->opts & MONO_OPT_GSHARED)) {
if (method->is_generic || method->klass->generic_container) {
acfg->stats.genericcount ++;
return;
}
}
+#endif
if (acfg->aot_opts.full_aot)
mono_use_imt = FALSE;
return;
}
+ /* Convert method patches referring to wrapper methods to MONO_PATCH_INFO_WRAPPER */
skip = FALSE;
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
- if (patch_info->type == MONO_PATCH_INFO_METHOD_JUMP) {
- /*
- * FIXME: We can't handle this because mono_jit_compile_method_inner will try
- * to patch the AOT code when the target of the jump is compiled.
- */
- skip = TRUE;
- break;
- }
- }
-
- if (skip) {
- acfg->stats.ocount++;
- mono_destroy_compile (cfg);
- return;
- }
-
- /* 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_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) {
+ if ((patch_info->type == MONO_PATCH_INFO_METHODCONST) || (patch_info->type == MONO_PATCH_INFO_METHOD)) {
switch (patch_info->data.method->wrapper_type) {
+ case MONO_WRAPPER_NONE:
+ break;
case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
case MONO_WRAPPER_XDOMAIN_INVOKE:
case MONO_WRAPPER_STFLD:
case MONO_WRAPPER_REMOTING_INVOKE:
patch_info->type = MONO_PATCH_INFO_WRAPPER;
break;
+ default:
+ /* 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 (skip) {
+ acfg->stats.wrappercount++;
+ mono_destroy_compile (cfg);
+ return;
+ }
+
skip = FALSE;
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:
- 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 (). */
if (!g_hash_table_lookup (acfg->token_info_hash, patch_info->data.method))
skip = TRUE;
}
- if (patch_info->data.method->is_inflated && !g_hash_table_lookup (acfg->token_info_hash, patch_info->data.method))
- /* FIXME: Can't encode these */
- skip = TRUE;
+ if (patch_info->data.method->is_inflated && !g_hash_table_lookup (acfg->token_info_hash, patch_info->data.method)) {
+ /*
+ * encode_method_ref () can handle this method if it is not generic
+ * and its class can be encoded.
+ */
+ if (!g_hash_table_lookup (acfg->token_info_hash, patch_info->data.method->klass) || mono_method_get_context (patch_info->data.method)->method_inst) {
+ /* FIXME: Can't encode these */
+ //printf ("Skip (can't encode): %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;
case MONO_PATCH_INFO_VTABLE:
case MONO_PATCH_INFO_CLASS_INIT:
}
if (skip) {
- acfg->stats.wrappercount++;
+ acfg->stats.ocount++;
mono_destroy_compile (cfg);
return;
}
switch (patch_info->type) {
case MONO_PATCH_INFO_GOT_OFFSET:
case MONO_PATCH_INFO_NONE:
- case MONO_PATCH_INFO_METHOD:
- case MONO_PATCH_INFO_INTERNAL_METHOD:
- case MONO_PATCH_INFO_JIT_ICALL_ADDR:
- case MONO_PATCH_INFO_WRAPPER:
break;
case MONO_PATCH_INFO_IMAGE:
- if (patch_info->data.image == acfg->image)
- /* Stored in GOT slot 0 */
- break;
- /* Fall through */
+ /* The assembly is stored in GOT slot 0 */
+ if (patch_info->data.image != acfg->image)
+ cfg->has_got_slots = TRUE;
+ break;
default:
- cfg->has_got_slots = TRUE;
+ if (!is_plt_patch (patch_info))
+ cfg->has_got_slots = TRUE;
break;
}
}
acfg->cfgs [index] = cfg;
- g_hash_table_insert (acfg->method_to_cfg, cfg->method, cfg);
+ g_hash_table_insert (acfg->method_to_cfg, cfg->orig_method, cfg);
acfg->stats.ccount++;
}
while (TRUE) {
tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
- if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
+ if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) {
+ g_free (tmp);
break;
+ }
infile = fopen (tmp, "r");
g_assert (infile);
printf ("Using profile data file '%s'\n", tmp);
+ g_free (tmp);
file_index ++;
MonoCompile *cfg = acfg->cfgs [i];
for (ji = cfg->patch_info; ji; ji = ji->next) {
- switch (ji->type) {
- 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_FIELD:
- case MONO_PATCH_INFO_SFLDA:
- case MONO_PATCH_INFO_DECLSEC:
- case MONO_PATCH_INFO_LDTOKEN:
- case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
- case MONO_PATCH_INFO_RVA:
+ if (is_shared_got_patch (ji))
get_shared_got_offset (acfg, ji);
- break;
- default:
- break;
- }
}
}
}
emit_global (acfg, symbol, TRUE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
for (l = acfg->method_order; l != NULL; l = l->next) {
i = GPOINTER_TO_UINT (l->data);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
symbol = g_strdup_printf ("method_offsets");
emit_section_change (acfg, ".text", 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
symbol = g_strdup_printf (".Lm_%x", i);
emit_symbol_diff (acfg, symbol, "methods", 0);
+ g_free (symbol);
} else {
emit_int32 (acfg, 0xffffffff);
}
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
/* To reduce size of generated assembly code */
symbol = g_strdup_printf ("mi");
emit_label (acfg, symbol);
+ g_free (symbol);
for (l = acfg->method_order; l != NULL; l = l->next) {
i = GPOINTER_TO_UINT (l->data);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
symbol = g_strdup_printf (".Lm_%x_p", i);
emit_symbol_diff (acfg, symbol, "mi", 0);
+ g_free (symbol);
} else {
emit_int32 (acfg, 0);
}
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
if (!acfg->aot_opts.full_aot)
return;
for (i = 0; i < acfg->nmethods; ++i) {
MonoCompile *cfg = acfg->cfgs [i];
- if (!cfg || !cfg->method->wrapper_type)
+ if (!cfg || !cfg->orig_method->wrapper_type)
continue;
- index = get_method_index (acfg, cfg->method);
+ index = get_method_index (acfg, cfg->orig_method);
// FIXME: Optimize disk usage and lookup speed
- name = mono_method_full_name (cfg->method, TRUE);
+ name = mono_method_full_name (cfg->orig_method, TRUE);
emit_string (acfg, name);
emit_alignment (acfg, 4);
emit_int32 (acfg, index);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
/* First emit an index table */
index = 0;
emit_section_change (acfg, ".text", 1);
emit_global (acfg, symbol, FALSE);
emit_label (acfg, symbol);
+ g_free (symbol);
}
static void
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
/* To reduce size of generated assembly */
symbol = g_strdup_printf ("ex");
emit_label (acfg, symbol);
+ g_free (symbol);
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i])
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
symbol = g_strdup_printf (".Le_%x_p", i);
emit_symbol_diff (acfg, symbol, "ex", 0);
+ g_free (symbol);
} else {
emit_int32 (acfg, 0);
}
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
symbol = g_strdup_printf (".LK_I_%x", i);
emit_symbol_diff (acfg, symbol, "class_info", 0);
+ g_free (symbol);
}
emit_line (acfg);
}
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
/* FIXME: Optimize memory usage */
g_assert (table_size < 65000);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
+
emit_int32 (acfg, acfg->image_table->len);
for (i = 0; i < acfg->image_table->len; i++) {
MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
/* No need to encode the patch type */
got_info_offsets [i] = p - buf;
- encode_patch (acfg, ji, p, &p, FALSE);
+ encode_patch (acfg, ji, p, &p);
}
g_assert (p - buf <= buf_size);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
emit_bytes (acfg, buf, p - buf);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
for (i = 0; i < acfg->shared_patches->len; ++i)
emit_int32 (acfg, got_info_offsets [i]);
emit_label (acfg, symbol);
if ((acfg->got_offset + acfg->num_trampoline_got_entries) > 0)
emit_zero_bytes (acfg, (int)((acfg->got_offset + acfg->num_trampoline_got_entries) * sizeof (gpointer)));
+ g_free (symbol);
symbol = g_strdup_printf ("got_addr");
emit_section_change (acfg, ".data", 1);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
emit_pointer (acfg, "got");
+ g_free (symbol);
symbol = g_strdup_printf ("got_size");
emit_section_change (acfg, ".data", 1);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
+ g_free (symbol);
}
static void
emit_string_symbol (acfg, "mono_runtime_version", FULL_VERSION);
else
emit_string_symbol (acfg, "mono_runtime_version", "");
+
+ /*
+ * Some platforms like the iphone have no working dlsym (). To work around this,
+ * we create an ELF ctor function which will be invoked by dlopen, and which
+ * will call a function in the AOT loader to register the symbols used by the
+ * image.
+ * When static linking, we emit a global which will point to the symbol table.
+ */
+ if (acfg->aot_opts.no_dlsym) {
+ int i;
+ char *symbol;
+
+ if (acfg->aot_opts.static_link)
+ /* Emit a string holding the assembly name */
+ emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name);
+
+ /* Emit the names */
+ for (i = 0; i < acfg->globals->len; ++i) {
+ char *name = g_ptr_array_index (acfg->globals, i);
+
+ symbol = g_strdup_printf ("name_%d", i);
+ emit_section_change (acfg, ".text", 1);
+ emit_label (acfg, symbol);
+ emit_string (acfg, name);
+ g_free (symbol);
+ }
+
+ /* Emit the globals table */
+ symbol = g_strdup_printf ("globals");
+ emit_section_change (acfg, ".data", 0);
+ /* This is not a global, since it is accessed by the init function */
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+
+ for (i = 0; i < acfg->globals->len; ++i) {
+ char *name = g_ptr_array_index (acfg->globals, i);
+
+ symbol = g_strdup_printf ("name_%d", i);
+ emit_pointer (acfg, symbol);
+ g_free (symbol);
+
+ symbol = g_strdup_printf ("%s", name);
+ emit_pointer (acfg, symbol);
+ g_free (symbol);
+ }
+ /* Null terminate the table */
+ emit_pointer (acfg, NULL);
+ emit_pointer (acfg, NULL);
+
+ if (acfg->aot_opts.static_link) {
+ /*
+ * Emit a global symbol which can be passed by an embedding app to
+ * mono_aot_register_module ().
+ */
+ symbol = g_strdup_printf ("mono_aot_module_%s_info", acfg->image->assembly->aname.name);
+ acfg->static_linking_symbol = g_strdup (symbol);
+ emit_global_inner (acfg, symbol, FALSE);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+ emit_pointer (acfg, "globals");
+ } else {
+ symbol = g_strdup_printf ("init_%s", acfg->image->assembly->aname.name);
+ emit_section_change (acfg, ".text", 1);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+#ifdef USE_BIN_WRITER
+ g_assert_not_reached ();
+#else
+#ifdef __x86_64__
+ fprintf (acfg->fp, "leaq globals(%%rip), %%rdi\n");
+ fprintf (acfg->fp, "call mono_aot_register_globals@PLT\n");
+ fprintf (acfg->fp, "ret\n");
+ fprintf (acfg->fp, ".section .ctors,\"aw\",@progbits\n");
+ emit_alignment (acfg, 8);
+ emit_pointer (acfg, symbol);
+#elif defined(__arm__)
+ /*
+ * Taken from gcc generated code for:
+ * static int i;
+ * void foo () { bar (&i); }
+ * gcc --shared -fPIC -O2
+ */
+ fprintf (acfg->fp, "ldr r3, .L5\n");
+ fprintf (acfg->fp, "ldr r0, .L5+4\n");
+ fprintf (acfg->fp, ".LPIC0:\n");
+ fprintf (acfg->fp, "add r3, pc, r3\n");
+ fprintf (acfg->fp, "add r0, r3, r0\n");
+ fprintf (acfg->fp, "b mono_aot_register_globals(PLT)\n");
+
+ fprintf (acfg->fp, ".L5:\n");
+ fprintf (acfg->fp, ".word _GLOBAL_OFFSET_TABLE_-(.LPIC0+8)\n");
+ fprintf (acfg->fp, ".word globals(GOTOFF)\n");
+
+ fprintf (acfg->fp, ".section .init_array,\"aw\",%%init_array\n");
+ fprintf (acfg->fp, ".align 2\n");
+ fprintf (acfg->fp, ".word %s(target1)\n", symbol);
+#else
+ g_assert_not_reached ();
+#endif
+#endif
+ g_free (symbol);
+ }
+ }
+}
+
+static void
+acfg_free (MonoAotCompile *acfg)
+{
+ int i;
+
+ for (i = 0; i < acfg->nmethods; ++i)
+ if (acfg->cfgs [i])
+ g_free (acfg->cfgs [i]);
+ g_free (acfg->cfgs);
+ g_free (acfg->method_got_offsets);
+ g_free (acfg->static_linking_symbol);
+ g_ptr_array_free (acfg->methods, TRUE);
+ g_ptr_array_free (acfg->shared_patches, TRUE);
+ g_ptr_array_free (acfg->image_table, TRUE);
+ g_ptr_array_free (acfg->globals, TRUE);
+ g_hash_table_destroy (acfg->method_indexes);
+ g_hash_table_destroy (acfg->plt_offset_to_patch);
+ g_hash_table_destroy (acfg->patch_to_plt_offset);
+ g_hash_table_destroy (acfg->patch_to_shared_got_offset);
+ g_hash_table_destroy (acfg->method_to_cfg);
+ g_hash_table_destroy (acfg->token_info_hash);
+ g_hash_table_destroy (acfg->image_hash);
+ mono_mempool_destroy (acfg->mempool);
+ g_free (acfg);
}
int
acfg->methods = g_ptr_array_new ();
acfg->method_indexes = g_hash_table_new (NULL, NULL);
acfg->plt_offset_to_patch = g_hash_table_new (NULL, NULL);
- acfg->patch_to_plt_offset = g_hash_table_new (NULL, NULL);
- acfg->patch_to_plt_offset_wrapper = g_malloc0 (sizeof (GHashTable*) * 128);
+ acfg->patch_to_plt_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
acfg->patch_to_shared_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
acfg->shared_patches = g_ptr_array_new ();
acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
- acfg->token_info_hash = g_hash_table_new (NULL, NULL);
+ acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, g_free);
acfg->image_hash = g_hash_table_new (NULL, NULL);
acfg->image_table = g_ptr_array_new ();
+ acfg->globals = g_ptr_array_new ();
acfg->image = image;
acfg->opts = opts;
acfg->mempool = mono_mempool_new ();
if (acfg->aot_opts.full_aot && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
/* Compile the wrapper instead */
/* We do this here instead of add_wrappers () because it is easy to do it here */
- MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc);
+ MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc, TRUE);
method = wrapper;
}
if (acfg->aot_opts.full_aot)
add_wrappers (acfg);
- acfg->nmethods = acfg->methods->len;
+ acfg->nmethods = acfg->methods->len + 1;
acfg->cfgs = g_new0 (MonoCompile*, acfg->nmethods + 32);
acfg->method_got_offsets = g_new0 (guint32, acfg->nmethods + 32);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ g_free (symbol);
printf ("Code: %d Info: %d Ex Info: %d Class Info: %d PLT: %d GOT Info: %d GOT Info Offsets: %d GOT: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, acfg->stats.got_info_offsets_size, (int)(acfg->got_offset * sizeof (gpointer)));
res = emit_writeout (acfg);
- if (res != 0)
+ if (res != 0) {
+ acfg_free (acfg);
return res;
+ }
printf ("Compiled %d out of %d methods (%d%%)\n", acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100);
- printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
- printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
- printf ("%d methods contain wrapper references (%d%%)\n", acfg->stats.wrappercount, acfg->stats.mcount ? (acfg->stats.wrappercount * 100) / acfg->stats.mcount : 100);
- printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
- printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
+ if (acfg->stats.genericcount)
+ printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
+ if (acfg->stats.abscount)
+ printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
+ if (acfg->stats.wrappercount)
+ printf ("%d methods contain wrapper references (%d%%)\n", acfg->stats.wrappercount, acfg->stats.mcount ? (acfg->stats.wrappercount * 100) / acfg->stats.mcount : 100);
+ if (acfg->stats.lmfcount)
+ printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
+ if (acfg->stats.ocount)
+ printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
printf ("Methods without GOT slots: %d (%d%%)\n", acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100);
printf ("Direct calls: %d (%d%%)\n", acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
if (acfg->stats.got_slot_types [i])
printf ("\t%s: %d\n", get_patch_name (i), acfg->stats.got_slot_types [i]);
+ acfg_free (acfg);
+
return 0;
}