/*
- * aot.c: mono Ahead of Time compiler
+ * aot-compiler.c: mono Ahead of Time compiler
*
* Author:
* Dietmar Maurer (dietmar@ximian.com)
#include <errno.h>
#include <sys/stat.h>
-#include <limits.h> /* for PAGESIZE */
-#ifndef PAGESIZE
-#define PAGESIZE 4096
-#endif
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/class.h>
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/gc-internal.h>
-#include <mono/metadata/method-builder.h>
#include <mono/metadata/monitor.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/mono-endian.h>
-#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/debug-mono-symfile.h>
+#include <mono/metadata/threads-types.h>
#include <mono/utils/mono-logger.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-time.h>
-
-#ifndef PLATFORM_WIN32
-#include <mono/utils/freebsd-elf32.h>
-#include <mono/utils/freebsd-elf64.h>
-#endif
-
-#include <mono/utils/freebsd-dwarf.h>
+#include <mono/utils/mono-mmap.h>
#include "mini.h"
#include "image-writer.h"
+#include "dwarfwriter.h"
-#ifndef DISABLE_AOT
+#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
#define TV_DECLARE(name) gint64 name
#define TV_GETTIME(tv) tv = mono_100ns_ticks ()
gboolean static_link;
gboolean asm_only;
gboolean asm_writer;
+ gboolean nodebug;
int nthreads;
+ int ntrampolines;
gboolean print_skipped_methods;
} MonoAotOptions;
typedef struct MonoAotStats {
int ccount, mcount, lmfcount, abscount, gcount, ocount, genericcount;
- int code_size, info_size, ex_info_size, got_size, class_info_size, got_info_size, got_info_offsets_size;
+ int code_size, info_size, ex_info_size, unwind_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;
int got_slot_types [MONO_PATCH_INFO_NONE];
GPtrArray *globals;
GList *method_order;
guint32 *plt_got_info_offsets;
- /* Number of trampolines emitted into the AOT file */
- guint32 num_aot_trampolines;
guint32 got_offset, plt_offset, plt_got_offset_base;
/* Number of GOT entries reserved for trampolines */
guint32 num_trampoline_got_entries;
- guint32 trampoline_got_offset_base;
+ guint32 num_specific_trampolines;
guint32 specific_trampoline_size;
+ guint32 specific_trampoline_got_offset_base;
+ /* Same for static rgctx trampolines */
+ guint32 num_static_rgctx_trampolines;
+ guint32 static_rgctx_trampoline_size;
+ guint32 static_rgctx_trampoline_got_offset_base;
MonoAotOptions aot_opts;
guint32 nmethods;
guint32 opts;
CRITICAL_SECTION mutex;
gboolean use_bin_writer;
MonoImageWriter *w;
- const char *current_section;
- int current_subsection;
- const char *section_stack [16];
- int subsection_stack [16];
- int stack_pos;
+ MonoDwarfWriter *dwarf;
FILE *fp;
char *tmpfname;
GSList *cie_program;
- /* xdebug */
- GHashTable *class_to_die;
- int fde_index, tdie_index, line_number_file_index, line_number_dir_index;
- GHashTable *file_to_index, *dir_to_index;
- FILE *il_file;
- int il_file_line_index, loclist_index;
+ GHashTable *unwind_info_offsets;
+ GPtrArray *unwind_ops;
+ guint32 unwind_info_offset;
} MonoAotCompile;
#define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
#undef PATCH_INFO
};
-static const char*
+static G_GNUC_UNUSED const char*
get_patch_name (int info)
{
return (const char*)&opstr + opidx [info];
#endif
-static void
-emit_global (MonoAotCompile *acfg, const char *name, gboolean func);
-
/* Wrappers around the image writer functions */
static inline void
/* ARCHITECTURE SPECIFIC CODE */
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM)
#define EMIT_DWARF_INFO 1
#endif
static void
arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
{
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
/* Need to make sure this is exactly 5 bytes long */
emit_byte (acfg, '\xe8');
emit_symbol_diff (acfg, target, ".", -4);
*call_size = 5;
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
if (acfg->use_bin_writer) {
guint8 buf [4];
guint8 *code;
#endif
}
+#ifdef MONO_ARCH_AOT_SUPPORTED
+/*
+ * arch_emit_got_offset:
+ *
+ * The memory pointed to by CODE should hold native code for computing the GOT
+ * address. Emit this code while patching it with the offset between code and
+ * the GOT. CODE_SIZE is set to the number of bytes emitted.
+ */
+static void
+arch_emit_got_offset (MonoAotCompile *acfg, guint8 *code, int *code_size)
+{
+ guint32 offset = mono_arch_get_patch_offset (code);
+ emit_bytes (acfg, code, offset);
+ emit_symbol_diff (acfg, "got", ".", offset);
+
+ *code_size = offset + 4;
+}
+
/*
* arch_emit_got_access:
*
emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
/* Emit the offset */
-#ifdef __x86_64__
+#ifdef TARGET_AMD64
emit_symbol_diff (acfg, "got", ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
-#elif defined(__i386__)
+#elif defined(TARGET_X86)
emit_int32 (acfg, (unsigned int) ((got_slot * sizeof (gpointer))));
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
emit_symbol_diff (acfg, "got", ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12);
#else
g_assert_not_reached ();
*code_size = mono_arch_get_patch_offset (code) + 4;
}
+#endif
+
/*
* arch_emit_plt_entry:
*
static void
arch_emit_plt_entry (MonoAotCompile *acfg, int index)
{
-#if defined(__i386__)
+#if defined(TARGET_X86)
if (index == 0) {
/* It is filled up during loading by the AOT loader. */
emit_zero_bytes (acfg, 16);
emit_symbol_diff (acfg, "plt", ".", -4);
emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
}
-#elif defined(__x86_64__)
+#elif defined(TARGET_AMD64)
/*
* We can't emit jumps because they are 32 bits only so they can't be patched.
* So we make indirect calls through GOT entries which are patched by the AOT
emit_symbol_diff (acfg, "got", ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4);
/* Used by mono_aot_get_plt_info_offset */
emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
guint8 buf [256];
guint8 *code;
* loading the argument from there.
* - all the trampolines should be of the same length.
*/
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
/* This should be exactly 16 bytes long */
*tramp_size = 16;
/* call *<offset>(%rip) */
/* This should be relative to the start of the trampoline */
emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4 + 19);
emit_zero_bytes (acfg, 5);
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
guint8 buf [128];
guint8 *code;
static void
arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGenericSharingContext *gsctx, const char *call_target)
{
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
guint8 buf [32];
guint8 *code;
int this_reg;
/* jump <method> */
emit_byte (acfg, '\xe9');
emit_symbol_diff (acfg, call_target, ".", -4);
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
guint8 buf [128];
guint8 *code;
int this_pos = 0;
emit_bytes (acfg, buf, code - buf);
/* jump to method */
- if (acfg->use_bin_writer)
- g_assert_not_reached ();
- else
+ if (acfg->use_bin_writer) {
+ guint8 buf [4];
+ guint8 *code;
+
+ code = buf;
+ ARM_B (code, 0);
+
+ img_writer_emit_reloc (acfg->w, R_ARM_JUMP24, call_target, -8);
+ emit_bytes (acfg, buf, 4);
+ } else {
fprintf (acfg->fp, "\n\tb %s\n", call_target);
+ }
#else
g_assert_not_reached ();
#endif
}
+/*
+ * arch_emit_static_rgctx_trampoline:
+ *
+ * Emit code for a static rgctx trampoline. OFFSET is the offset of the first of
+ * two GOT slots which contain the rgctx argument, and the method to jump to.
+ * TRAMP_SIZE is set to the size of the emitted trampoline.
+ * These kinds of trampolines cannot be enumerated statically, since there could
+ * be one trampoline per method instantiation, so we emit the same code for all
+ * trampolines, and parameterize them using two GOT slots.
+ */
+static void
+arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+#if defined(TARGET_AMD64)
+ /* This should be exactly 13 bytes long */
+ *tramp_size = 13;
+
+ /* mov <OFFSET>(%rip), %r10 */
+ emit_byte (acfg, '\x4d');
+ emit_byte (acfg, '\x8b');
+ emit_byte (acfg, '\x15');
+ emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4);
+
+ /* jmp *<offset>(%rip) */
+ emit_byte (acfg, '\xff');
+ emit_byte (acfg, '\x25');
+ emit_symbol_diff (acfg, "got", ".", ((offset + 1) * sizeof (gpointer)) - 4);
+#elif defined(TARGET_ARM)
+ guint8 buf [128];
+ guint8 *code;
+
+ /* This should be exactly 24 bytes long */
+ *tramp_size = 24;
+ code = buf;
+ /* Load rgctx value */
+ ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 8);
+ ARM_LDR_REG_REG (code, MONO_ARCH_RGCTX_REG, ARMREG_PC, ARMREG_R1);
+ /* Load branch addr + branch */
+ ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 4);
+ ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_R1);
+
+ g_assert (code - buf == 16);
+
+ /* Emit it */
+ emit_bytes (acfg, buf, code - buf);
+ emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4 + 8);
+ emit_symbol_diff (acfg, "got", ".", ((offset + 1) * sizeof (gpointer)) - 4 + 4);
+#else
+ g_assert_not_reached ();
+#endif
+}
+
/*
* arch_get_cie_program:
*
* Get the unwind bytecode for the DWARF CIE.
*/
static GSList*
-arch_get_cie_program (MonoAotCompile *acfg)
+arch_get_cie_program (void)
{
-#ifdef __x86_64__
+#ifdef TARGET_AMD64
GSList *l = NULL;
mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, AMD64_RSP, 8);
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;
+ MonoGenericContainer *container = mono_type_get_generic_param_owner (&klass->byval_arg);
+ g_assert (container);
/* Marker */
encode_value (MONO_TOKEN_TYPE_SPEC, p, &p);
encode_value (klass->byval_arg.type, p, &p);
- encode_value (param->num, p, &p);
+ encode_value (mono_type_get_generic_param_num (&klass->byval_arg), 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);
+ encode_value (container->is_method, p, &p);
+ if (container->is_method)
+ encode_method_ref (acfg, container->owner.method, p, &p);
else
- encode_klass_ref (acfg, param->owner->owner.klass, p, &p);
+ encode_klass_ref (acfg, container->owner.klass, p, &p);
} else {
/* Array class */
g_assert (klass->rank > 0);
guint32 token = method->token;
MonoJumpInfoToken *ji;
guint8 *p = buf;
+ char *name;
+
+ /*
+ * The encoding for most methods is as follows:
+ * - image index encoded as a leb128
+ * - token index encoded as a leb128
+ * Values of image index >= MONO_AOT_METHODREF_MIN are used to mark additional
+ * types of method encodings.
+ */
- g_assert (image_index < MAX_IMAGE_INDEX);
+ g_assert (image_index < MONO_AOT_METHODREF_MIN);
/* Mark methods which can't use aot trampolines because they need the further
* processing in mono_magic_trampoline () which requires a MonoMethod*.
*/
if ((method->is_generic && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) ||
(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
- encode_value ((252 << 24), p, &p);
+ encode_value ((MONO_AOT_METHODREF_NO_AOT_TRAMPOLINE << 24), p, &p);
+ /*
+ * Some wrapper methods are shared using their signature, encode their
+ * stringified signature instead.
+ * FIXME: Optimize disk usage
+ */
+ name = NULL;
if (method->wrapper_type) {
- /* Marker */
- encode_value ((253 << 24), p, &p);
+ if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
+ char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
+ name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig);
+ g_free (tmpsig);
+ } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
+ char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
+ name = g_strdup_printf ("(wrapper delegate-invoke):%s (%s)", method->name, tmpsig);
+ g_free (tmpsig);
+ } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_BEGIN_INVOKE) {
+ char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
+ name = g_strdup_printf ("(wrapper delegate-begin-invoke):%s (%s)", method->name, tmpsig);
+ g_free (tmpsig);
+ } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_END_INVOKE) {
+ char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
+ name = g_strdup_printf ("(wrapper delegate-end-invoke):%s (%s)", method->name, tmpsig);
+ g_free (tmpsig);
+ }
+ }
+
+ if (name) {
+ encode_value ((MONO_AOT_METHODREF_WRAPPER_NAME << 24), p, &p);
+ strcpy ((char*)p, name);
+ p += strlen (name) + 1;
+ g_free (name);
+ } else if (method->wrapper_type) {
+ encode_value ((MONO_AOT_METHODREF_WRAPPER << 24), p, &p);
encode_value (method->wrapper_type, p, &p);
g_assert_not_reached ();
break;
case MONO_WRAPPER_STATIC_RGCTX_INVOKE:
- case MONO_WRAPPER_SYNCHRONIZED: {
+ case MONO_WRAPPER_SYNCHRONIZED:
+ case MONO_WRAPPER_MANAGED_TO_NATIVE: {
MonoMethod *m;
m = mono_marshal_method_from_wrapper (method);
g_assert (m);
+ g_assert (m != method);
encode_method_ref (acfg, m, p, &p);
break;
}
g_assert (image_index < MAX_IMAGE_INDEX);
token = ji->token;
- /* Marker */
- encode_value ((255 << 24), p, &p);
+ encode_value ((MONO_AOT_METHODREF_METHODSPEC << 24), p, &p);
encode_value (image_index, p, &p);
encode_value (token, p, &p);
} else {
* like Nullable:Box/Unbox, or by generic sharing.
*/
- /* Marker */
- encode_value ((254 << 24), p, &p);
+ encode_value ((MONO_AOT_METHODREF_GINST << 24), p, &p);
/* Encode the klass */
encode_klass_ref (acfg, method->klass, p, &p);
/* Encode the method */
g_assert (image_index < MAX_IMAGE_INDEX);
token = ji->token;
- /* Marker */
- encode_value ((255 << 24), p, &p);
+ encode_value ((MONO_AOT_METHODREF_METHODSPEC << 24), p, &p);
encode_value (image_index, p, &p);
encode_value (token, p, &p);
} else {
g_assert (method->klass->rank);
/* Encode directly */
- /* Marker */
- encode_value ((251 << 24), p, &p);
+ encode_value ((MONO_AOT_METHODREF_ARRAY << 24), p, &p);
encode_klass_ref (acfg, method->klass, p, &p);
if (!strcmp (method->name, ".ctor") && mono_method_signature (method)->param_count == method->klass->rank)
encode_value (0, p, &p);
}
}
-static gboolean
-is_got_patch (MonoJumpInfoType patch_type)
-{
- return TRUE;
-}
-
-/*
- * 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:
- case MONO_PATCH_INFO_IMAGE:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
static int
get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
{
mb = mono_mb_new (mono_defaults.object_class, "FOO", MONO_WRAPPER_NONE);
m = mono_mb_create_method (mb, sig, 16);
- return mono_marshal_get_runtime_invoke (m);
+ return mono_marshal_get_runtime_invoke (m, FALSE);
}
static void
csig->params [1] = &mono_defaults.boolean_class->byval_arg;
add_method (acfg, get_runtime_invoke_sig (csig));
+ /* runtime-invoke used by finalizers */
+ add_method (acfg, mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE));
+
for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
MonoMethod *method;
guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
}
if (!skip)
- add_method (acfg, mono_marshal_get_runtime_invoke (method));
+ add_method (acfg, mono_marshal_get_runtime_invoke (method, FALSE));
}
if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
sig = mono_method_signature (method);
- if (sig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
- !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+ if (sig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class)) {
m = mono_marshal_get_remoting_invoke_with_check (method);
add_method (acfg, m);
add_method (acfg, mono_marshal_get_synchronized_wrapper (method));
}
-#if 0
- /* static rgctx wrappers */
- /* FIXME: Each wrapper belongs to a given instantiation of a generic method */
- for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
- token = MONO_TOKEN_METHOD_DEF | (i + 1);
- method = mono_get_method (acfg->image, token, NULL);
-
- if (((method->flags & METHOD_ATTRIBUTE_STATIC) ||
- (method->is_inflated && mono_method_get_context (method)->method_inst)) &&
- mono_class_generic_sharing_enabled (method->klass) &&
- mono_method_is_generic_sharable_impl (method, FALSE)) {
- m = mono_marshal_get_static_rgctx_invoke (method);
- add_method (acfg, m);
- }
- }
-#endif
-
/* pinvoke wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
MonoMethod *method;
* since rgctx wrappers belong to inflated methods.
*/
method = mono_class_get_cctor (klass);
- if (method)
+ if (method && mono_method_needs_static_rgctx_invoke (method, FALSE))
add_extra_method (acfg, mono_marshal_get_static_rgctx_invoke (method));
iter = NULL;
*/
add_extra_method (acfg, method);
}
+
+ /*
+ * For ICollection<T>, where T is a vtype, add instances of the helper methods
+ * in Array, since a T[] could be cast to ICollection<T>.
+ */
+ if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") &&
+ (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1")) &&
+ MONO_TYPE_ISSTRUCT (klass->generic_class->context.class_inst->type_argv [0])) {
+ MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ MonoClass *array_class = mono_bounded_array_class_get (tclass, 1, FALSE);
+ gpointer iter;
+ char *name_prefix;
+
+ if (!strcmp (klass->name, "IEnumerator`1"))
+ name_prefix = g_strdup_printf ("%s.%s", klass->name_space, "IEnumerable`1");
+ else
+ name_prefix = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
+
+ /* Add the T[]/InternalEnumerator class */
+ if (!strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IEnumerator`1")) {
+ MonoClass *nclass;
+
+ iter = NULL;
+ while ((nclass = mono_class_get_nested_types (array_class->parent, &iter))) {
+ if (!strcmp (nclass->name, "InternalEnumerator`1"))
+ break;
+ }
+ g_assert (nclass);
+ nclass = mono_class_inflate_generic_class (nclass, mono_generic_class_get_context (klass->generic_class));
+ add_generic_class (acfg, nclass);
+ }
+
+ iter = NULL;
+ while ((method = mono_class_get_methods (array_class, &iter))) {
+ if (strstr (method->name, name_prefix))
+ add_extra_method (acfg, method);
+ }
+
+ g_free (name_prefix);
+ }
}
/*
int i;
guint32 token;
MonoMethod *method;
+ MonoMethodHeader *header;
+ MonoMethodSignature *sig;
MonoGenericContext *context;
for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) {
add_generic_class (acfg, klass);
}
+
+ /* Add types of args/locals */
+ for (i = 0; i < acfg->methods->len; ++i) {
+ int j;
+
+ method = g_ptr_array_index (acfg->methods, i);
+
+ sig = mono_method_signature (method);
+
+ if (sig) {
+ for (j = 0; j < sig->param_count; ++j)
+ if (sig->params [j]->type == MONO_TYPE_GENERICINST)
+ add_generic_class (acfg, mono_class_from_mono_type (sig->params [j]));
+ }
+
+ header = mono_method_get_header (method);
+
+ if (header) {
+ for (j = 0; j < header->num_locals; ++j)
+ if (header->locals [j]->type == MONO_TYPE_GENERICINST)
+ add_generic_class (acfg, mono_class_from_mono_type (header->locals [j]));
+ }
+ }
}
/*
case MONO_PATCH_INFO_NONE:
break;
case MONO_PATCH_INFO_GOT_OFFSET: {
- guint32 offset = mono_arch_get_patch_offset (code + i);
- emit_bytes (acfg, code + i, offset);
- emit_symbol_diff (acfg, "got", ".", offset);
-
- i += offset + 4 - 1;
+ int code_size;
+
+ arch_emit_got_offset (acfg, code + i, &code_size);
+ i += code_size - 1;
skip = TRUE;
break;
}
default: {
- if (!is_got_patch (patch_info->type))
- break;
-
/*
* If this patch is a call, try emitting a direct call instead of
* through a PLT entry. This is possible if the called method is in
emit_alignment (acfg, func_alignment);
emit_label (acfg, symbol);
- if (acfg->aot_opts.write_symbols && acfg->use_bin_writer) {
+ if (acfg->aot_opts.write_symbols && !acfg->aot_opts.nodebug && acfg->use_bin_writer) {
char *full_name;
/* Emit a local symbol into the symbol table */
full_name = mono_method_full_name (method, TRUE);
encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int first_got_offset, guint8 *buf, guint8 **endbuf)
{
guint8 *p = buf;
- guint32 last_offset, j, pindex;
+ guint32 pindex;
MonoJumpInfo *patch_info;
encode_value (n_patches, p, &p);
if (n_patches)
encode_value (first_got_offset, p, &p);
- /* First encode 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_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;
-
- /* Only the type is needed */
- *p = patch_info->type;
- p++;
- }
-
- /* Then encode the other info */
- for (pindex = 0; pindex < patches->len; ++pindex) {
- patch_info = g_ptr_array_index (patches, pindex);
-
- if (is_shared_got_patch (patch_info)) {
+ encode_value (patch_info->type, p, &p);
+ if (mono_aot_is_shared_got_patch (patch_info)) {
guint32 offset = get_got_offset (acfg, patch_info);
encode_value (offset, p, &p);
} else {
g_free (buf);
}
+static guint32
+get_unwind_info_offset (MonoAotCompile *acfg, guint8 *encoded, guint32 encoded_len)
+{
+ guint32 cache_index;
+ guint32 offset;
+
+ /* Reuse the unwind module to canonize and store unwind info entries */
+ cache_index = mono_cache_unwind_info (encoded, encoded_len);
+
+ /* Use +/- 1 to distinguish 0s from missing entries */
+ offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->unwind_info_offsets, GUINT_TO_POINTER (cache_index + 1)));
+ if (offset)
+ return offset - 1;
+ else {
+ guint8 buf [16];
+ guint8 *p;
+
+ /*
+ * It would be easier to use assembler symbols, but the caller needs an
+ * offset now.
+ */
+ offset = acfg->unwind_info_offset;
+ g_hash_table_insert (acfg->unwind_info_offsets, GUINT_TO_POINTER (cache_index + 1), GUINT_TO_POINTER (offset + 1));
+ g_ptr_array_add (acfg->unwind_ops, GUINT_TO_POINTER (cache_index));
+
+ p = buf;
+ encode_value (encoded_len, p, &p);
+
+ acfg->unwind_info_offset += encoded_len + (p - buf);
+ return offset;
+ }
+}
+
static void
emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
{
/* Make the labels local */
sprintf (symbol, ".Le_%x_p", method_index);
- mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
+ if (!acfg->aot_opts.nodebug) {
+ mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
+ } else {
+ debug_info = NULL;
+ debug_info_size = 0;
+ }
- buf_size = header->num_clauses * 256 + debug_info_size + 256;
+ buf_size = header->num_clauses * 256 + debug_info_size + 1024;
p = buf = g_malloc (buf_size);
#ifdef MONO_ARCH_HAVE_XP_UNWIND
* section cannot be accessed using the dl interface.
*/
encoded = mono_unwind_ops_encode (cfg->unwind_ops, &encoded_len);
- encode_value (encoded_len, p, &p);
- memcpy (p, encoded, encoded_len);
- p += encoded_len;
+ encode_value (get_unwind_info_offset (acfg, encoded, encoded_len), p, &p);
g_free (encoded);
} else {
encode_value (jinfo->used_regs, p, &p);
emit_section_change (acfg, ".text", 0);
emit_global (acfg, symbol, TRUE);
-#ifdef __i386__
+#ifdef TARGET_X86
/* This section will be made read-write by the AOT loader */
- emit_alignment (acfg, PAGESIZE);
+ emit_alignment (acfg, mono_pagesize ());
#else
emit_alignment (acfg, 16);
#endif
}
static G_GNUC_UNUSED void
-emit_named_code (MonoAotCompile *acfg, const char *name, guint8 *code,
- guint32 code_size, int got_offset, MonoJumpInfo *ji)
+emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
+ guint32 code_size, int got_offset, MonoJumpInfo *ji, GSList *unwind_ops)
{
char symbol [256];
guint32 buf_size;
emit_alignment (acfg, 16);
emit_label (acfg, symbol);
+ sprintf (symbol, ".Lnamed_%s", name);
+ emit_label (acfg, symbol);
+
/*
* The code should access everything through the GOT, so we pass
* TRUE here.
emit_label (acfg, symbol);
emit_bytes (acfg, buf, p - buf);
+
+ /* Emit debug info */
+ if (unwind_ops) {
+ char symbol2 [256];
+
+ sprintf (symbol, "%s", name);
+ sprintf (symbol2, ".Lnamed_%s", name);
+
+ if (acfg->dwarf)
+ mono_dwarf_writer_emit_trampoline (acfg->dwarf, symbol, symbol2, NULL, NULL, code_size, unwind_ops);
+ }
}
/*
emit_trampolines (MonoAotCompile *acfg)
{
char symbol [256];
- int i, offset;
+ int i, tramp_got_offset;
#ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
int tramp_type;
guint32 code_size;
MonoJumpInfo *ji;
guint8 *code;
+ GSList *unwind_ops;
#endif
if (!acfg->aot_opts.full_aot)
* method.
*/
for (tramp_type = 0; tramp_type < MONO_TRAMPOLINE_NUM; ++tramp_type) {
- code = mono_arch_create_trampoline_code_full (tramp_type, &code_size, &ji, TRUE);
+ code = mono_arch_create_trampoline_code_full (tramp_type, &code_size, &ji, &unwind_ops, TRUE);
/* Emit trampoline code */
sprintf (symbol, "generic_trampoline_%d", tramp_type);
- emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, unwind_ops);
}
code = mono_arch_get_nullified_class_init_trampoline (&code_size);
- emit_named_code (acfg, "nullified_class_init_trampoline", code, code_size, acfg->got_offset, NULL);
-#if defined(__x86_64__) && defined(MONO_ARCH_MONITOR_OBJECT_REG)
+ emit_trampoline (acfg, "nullified_class_init_trampoline", code, code_size, acfg->got_offset, NULL, NULL);
+#if defined(TARGET_AMD64) && defined(MONO_ARCH_MONITOR_OBJECT_REG)
code = mono_arch_create_monitor_enter_trampoline_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "monitor_enter_trampoline", code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, "monitor_enter_trampoline", code, code_size, acfg->got_offset, ji, NULL);
code = mono_arch_create_monitor_exit_trampoline_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "monitor_exit_trampoline", code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, "monitor_exit_trampoline", code, code_size, acfg->got_offset, ji, NULL);
#endif
-#if defined(__x86_64__)
code = mono_arch_create_generic_class_init_trampoline_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "generic_class_init_trampoline", code, code_size, acfg->got_offset, ji);
-#endif
+ emit_trampoline (acfg, "generic_class_init_trampoline", code, code_size, acfg->got_offset, ji, NULL);
/* Emit the exception related code pieces */
code = mono_arch_get_restore_context_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "restore_context", code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, "restore_context", code, code_size, acfg->got_offset, ji, NULL);
code = mono_arch_get_call_filter_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "call_filter", code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, "call_filter", code, code_size, acfg->got_offset, ji, NULL);
code = mono_arch_get_throw_exception_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "throw_exception", code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, "throw_exception", code, code_size, acfg->got_offset, ji, NULL);
code = mono_arch_get_rethrow_exception_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "rethrow_exception", code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, "rethrow_exception", code, code_size, acfg->got_offset, ji, NULL);
code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "throw_exception_by_name", code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, "throw_exception_by_name", code, code_size, acfg->got_offset, ji, NULL);
code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji, NULL);
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
code = mono_arch_get_throw_pending_exception_full (&code_size, &ji, TRUE);
- emit_named_code (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji, NULL);
#endif
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(TARGET_AMD64) || defined(TARGET_ARM)
for (i = 0; i < 128; ++i) {
int offset;
offset = MONO_RGCTX_SLOT_MAKE_RGCTX (i);
code = mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset, &code_size, &ji, TRUE);
sprintf (symbol, "rgctx_fetch_trampoline_%u", offset);
- emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
offset = MONO_RGCTX_SLOT_MAKE_MRGCTX (i);
code = mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset, &code_size, &ji, TRUE);
sprintf (symbol, "rgctx_fetch_trampoline_%u", offset);
- emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji);
+ emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
}
#endif
+
+#if defined(TARGET_AMD64) || defined(TARGET_ARM)
+ {
+ GSList *l;
+
+ /* delegate_invoke_impl trampolines */
+ l = mono_arch_get_delegate_invoke_impls ();
+ while (l) {
+ MonoAotTrampInfo *info = l->data;
+
+ emit_trampoline (acfg, info->name, info->code, info->code_size, acfg->got_offset, NULL, NULL);
+ l = l->next;
+ }
+ }
#endif
+#endif /* #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES */
+
/*
* FIXME: Maybe we should use more specific trampolines (i.e. one class init for
* each class).
*/
/* Reserve some entries at the end of the GOT for our use */
- acfg->num_trampoline_got_entries = acfg->num_aot_trampolines * 2;
+ acfg->num_trampoline_got_entries = (acfg->num_specific_trampolines * 2) + (acfg->num_static_rgctx_trampolines * 2);
- sprintf (symbol, "trampolines");
+ sprintf (symbol, "specific_trampolines");
emit_section_change (acfg, ".text", 0);
emit_global (acfg, symbol, TRUE);
emit_alignment (acfg, 16);
emit_label (acfg, symbol);
- for (i = 0; i < acfg->num_aot_trampolines; ++i) {
- int tramp_size = 0;
+ tramp_got_offset = acfg->got_offset;
- offset = acfg->got_offset + (i * 2);
+ acfg->specific_trampoline_got_offset_base = tramp_got_offset;
- arch_emit_specific_trampoline (acfg, offset, &tramp_size);
+ for (i = 0; i < acfg->num_specific_trampolines; ++i) {
+ int tramp_size = 0;
+
+ arch_emit_specific_trampoline (acfg, tramp_got_offset, &tramp_size);
if (!acfg->specific_trampoline_size) {
g_assert (tramp_size);
acfg->specific_trampoline_size = tramp_size;
}
+
+ tramp_got_offset += 2;
+ }
+
+ sprintf (symbol, "static_rgctx_trampolines");
+
+ emit_section_change (acfg, ".text", 0);
+ emit_global (acfg, symbol, TRUE);
+ emit_alignment (acfg, 16);
+ emit_label (acfg, symbol);
+
+ acfg->static_rgctx_trampoline_got_offset_base = tramp_got_offset;
+
+ for (i = 0; i < acfg->num_static_rgctx_trampolines; ++i) {
+ int tramp_size = 0;
+
+ arch_emit_static_rgctx_trampoline (acfg, tramp_got_offset, &tramp_size);
+ if (!acfg->static_rgctx_trampoline_size) {
+ g_assert (tramp_size);
+ acfg->static_rgctx_trampoline_size = tramp_size;
+ }
+
+ tramp_got_offset += 2;
}
}
/* Unbox trampolines */
-
- for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
- MonoMethod *method;
- guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+ for (i = 0; i < acfg->methods->len; ++i) {
+ MonoMethod *method = g_ptr_array_index (acfg->methods, i);
MonoCompile *cfg;
char call_target [256];
- method = mono_get_method (acfg->image, token, NULL);
-
cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
if (!cfg || !cfg->orig_method->klass->valuetype || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL))
continue;
- sprintf (symbol, "unbox_trampoline_%d", i);
+ if (!method->wrapper_type && !method->is_inflated) {
+ g_assert (method->token);
+ sprintf (symbol, "ut_%d", mono_metadata_token_index (method->token) - 1);
+ } else {
+ sprintf (symbol, "ut_e_%d", get_method_index (acfg, method));
+ }
emit_section_change (acfg, ".text", 0);
emit_global (acfg, symbol, TRUE);
arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
}
- acfg->trampoline_got_offset_base = acfg->got_offset;
-
acfg->got_offset += acfg->num_trampoline_got_entries;
}
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, "threads=")) {
opts->nthreads = atoi (arg + strlen ("threads="));
} else if (str_begins_with (arg, "static")) {
opts->asm_only = TRUE;
} else if (str_begins_with (arg, "asmwriter")) {
opts->asm_writer = TRUE;
+ } else if (str_begins_with (arg, "nodebug")) {
+ opts->nodebug = TRUE;
+ } else if (str_begins_with (arg, "ntrampolines=")) {
+ opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
} else {
fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
exit (1);
}
#endif
+ //acfg->aot_opts.print_skipped_methods = TRUE;
+
if (acfg->aot_opts.full_aot)
mono_use_imt = FALSE;
if (m->is_inflated) {
if (!(mono_class_generic_sharing_enabled (m->klass) &&
mono_method_is_generic_sharable_impl (m, FALSE)) &&
- !method_has_type_vars (m))
- add_extra_method (acfg, m);
+ !method_has_type_vars (m)) {
+ if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+ if (acfg->aot_opts.full_aot)
+ add_extra_method (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE));
+ } else {
+ add_extra_method (acfg, m);
+ }
+ }
add_generic_class (acfg, m->klass);
}
break;
MonoCompile *cfg = acfg->cfgs [i];
for (ji = cfg->patch_info; ji; ji = ji->next) {
- if (is_shared_got_patch (ji))
+ if (mono_aot_is_shared_got_patch (ji))
get_shared_got_offset (acfg, ji);
}
}
}
emit_line (acfg);
}
-
-typedef struct HashEntry {
- guint32 key, value, index;
- struct HashEntry *next;
-} HashEntry;
+
+#endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */
/*
- * emit_extra_methods:
+ * mono_aot_str_hash:
*
- * Emit methods which are not in the METHOD table, like wrappers.
+ * Hash function for strings which we use to hash strings for things which are
+ * saved in the AOT image, since g_str_hash () can change.
*/
-static void
-emit_extra_methods (MonoAotCompile *acfg)
+guint
+mono_aot_str_hash (gconstpointer v1)
{
- int i, table_size, buf_size;
- char symbol [256];
- guint8 *p, *buf;
- guint32 *info_offsets;
- guint32 hash;
- GPtrArray *table;
- HashEntry *entry, *new_entry;
- int nmethods;
-
- info_offsets = g_new0 (guint32, acfg->extra_methods->len);
+ /* Same as g_str_hash () in glib */
+ char *p = (char *) v1;
+ guint hash = *p;
- buf_size = acfg->extra_methods->len * 256 + 256;
- p = buf = g_malloc (buf_size);
+ while (*p++) {
+ if (*p)
+ hash = (hash << 5) - hash + *p;
+ }
- /* Encode method info */
- nmethods = 0;
- /* So offsets are > 0 */
- *p = 0;
- p++;
- for (i = 0; i < acfg->extra_methods->len; ++i) {
- MonoMethod *method = g_ptr_array_index (acfg->extra_methods, i);
- MonoCompile *cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
+ return hash;
+}
- if (!cfg)
- continue;
+/*
+ * mono_aot_method_hash:
+ *
+ * Return a hash code for methods which only depends on metadata.
+ */
+guint32
+mono_aot_method_hash (MonoMethod *method)
+{
+ guint32 hash;
- nmethods ++;
+ if (method->wrapper_type) {
+ hash = mono_aot_str_hash (method->name);
+ } else {
+ char *full_name = mono_method_full_name (method, TRUE);
+ // FIXME: Improve this (changing this requires bumping MONO_AOT_FILE_VERSION)
+ hash = mono_aot_str_hash (full_name);
+ g_free (full_name);
+ }
+
+ return hash;
+}
+
+/*
+ * mono_aot_wrapper_name:
+ *
+ * Return a string which uniqely identifies the given wrapper method.
+ */
+char*
+mono_aot_wrapper_name (MonoMethod *method)
+{
+ char *name, *tmpsig, *klass_desc;
+
+ tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
+
+ switch (method->wrapper_type) {
+ case MONO_WRAPPER_RUNTIME_INVOKE:
+ case MONO_WRAPPER_DELEGATE_INVOKE:
+ case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
+ case MONO_WRAPPER_DELEGATE_END_INVOKE:
+ /* This is a hack to work around the fact that runtime invoke wrappers get assigned to some random class */
+ name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
+ break;
+ default:
+ klass_desc = mono_type_full_name (&method->klass->byval_arg);
+
+ name = g_strdup_printf ("%s:%s (%s)", klass_desc, method->name, tmpsig);
+ break;
+ }
+
+ g_free (tmpsig);
+
+ return name;
+}
+
+/*
+ * mono_aot_tramp_info_create:
+ *
+ * Create a MonoAotTrampInfo structure from the arguments.
+ */
+MonoAotTrampInfo*
+mono_aot_tramp_info_create (char *name, guint8 *code, guint32 code_size)
+{
+ MonoAotTrampInfo *info = g_new0 (MonoAotTrampInfo, 1);
+
+ info->name = name;
+ info->code = code;
+ info->code_size = code_size;
+
+ return info;
+}
+
+/*
+ * mono_is_shared_got_patch:
+ *
+ * Return whenever PATCH_INFO refers to a patch which needs a shared GOT
+ * entry.
+ */
+gboolean
+mono_aot_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:
+ case MONO_PATCH_INFO_IMAGE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
+
+typedef struct HashEntry {
+ guint32 key, value, index;
+ struct HashEntry *next;
+} HashEntry;
+
+/*
+ * emit_extra_methods:
+ *
+ * Emit methods which are not in the METHOD table, like wrappers.
+ */
+static void
+emit_extra_methods (MonoAotCompile *acfg)
+{
+ int i, table_size, buf_size;
+ char symbol [256];
+ guint8 *p, *buf;
+ guint32 *info_offsets;
+ guint32 hash;
+ GPtrArray *table;
+ HashEntry *entry, *new_entry;
+ int nmethods, max_chain_length;
+ int *chain_lengths;
+
+ info_offsets = g_new0 (guint32, acfg->extra_methods->len);
+
+ buf_size = acfg->extra_methods->len * 256 + 256;
+ p = buf = g_malloc (buf_size);
+
+ /* Encode method info */
+ nmethods = 0;
+ /* So offsets are > 0 */
+ *p = 0;
+ p++;
+ for (i = 0; i < acfg->extra_methods->len; ++i) {
+ MonoMethod *method = g_ptr_array_index (acfg->extra_methods, i);
+ MonoCompile *cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
+ char *name;
+
+ if (!cfg)
+ continue;
+
+ nmethods ++;
info_offsets [i] = p - buf;
+ name = NULL;
if (method->wrapper_type) {
- char *name;
-
- // FIXME: Optimize disk usage
- if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
- char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
- name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig);
- g_free (tmpsig);
- } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
- char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
- name = g_strdup_printf ("(wrapper delegate-invoke):%s (%s)", method->name, tmpsig);
- g_free (tmpsig);
- } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_BEGIN_INVOKE) {
- char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
- name = g_strdup_printf ("(wrapper delegate-begin-invoke):%s (%s)", method->name, tmpsig);
- g_free (tmpsig);
- } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_END_INVOKE) {
- char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
- name = g_strdup_printf ("(wrapper delegate-end-invoke):%s (%s)", method->name, tmpsig);
- g_free (tmpsig);
- } else {
- name = mono_method_full_name (cfg->orig_method, TRUE);
+ /*
+ * We encode some wrappers using their name, since encoding them
+ * directly would be difficult. This also avoids creating the wrapper
+ * methods at runtime, since they are not needed anyway.
+ */
+ switch (method->wrapper_type) {
+ case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+ case MONO_WRAPPER_SYNCHRONIZED:
+ /* encode_method_ref () can handle these */
+ break;
+ default:
+ name = mono_aot_wrapper_name (method);
+ break;
}
+ }
+ if (name) {
encode_value (1, p, &p);
+ encode_value (method->wrapper_type, p, &p);
strcpy ((char*)p, name);
p += strlen (name ) + 1;
g_free (name);
table = g_ptr_array_sized_new (table_size);
for (i = 0; i < table_size; ++i)
g_ptr_array_add (table, NULL);
+ chain_lengths = g_new0 (int, table_size);
+ max_chain_length = 0;
for (i = 0; i < acfg->extra_methods->len; ++i) {
MonoMethod *method = g_ptr_array_index (acfg->extra_methods, i);
MonoCompile *cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
key = info_offsets [i];
value = get_method_index (acfg, method);
- if (method->wrapper_type) {
- hash = g_str_hash (method->name) % table_size;
- } else {
- // FIXME:
- hash = 0 % table_size;
- }
+ hash = mono_aot_method_hash (method) % table_size;
+
+ chain_lengths [hash] ++;
+ max_chain_length = MAX (max_chain_length, chain_lengths [hash]);
/* FIXME: Allocate from the mempool */
new_entry = g_new0 (HashEntry, 1);
}
}
+ //printf ("MAX: %d\n", max_chain_length);
+
/* Emit the table */
sprintf (symbol, "extra_method_table");
emit_section_change (acfg, ".text", 0);
emit_line (acfg);
}
+static void
+emit_unwind_info (MonoAotCompile *acfg)
+{
+ int i;
+ char symbol [128];
+
+ /*
+ * The unwind info contains a lot of duplicates so we emit each unique
+ * entry once, and only store the offset from the start of the table in the
+ * exception info.
+ */
+
+ sprintf (symbol, "unwind_info");
+ emit_section_change (acfg, ".text", 1);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+ emit_global (acfg, symbol, FALSE);
+
+ for (i = 0; i < acfg->unwind_ops->len; ++i) {
+ guint32 index = GPOINTER_TO_UINT (g_ptr_array_index (acfg->unwind_ops, i));
+ guint8 *unwind_info;
+ guint32 unwind_info_len;
+ guint8 buf [16];
+ guint8 *p;
+
+ unwind_info = mono_get_cached_unwind_info (index, &unwind_info_len);
+
+ p = buf;
+ encode_value (unwind_info_len, p, &p);
+ emit_bytes (acfg, buf, p - buf);
+ emit_bytes (acfg, unwind_info, unwind_info_len);
+
+ acfg->stats.unwind_info_size += (p - buf) + unwind_info_len;
+ }
+}
+
static void
emit_class_info (MonoAotCompile *acfg)
{
token = MONO_TOKEN_TYPE_DEF | (i + 1);
klass = mono_class_get (acfg->image, token);
full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
- hash = g_str_hash (full_name) % table_size;
+ hash = mono_aot_str_hash (full_name) % table_size;
g_free (full_name);
/* FIXME: Allocate from the mempool */
emit_label (acfg, symbol);
if (acfg->got_offset > 0)
emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
+
+ sprintf (symbol, "mono_aot_got_addr");
+ emit_section_change (acfg, ".data", 0);
+ emit_global (acfg, symbol, FALSE);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+ emit_pointer (acfg, "got");
}
static void
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) {
+ if (acfg->aot_opts.static_link) {
int i;
char symbol [256];
+ char *p;
- 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 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) {
emit_pointer (acfg, symbol);
}
/* Null terminate the table */
- emit_pointer (acfg, NULL);
- emit_pointer (acfg, NULL);
-
-#if 0
- if (acfg->aot_opts.static_link) {
- char *p;
+ emit_int32 (acfg, 0);
+ emit_int32 (acfg, 0);
- /*
- * Emit a global symbol which can be passed by an embedding app to
- * mono_aot_register_module ().
- */
+ /*
+ * Emit a global symbol which can be passed by an embedding app to
+ * mono_aot_register_module ().
+ */
#if defined(__MACH__)
- sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name);
+ sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name);
#else
- sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name);
+ sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name);
#endif
- /* Get rid of characters which cannot occur in symbols */
- p = symbol;
- for (p = symbol; *p; ++p) {
- if (!(isalnum (*p) || *p == '_'))
- *p = '_';
- }
- 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 {
- sprintf (symbol, "init_%s", acfg->image->assembly->aname.name);
- emit_section_change (acfg, ".text", 1);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
- if (acfg->use_bin_writer)
- g_assert_not_reached ();
-#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__) && defined(__MACH__)
-
- fprintf (acfg->fp, ".text\n");
- fprintf (acfg->fp, ".align 3\n");
-
- fprintf (acfg->fp, "ldr r0, .L5\n");
- fprintf (acfg->fp, ".LPIC0:\n");
- fprintf (acfg->fp, "add r0, pc, r0\n");
- fprintf (acfg->fp, "ldr r0, [r0]\n");
- fprintf (acfg->fp, "b _mono_aot_register_globals@PLT\n");
- fprintf (acfg->fp, ".align 2\n");
-
- fprintf (acfg->fp, ".L5:\n");
- fprintf (acfg->fp, ".long globals_ptr-(.LPIC0+8)\n");
-
- fprintf (acfg->fp, ".data\n");
- fprintf (acfg->fp, ".align 2\n");
- fprintf (acfg->fp, "globals_ptr:\n");
- fprintf (acfg->fp, ".long globals\n");
-
- fprintf (acfg->fp, ".mod_init_func\n");
- fprintf (acfg->fp, ".align 2\n");
- fprintf (acfg->fp, ".long %s@target1\n", 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
+ /* Get rid of characters which cannot occur in symbols */
+ p = symbol;
+ for (p = symbol; *p; ++p) {
+ if (!(isalnum (*p) || *p == '_'))
+ *p = '_';
}
-#endif
+ 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");
}
}
+static void
+emit_mem_end (MonoAotCompile *acfg)
+{
+ char symbol [128];
+
+ sprintf (symbol, "mem_end");
+ emit_section_change (acfg, ".text", 1);
+ emit_global (acfg, symbol, FALSE);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+}
+
/*
* Emit a structure containing all the information not stored elsewhere.
*/
/* The data emitted here must match MonoAotFileInfo in aot-runtime.c. */
emit_int32 (acfg, acfg->plt_got_offset_base);
- emit_int32 (acfg, acfg->trampoline_got_offset_base);
- emit_int32 (acfg, acfg->num_aot_trampolines);
emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
emit_int32 (acfg, acfg->plt_offset);
+ emit_int32 (acfg, acfg->num_specific_trampolines);
emit_int32 (acfg, acfg->specific_trampoline_size);
- emit_pointer (acfg, "got");
+ emit_int32 (acfg, acfg->specific_trampoline_got_offset_base);
+ emit_int32 (acfg, acfg->num_static_rgctx_trampolines);
+ emit_int32 (acfg, acfg->static_rgctx_trampoline_size);
+ emit_int32 (acfg, acfg->static_rgctx_trampoline_got_offset_base);
}
-/*****************************************/
-/* Emitting DWARF debug information */
-/*****************************************/
-
static void
-emit_dwarf_abbrev (MonoAotCompile *acfg, int code, int tag, gboolean has_child,
- int *attrs, int attrs_len)
+emit_dwarf_info (MonoAotCompile *acfg)
{
+#ifdef EMIT_DWARF_INFO
int i;
+ char symbol [128], symbol2 [128];
- emit_uleb128 (acfg, code);
- emit_uleb128 (acfg, tag);
- emit_byte (acfg, has_child);
-
- for (i = 0; i < attrs_len; i++)
- emit_uleb128 (acfg, attrs [i]);
- emit_uleb128 (acfg, 0);
- emit_uleb128 (acfg, 0);
-}
+ /* DIEs for methods */
+ for (i = 0; i < acfg->nmethods; ++i) {
+ MonoCompile *cfg = acfg->cfgs [i];
-static void
-emit_cie (MonoAotCompile *acfg)
-{
-#ifdef EMIT_DWARF_INFO
- emit_section_change (acfg, ".debug_frame", 0);
+ if (!cfg)
+ continue;
- emit_alignment (acfg, 8);
+ sprintf (symbol, ".Lm_%x", i);
+ sprintf (symbol2, ".Lme_%x", i);
- /* Emit a CIE */
- emit_symbol_diff (acfg, ".Lcie0_end", ".", -4); /* length */
- emit_int32 (acfg, 0xffffffff); /* CIE id */
- emit_byte (acfg, 3); /* version */
- emit_string (acfg, ""); /* augmention */
- emit_sleb128 (acfg, 1); /* code alignment factor */
- emit_sleb128 (acfg, mono_unwind_get_dwarf_data_align ()); /* data alignment factor */
- emit_uleb128 (acfg, mono_unwind_get_dwarf_pc_reg ());
-
- acfg->cie_program = arch_get_cie_program (acfg);
- if (acfg->cie_program) {
- guint32 uw_info_len;
- guint8 *uw_info = mono_unwind_ops_encode (acfg->cie_program, &uw_info_len);
- emit_bytes (acfg, uw_info, uw_info_len);
- g_free (uw_info);
+ mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, symbol, symbol2, NULL, 0, cfg->args, cfg->locals, cfg->unwind_ops, NULL);
}
-
- emit_alignment (acfg, sizeof (gpointer));
- emit_label (acfg, ".Lcie0_end");
#endif
}
static void
-emit_pointer_value (MonoAotCompile *acfg, gpointer ptr)
-{
- gssize val = (gssize)ptr;
- emit_bytes (acfg, (guint8*)&val, sizeof (gpointer));
-}
-
-static void
-emit_fde (MonoAotCompile *acfg, int fde_index, char *start_symbol, char *end_symbol,
- guint8 *code, guint32 code_size, GSList *unwind_ops, gboolean use_cie)
+collect_methods (MonoAotCompile *acfg)
{
-#ifdef EMIT_DWARF_INFO
- char symbol [128];
- GSList *l;
- guint8 *uw_info;
- guint32 uw_info_len;
-
- emit_section_change (acfg, ".debug_frame", 0);
-
- sprintf (symbol, ".Lfde%d_end", fde_index);
- emit_symbol_diff (acfg, symbol, ".", -4); /* length */
- emit_int32 (acfg, 0); /* CIE_pointer */
- if (start_symbol) {
- emit_pointer (acfg, start_symbol); /* initial_location */
- emit_symbol_diff (acfg, end_symbol, start_symbol, 0); /* address_range */
- } else {
- emit_pointer_value (acfg, code);
- emit_int32 (acfg, code_size);
- }
-#if SIZEOF_VOID_P == 8
- /* Upper 32 bits of code size */
- emit_int32 (acfg, 0);
-#endif
-
- l = unwind_ops;
- if (acfg->cie_program) {
- // FIXME: Check that the ops really begin with the CIE program */
- int i;
+ int i;
+ MonoImage *image = acfg->image;
- for (i = 0; i < g_slist_length (acfg->cie_program); ++i)
- l = l->next;
- }
+ /* Collect methods */
+ for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+ MonoMethod *method;
+ guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
- /* Convert the list of MonoUnwindOps to the format used by DWARF */
- uw_info = mono_unwind_ops_encode (l, &uw_info_len);
- emit_bytes (acfg, uw_info, uw_info_len);
- g_free (uw_info);
+ method = mono_get_method (acfg->image, token, NULL);
- emit_alignment (acfg, sizeof (gpointer));
- sprintf (symbol, ".Lfde%d_end", fde_index);
- emit_label (acfg, symbol);
-#endif
-}
+ if (!method) {
+ printf ("Failed to load method 0x%x from '%s'.\n", token, image->name);
+ exit (1);
+ }
+
+ /* Load all methods eagerly to skip the slower lazy loading code */
+ mono_class_setup_methods (method->klass);
-/* Abbrevations */
-#define ABBREV_COMPILE_UNIT 1
-#define ABBREV_SUBPROGRAM 2
-#define ABBREV_PARAM 3
-#define ABBREV_BASE_TYPE 4
-#define ABBREV_STRUCT_TYPE 5
-#define ABBREV_DATA_MEMBER 6
-#define ABBREV_TYPEDEF 7
-#define ABBREV_ENUM_TYPE 8
-#define ABBREV_ENUMERATOR 9
-#define ABBREV_NAMESPACE 10
-#define ABBREV_VARIABLE 11
-#define ABBREV_VARIABLE_LOCLIST 12
-
-static int compile_unit_attr [] = {
- DW_AT_producer ,DW_FORM_string,
- DW_AT_name ,DW_FORM_string,
- DW_AT_comp_dir ,DW_FORM_string,
- DW_AT_language ,DW_FORM_data1,
- DW_AT_low_pc ,DW_FORM_addr,
- DW_AT_high_pc ,DW_FORM_addr,
- DW_AT_stmt_list ,DW_FORM_data4
-};
+ 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, TRUE);
+ method = wrapper;
+ }
-static int subprogram_attr [] = {
- DW_AT_name , DW_FORM_string,
- DW_AT_low_pc , DW_FORM_addr,
- DW_AT_high_pc , DW_FORM_addr,
- DW_AT_frame_base , DW_FORM_block1
-};
+ /* Since we add the normal methods first, their index will be equal to their zero based token index */
+ add_method_with_index (acfg, method, i);
+ acfg->method_index ++;
+ }
-static int param_attr [] = {
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref4,
- DW_AT_location, DW_FORM_block1
-};
+ add_generic_instances (acfg);
-static int base_type_attr [] = {
- DW_AT_byte_size, DW_FORM_data1,
- DW_AT_encoding, DW_FORM_data1,
- DW_AT_name, DW_FORM_string
-};
+ if (acfg->aot_opts.full_aot)
+ add_wrappers (acfg);
+}
-static int struct_type_attr [] = {
- DW_AT_name, DW_FORM_string,
- DW_AT_byte_size, DW_FORM_udata,
-};
+static void
+compile_methods (MonoAotCompile *acfg)
+{
+ int i, methods_len;
-static int data_member_attr [] = {
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref4,
- DW_AT_data_member_location, DW_FORM_block1
-};
+ if (acfg->aot_opts.nthreads > 0) {
+ GPtrArray *frag;
+ int len, j;
+ GPtrArray *threads;
+ HANDLE handle;
+ gpointer *user_data;
+ MonoMethod **methods;
-static int typedef_attr [] = {
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref4
-};
-
-static int enum_type_attr [] = {
- DW_AT_name, DW_FORM_string,
- DW_AT_byte_size, DW_FORM_udata,
- DW_AT_type, DW_FORM_ref4,
-};
-
-static int enumerator_attr [] = {
- DW_AT_name, DW_FORM_string,
- DW_AT_const_value, DW_FORM_sdata,
-};
-
-static int namespace_attr [] = {
- DW_AT_name, DW_FORM_string,
-};
-
-static int variable_attr [] = {
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref4,
- DW_AT_location, DW_FORM_block1
-};
-
-static int variable_loclist_attr [] = {
- DW_AT_name, DW_FORM_string,
- DW_AT_type, DW_FORM_ref4,
- DW_AT_location, DW_FORM_data4
-};
-
-typedef struct DwarfBasicType {
- const char *die_name, *name;
- int type;
- int size;
- int encoding;
-} DwarfBasicType;
-
-static DwarfBasicType basic_types [] = {
- { ".LDIE_I1", "sbyte", MONO_TYPE_I1, 1, DW_ATE_signed },
- { ".LDIE_U1", "byte", MONO_TYPE_U1, 1, DW_ATE_unsigned },
- { ".LDIE_I2", "short", MONO_TYPE_I2, 2, DW_ATE_signed },
- { ".LDIE_U2", "ushort", MONO_TYPE_U2, 2, DW_ATE_unsigned },
- { ".LDIE_I4", "int", MONO_TYPE_I4, 4, DW_ATE_signed },
- { ".LDIE_U4", "uint", MONO_TYPE_U4, 4, DW_ATE_unsigned },
- { ".LDIE_I8", "long", MONO_TYPE_I8, 8, DW_ATE_signed },
- { ".LDIE_U8", "ulong", MONO_TYPE_U8, 8, DW_ATE_unsigned },
- { ".LDIE_I", "intptr", MONO_TYPE_I, SIZEOF_VOID_P, DW_ATE_signed },
- { ".LDIE_U", "uintptr", MONO_TYPE_U, SIZEOF_VOID_P, DW_ATE_unsigned },
- { ".LDIE_R4", "float", MONO_TYPE_R4, 4, DW_ATE_float },
- { ".LDIE_R8", "double", MONO_TYPE_R8, 8, DW_ATE_float },
- { ".LDIE_BOOLEAN", "boolean", MONO_TYPE_BOOLEAN, 1, DW_ATE_boolean },
- { ".LDIE_CHAR", "char", MONO_TYPE_CHAR, 2, DW_ATE_unsigned_char },
- { ".LDIE_STRING", "string", MONO_TYPE_STRING, sizeof (gpointer), DW_ATE_address },
- { ".LDIE_OBJECT", "object", MONO_TYPE_OBJECT, sizeof (gpointer), DW_ATE_address },
- { ".LDIE_SZARRAY", "object", MONO_TYPE_SZARRAY, sizeof (gpointer), DW_ATE_address },
-};
-
-/* Constants for encoding line number special opcodes */
-#define OPCODE_BASE 13
-#define LINE_BASE -5
-#define LINE_RANGE 14
-
-/* Subsections of the .debug_line section */
-#define LINE_SUBSECTION_HEADER 1
-#define LINE_SUBSECTION_INCLUDES 2
-#define LINE_SUBSECTION_FILES 3
-#define LINE_SUBSECTION_DATA 4
-#define LINE_SUBSECTION_END 5
-
-static int
-emit_line_number_file_name (MonoAotCompile *acfg, const char *name,
- gint64 last_mod_time, gint64 file_size)
-{
- int index;
- int dir_index;
- char *basename = NULL;
-
- if (!acfg->file_to_index)
- acfg->file_to_index = g_hash_table_new (g_str_hash, g_str_equal);
-
- index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->file_to_index, name));
- if (index > 0)
- return index;
-
- if (g_path_is_absolute (name)) {
- char *dir = g_path_get_dirname (name);
-
- if (!acfg->dir_to_index)
- acfg->dir_to_index = g_hash_table_new (g_str_hash, g_str_equal);
-
- dir_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->dir_to_index, dir));
- if (dir_index == 0) {
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_INCLUDES);
- emit_string (acfg, dir);
-
- dir_index = ++ acfg->line_number_dir_index;
- g_hash_table_insert (acfg->dir_to_index, g_strdup (dir), GUINT_TO_POINTER (dir_index));
- }
-
- g_free (dir);
-
- basename = g_path_get_basename (name);
- } else {
- dir_index = 0;
- }
-
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_FILES);
-
- if (basename)
- emit_string (acfg, basename);
- else
- emit_string (acfg, name);
- emit_uleb128 (acfg, dir_index);
- emit_byte (acfg, 0);
- emit_byte (acfg, 0);
-
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_DATA);
-
- if (basename)
- g_free (basename);
-
- index = ++ acfg->line_number_file_index;
- g_hash_table_insert (acfg->file_to_index, g_strdup (name), GUINT_TO_POINTER (index));
-
- return index;
-}
-
-static void
-emit_line_number_info_begin (MonoAotCompile *acfg)
-{
- if (acfg->image) {
- /* FIXME: This doesn't seem to work with !xdebug */
- emit_section_change (acfg, ".debug_line", 0);
- emit_label (acfg, ".Ldebug_line_start");
- emit_label (acfg, ".Ldebug_line_section_start");
- return;
- }
-
- /* Line number info header */
- /*
- * GAS seems to emit its own data to the end of the first subsection, so we use
- * subsections 1, 2 etc:
- * 1 - contains the header
- * 2 - contains the file names
- * 3 - contains the end of the header + the data
- * 4 - the end symbol
- */
- emit_section_change (acfg, ".debug_line", 0);
- emit_label (acfg, ".Ldebug_line_section_start");
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_HEADER);
- emit_label (acfg, ".Ldebug_line_start");
- emit_symbol_diff (acfg, ".Ldebug_line_end", ".", -4); /* length */
- emit_int16 (acfg, 0x2); /* version */
- emit_symbol_diff (acfg, ".Ldebug_line_header_end", ".", -4); /* header_length */
- emit_byte (acfg, 1); /* minimum_instruction_length */
- emit_byte (acfg, 1); /* default_is_stmt */
- emit_byte (acfg, LINE_BASE); /* line_base */
- emit_byte (acfg, LINE_RANGE); /* line_range */
- emit_byte (acfg, OPCODE_BASE); /* opcode_base */
- emit_byte (acfg, 0); /* standard_opcode_lengths */
- emit_byte (acfg, 1);
- emit_byte (acfg, 1);
- emit_byte (acfg, 1);
- emit_byte (acfg, 1);
- emit_byte (acfg, 0);
- emit_byte (acfg, 0);
- emit_byte (acfg, 0);
- emit_byte (acfg, 1);
- emit_byte (acfg, 0);
- emit_byte (acfg, 0);
- emit_byte (acfg, 1);
-
- /* Includes */
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_INCLUDES);
-
- /* End of Includes */
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_FILES);
- emit_byte (acfg, 0);
-
- /* Files */
- emit_line_number_file_name (acfg, "xdb.il", 0, 0);
-
- /* End of Files */
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_DATA);
- emit_byte (acfg, 0);
-
- emit_label (acfg, ".Ldebug_line_header_end");
-
- /* Emit this into a separate subsection so it gets placed at the end */
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_END);
-
- emit_byte (acfg, 0);
- emit_byte (acfg, 1);
- emit_byte (acfg, DW_LNE_end_sequence);
-
- emit_label (acfg, ".Ldebug_line_end");
-}
-
-static void
-emit_base_dwarf_info (MonoAotCompile *acfg)
-{
- char *s, *build_info;
- int i;
-
- emit_section_change (acfg, ".debug_abbrev", 0);
- emit_dwarf_abbrev (acfg, ABBREV_COMPILE_UNIT, DW_TAG_compile_unit, TRUE,
- compile_unit_attr, G_N_ELEMENTS (compile_unit_attr));
- emit_dwarf_abbrev (acfg, ABBREV_SUBPROGRAM, DW_TAG_subprogram, TRUE,
- subprogram_attr, G_N_ELEMENTS (subprogram_attr));
- emit_dwarf_abbrev (acfg, ABBREV_PARAM, DW_TAG_formal_parameter, FALSE,
- param_attr, G_N_ELEMENTS (param_attr));
- emit_dwarf_abbrev (acfg, ABBREV_BASE_TYPE, DW_TAG_base_type, FALSE,
- base_type_attr, G_N_ELEMENTS (base_type_attr));
- emit_dwarf_abbrev (acfg, ABBREV_STRUCT_TYPE, DW_TAG_class_type, TRUE,
- struct_type_attr, G_N_ELEMENTS (struct_type_attr));
- emit_dwarf_abbrev (acfg, ABBREV_DATA_MEMBER, DW_TAG_member, FALSE,
- data_member_attr, G_N_ELEMENTS (data_member_attr));
- emit_dwarf_abbrev (acfg, ABBREV_TYPEDEF, DW_TAG_typedef, FALSE,
- typedef_attr, G_N_ELEMENTS (typedef_attr));
- emit_dwarf_abbrev (acfg, ABBREV_ENUM_TYPE, DW_TAG_enumeration_type, TRUE,
- enum_type_attr, G_N_ELEMENTS (enum_type_attr));
- emit_dwarf_abbrev (acfg, ABBREV_ENUMERATOR, DW_TAG_enumerator, FALSE,
- enumerator_attr, G_N_ELEMENTS (enumerator_attr));
- emit_dwarf_abbrev (acfg, ABBREV_NAMESPACE, DW_TAG_namespace, TRUE,
- namespace_attr, G_N_ELEMENTS (namespace_attr));
- emit_dwarf_abbrev (acfg, ABBREV_VARIABLE, DW_TAG_variable, FALSE,
- variable_attr, G_N_ELEMENTS (variable_attr));
- emit_dwarf_abbrev (acfg, ABBREV_VARIABLE_LOCLIST, DW_TAG_variable, FALSE,
- variable_loclist_attr, G_N_ELEMENTS (variable_loclist_attr));
- emit_byte (acfg, 0);
-
- emit_section_change (acfg, ".debug_info", 0);
- emit_label (acfg, ".Ldebug_info_start");
- emit_symbol_diff (acfg, ".Ldebug_info_end", ".", -4); /* length */
- emit_int16 (acfg, 0x3); /* DWARF version 3 */
- emit_int32 (acfg, 0); /* .debug_abbrev offset */
- emit_byte (acfg, sizeof (gpointer)); /* address size */
-
- /* Emit this into a separate section so it gets placed at the end */
- emit_section_change (acfg, ".debug_info", 1);
- emit_int32 (acfg, 0); /* close everything */
- emit_label (acfg, ".Ldebug_info_end");
- emit_section_change (acfg, ".debug_info", 0);
-
- /* Compilation unit */
- emit_uleb128 (acfg, ABBREV_COMPILE_UNIT);
- build_info = mono_get_runtime_build_info ();
- s = g_strdup_printf ("Mono AOT Compiler %s", build_info);
- emit_string (acfg, s);
- g_free (build_info);
- g_free (s);
- emit_string (acfg, "JITted code");
- emit_string (acfg, "");
- emit_byte (acfg, DW_LANG_C);
- emit_pointer_value (acfg, 0);
- emit_pointer_value (acfg, 0);
- /* offset into .debug_line section */
- emit_symbol_diff (acfg, ".Ldebug_line_start", ".Ldebug_line_section_start", 0);
-
- /* Base types */
- for (i = 0; i < G_N_ELEMENTS (basic_types); ++i) {
- emit_label (acfg, basic_types [i].die_name);
- emit_uleb128 (acfg, ABBREV_BASE_TYPE);
- emit_byte (acfg, basic_types [i].size);
- emit_byte (acfg, basic_types [i].encoding);
- emit_string (acfg, basic_types [i].name);
- }
-
- /* debug_loc section */
- emit_section_change (acfg, ".debug_loc", 0);
- emit_label (acfg, ".Ldebug_loc_start");
-
- /* debug_line section */
- emit_line_number_info_begin (acfg);
-
- emit_cie (acfg);
-}
-
-/* Returns the local symbol pointing to the emitted debug info */
-static char*
-emit_class_dwarf_info (MonoAotCompile *acfg, MonoClass *klass)
-{
- char *die;
- char *full_name;
- gpointer iter;
- MonoClassField *field;
- const char *fdie;
- int k;
- gboolean emit_namespace = FALSE;
-
- // FIXME: Appdomains
- if (!acfg->class_to_die)
- acfg->class_to_die = g_hash_table_new (NULL, NULL);
-
- die = g_hash_table_lookup (acfg->class_to_die, klass);
- if (die)
- return die;
-
- if (!((klass->byval_arg.type == MONO_TYPE_CLASS) || klass->enumtype))
- return NULL;
-
- /*
- * FIXME: gdb can't handle namespaces in languages it doesn't know about.
- */
- /*
- if (klass->name_space && klass->name_space [0] != '\0')
- emit_namespace = TRUE;
- */
- if (emit_namespace) {
- emit_uleb128 (acfg, ABBREV_NAMESPACE);
- emit_string (acfg, klass->name_space);
- }
-
- full_name = g_strdup_printf ("%s%s%s", klass->name_space, klass->name_space ? "." : "", klass->name);
-
- die = g_strdup_printf (".LTDIE_%d", acfg->tdie_index);
- emit_label (acfg, die);
-
- if (klass->enumtype) {
- int size = mono_class_value_size (mono_class_from_mono_type (mono_class_enum_basetype (klass)), NULL);
-
- emit_uleb128 (acfg, ABBREV_ENUM_TYPE);
- emit_string (acfg, full_name);
- emit_uleb128 (acfg, size);
- for (k = 0; k < G_N_ELEMENTS (basic_types); ++k)
- if (basic_types [k].type == mono_class_enum_basetype (klass)->type)
- break;
- g_assert (k < G_N_ELEMENTS (basic_types));
- emit_symbol_diff (acfg, basic_types [k].die_name, ".Ldebug_info_start", 0);
-
- /* Emit enum values */
- iter = NULL;
- while ((field = mono_class_get_fields (klass, &iter))) {
- const char *p;
- int len;
- MonoTypeEnum def_type;
-
- if (strcmp ("value__", mono_field_get_name (field)) == 0)
- continue;
- if (mono_field_is_deleted (field))
- continue;
-
- emit_uleb128 (acfg, ABBREV_ENUMERATOR);
- emit_string (acfg, mono_field_get_name (field));
-
- p = mono_class_get_field_default_value (field, &def_type);
- len = mono_metadata_decode_blob_size (p, &p);
- switch (mono_class_enum_basetype (klass)->type) {
- case MONO_TYPE_U1:
- case MONO_TYPE_I1:
- case MONO_TYPE_BOOLEAN:
- emit_sleb128 (acfg, *p);
- break;
- case MONO_TYPE_U2:
- case MONO_TYPE_I2:
- case MONO_TYPE_CHAR:
- emit_sleb128 (acfg, read16 (p));
- break;
- case MONO_TYPE_U4:
- case MONO_TYPE_I4:
- emit_sleb128 (acfg, read32 (p));
- break;
- case MONO_TYPE_U8:
- case MONO_TYPE_I8:
- emit_sleb128 (acfg, read64 (p));
- break;
- case MONO_TYPE_I:
- case MONO_TYPE_U:
-#if SIZEOF_VOID_P == 8
- emit_sleb128 (acfg, read64 (p));
-#else
- emit_sleb128 (acfg, read32 (p));
-#endif
- break;
- default:
- g_assert_not_reached ();
- }
- }
- } else {
- emit_uleb128 (acfg, ABBREV_STRUCT_TYPE);
- emit_string (acfg, full_name);
- emit_uleb128 (acfg, klass->instance_size);
-
- /* Emit fields */
- iter = NULL;
- while ((field = mono_class_get_fields (klass, &iter))) {
- guint8 buf [128];
- guint8 *p;
-
- if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
- continue;
-
- for (k = 0; k < G_N_ELEMENTS (basic_types); ++k)
- if (basic_types [k].type == field->type->type)
- break;
- if (k < G_N_ELEMENTS (basic_types) && field->type->type != MONO_TYPE_SZARRAY && field->type->type != MONO_TYPE_CLASS) {
- fdie = basic_types [k].die_name;
-
- emit_uleb128 (acfg, ABBREV_DATA_MEMBER);
- emit_string (acfg, field->name);
- emit_symbol_diff (acfg, fdie, ".Ldebug_info_start", 0);
- /* location */
- p = buf;
- *p ++= DW_OP_plus_uconst;
- encode_uleb128 (field->offset, p, &p);
-
- emit_byte (acfg, p - buf);
- emit_bytes (acfg, buf, p - buf);
- }
- }
- }
-
- /* Type end */
- emit_uleb128 (acfg, 0x0);
-
- /* Add a typedef, so we can reference the type without a 'struct' in gdb */
- emit_uleb128 (acfg, ABBREV_TYPEDEF);
- emit_string (acfg, full_name);
- emit_symbol_diff (acfg, die, ".Ldebug_info_start", 0);
-
- g_free (full_name);
- acfg->tdie_index ++;
-
-
- if (emit_namespace) {
- /* Namespace end */
- emit_uleb128 (acfg, 0x0);
- }
-
- g_hash_table_insert (acfg->class_to_die, klass, die);
- return die;
-}
-
-static void
-emit_var_type (MonoAotCompile *acfg, MonoType *t)
-{
- MonoClass *klass = mono_class_from_mono_type (t);
- int j;
- const char *tdie;
-
- for (j = 0; j < G_N_ELEMENTS (basic_types); ++j)
- if (basic_types [j].type == t->type)
- break;
- if (j < G_N_ELEMENTS (basic_types))
- tdie = basic_types [j].die_name;
- else {
- switch (t->type) {
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- tdie = ".LDIE_OBJECT";
- break;
- case MONO_TYPE_VALUETYPE:
- if (klass->enumtype)
- tdie = emit_class_dwarf_info (acfg, klass);
- else
- tdie = ".LDIE_I4";
- break;
- default:
- tdie = ".LDIE_I4";
- break;
- }
- }
- if (t->byref)
- // FIXME:
- tdie = ".LDIE_I4";
- emit_symbol_diff (acfg, tdie, ".Ldebug_info_start", 0);
-}
-
-static void
-encode_var_location (MonoAotCompile *acfg, MonoInst *ins, guint8 *p, guint8 **endp)
-{
- /* location */
- /* FIXME: This needs a location list, since the args can go from reg->stack */
- if (!ins || ins->flags & MONO_INST_IS_DEAD) {
- /* gdb treats this as optimized out */
- } else if (ins->opcode == OP_REGVAR) {
- *p = DW_OP_reg0 + mono_hw_reg_to_dwarf_reg (ins->dreg);
- p ++;
- } else if (ins->opcode == OP_REGOFFSET) {
- *p ++= DW_OP_breg0 + mono_hw_reg_to_dwarf_reg (ins->inst_basereg);
- encode_sleb128 (ins->inst_offset, p, &p);
- } else {
- // FIXME:
- *p ++ = DW_OP_reg0;
- }
-
- *endp = p;
-}
-
-static void
-emit_loclist (MonoAotCompile *acfg, MonoInst *ins,
- guint8 *loclist_begin_addr, guint8 *loclist_end_addr,
- guint8 *expr, guint32 expr_len)
-{
- char label [128];
-
- emit_push_section (acfg, ".debug_loc", 0);
- sprintf (label, ".Lloclist_%d", acfg->loclist_index ++ );
- emit_label (acfg, label);
-
- emit_pointer_value (acfg, loclist_begin_addr);
- emit_pointer_value (acfg, loclist_end_addr);
- emit_byte (acfg, expr_len % 256);
- emit_byte (acfg, expr_len / 256);
- emit_bytes (acfg, expr, expr_len);
-
- emit_pointer_value (acfg, NULL);
- emit_pointer_value (acfg, NULL);
-
- emit_pop_section (acfg);
- emit_symbol_diff (acfg, label, ".Ldebug_loc_start", 0);
-}
-
-/*
- * MonoDisHelper->tokener doesn't take an IP argument, and we can't add one since
- * it is a public header.
- */
-static const guint8 *token_handler_ip;
-
-static char*
-token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token)
-{
- char *res, *desc;
-
- if (method->wrapper_type) {
- gpointer data = mono_method_get_wrapper_data (method, token);
-
- switch (*token_handler_ip) {
- case CEE_ISINST:
- case CEE_LDELEMA:
- res = g_strdup_printf ("<%s>", ((MonoClass*)data)->name);
- break;
- case CEE_NEWOBJ:
- case CEE_CALL:
- desc = mono_method_full_name (data, TRUE);
- res = g_strdup_printf ("<%s>", desc);
- g_free (desc);
- break;
- case CEE_CALLI:
- desc = mono_signature_get_desc (data, FALSE);
- res = g_strdup_printf ("<%s>", desc);
- g_free (desc);
- break;
- default:
- res = g_strdup_printf ("<%p>", data);
- }
- } else {
- res = g_strdup_printf ("<0x%08x>", token);
- }
-
- return res;
-}
-
-/*
- * disasm_ins:
- *
- * Produce a disassembled form of the IL instruction at IP. This is an extension
- * of mono_disasm_code_one () which can disasm tokens, handle wrapper methods, and
- * CEE_MONO_ opcodes.
- */
-static char*
-disasm_ins (MonoMethod *method, const guchar *ip, const guint8 **endip)
-{
- char *dis;
- MonoDisHelper dh;
- MonoMethodHeader *header = mono_method_get_header (method);
-
- memset (&dh, 0, sizeof (dh));
- dh.newline = "";
- dh.label_format = "IL_%04x: ";
- dh.label_target = "IL_%04x";
- dh.tokener = token_handler;
-
- token_handler_ip = ip;
- if (*ip == MONO_CUSTOM_PREFIX) {
- guint32 token;
- gpointer data;
-
- switch (ip [1]) {
- case CEE_MONO_ICALL: {
- MonoJitICallInfo *info;
-
- token = read32 (ip + 2);
- data = mono_method_get_wrapper_data (method, token);
- info = mono_find_jit_icall_by_addr (data);
- g_assert (info);
-
- dis = g_strdup_printf ("IL_%04x: mono_icall <%s>", (int)(ip - header->code), info->name);
- ip += 6;
- break;
- }
- case CEE_MONO_CLASSCONST: {
- token = read32 (ip + 2);
- data = mono_method_get_wrapper_data (method, token);
-
- dis = g_strdup_printf ("IL_%04x: mono_classconst <%s>", (int)(ip - header->code), ((MonoClass*)data)->name);
- ip += 6;
- break;
- }
- default:
- dis = mono_disasm_code_one (&dh, method, ip, &ip);
- }
- } else {
- dis = mono_disasm_code_one (&dh, method, ip, &ip);
- }
- token_handler_ip = NULL;
-
- *endip = ip;
- return dis;
-}
-
-static gint32
-il_offset_from_address (MonoMethod *method, MonoDebugMethodJitInfo *jit,
- guint32 native_offset)
-{
- int i;
-
- if (!jit->line_numbers)
- return -1;
-
- for (i = jit->num_line_numbers - 1; i >= 0; i--) {
- MonoDebugLineNumberEntry lne = jit->line_numbers [i];
-
- if (lne.native_offset <= native_offset)
- return lne.il_offset;
- }
-
- return -1;
-}
-
-static int max_special_addr_diff = 0;
-
-static inline void
-emit_advance_op (MonoAotCompile *acfg, int line_diff, int addr_diff)
-{
- gint64 opcode = 0;
-
- /* Use a special opcode if possible */
- if (line_diff - LINE_BASE >= 0 && line_diff - LINE_BASE < LINE_RANGE) {
- if (max_special_addr_diff == 0)
- max_special_addr_diff = (255 - OPCODE_BASE) / LINE_RANGE;
-
- if (addr_diff > max_special_addr_diff && (addr_diff < 2 * max_special_addr_diff)) {
- emit_byte (acfg, DW_LNS_const_add_pc);
- addr_diff -= max_special_addr_diff;
- }
-
- opcode = (line_diff - LINE_BASE) + (LINE_RANGE * addr_diff) + OPCODE_BASE;
- if (opcode > 255)
- opcode = 0;
- }
-
- if (opcode != 0) {
- emit_byte (acfg, opcode);
- } else {
- emit_byte (acfg, DW_LNS_advance_line);
- emit_sleb128 (acfg, line_diff);
- emit_byte (acfg, DW_LNS_advance_pc);
- emit_sleb128 (acfg, addr_diff);
- emit_byte (acfg, DW_LNS_copy);
- }
-}
-
-static void
-emit_line_number_info (MonoAotCompile *acfg, MonoMethod *method, guint8 *code,
- guint32 code_size, MonoDebugMethodJitInfo *debug_info)
-{
- guint32 prev_line = 0;
- guint32 prev_native_offset = 0;
- int i, file_index, il_offset, prev_il_offset;
- gboolean first = TRUE;
- MonoDebugSourceLocation *loc;
- char *prev_file_name = NULL;
- MonoMethodHeader *header = mono_method_get_header (method);
- MonoDebugMethodInfo *minfo;
-
- if (acfg->image)
- // FIXME: The set_address op below only works with xdebug
- return;
-
- minfo = mono_debug_lookup_method (method);
-
- /* FIXME: Avoid quadratic behavior */
-
- prev_line = 1;
- prev_il_offset = -1;
-
- for (i = 0; i < code_size; ++i) {
- if (!minfo)
- continue;
-
- if (!debug_info->line_numbers)
- continue;
+ methods_len = acfg->methods->len;
+ len = acfg->methods->len / acfg->aot_opts.nthreads;
+ g_assert (len > 0);
/*
- * FIXME: Its hard to optimize this, since the line number info is not
- * sorted by il offset or native offset
- */
- il_offset = il_offset_from_address (method, debug_info, i);
-
- if (il_offset < 0)
- continue;
-
- if (il_offset == prev_il_offset)
- continue;
-
- prev_il_offset = il_offset;
-
- loc = mono_debug_symfile_lookup_location (minfo, il_offset);
-
- if (loc) {
- int line_diff = (gint32)loc->row - (gint32)prev_line;
- int addr_diff = i - prev_native_offset;
-
- if (first) {
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_DATA);
-
- emit_byte (acfg, 0);
- emit_byte (acfg, sizeof (gpointer) + 1);
- emit_byte (acfg, DW_LNE_set_address);
- emit_pointer_value (acfg, code);
-
- /*
- * The prolog+initlocals region does not have a line number, this
- * makes them belong to the first line of the method.
- */
- emit_byte (acfg, DW_LNS_advance_line);
- emit_sleb128 (acfg, (gint32)loc->row - (gint32)prev_line);
- prev_line = loc->row;
- }
-
- if (loc->row != prev_line) {
- if (!prev_file_name || strcmp (loc->source_file, prev_file_name) != 0) {
- /* Add an entry to the file table */
- /* FIXME: Avoid duplicates */
- file_index = emit_line_number_file_name (acfg, loc->source_file, 0, 0);
- g_free (prev_file_name);
- prev_file_name = g_strdup (loc->source_file);
-
- emit_byte (acfg, DW_LNS_set_file);
- emit_uleb128 (acfg, file_index);
- emit_byte (acfg, DW_LNS_copy);
- }
-
- //printf ("X: %p(+0x%x) %d %s:%d(+%d)\n", code + i, addr_diff, loc->il_offset, loc->source_file, loc->row, line_diff);
-
- emit_advance_op (acfg, line_diff, addr_diff);
-
- prev_line = loc->row;
- prev_native_offset = i;
- }
-
- first = FALSE;
- g_free (loc);
- }
- }
-
- g_free (prev_file_name);
-
- if (!first) {
- emit_byte (acfg, DW_LNS_advance_pc);
- emit_sleb128 (acfg, code_size - prev_native_offset);
- emit_byte (acfg, DW_LNS_copy);
-
- emit_byte (acfg, 0);
- emit_byte (acfg, 1);
- emit_byte (acfg, DW_LNE_end_sequence);
- } else if (!acfg->image) {
- /* No debug info, XDEBUG mode */
- char *name, *dis;
- const guint8 *ip = header->code;
- int prev_line, prev_native_offset;
- int *il_to_line;
-
- /*
- * Emit the IL code into a temporary file and emit line number info
- * referencing that file.
+ * Partition the list of methods into fragments, and hand it to threads to
+ * process.
*/
-
- name = mono_method_full_name (method, TRUE);
- fprintf (acfg->il_file, "// %s\n", name);
- acfg->il_file_line_index ++;
- g_free (name);
-
- il_to_line = g_new0 (int, header->code_size);
-
- emit_section_change (acfg, ".debug_line", LINE_SUBSECTION_DATA);
- emit_byte (acfg, 0);
- emit_byte (acfg, sizeof (gpointer) + 1);
- emit_byte (acfg, DW_LNE_set_address);
- emit_pointer_value (acfg, code);
-
- // FIXME: Optimize this
- while (ip < header->code + header->code_size) {
- int il_offset = ip - header->code;
-
- /* Emit IL */
- acfg->il_file_line_index ++;
-
- dis = disasm_ins (method, ip, &ip);
- fprintf (acfg->il_file, "%s\n", dis);
- g_free (dis);
-
- il_to_line [il_offset] = acfg->il_file_line_index;
- }
-
- /* Emit line number info */
- prev_line = 0;
- prev_native_offset = 0;
- for (i = 0; i < debug_info->num_line_numbers; ++i) {
- MonoDebugLineNumberEntry *lne = &debug_info->line_numbers [i];
- int line;
-
- if (lne->il_offset >= header->code_size)
- continue;
- line = il_to_line [lne->il_offset];
- g_assert (line);
-
- if (line - prev_line != 0) {
- emit_advance_op (acfg, line - prev_line, (gint32)lne->native_offset - prev_native_offset);
-
- prev_line = line;
- prev_native_offset = lne->native_offset;
- }
- }
-
- emit_byte (acfg, DW_LNS_advance_pc);
- emit_sleb128 (acfg, code_size - prev_native_offset);
- emit_byte (acfg, DW_LNS_copy);
-
- emit_byte (acfg, 0);
- emit_byte (acfg, 1);
- emit_byte (acfg, DW_LNE_end_sequence);
-
- fflush (acfg->il_file);
- g_free (il_to_line);
- }
-}
-
-static void
-emit_method_dwarf_info (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *method, char *start_symbol, char *end_symbol, guint8 *code, guint32 code_size, MonoInst **args, MonoInst **locals, GSList *unwind_info, MonoDebugMethodJitInfo *debug_info)
-{
- char *name;
- MonoMethodSignature *sig;
- MonoMethodHeader *header;
- char **names, **tdies, **local_tdies;
- char **local_names;
- int *local_indexes;
- int i, num_locals;
- guint8 buf [128];
- guint8 *p;
-
- emit_section_change (acfg, ".debug_info", 0);
-
- sig = mono_method_signature (method);
- header = mono_method_get_header (method);
-
- /* Parameter types */
- tdies = g_new0 (char *, sig->param_count + sig->hasthis);
- for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
- MonoType *t;
-
- if (i == 0 && sig->hasthis) {
- t = &method->klass->this_arg;
- } else {
- t = sig->params [i - sig->hasthis];
- }
-
- emit_class_dwarf_info (acfg, mono_class_from_mono_type (t));
- }
-
- /* Local types */
- local_tdies = g_new0 (char *, header->num_locals);
- for (i = 0; i < header->num_locals; ++i) {
- emit_class_dwarf_info (acfg, mono_class_from_mono_type (header->locals [i]));
- }
-
- /* Subprogram */
- names = g_new0 (char *, sig->param_count);
- mono_method_get_param_names (method, (const char **) names);
-
- emit_uleb128 (acfg, ABBREV_SUBPROGRAM);
- name = mono_method_full_name (method, FALSE);
- emit_string (acfg, name);
- g_free (name);
- if (start_symbol) {
- emit_pointer_unaligned (acfg, start_symbol);
- emit_pointer_unaligned (acfg, end_symbol);
- } else {
- emit_pointer_value (acfg, code);
- emit_pointer_value (acfg, code + code_size);
- }
- /* frame_base */
- emit_byte (acfg, 2);
- emit_byte (acfg, DW_OP_breg6);
- emit_byte (acfg, 16);
-
- /* Parameters */
- for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
- MonoInst *arg = args ? args [i] : NULL;
- MonoType *t;
- const char *pname;
- char pname_buf [128];
-
- if (i == 0 && sig->hasthis) {
- t = &mono_defaults.object_class->byval_arg;
- pname = "this";
- } else {
- t = sig->params [i - sig->hasthis];
- pname = names [i - sig->hasthis];
- }
-
- emit_uleb128 (acfg, ABBREV_PARAM);
- /* name */
- if (pname[0] == '\0') {
- sprintf (pname_buf, "param%d", i - sig->hasthis);
- pname = pname_buf;
- }
- emit_string (acfg, pname);
- /* type */
- if (!arg || arg->flags & MONO_INST_IS_DEAD)
- emit_var_type (acfg, &mono_defaults.int32_class->byval_arg);
- else
- emit_var_type (acfg, t);
-
- p = buf;
- encode_var_location (acfg, arg, p, &p);
- emit_byte (acfg, p - buf);
- emit_bytes (acfg, buf, p - buf);
- }
- g_free (names);
-
- /* Locals */
- num_locals = mono_debug_lookup_locals (method, &local_names, &local_indexes);
-
- for (i = 0; i < header->num_locals; ++i) {
- MonoInst *ins = locals [i];
- char name_buf [128];
- int j;
- MonoMethodVar *vmv = NULL;
- gboolean need_loclist = FALSE;
-
- /* ins->dreg no longer contains the original vreg */
- if (cfg->varinfo) {
- for (j = 0; j < cfg->num_varinfo; ++j) {
- if (cfg->varinfo [j] == ins)
- break;
- }
-
- if (code && j < cfg->num_varinfo) {
- vmv = MONO_VARINFO (cfg, j);
- if (vmv->live_range_start) {
- /* This variable has a precise live range */
- need_loclist = TRUE;
+ threads = g_ptr_array_new ();
+ /* Make a copy since acfg->methods is modified by compile_method () */
+ methods = g_new0 (MonoMethod*, methods_len);
+ //memcpy (methods, g_ptr_array_index (acfg->methods, 0), sizeof (MonoMethod*) * methods_len);
+ for (i = 0; i < methods_len; ++i)
+ methods [i] = g_ptr_array_index (acfg->methods, i);
+ i = 0;
+ while (i < methods_len) {
+ frag = g_ptr_array_new ();
+ for (j = 0; j < len; ++j) {
+ if (i < methods_len) {
+ g_ptr_array_add (frag, methods [i]);
+ i ++;
}
}
- }
- if (need_loclist)
- emit_uleb128 (acfg, ABBREV_VARIABLE_LOCLIST);
- else
- emit_uleb128 (acfg, ABBREV_VARIABLE);
- /* name */
- for (j = 0; j < num_locals; ++j)
- if (local_indexes [j] == i)
- break;
- if (j < num_locals) {
- emit_string (acfg, local_names [j]);
- } else {
- sprintf (name_buf, "V_%d", i);
- emit_string (acfg, name_buf);
+ user_data = g_new0 (gpointer, 3);
+ user_data [0] = mono_domain_get ();
+ user_data [1] = acfg;
+ user_data [2] = frag;
+
+ handle = mono_create_thread (NULL, 0, (gpointer)compile_thread_main, user_data, 0, NULL);
+ g_ptr_array_add (threads, handle);
}
- /* type */
- if (!ins || ins->flags & MONO_INST_IS_DEAD)
- emit_var_type (acfg, &mono_defaults.int32_class->byval_arg);
- else
- emit_var_type (acfg, header->locals [i]);
-
- p = buf;
- encode_var_location (acfg, ins, p, &p);
+ g_free (methods);
- if (need_loclist) {
- if (vmv->live_range_end == 0)
- /* FIXME: Uses made in calls are not recorded */
- vmv->live_range_end = code_size;
- emit_loclist (acfg, ins, code + vmv->live_range_start, code + vmv->live_range_end, buf, p - buf);
- } else {
- emit_byte (acfg, p - buf);
- emit_bytes (acfg, buf, p - buf);
+ for (i = 0; i < threads->len; ++i) {
+ WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE);
}
+ } else {
+ methods_len = 0;
}
- g_free (local_names);
- g_free (local_indexes);
-
- /* Subprogram end */
- emit_uleb128 (acfg, 0x0);
-
- emit_line (acfg);
-
- /* Emit unwind info */
- emit_fde (acfg, acfg->fde_index, start_symbol, end_symbol, code, code_size, unwind_info, TRUE);
- acfg->fde_index ++;
-
- /* Emit line number info */
- if (code && debug_info)
- emit_line_number_info (acfg, method, code, code_size, debug_info);
-
- emit_line (acfg);
-}
-
-static void
-emit_trampoline_dwarf_info (MonoAotCompile *acfg, const char *tramp_name, char *start_symbol, char *end_symbol, guint8 *code, guint32 code_size, GSList *unwind_info)
-{
- emit_section_change (acfg, ".debug_info", 0);
-
- /* Subprogram */
- emit_uleb128 (acfg, ABBREV_SUBPROGRAM);
- emit_string (acfg, tramp_name);
- emit_pointer_value (acfg, code);
- emit_pointer_value (acfg, code + code_size);
- /* frame_base */
- emit_byte (acfg, 2);
- emit_byte (acfg, DW_OP_breg6);
- emit_byte (acfg, 16);
-
- /* Subprogram end */
- emit_uleb128 (acfg, 0x0);
-
- /* Emit unwind info */
- emit_fde (acfg, acfg->fde_index, NULL, NULL, code, code_size, unwind_info, FALSE);
- acfg->fde_index ++;
-}
-
-static void
-emit_dwarf_info (MonoAotCompile *acfg)
-{
-#ifdef EMIT_DWARF_INFO
- int i;
- char symbol [128], symbol2 [128];
-
- emit_base_dwarf_info (acfg);
-
- /* DIEs for methods */
- for (i = 0; i < acfg->nmethods; ++i) {
- MonoCompile *cfg = acfg->cfgs [i];
-
- if (!cfg)
- continue;
-
- sprintf (symbol, ".Lm_%x", i);
- sprintf (symbol2, ".Lme_%x", i);
-
- emit_method_dwarf_info (acfg, cfg, cfg->method, symbol, symbol2, NULL, 0, cfg->args, cfg->locals, cfg->unwind_ops, NULL);
+ /* Compile methods added by compile_method () or all methods if nthreads == 0 */
+ for (i = methods_len; i < acfg->methods->len; ++i) {
+ /* This can new methods to acfg->methods */
+ compile_method (acfg, g_ptr_array_index (acfg->methods, i));
}
-#endif
}
static int
char *command, *objfile;
char *outfile_name, *tmp_outfile_name;
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
#define AS_OPTIONS "--64"
#elif defined(sparc) && SIZEOF_VOID_P == 8
#define AS_OPTIONS "-xarch=v9"
tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
#if defined(sparc)
- command = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, acfg->tmpfname);
+ command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
#elif defined(__ppc__) && defined(__MACH__)
- command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, acfg->tmpfname);
+ command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
#elif defined(PLATFORM_WIN32)
- command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, acfg->tmpfname);
+ command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
#else
- 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);
- }
+ command = g_strdup_printf ("ld -shared -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
#endif
printf ("Executing the native linker: %s\n", command);
if (system (command) != 0) {
system (com);
g_free (com);*/
+#if defined(TARGET_ARM) && !defined(__MACH__)
+ /*
+ * gas generates 'mapping symbols' each time code and data is mixed, which
+ * happens a lot in emit_and_reloc_code (), so we need to get rid of them.
+ */
+ command = g_strdup_printf ("strip --strip-symbol=\\$a --strip-symbol=\\$d %s", tmp_outfile_name);
+ printf ("Stripping the binary: %s\n", command);
+ if (system (command) != 0) {
+ g_free (tmp_outfile_name);
+ g_free (outfile_name);
+ g_free (command);
+ g_free (objfile);
+ return 1;
+ }
+#endif
+
rename (tmp_outfile_name, outfile_name);
g_free (tmp_outfile_name);
return 0;
}
+static MonoAotCompile*
+acfg_create (MonoAssembly *ass, guint32 opts)
+{
+ MonoImage *image = ass->image;
+ MonoAotCompile *acfg;
+
+ acfg = g_new0 (MonoAotCompile, 1);
+ 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 (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_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 ();
+ acfg->extra_methods = g_ptr_array_new ();
+ acfg->unwind_info_offsets = g_hash_table_new (NULL, NULL);
+ acfg->unwind_ops = g_ptr_array_new ();
+ InitializeCriticalSection (&acfg->mutex);
+
+ return acfg;
+}
+
static void
acfg_free (MonoAotCompile *acfg)
{
g_ptr_array_free (acfg->shared_patches, TRUE);
g_ptr_array_free (acfg->image_table, TRUE);
g_ptr_array_free (acfg->globals, TRUE);
+ g_ptr_array_free (acfg->unwind_ops, 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->method_to_cfg);
g_hash_table_destroy (acfg->token_info_hash);
g_hash_table_destroy (acfg->image_hash);
+ g_hash_table_destroy (acfg->unwind_info_offsets);
mono_mempool_destroy (acfg->mempool);
g_free (acfg);
}
mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
{
MonoImage *image = ass->image;
- char symbol [256];
- int i, res, methods_len;
+ int res;
MonoAotCompile *acfg;
char *outfile_name, *tmp_outfile_name;
TV_DECLARE (atv);
printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
- acfg = g_new0 (MonoAotCompile, 1);
- 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 (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_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 ();
- acfg->extra_methods = g_ptr_array_new ();
- InitializeCriticalSection (&acfg->mutex);
+ acfg = acfg_create (ass, opts);
memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts));
acfg->aot_opts.write_symbols = TRUE;
+ acfg->aot_opts.ntrampolines = 10240;
mono_aot_parse_options (aot_options, &acfg->aot_opts);
//acfg->aot_opts.print_skipped_methods = TRUE;
+#ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
+ if (acfg->aot_opts.full_aot) {
+ printf ("--aot=full is not supported on this platform.\n");
+ return 1;
+ }
+#endif
+
+ if (acfg->aot_opts.static_link)
+ acfg->aot_opts.asm_writer = TRUE;
+
if (!acfg->aot_opts.asm_only && !acfg->aot_opts.asm_writer && bin_writer_supported ()) {
if (acfg->aot_opts.outfile)
outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
acfg->w = img_writer_create (acfg->fp, FALSE);
- /* hush compiler warnings about these being possibly uninitialized */
tmp_outfile_name = NULL;
outfile_name = NULL;
}
load_profile_files (acfg);
- img_writer_emit_start (acfg->w);
+ if (!acfg->aot_opts.nodebug)
+ acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL);
- acfg->num_aot_trampolines = acfg->aot_opts.full_aot ? 10240 : 0;
+ acfg->num_specific_trampolines = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0;
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+ acfg->num_static_rgctx_trampolines = acfg->aot_opts.full_aot ? 1024 : 0;
+#endif
acfg->method_index = 1;
- /* Collect methods */
- for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
- MonoMethod *method;
- guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
-
- method = mono_get_method (acfg->image, token, NULL);
-
- if (!method) {
- printf ("Failed to load method 0x%x from '%s'.\n", token, image->name);
- exit (1);
- }
-
- /* Load all methods eagerly to skip the slower lazy loading code */
- mono_class_setup_methods (method->klass);
-
- 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, TRUE);
- method = wrapper;
- }
-
- /* Since we add the normal methods first, their index will be equal to their zero based token index */
- add_method_with_index (acfg, method, i);
- acfg->method_index ++;
- }
-
- add_generic_instances (acfg);
-
- if (acfg->aot_opts.full_aot)
- add_wrappers (acfg);
+ collect_methods (acfg);
acfg->cfgs_size = acfg->methods->len + 32;
acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size);
/* PLT offset 0 is reserved for the PLT trampoline */
acfg->plt_offset = 1;
- /* Compile methods */
TV_GETTIME (atv);
- if (acfg->aot_opts.nthreads > 0) {
- GPtrArray *frag;
- int len, j;
- GPtrArray *threads;
- HANDLE handle;
- gpointer *user_data;
- MonoMethod **methods;
-
- methods_len = acfg->methods->len;
-
- len = acfg->methods->len / acfg->aot_opts.nthreads;
- g_assert (len > 0);
- /*
- * Partition the list of methods into fragments, and hand it to threads to
- * process.
- */
- threads = g_ptr_array_new ();
- /* Make a copy since acfg->methods is modified by compile_method () */
- methods = g_new0 (MonoMethod*, methods_len);
- //memcpy (methods, g_ptr_array_index (acfg->methods, 0), sizeof (MonoMethod*) * methods_len);
- for (i = 0; i < methods_len; ++i)
- methods [i] = g_ptr_array_index (acfg->methods, i);
- i = 0;
- while (i < methods_len) {
- frag = g_ptr_array_new ();
- for (j = 0; j < len; ++j) {
- if (i < methods_len) {
- g_ptr_array_add (frag, methods [i]);
- i ++;
- }
- }
-
- user_data = g_new0 (gpointer, 3);
- user_data [0] = mono_domain_get ();
- user_data [1] = acfg;
- user_data [2] = frag;
-
- handle = CreateThread (NULL, 0, (gpointer)compile_thread_main, user_data, 0, NULL);
- g_ptr_array_add (threads, handle);
- }
- g_free (methods);
-
- for (i = 0; i < threads->len; ++i) {
- WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE);
- }
- } else {
- methods_len = 0;
- }
-
- /* Compile methods added by compile_method () or all methods if nthreads == 0 */
- for (i = methods_len; i < acfg->methods->len; ++i) {
- /* This can new methods to acfg->methods */
- compile_method (acfg, g_ptr_array_index (acfg->methods, i));
- }
+ compile_methods (acfg);
TV_GETTIME (btv);
-
+
acfg->stats.jit_time = TV_ELAPSED (atv, btv);
TV_GETTIME (atv);
alloc_got_slots (acfg);
+ img_writer_emit_start (acfg->w);
+
+ if (acfg->dwarf)
+ mono_dwarf_writer_emit_base_info (acfg->dwarf, arch_get_cie_program ());
+
emit_code (acfg);
emit_info (acfg);
emit_exception_info (acfg);
+ emit_unwind_info (acfg);
+
emit_class_info (acfg);
emit_plt (acfg);
emit_globals (acfg);
- emit_dwarf_info (acfg);
+ if (acfg->dwarf)
+ emit_dwarf_info (acfg);
- sprintf (symbol, "mem_end");
- emit_section_change (acfg, ".text", 1);
- emit_global (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
+ emit_mem_end (acfg);
TV_GETTIME (btv);
acfg->stats.gen_time = TV_ELAPSED (atv, btv);
- 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)));
+ printf ("Code: %d Info: %d Ex Info: %d Unwind 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.unwind_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)));
TV_GETTIME (atv);
res = img_writer_emit_writeout (acfg->w);
if (acfg->use_bin_writer) {
rename (tmp_outfile_name, outfile_name);
} else {
- compile_asm (acfg);
+ res = compile_asm (acfg);
if (res != 0) {
acfg_free (acfg);
return res;
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);
- printf ("JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
+ /*
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", get_patch_name (i), acfg->stats.got_slot_types [i]);
+ */
+
+ printf ("JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
acfg_free (acfg);
end
*/
-static MonoAotCompile *xdebug_acfg;
+static MonoDwarfWriter *xdebug_writer;
+static FILE *xdebug_fp;
void
mono_xdebug_init (void)
{
- MonoAotCompile *acfg;
-
- acfg = g_new0 (MonoAotCompile, 1);
- acfg->mempool = mono_mempool_new ();
- InitializeCriticalSection (&acfg->mutex);
- acfg->aot_opts.asm_only = TRUE;
- acfg->aot_opts.outfile = g_strdup ("xdb.s");
+ FILE *il_file;
+ MonoImageWriter *w;
unlink ("xdb.s");
- acfg->fp = fopen ("xdb.s", "w");
+ xdebug_fp = fopen ("xdb.s", "w");
- acfg->w = img_writer_create (acfg->fp, FALSE);
+ w = img_writer_create (xdebug_fp, FALSE);
- img_writer_emit_start (acfg->w);
+ img_writer_emit_start (w);
- xdebug_acfg = acfg;
+ /* This file will contain the IL code for methods which don't have debug info */
+ il_file = fopen ("xdb.il", "w");
- /* Emit something so the file has a text segment */
- emit_section_change (acfg, ".text", 0);
- emit_string (acfg, "");
+ xdebug_writer = mono_dwarf_writer_create (w, il_file);
- emit_base_dwarf_info (acfg);
+ /* Emit something so the file has a text segment */
+ img_writer_emit_section_change (w, ".text", 0);
+ img_writer_emit_string (w, "");
- /* This file will contain the IL code for methods which don't have debug info */
- acfg->il_file = fopen ("xdb.il", "w");
+ mono_dwarf_writer_emit_base_info (xdebug_writer, arch_get_cie_program ());
}
/*
*
* Emit debugging info for METHOD into an assembly file which can be assembled
* and loaded into gdb to provide debugging info for JITted code.
+ * LOCKING: Acquires the loader lock.
*/
void
mono_save_xdebug_info (MonoCompile *cfg)
{
- MonoAotCompile *acfg;
-
- if (!xdebug_acfg)
+ if (!xdebug_writer)
return;
-
- acfg = xdebug_acfg;
- mono_acfg_lock (acfg);
- emit_method_dwarf_info (acfg, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
- fflush (acfg->fp);
- mono_acfg_unlock (acfg);
+ mono_loader_lock ();
+ mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
+ fflush (xdebug_fp);
+ mono_loader_unlock ();
}
/*
* mono_save_trampoline_xdebug_info:
*
* Same as mono_save_xdebug_info, but for trampolines.
+ * LOCKING: Acquires the loader lock.
*/
void
mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
{
- MonoAotCompile *acfg;
-
- if (!xdebug_acfg)
+ if (!xdebug_writer)
return;
- acfg = xdebug_acfg;
-
- mono_acfg_lock (acfg);
- emit_trampoline_dwarf_info (acfg, tramp_name, NULL, NULL, code, code_size, unwind_info);
- fflush (acfg->fp);
- mono_acfg_unlock (acfg);
+ mono_loader_lock ();
+ mono_dwarf_writer_emit_trampoline (xdebug_writer, tramp_name, NULL, NULL, code, code_size, unwind_info);
+ fflush (xdebug_fp);
+ mono_loader_unlock ();
}
#else