* - every shared method has a MonoGenericJitInfo structure which is only really
* used for handling catch clauses with open types, not a very common use case.
*/
-
#include "config.h"
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
#include <sys/time.h>
#else
#include <winsock2.h>
#include <errno.h>
#include <sys/stat.h>
+
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/class.h>
#include <mono/metadata/object.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/threads-types.h>
-#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-logger-internal.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-time.h>
#include <mono/utils/mono-mmap.h>
#define TV_GETTIME(tv) tv = mono_100ns_ticks ()
#define TV_ELAPSED(start,end) (((end) - (start)) / 10)
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
#define SHARED_EXT ".dll"
#elif defined(__ppc__) && defined(__MACH__)
#define SHARED_EXT ".dylib"
gboolean asm_only;
gboolean asm_writer;
gboolean nodebug;
+ gboolean soft_debug;
int nthreads;
int ntrampolines;
+ int nrgctx_trampolines;
+ int nimt_trampolines;
gboolean print_skipped_methods;
+ gboolean stats;
char *tool_prefix;
+ gboolean autoreg;
} MonoAotOptions;
typedef struct MonoAotStats {
int ccount, mcount, lmfcount, abscount, gcount, ocount, genericcount;
- 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 code_size, info_size, ex_info_size, unwind_info_size, got_size, class_info_size, got_info_size;
+ int methods_without_got_slots, direct_calls, all_calls, llvm_count;
+ int got_slots, offsets_size;
int got_slot_types [MONO_PATCH_INFO_NONE];
int jit_time, gen_time, link_time;
} MonoAotStats;
MonoImage *image;
GPtrArray *methods;
GHashTable *method_indexes;
+ GHashTable *method_depth;
MonoCompile **cfgs;
int cfgs_size;
GHashTable *patch_to_plt_offset;
GHashTable *plt_offset_to_patch;
GHashTable *patch_to_got_offset;
+ GHashTable **patch_to_got_offset_by_type;
GPtrArray *got_patches;
GHashTable *image_hash;
GHashTable *method_to_cfg;
GList *method_order;
guint32 *plt_got_info_offsets;
guint32 got_offset, plt_offset, plt_got_offset_base;
+ guint32 final_got_size;
/* Number of GOT entries reserved for trampolines */
guint32 num_trampoline_got_entries;
GHashTable *unwind_info_offsets;
GPtrArray *unwind_ops;
guint32 unwind_info_offset;
+ char *got_symbol_base;
char *got_symbol;
char *plt_symbol;
GHashTable *method_label_hash;
const char *temp_prefix;
+ const char *llvm_label_prefix;
guint32 label_generator;
+ gboolean llvm;
+ MonoAotFileFlags flags;
+ MonoDynamicStream blob;
} MonoAotCompile;
#define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
#define mono_acfg_unlock(acfg) LeaveCriticalSection (&((acfg)->mutex))
+/* This points to the current acfg in LLVM mode */
+static MonoAotCompile *llvm_acfg;
+
#ifdef HAVE_ARRAY_ELEM_INIT
#define MSGSTRFIELD(line) MSGSTRFIELD1(line)
#define MSGSTRFIELD1(line) str##line
#define PPC_LDX_OP "lwzx"
#endif
+//#define TARGET_ARM
+
+#ifdef TARGET_ARM
+#define LLVM_LABEL_PREFIX "_"
+#else
+#define LLVM_LABEL_PREFIX ""
+#endif
+
+#ifdef TARGET_ARM
+/* iphone */
+#define LLC_TARGET_ARGS "-march=arm -mattr=+v6 -mtriple=arm-apple-darwin"
+/* ELF */
+//#define LLC_TARGET_ARGS "-march=arm -mtriple=arm-linux-gnueabi -soft-float"
+#else
+#define LLC_TARGET_ARGS ""
+#endif
+
/*
* arch_emit_direct_call:
*
* 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
* loader to point to .Lpd entries.
- * An x86_64 plt entry is 10 bytes long, init_plt () depends on this.
*/
/* jmpq *<offset>(%rip) */
emit_byte (acfg, '\xff');
* - optimize OP_AOTCONST implementation
* - optimize the PLT entries
* - optimize SWITCH AOT implementation
- * - implement IMT support
*/
code = buf;
if (acfg->use_bin_writer && FALSE) {
*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);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 8);
+ ARM_LDR_REG_REG (code, MONO_ARCH_RGCTX_REG, ARMREG_PC, ARMREG_IP);
/* Load branch addr + branch */
- ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 4);
- ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_R1);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 4);
+ ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
g_assert (code - buf == 16);
#endif
}
-/*
- * arch_get_cie_program:
- *
- * Get the unwind bytecode for the DWARF CIE.
- */
-static GSList*
-arch_get_cie_program (void)
+static void
+arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
{
-#ifdef TARGET_AMD64
- GSList *l = NULL;
-
- mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, AMD64_RSP, 8);
- mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, AMD64_RIP, -8);
+#if defined(TARGET_POWERPC) && defined(__mono_ilp32__)
+ /* Based on code generated by gcc */
+ img_writer_emit_unset_mode (acfg->w);
- return l;
-#elif defined(TARGET_POWERPC)
- GSList *l = NULL;
+ fprintf (acfg->fp,
+#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE)
+ ".section .ctors,\"aw\",@progbits\n"
+ ".align 2\n"
+ ".globl %s\n"
+ ".long %s\n"
+ ".section .opd,\"aw\"\n"
+ ".align 2\n"
+ "%s:\n"
+ ".long .%s,.TOC.@tocbase32\n"
+ ".size %s,.-%s\n"
+ ".section .text\n"
+ ".type .%s,@function\n"
+ ".align 2\n"
+ ".%s:\n", symbol, symbol, symbol, symbol, symbol, symbol, symbol, symbol);
+#else
+ ".section .ctors,\"aw\",@progbits\n"
+ ".align 2\n"
+ ".globl %1$s\n"
+ ".long %1$s\n"
+ ".section .opd,\"aw\"\n"
+ ".align 2\n"
+ "%1$s:\n"
+ ".long .%1$s,.TOC.@tocbase32\n"
+ ".size %1$s,.-%1$s\n"
+ ".section .text\n"
+ ".type .%1$s,@function\n"
+ ".align 2\n"
+ ".%1$s:\n", symbol);
+#endif
- mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
- return l;
+ fprintf (acfg->fp,
+ "stdu 1,-128(1)\n"
+ "mflr 0\n"
+ "std 31,120(1)\n"
+ "std 0,144(1)\n"
+
+ ".Lautoreg:\n"
+ "lis 3, .Lglobals@h\n"
+ "ori 3, 3, .Lglobals@l\n"
+ "bl .mono_aot_register_module\n"
+ "ld 11,0(1)\n"
+ "ld 0,16(11)\n"
+ "mtlr 0\n"
+ "ld 31,-8(11)\n"
+ "mr 1,11\n"
+ "blr\n"
+ );
+#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE)
+ fprintf (acfg->fp,
+ ".size .%s,.-.%s\n", symbol, symbol);
+#else
+ fprintf (acfg->fp,
+ ".size .%1$s,.-.%1$s\n", symbol);
+#endif
#else
- return NULL;
#endif
}
*endbuf = p;
}
+static void
+stream_init (MonoDynamicStream *sh)
+{
+ sh->index = 0;
+ sh->alloc_size = 4096;
+ sh->data = g_malloc (4096);
+
+ /* So offsets are > 0 */
+ sh->index ++;
+}
+
+static void
+make_room_in_stream (MonoDynamicStream *stream, int size)
+{
+ if (size <= stream->alloc_size)
+ return;
+
+ while (stream->alloc_size <= size) {
+ if (stream->alloc_size < 4096)
+ stream->alloc_size = 4096;
+ else
+ stream->alloc_size *= 2;
+ }
+
+ stream->data = g_realloc (stream->data, stream->alloc_size);
+}
+
+static guint32
+add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
+{
+ guint32 idx;
+
+ make_room_in_stream (stream, stream->index + len);
+ memcpy (stream->data + stream->index, data, len);
+ idx = stream->index;
+ stream->index += len;
+ return idx;
+}
+
+/*
+ * add_to_blob:
+ *
+ * Add data to the binary blob inside the aot image. Returns the offset inside the
+ * blob where the data was stored.
+ */
+static guint32
+add_to_blob (MonoAotCompile *acfg, guint8 *data, guint32 data_len)
+{
+ if (acfg->blob.alloc_size == 0)
+ stream_init (&acfg->blob);
+
+ return add_stream_data (&acfg->blob, (char*)data, data_len);
+}
+
+/*
+ * emit_offset_table:
+ *
+ * Emit a table of increasing offsets in a compact form using differential encoding.
+ * There is an index entry for each GROUP_SIZE number of entries. The greater the
+ * group size, the more compact the table becomes, but the slower it becomes to compute
+ * a given entry. Returns the size of the table.
+ */
+static guint32
+emit_offset_table (MonoAotCompile *acfg, int noffsets, int group_size, gint32 *offsets)
+{
+ gint32 current_offset;
+ int i, buf_size, ngroups, index_entry_size;
+ guint8 *p, *buf;
+ guint32 *index_offsets;
+
+ ngroups = (noffsets + (group_size - 1)) / group_size;
+
+ index_offsets = g_new0 (guint32, ngroups);
+
+ buf_size = noffsets * 4;
+ p = buf = g_malloc0 (buf_size);
+
+ current_offset = 0;
+ for (i = 0; i < noffsets; ++i) {
+ //printf ("D: %d -> %d\n", i, offsets [i]);
+ if ((i % group_size) == 0) {
+ index_offsets [i / group_size] = p - buf;
+ /* Emit the full value for these entries */
+ encode_value (offsets [i], p, &p);
+ } else {
+ /* The offsets are allowed to be non-increasing */
+ //g_assert (offsets [i] >= current_offset);
+ encode_value (offsets [i] - current_offset, p, &p);
+ }
+ current_offset = offsets [i];
+ }
+
+ if (ngroups && index_offsets [ngroups - 1] < 65000)
+ index_entry_size = 2;
+ else
+ index_entry_size = 4;
+
+ /* Emit the header */
+ emit_int32 (acfg, noffsets);
+ emit_int32 (acfg, group_size);
+ emit_int32 (acfg, ngroups);
+ emit_int32 (acfg, index_entry_size);
+
+ /* Emit the index */
+ for (i = 0; i < ngroups; ++i) {
+ if (index_entry_size == 2)
+ emit_int16 (acfg, index_offsets [i]);
+ else
+ emit_int32 (acfg, index_offsets [i]);
+ }
+
+ /* Emit the data */
+ emit_bytes (acfg, buf, p - buf);
+
+ return (int)(p - buf) + (ngroups * 4);
+}
+
static guint32
get_image_index (MonoAotCompile *cfg, MonoImage *image)
{
if (method->wrapper_type) {
if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
- if (mono_marshal_method_from_wrapper (method) != method) {
+ if (strcmp (method->name, "runtime_invoke_dynamic")) {
+ name = mono_aot_wrapper_name (method);
+ } else if (mono_marshal_method_from_wrapper (method) != method) {
/* Direct wrapper, encode it normally */
} else {
name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig);
case MONO_WRAPPER_LDFLDA:
case MONO_WRAPPER_STFLD:
case MONO_WRAPPER_ISINST: {
- MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (method);
+ MonoClass *proxy_class = mono_marshal_get_wrapper_info (method);
encode_klass_ref (acfg, proxy_class, p, &p);
break;
}
case MONO_WRAPPER_STFLD_REMOTE:
break;
case MONO_WRAPPER_ALLOC: {
- int alloc_type = mono_gc_get_managed_allocator_type (method);
- g_assert (alloc_type != -1);
- encode_value (alloc_type, p, &p);
+ AllocatorWrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+ g_assert (info->alloc_type != -1);
+ encode_value (info->alloc_type, p, &p);
break;
}
+ case MONO_WRAPPER_WRITE_BARRIER:
+ break;
case MONO_WRAPPER_STELEMREF:
break;
case MONO_WRAPPER_UNKNOWN:
encode_method_ref (acfg, m, p, &p);
break;
}
+ case MONO_WRAPPER_MANAGED_TO_MANAGED:
+ if (!strcmp (method->name, "ElementAddr")) {
+ ElementAddrWrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+ g_assert (info);
+ encode_value (MONO_AOT_WRAPPER_ELEMENT_ADDR, p, &p);
+ encode_value (info->rank, p, &p);
+ encode_value (info->elem_size, p, &p);
+ } else {
+ g_assert_not_reached ();
+ }
+ break;
default:
g_assert_not_reached ();
}
case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
case MONO_PATCH_INFO_MONITOR_ENTER:
case MONO_PATCH_INFO_MONITOR_EXIT:
+ case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
return TRUE;
default:
return FALSE;
if (is_plt_patch (patch_info)) {
int idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info));
- if (patch_info->type == MONO_PATCH_INFO_METHOD && (patch_info->data.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
+ // FIXME: This breaks the calculation of final_got_size
+ if (!acfg->llvm && patch_info->type == MONO_PATCH_INFO_METHOD && (patch_info->data.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
/*
* Allocate a separate PLT slot for each such patch, since some plt
- * entries will refer to the method itself, and some will refer to
+ * entries will refer to the method itself, and some will refer to the
* wrapper.
*/
idx = 0;
} else {
MonoJumpInfo *new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
+ g_assert (!acfg->final_got_size);
+
res = acfg->plt_offset;
g_hash_table_insert (acfg->plt_offset_to_patch, GUINT_TO_POINTER (res), new_ji);
g_hash_table_insert (acfg->patch_to_plt_offset, new_ji, GUINT_TO_POINTER (res));
{
guint32 got_offset;
- got_offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_got_offset, ji));
+ got_offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_got_offset_by_type [ji->type], ji));
if (got_offset)
return got_offset - 1;
got_offset = acfg->got_offset;
acfg->got_offset ++;
+ if (acfg->final_got_size)
+ g_assert (got_offset < acfg->final_got_size);
+
acfg->stats.got_slots ++;
acfg->stats.got_slot_types [ji->type] ++;
g_hash_table_insert (acfg->patch_to_got_offset, ji, GUINT_TO_POINTER (got_offset + 1));
+ g_hash_table_insert (acfg->patch_to_got_offset_by_type [ji->type], ji, GUINT_TO_POINTER (got_offset + 1));
g_ptr_array_add (acfg->got_patches, ji);
return got_offset;
}
static int
-add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra)
+add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra, int depth)
{
int index;
/* FIXME: Fix quadratic behavior */
acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (index));
+ g_hash_table_insert (acfg->method_depth, method, GUINT_TO_POINTER (depth));
+
acfg->method_index ++;
return index;
static int
add_method (MonoAotCompile *acfg, MonoMethod *method)
{
- return add_method_full (acfg, method, FALSE);
+ return add_method_full (acfg, method, FALSE, 0);
}
static void
add_extra_method (MonoAotCompile *acfg, MonoMethod *method)
{
- add_method_full (acfg, method, TRUE);
+ add_method_full (acfg, method, TRUE, 0);
+}
+
+static void
+add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth)
+{
+ add_method_full (acfg, method, TRUE, depth);
}
static void
return mono_marshal_get_runtime_invoke (m, FALSE);
}
+static gboolean
+can_marshal_struct (MonoClass *klass)
+{
+ MonoClassField *field;
+ gboolean can_marshal = TRUE;
+ gpointer iter = NULL;
+
+ if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ return FALSE;
+
+ /* Only allow a few field types to avoid asserts in the marshalling code */
+ while ((field = mono_class_get_fields (klass, &iter))) {
+ if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+ continue;
+
+ switch (field->type->type) {
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ case MONO_TYPE_STRING:
+ break;
+ case MONO_TYPE_VALUETYPE:
+ if (!mono_class_from_mono_type (field->type)->enumtype && !can_marshal_struct (mono_class_from_mono_type (field->type)))
+ can_marshal = FALSE;
+ break;
+ default:
+ can_marshal = FALSE;
+ break;
+ }
+ }
+
+ /* Special cases */
+ /* Its hard to compute whenever these can be marshalled or not */
+ if (!strcmp (klass->name_space, "System.Net.NetworkInformation.MacOsStructs"))
+ return TRUE;
+
+ return can_marshal;
+}
+
static void
add_wrappers (MonoAotCompile *acfg)
{
skip = TRUE;
}
- if (!skip)
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+ if (!method->klass->contextbound) {
+ MonoDynCallInfo *info = mono_arch_dyn_call_prepare (sig);
+ gboolean has_nullable = FALSE;
+
+ for (j = 0; j < sig->param_count; j++) {
+ if (sig->params [j]->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (sig->params [j])))
+ has_nullable = TRUE;
+ }
+
+ if (info && !has_nullable) {
+ /* Supported by the dynamic runtime-invoke wrapper */
+ skip = TRUE;
+ g_free (info);
+ }
+ }
+#endif
+
+ if (!skip) {
+ //printf ("%s\n", mono_method_full_name (method, TRUE));
add_method (acfg, mono_marshal_get_runtime_invoke (method, FALSE));
- }
+ }
+ }
if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
#ifdef MONO_ARCH_HAVE_TLS_GET
/* 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));
+ /* This is used by mono_runtime_capture_context () */
+ method = mono_get_context_capture_method ();
+ if (method)
+ add_method (acfg, mono_marshal_get_runtime_invoke (method, FALSE));
+
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+ add_method (acfg, mono_marshal_get_runtime_invoke_dynamic ());
+#endif
+
/* JIT icall wrappers */
/* FIXME: locking */
g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
token = MONO_TOKEN_METHOD_DEF | (i + 1);
method = mono_get_method (acfg->image, token, NULL);
- if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !method->is_generic)
add_method (acfg, mono_marshal_get_synchronized_wrapper (method));
}
add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
}
}
+
+ /* native-to-managed wrappers */
+ for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+ MonoMethod *method;
+ guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+ MonoCustomAttrInfo *cattr;
+ int j;
+
+ method = mono_get_method (acfg->image, token, NULL);
+
+ /*
+ * Only generate native-to-managed wrappers for methods which have an
+ * attribute named MonoPInvokeCallbackAttribute. We search for the attribute by
+ * name to avoid defining a new assembly to contain it.
+ */
+ cattr = mono_custom_attrs_from_method (method);
+
+ if (cattr) {
+ for (j = 0; j < cattr->num_attrs; ++j)
+ if (cattr->attrs [j].ctor && !strcmp (cattr->attrs [j].ctor->klass->name, "MonoPInvokeCallbackAttribute"))
+ break;
+ if (j < cattr->num_attrs) {
+ MonoCustomAttrEntry *e = &cattr->attrs [j];
+ MonoMethodSignature *sig = mono_method_signature (e->ctor);
+ const char *p = (const char*)e->data;
+ int slen;
+ char *n;
+ MonoType *t;
+ MonoClass *klass;
+
+ g_assert (method->flags & METHOD_ATTRIBUTE_STATIC);
+
+ g_assert (sig->param_count == 1);
+ g_assert (sig->params [0]->type == MONO_TYPE_CLASS && !strcmp (mono_class_from_mono_type (sig->params [0])->name, "Type"));
+
+ /*
+ * Decode the cattr manually since we can't create objects
+ * during aot compilation.
+ */
+
+ /* Skip prolog */
+ p += 2;
+
+ /* From load_cattr_value () in reflection.c */
+ slen = mono_metadata_decode_value (p, &p);
+ n = g_memdup (p, slen + 1);
+ n [slen] = 0;
+ t = mono_reflection_type_from_name (n, acfg->image);
+ g_assert (t);
+ g_free (n);
+
+ klass = mono_class_from_mono_type (t);
+ g_assert (klass->parent == mono_defaults.multicastdelegate_class);
+
+ add_method (acfg, mono_marshal_get_managed_wrapper (method, klass, NULL));
+ }
+ }
+
+ if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
+ add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
+ }
+ }
/* StructureToPtr/PtrToStructure wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
token = MONO_TOKEN_TYPE_DEF | (i + 1);
klass = mono_class_get (acfg->image, token);
- if (klass->valuetype && !klass->generic_container && ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)) {
- gboolean can_marshal = TRUE;
- gpointer iter = NULL;
- MonoClassField *field;
-
- /* Only allow a few field types to avoid asserts in the marshalling code */
- while ((field = mono_class_get_fields (klass, &iter))) {
- switch (field->type->type) {
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_PTR:
- case MONO_TYPE_R4:
- case MONO_TYPE_R8:
- break;
- default:
- can_marshal = FALSE;
- break;
- }
- }
-
- if (can_marshal) {
- add_method (acfg, mono_marshal_get_struct_to_ptr (klass));
- add_method (acfg, mono_marshal_get_ptr_to_struct (klass));
- }
+ if (klass->valuetype && !klass->generic_container && can_marshal_struct (klass)) {
+ add_method (acfg, mono_marshal_get_struct_to_ptr (klass));
+ add_method (acfg, mono_marshal_get_ptr_to_struct (klass));
}
}
}
iter = NULL;
while ((method = mono_class_get_methods (klass, &iter))) {
- if (mono_method_is_generic_sharable_impl (method, FALSE))
+ if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
/* Already added */
continue;
}
/*
- * For ICollection<T>, where T is a vtype, add instances of the helper methods
+ * For ICollection<T>, 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])) {
+ (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1"))) {
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;
iter = NULL;
while ((method = mono_class_get_methods (array_class, &iter))) {
- if (strstr (method->name, name_prefix))
- add_extra_method (acfg, method);
+ if (strstr (method->name, name_prefix)) {
+ MonoMethod *m = mono_aot_get_array_helper_from_wrapper (method);
+ add_extra_method (acfg, m);
+ }
}
g_free (name_prefix);
}
+
+ /* Add an instance of GenericComparer<T> which is created dynamically by Comparer<T> */
+ if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) {
+ MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ MonoClass *icomparable, *gcomparer;
+ MonoGenericContext ctx;
+ MonoType *args [16];
+
+ memset (&ctx, 0, sizeof (ctx));
+
+ icomparable = mono_class_from_name (mono_defaults.corlib, "System", "IComparable`1");
+ g_assert (icomparable);
+ args [0] = &tclass->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+
+ if (mono_class_is_assignable_from (mono_class_inflate_generic_class (icomparable, &ctx), tclass)) {
+ gcomparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericComparer`1");
+ g_assert (gcomparer);
+ add_generic_class (acfg, mono_class_inflate_generic_class (gcomparer, &ctx));
+ }
+ }
}
static void
-add_array_wrappers (MonoAotCompile *acfg, MonoClass *klass)
+add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int ninsts)
{
int i;
+ MonoGenericContext ctx;
+ MonoType *args [16];
- mono_class_setup_methods (klass);
- for (i = 0; i < klass->method.count; ++i) {
- if (klass->methods [i]->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED)
- add_extra_method (acfg, klass->methods [i]);
+ memset (&ctx, 0, sizeof (ctx));
+
+ for (i = 0; i < ninsts; ++i) {
+ args [0] = insts [i];
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
}
}
token = MONO_TOKEN_METHOD_SPEC | (i + 1);
method = mono_get_method (acfg->image, token, NULL);
- context = mono_method_get_context (method);
- if (context && ((context->class_inst && context->class_inst->is_open) ||
- (context->method_inst && context->method_inst->is_open)))
+ if (method->klass->image != acfg->image)
continue;
- if (method->klass->image != acfg->image)
+ context = mono_method_get_context (method);
+
+ if (context && ((context->class_inst && context->class_inst->is_open)))
continue;
- if (mono_method_is_generic_sharable_impl (method, FALSE))
- /* Already added */
+ /*
+ * For open methods, create an instantiation which can be passed to the JIT.
+ * FIXME: Handle class_inst as well.
+ */
+ if (context && context->method_inst && context->method_inst->is_open) {
+ MonoGenericContext shared_context;
+ MonoGenericInst *inst;
+ MonoType **type_argv;
+ int i;
+ MonoMethod *declaring_method;
+ gboolean supported = TRUE;
+
+ /* Check that the context doesn't contain open constructed types */
+ if (context->class_inst) {
+ inst = context->class_inst;
+ for (i = 0; i < inst->type_argc; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+ continue;
+ if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+ supported = FALSE;
+ }
+ }
+ if (context->method_inst) {
+ inst = context->method_inst;
+ for (i = 0; i < inst->type_argc; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+ continue;
+ if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+ supported = FALSE;
+ }
+ }
+
+ if (!supported)
+ continue;
+
+ memset (&shared_context, 0, sizeof (MonoGenericContext));
+
+ inst = context->class_inst;
+ if (inst) {
+ type_argv = g_new0 (MonoType*, inst->type_argc);
+ for (i = 0; i < inst->type_argc; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+ type_argv [i] = &mono_defaults.object_class->byval_arg;
+ else
+ type_argv [i] = inst->type_argv [i];
+ }
+
+ shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+ g_free (type_argv);
+ }
+
+ inst = context->method_inst;
+ if (inst) {
+ type_argv = g_new0 (MonoType*, inst->type_argc);
+ for (i = 0; i < inst->type_argc; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+ type_argv [i] = &mono_defaults.object_class->byval_arg;
+ else
+ type_argv [i] = inst->type_argv [i];
+ }
+
+ shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+ g_free (type_argv);
+ }
+
+ if (method->is_generic || method->klass->generic_container)
+ declaring_method = method;
+ else
+ declaring_method = mono_method_get_declaring_generic_method (method);
+
+ method = mono_class_inflate_generic_method (declaring_method, &shared_context);
+ }
+
+ /*
+ * If the method is fully sharable, it was already added in place of its
+ * generic definition.
+ */
+ if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
continue;
+ /*
+ * FIXME: Partially shared methods are not shared here, so we end up with
+ * many identical methods.
+ */
add_extra_method (acfg, method);
}
}
if (acfg->image == mono_defaults.corlib) {
- /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
- MonoClass *klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
-
- if (klass) {
- MonoGenericContext ctx;
- MonoType *args [16];
-
- memset (&ctx, 0, sizeof (ctx));
-
- args [0] = &mono_defaults.byte_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.sbyte_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.int16_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.uint16_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.int32_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.uint32_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.int64_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.uint64_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
- }
+ MonoClass *klass;
+ MonoType *insts [256];
+ int ninsts = 0;
+
+ insts [ninsts ++] = &mono_defaults.byte_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.sbyte_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.int16_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.uint16_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.int32_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.uint32_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.int64_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.uint64_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.single_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.double_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.char_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.boolean_class->byval_arg;
- /* Add GenericEqualityComparer<T> instances for primitive types */
+ /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
+ klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
+ if (klass)
+ add_instances_of (acfg, klass, insts, ninsts);
klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericEqualityComparer`1");
+ if (klass)
+ add_instances_of (acfg, klass, insts, ninsts);
+
+ /* Add instances of the array generic interfaces for primitive types */
+ /* This will add instances of the InternalArray_ helper methods in Array too */
+ klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "ICollection`1");
+ if (klass)
+ add_instances_of (acfg, klass, insts, ninsts);
+ klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IList`1");
+ if (klass)
+ add_instances_of (acfg, klass, insts, ninsts);
+ klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IEnumerable`1");
+ if (klass)
+ add_instances_of (acfg, klass, insts, ninsts);
- if (klass) {
- MonoGenericContext ctx;
- MonoType *args [16];
-
- memset (&ctx, 0, sizeof (ctx));
-
- args [0] = &mono_defaults.byte_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.sbyte_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.int16_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.uint16_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.int32_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.uint32_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.int64_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
- args [0] = &mono_defaults.uint64_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
- }
-
- /* Emit the array wrapper methods for arrays of primitive types */
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.byte_class, 1));
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.sbyte_class, 1));
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int16_class, 1));
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.uint16_class, 1));
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int32_class, 1));
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.uint32_class, 1));
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int64_class, 1));
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.single_class, 1));
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.double_class, 1));
- /* These are not handled by generic sharing */
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.object_class, 1));
- add_array_wrappers (acfg, mono_array_class_get (mono_defaults.string_class, 1));
-
- /* Add instances of Array.GetGenericValueImpl */
+ /*
+ * Add a managed-to-native wrapper of Array.GetGenericValueImpl<object>, which is
+ * used for all instances of GetGenericValueImpl by the AOT runtime.
+ */
{
MonoGenericContext ctx;
MonoType *args [16];
- MonoMethod *method;
+ MonoMethod *get_method;
+ MonoClass *array_klass = mono_array_class_get (mono_defaults.object_class, 1)->parent;
- memset (&ctx, 0, sizeof (ctx));
-
- /*
- * managed-to-native wrappers are not shared, so have to generate
- * these for ref types too.
- */
- klass = mono_array_class_get (mono_defaults.int_class, 1)->parent;
- method = mono_class_get_method_from_name (klass, "GetGenericValueImpl", 2);
+ get_method = mono_class_get_method_from_name (array_klass, "GetGenericValueImpl", 2);
- if (method) {
- /* String */
- args [0] = &mono_defaults.string_class->byval_arg;
+ if (get_method) {
+ memset (&ctx, 0, sizeof (ctx));
+ args [0] = &mono_defaults.object_class->byval_arg;
ctx.method_inst = mono_metadata_get_generic_inst (1, args);
- add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (method, &ctx), TRUE, TRUE));
+ add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (get_method, &ctx), TRUE, TRUE));
}
}
}
MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
//printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
direct_call = TRUE;
- sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
+ sprintf (direct_call_target, callee_cfg->asm_symbol);
patch_info->type = MONO_PATCH_INFO_NONE;
acfg->stats.direct_calls ++;
}
if (plt_offset != -1) {
/* This patch has a PLT entry, so we must emit a call to the PLT entry */
direct_call = TRUE;
- sprintf (direct_call_target, "%sp_%d", acfg->temp_prefix, plt_offset);
+ sprintf (direct_call_target, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, plt_offset);
/* Nullify the patch */
patch_info->type = MONO_PATCH_INFO_NONE;
method_index = get_method_index (acfg, method);
- /* Emit unbox trampoline */
- if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
- char call_target [256];
-
- 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);
- emit_label (acfg, symbol);
-
- sprintf (call_target, "%sm_%x", acfg->temp_prefix, method_index);
-
- arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
- }
-
/* Make the labels local */
- sprintf (symbol, "%sm_%x", acfg->temp_prefix, method_index);
+ sprintf (symbol, "%s", cfg->asm_symbol);
+ emit_section_change (acfg, ".text", 0);
emit_alignment (acfg, func_alignment);
emit_label (acfg, symbol);
encode_value (*((guint32 *)patch_info->data.target), p, &p);
break;
case MONO_PATCH_INFO_R8:
- encode_value (*((guint32 *)patch_info->data.target), p, &p);
- encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
+ encode_value (((guint32 *)patch_info->data.target) [MINI_LS_WORD_IDX], p, &p);
+ encode_value (((guint32 *)patch_info->data.target) [MINI_MS_WORD_IDX], p, &p);
break;
case MONO_PATCH_INFO_VTABLE:
case MONO_PATCH_INFO_CLASS:
case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
case MONO_PATCH_INFO_MONITOR_ENTER:
case MONO_PATCH_INFO_MONITOR_EXIT:
+ case MONO_PATCH_INFO_SEQ_POINT_INFO:
+ break;
+ case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
+ encode_method_ref (acfg, patch_info->data.imt_tramp->method, p, &p);
+ encode_value (patch_info->data.imt_tramp->vt_offset, p, &p);
break;
default:
g_warning ("unable to handle jump info %d", patch_info->type);
for (pindex = 0; pindex < patches->len; ++pindex) {
patch_info = g_ptr_array_index (patches, pindex);
- if (patch_info->type == MONO_PATCH_INFO_NONE)
+ if (patch_info->type == MONO_PATCH_INFO_NONE || patch_info->type == MONO_PATCH_INFO_BB)
/* Nothing to do */
continue;
GList *l;
int pindex, buf_size, n_patches;
guint8 *code;
- char symbol [128];
GPtrArray *patches;
MonoJumpInfo *patch_info;
MonoMethodHeader *header;
method_index = get_method_index (acfg, method);
- /* Make the labels local */
- sprintf (symbol, "%sm_%x_p", acfg->temp_prefix, method_index);
-
/* Sort relocations */
patches = g_ptr_array_new ();
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
acfg->stats.info_size += p - buf;
- /* Emit method info */
-
- emit_label (acfg, symbol);
-
g_assert (p - buf < buf_size);
- emit_bytes (acfg, buf, p - buf);
+
+ cfg->method_info_offset = add_to_blob (acfg, buf, p - buf);
g_free (buf);
}
emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
{
MonoMethod *method;
- int k, buf_size, method_index;
+ int i, k, buf_size, method_index;
guint32 debug_info_size;
guint8 *code;
- char symbol [128];
MonoMethodHeader *header;
guint8 *p, *buf, *debug_info;
MonoJitInfo *jinfo = cfg->jit_info;
guint32 flags;
gboolean use_unwind_ops = FALSE;
+ MonoSeqPointInfo *seq_points;
method = cfg->orig_method;
code = cfg->native_code;
method_index = get_method_index (acfg, method);
- /* Make the labels local */
- sprintf (symbol, "%se_%x_p", acfg->temp_prefix, method_index);
-
if (!acfg->aot_opts.nodebug) {
mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
} else {
debug_info_size = 0;
}
- buf_size = header->num_clauses * 256 + debug_info_size + 1024;
+ seq_points = cfg->seq_point_info;
+
+ buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (seq_points ? (seq_points->len * 64) : 0);
p = buf = g_malloc (buf_size);
#ifdef MONO_ARCH_HAVE_XP_UNWIND
use_unwind_ops = cfg->unwind_ops != NULL;
#endif
- flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0);
+ flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 0) | (cfg->compile_llvm ? 16 : 0);
- encode_value (jinfo->code_size, p, &p);
encode_value (flags, p, &p);
if (use_unwind_ops) {
}
/* Exception table */
- if (header->num_clauses) {
+ if (cfg->compile_llvm) {
+ /* The assembly might be CIL stripped so emit the data ourselves */
+ if (header->num_clauses)
+ encode_value (header->num_clauses, p, &p);
+
for (k = 0; k < header->num_clauses; ++k) {
+ MonoExceptionClause *clause;
+
+ clause = &header->clauses [k];
+
+ encode_value (clause->flags, p, &p);
+ if (clause->data.catch_class) {
+ encode_value (1, p, &p);
+ encode_klass_ref (acfg, clause->data.catch_class, p, &p);
+ } else {
+ encode_value (0, p, &p);
+ }
+ }
+ } else {
+ if (jinfo->num_clauses)
+ encode_value (jinfo->num_clauses, p, &p);
+
+ for (k = 0; k < jinfo->num_clauses; ++k) {
MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+ encode_value (ei->flags, p, &p);
encode_value (ei->exvar_offset, p, &p);
if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+ else {
+ if (ei->data.catch_class) {
+ encode_value (1, p, &p);
+ encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+ } else {
+ encode_value (0, p, &p);
+ }
+ }
encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
encode_method_ref (acfg, jinfo->method, p, &p);
}
+ if (seq_points) {
+ int il_offset, native_offset, last_il_offset, last_native_offset, j;
+
+ encode_value (seq_points->len, p, &p);
+ last_il_offset = last_native_offset = 0;
+ for (i = 0; i < seq_points->len; ++i) {
+ SeqPoint *sp = &seq_points->seq_points [i];
+ il_offset = sp->il_offset;
+ native_offset = sp->native_offset;
+ encode_value (il_offset - last_il_offset, p, &p);
+ encode_value (native_offset - last_native_offset, p, &p);
+ last_il_offset = il_offset;
+ last_native_offset = native_offset;
+
+ encode_value (sp->next_len, p, &p);
+ for (j = 0; j < sp->next_len; ++j)
+ encode_value (sp->next [j], p, &p);
+ }
+ }
+
+
g_assert (debug_info_size < buf_size);
encode_value (debug_info_size, p, &p);
acfg->stats.ex_info_size += p - buf;
- /* Emit info */
-
- emit_label (acfg, symbol);
-
g_assert (p - buf < buf_size);
- emit_bytes (acfg, buf, p - buf);
+
+ /* Emit info */
+ cfg->ex_info_offset = add_to_blob (acfg, buf, p - buf);
g_free (buf);
}
-static void
+static guint32
emit_klass_info (MonoAotCompile *acfg, guint32 token)
{
MonoClass *klass = mono_class_get (acfg->image, token);
guint8 *p, *buf;
- int i, buf_size;
- char symbol [128];
+ int i, buf_size, res;
gboolean no_special_static, cant_encode;
gpointer iter = NULL;
encode_value (-1, p, &p);
} else {
encode_value (klass->vtable_size, p, &p);
- encode_value ((no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
+ encode_value ((klass->generic_container ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
if (klass->has_cctor)
encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
if (klass->has_finalize)
acfg->stats.class_info_size += p - buf;
- /* Emit the info */
- sprintf (symbol, "%sK_I_%x", acfg->temp_prefix, token - MONO_TOKEN_TYPE_DEF - 1);
- emit_label (acfg, symbol);
-
g_assert (p - buf < buf_size);
- emit_bytes (acfg, buf, p - buf);
+ res = add_to_blob (acfg, buf, p - buf);
g_free (buf);
+
+ return res;
}
/*
for (i = 0; i < acfg->plt_offset; ++i) {
char label [128];
char *debug_sym = NULL;
+ MonoJumpInfo *ji;
+
+ sprintf (label, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, i);
+
+ if (acfg->llvm) {
+ /*
+ * If the target is directly callable, alias the plt symbol to point to
+ * the method code.
+ * FIXME: Use this to simplify emit_and_reloc_code ().
+ * FIXME: Avoid the got slot.
+ * FIXME: Add support to the binary writer.
+ */
+ ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
+ if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer) {
+ MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, ji->data.method);
+ fprintf (acfg->fp, "\n.set %s, %s\n", label, callee_cfg->asm_symbol);
+ continue;
+ }
+ }
- sprintf (label, "%sp_%d", acfg->temp_prefix, i);
emit_label (acfg, label);
if (acfg->aot_opts.write_symbols) {
MonoJumpInfo *ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
- char *debug_sym = NULL;
if (ji) {
switch (ji->type) {
{
char start_symbol [256];
char symbol [256];
- guint32 buf_size;
+ guint32 buf_size, info_offset;
MonoJumpInfo *patch_info;
guint8 *buf, *p;
GPtrArray *patches;
sprintf (symbol, "%s_p", name);
+ info_offset = add_to_blob (acfg, buf, p - buf);
+
emit_section_change (acfg, ".text", 0);
emit_global (acfg, symbol, FALSE);
emit_label (acfg, symbol);
-
- emit_bytes (acfg, buf, p - buf);
+
+ emit_int32 (acfg, info_offset);
/* Emit debug info */
if (unwind_ops) {
g_assert (acfg->image->assembly);
- /* Currently, we only emit most trampolines into the mscorlib AOT image. */
+ /* Currently, we emit most trampolines into the mscorlib AOT image. */
if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
#ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
/*
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_trampoline (acfg, "rethrow_exception", code, code_size, acfg->got_offset, ji, NULL);
+#ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, TRUE);
emit_trampoline (acfg, "throw_exception_by_name", code, code_size, acfg->got_offset, ji, NULL);
+#endif
code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, TRUE);
emit_trampoline (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji, NULL);
opts->nodebug = TRUE;
} else if (str_begins_with (arg, "ntrampolines=")) {
opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
+ } else if (str_begins_with (arg, "nrgctx-trampolines=")) {
+ opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines="));
+ } else if (str_begins_with (arg, "nimt-trampolines=")) {
+ opts->nimt_trampolines = atoi (arg + strlen ("nimt-trampolines="));
+ } else if (str_begins_with (arg, "autoreg")) {
+ opts->autoreg = TRUE;
} else if (str_begins_with (arg, "tool-prefix=")) {
opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
+ } else if (str_begins_with (arg, "soft-debug")) {
+ opts->soft_debug = TRUE;
+ } else if (str_begins_with (arg, "print-skipped")) {
+ opts->print_skipped_methods = TRUE;
+ } else if (str_begins_with (arg, "stats")) {
+ opts->stats = TRUE;
} else {
fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
exit (1);
case MONO_WRAPPER_ALLOC:
case MONO_WRAPPER_REMOTING_INVOKE:
case MONO_WRAPPER_UNKNOWN:
+ case MONO_WRAPPER_WRITE_BARRIER:
break;
+ case MONO_WRAPPER_MANAGED_TO_MANAGED:
+ if (!strcmp (method->name, "ElementAddr"))
+ return TRUE;
+ else
+ return FALSE;
default:
//printf ("Skip (wrapper call): %d -> %s\n", patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
return FALSE;
MonoCompile *cfg;
MonoJumpInfo *patch_info;
gboolean skip;
- int index;
+ int index, depth;
MonoMethod *wrapped;
if (acfg->aot_opts.metadata_only)
}
/* Adds generic instances referenced by this method */
- for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
- switch (patch_info->type) {
- case MONO_PATCH_INFO_METHOD: {
- MonoMethod *m = patch_info->data.method;
- 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)) {
- 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);
+ /*
+ * The depth is used to avoid infinite loops when generic virtual recursion is
+ * encountered.
+ */
+ depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
+ if (depth < 32) {
+ for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
+ switch (patch_info->type) {
+ case MONO_PATCH_INFO_METHOD: {
+ MonoMethod *m = patch_info->data.method;
+ 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)) {
+ if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+ if (acfg->aot_opts.full_aot)
+ add_extra_method_with_depth (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE), depth + 1);
+ } else {
+ add_extra_method_with_depth (acfg, m, depth + 1);
+ }
}
+ add_generic_class (acfg, m->klass);
}
- add_generic_class (acfg, m->klass);
+ if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && !strcmp (m->name, "ElementAddr"))
+ add_extra_method_with_depth (acfg, m, depth + 1);
+ break;
}
- break;
- }
- case MONO_PATCH_INFO_VTABLE: {
- MonoClass *klass = patch_info->data.klass;
+ case MONO_PATCH_INFO_VTABLE: {
+ MonoClass *klass = patch_info->data.klass;
- if (klass->generic_class && !mono_generic_context_is_sharable (&klass->generic_class->context, FALSE))
- add_generic_class (acfg, klass);
- break;
- }
- default:
- break;
+ if (klass->generic_class && !mono_generic_context_is_sharable (&klass->generic_class->context, FALSE))
+ add_generic_class (acfg, klass);
+ break;
+ }
+ default:
+ break;
+ }
}
}
if (!cfg->has_got_slots)
InterlockedIncrement (&acfg->stats.methods_without_got_slots);
+ /*
+ * FIXME: Instead of this mess, allocate the patches from the aot mempool.
+ */
/* Make a copy of the patch info which is in the mempool */
{
MonoJumpInfo *patches = NULL, *patches_end = NULL;
file_index = 0;
while (TRUE) {
- tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
+ tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%d", g_get_home_dir (), acfg->image->assembly_name, file_index);
if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) {
g_free (tmp);
file_index ++;
res = fscanf (infile, "%32s\n", ver);
- if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
+ if ((res != 1) || strcmp (ver, "#VER:2") != 0) {
printf ("Profile file has wrong version or invalid.\n");
fclose (infile);
continue;
}
while (TRUE) {
- res = fscanf (infile, "%d\n", &token);
- if (res < 1)
+ char name [1024];
+ MonoMethodDesc *desc;
+ MonoMethod *method;
+
+ if (fgets (name, 1023, infile) == NULL)
break;
- method_index = mono_metadata_token_index (token) - 1;
+ /* Kill the newline */
+ if (strlen (name) > 0)
+ name [strlen (name) - 1] = '\0';
+
+ desc = mono_method_desc_new (name, TRUE);
+
+ method = mono_method_desc_search_in_image (desc, acfg->image);
- if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
- acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+ if (method && mono_method_get_token (method)) {
+ token = mono_method_get_token (method);
+ method_index = mono_metadata_token_index (token) - 1;
+
+ if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index))) {
+ acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+ }
+ } else {
+ //printf ("No method found matching '%s'.\n", name);
+ }
}
fclose (infile);
}
else
acfg->method_order = unordered;
}
+
+/* Used by the LLVM backend */
+guint32
+mono_aot_get_got_offset (MonoJumpInfo *ji)
+{
+ return get_got_offset (llvm_acfg, ji);
+}
+
+char*
+mono_aot_get_method_name (MonoCompile *cfg)
+{
+ guint32 method_index = get_method_index (llvm_acfg, cfg->orig_method);
+
+ return g_strdup_printf ("m_%x", method_index);
+}
+
+char*
+mono_aot_get_method_debug_name (MonoCompile *cfg)
+{
+ return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
+}
+
+char*
+mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
+{
+ MonoJumpInfo *ji = mono_mempool_alloc (llvm_acfg->mempool, sizeof (MonoJumpInfo));
+ int offset;
+
+ ji->type = type;
+ ji->data.target = data;
+
+ if (!can_encode_patch (llvm_acfg, ji))
+ return NULL;
+
+ offset = get_plt_offset (llvm_acfg, ji);
+
+ return g_strdup_printf ("%sp_%d", llvm_acfg->temp_prefix, offset);
+}
+
+MonoJumpInfo*
+mono_aot_patch_info_dup (MonoJumpInfo* ji)
+{
+ MonoJumpInfo *res;
+
+ mono_acfg_lock (llvm_acfg);
+ res = mono_patch_info_dup_mp (llvm_acfg->mempool, ji);
+ mono_acfg_unlock (llvm_acfg);
+
+ return res;
+}
+
+#ifdef ENABLE_LLVM
+
+/*
+ * emit_llvm_file:
+ *
+ * Emit the LLVM code into an LLVM bytecode file, and compile it using the LLVM
+ * tools.
+ */
+static void
+emit_llvm_file (MonoAotCompile *acfg)
+{
+ char *command, *opts;
+ int i;
+ MonoJumpInfo *patch_info;
+ char *llc_target_args;
+
+ /*
+ * When using LLVM, we let llvm emit the got since the LLVM IL needs to refer
+ * to it.
+ */
+
+ /* Compute the final size of the got */
+ for (i = 0; i < acfg->nmethods; ++i) {
+ if (acfg->cfgs [i]) {
+ for (patch_info = acfg->cfgs [i]->patch_info; patch_info; patch_info = patch_info->next) {
+ if (patch_info->type != MONO_PATCH_INFO_NONE) {
+ if (!is_plt_patch (patch_info))
+ get_got_offset (acfg, patch_info);
+ else
+ get_plt_offset (acfg, patch_info);
+ }
+ }
+ }
+ }
+
+ acfg->final_got_size = acfg->got_offset + acfg->plt_offset;
+
+ if (acfg->aot_opts.full_aot) {
+ int ntype;
+
+ /*
+ * Need to add the got entries used by the trampolines.
+ * This is only a conservative approximation.
+ */
+ if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
+ /* For the generic + rgctx trampolines */
+ acfg->final_got_size += 200;
+ /* For the specific trampolines */
+ for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype)
+ acfg->final_got_size += acfg->num_trampolines [ntype] * 2;
+ }
+ }
+
+
+ mono_llvm_emit_aot_module ("temp.bc", acfg->final_got_size);
+
+ /*
+ * FIXME: Experiment with adding optimizations, the -std-compile-opts set takes
+ * a lot of time, and doesn't seem to save much space.
+ * The following optimizations cannot be enabled:
+ * - 'tailcallelim'
+ * The opt list below was produced by taking the output of:
+ * llvm-as < /dev/null | opt -O2 -disable-output -debug-pass=Arguments
+ * then removing tailcallelim + the global opts, and adding a second gvn.
+ */
+ opts = g_strdup ("-instcombine -simplifycfg");
+ opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -basiccg -prune-eh -inline -functionattrs -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -jump-threading -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loopsimplify -domfrontier -loopsimplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loopsimplify -lcssa -iv-users -indvars -loop-deletion -loopsimplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -jump-threading -domtree -memdep -dse -adce -gvn -simplifycfg -preverify -domtree -verify");
+#if 1
+ command = g_strdup_printf ("opt -f %s -o temp.opt.bc temp.bc", opts);
+ printf ("Executing opt: %s\n", command);
+ if (system (command) != 0) {
+ exit (1);
+ }
+#endif
+ g_free (opts);
+
+ llc_target_args = g_strdup (LLC_TARGET_ARGS);
+
+ command = g_strdup_printf ("llc %s -f -relocation-model=pic -unwind-tables -o %s temp.opt.bc", llc_target_args, acfg->tmpfname);
+ g_free (llc_target_args);
+
+ printf ("Executing llc: %s\n", command);
+
+ if (system (command) != 0) {
+ exit (1);
+ }
+}
+#endif
static void
emit_code (MonoAotCompile *acfg)
{
int i;
char symbol [256];
+ char end_symbol [256];
GList *l;
#if defined(TARGET_POWERPC64)
emit_pointer (acfg, acfg->got_symbol);
#endif
+ /*
+ * This global symbol is used to compute the address of each method using the
+ * code_offsets array. It is also used to compute the memory ranges occupied by
+ * AOT code, so it must be equal to the address of the first emitted method.
+ */
sprintf (symbol, "methods");
emit_section_change (acfg, ".text", 0);
emit_global (acfg, symbol, TRUE);
emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
+ if (acfg->llvm) {
+ for (i = 0; i < acfg->nmethods; ++i) {
+ if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm) {
+ fprintf (acfg->fp, "\n.set methods, %s\n", acfg->cfgs [i]->asm_symbol);
+ break;
+ }
+ }
+ if (i == acfg->nmethods)
+ /* No LLVM compiled methods */
+ emit_label (acfg, symbol);
+ } else {
+ emit_label (acfg, symbol);
+ }
/*
* Emit some padding so the local symbol for the first method doesn't have the
emit_zero_bytes (acfg, 16);
for (l = acfg->method_order; l != NULL; l = l->next) {
+ MonoCompile *cfg;
+ MonoMethod *method;
+
i = GPOINTER_TO_UINT (l->data);
- if (acfg->cfgs [i])
- emit_method_code (acfg, acfg->cfgs [i]);
+ cfg = acfg->cfgs [i];
+
+ if (!cfg)
+ continue;
+
+ method = cfg->orig_method;
+
+ /* Emit unbox trampoline */
+ if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+ char call_target [256];
+
+ 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);
+ emit_label (acfg, symbol);
+
+ sprintf (call_target, "%s", cfg->asm_symbol);
+
+ arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
+ }
+
+ if (cfg->compile_llvm)
+ acfg->stats.llvm_count ++;
+ else
+ emit_method_code (acfg, cfg);
}
sprintf (symbol, "methods_end");
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
- sprintf (symbol, "method_offsets");
+ sprintf (symbol, "code_offsets");
emit_section_change (acfg, ".text", 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ acfg->stats.offsets_size += acfg->nmethods * 4;
+
+ sprintf (end_symbol, "methods");
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
- sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
- emit_symbol_diff (acfg, symbol, "methods", 0);
+ emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
} else {
emit_int32 (acfg, 0xffffffff);
}
int i;
char symbol [256];
GList *l;
+ gint32 *offsets;
- /* Emit method info */
- sprintf (symbol, "method_info");
- emit_section_change (acfg, ".text", 1);
- emit_global (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
-
- /* To reduce size of generated assembly code */
- sprintf (symbol, "mi");
- emit_label (acfg, symbol);
+ offsets = g_new0 (gint32, acfg->nmethods);
for (l = acfg->method_order; l != NULL; l = l->next) {
i = GPOINTER_TO_UINT (l->data);
- if (acfg->cfgs [i])
+ if (acfg->cfgs [i]) {
emit_method_info (acfg, acfg->cfgs [i]);
+ offsets [i] = acfg->cfgs [i]->method_info_offset;
+ } else {
+ offsets [i] = 0;
+ }
}
sprintf (symbol, "method_info_offsets");
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
- for (i = 0; i < acfg->nmethods; ++i) {
- if (acfg->cfgs [i]) {
- sprintf (symbol, "%sm_%x_p", acfg->temp_prefix, i);
- emit_symbol_diff (acfg, symbol, "mi", 0);
- } else {
- emit_int32 (acfg, 0);
- }
- }
- emit_line (acfg);
+ acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets);
+
+ g_free (offsets);
}
#endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */
-/*
- * mono_aot_str_hash:
- *
- * 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.
- */
-guint
-mono_aot_str_hash (gconstpointer v1)
-{
- /* Same as g_str_hash () in glib */
- char *p = (char *) v1;
- guint hash = *p;
-
- while (*p++) {
- if (*p)
- hash = (hash << 5) - hash + *p;
- }
-
- return hash;
-}
-
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
#define mix(a,b,c) { \
a -= c; a ^= rot(c, 4); c += b; \
case MONO_TYPE_CLASS:
case MONO_TYPE_SZARRAY:
/* check if the distribution is good enough */
- return ((hash << 5) - hash) ^ mono_aot_str_hash (t1->data.klass->name);
+ return ((hash << 5) - hash) ^ mono_metadata_str_hash (t1->data.klass->name);
case MONO_TYPE_PTR:
- return ((hash << 5) - hash) ^ mono_aot_type_hash (t1->data.type);
+ return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
case MONO_TYPE_ARRAY:
- return ((hash << 5) - hash) ^ mono_aot_type_hash (&t1->data.array->eklass->byval_arg);
+ return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
case MONO_TYPE_GENERICINST:
return ((hash << 5) - hash) ^ 0;
}
if (!method->wrapper_type) {
char *full_name = mono_type_full_name (&klass->byval_arg);
- hashes [0] = mono_aot_str_hash (full_name);
+ hashes [0] = mono_metadata_str_hash (full_name);
hashes [1] = 0;
g_free (full_name);
} else {
- hashes [0] = mono_aot_str_hash (klass->name);
- hashes [1] = mono_aot_str_hash (klass->name_space);
+ hashes [0] = mono_metadata_str_hash (klass->name);
+ hashes [1] = mono_metadata_str_hash (klass->name_space);
}
- hashes [2] = mono_aot_str_hash (method->name);
+ if (method->wrapper_type == MONO_WRAPPER_STFLD || method->wrapper_type == MONO_WRAPPER_LDFLD || method->wrapper_type == MONO_WRAPPER_LDFLDA)
+ /* The method name includes a stringified pointer */
+ hashes [2] = 0;
+ else
+ hashes [2] = mono_metadata_str_hash (method->name);
hashes [3] = method->wrapper_type;
hashes [4] = mono_aot_type_hash (sig->ret);
for (i = 0; i < sig->param_count; i++) {
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);
+ if (!strcmp (method->name, "runtime_invoke_dynamic"))
+ name = g_strdup_printf ("(wrapper runtime-invoke-dynamic)");
+ else
+ 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);
+ g_free (klass_desc);
break;
}
return name;
}
+/*
+ * mono_aot_get_array_helper_from_wrapper;
+ *
+ * Get the helper method in Array called by an array wrapper method.
+ */
+MonoMethod*
+mono_aot_get_array_helper_from_wrapper (MonoMethod *method)
+{
+ MonoMethod *m;
+ const char *prefix;
+ MonoGenericContext ctx;
+ MonoType *args [16];
+ char *mname, *iname, *s, *s2, *helper_name = NULL;
+
+ prefix = "System.Collections.Generic";
+ s = g_strdup_printf ("%s", method->name + strlen (prefix) + 1);
+ s2 = strstr (s, "`1.");
+ g_assert (s2);
+ s2 [0] = '\0';
+ iname = s;
+ mname = s2 + 3;
+
+ //printf ("X: %s %s\n", iname, mname);
+
+ if (!strcmp (iname, "IList"))
+ helper_name = g_strdup_printf ("InternalArray__%s", mname);
+ else
+ helper_name = g_strdup_printf ("InternalArray__%s_%s", iname, mname);
+ m = mono_class_get_method_from_name (mono_defaults.array_class, helper_name, mono_method_signature (method)->param_count);
+ g_assert (m);
+ g_free (helper_name);
+ g_free (s);
+
+ if (m->is_generic) {
+ memset (&ctx, 0, sizeof (ctx));
+ args [0] = &method->klass->element_class->byval_arg;
+ ctx.method_inst = mono_metadata_get_generic_inst (1, args);
+ m = mono_class_inflate_generic_method (m, &ctx);
+ }
+
+ return m;
+}
+
/*
* mono_aot_tramp_info_create:
*
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 */
+ /* Emit 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);
if (!cfg)
continue;
+ buf_size = 512;
+ p = buf = g_malloc (buf_size);
+
nmethods ++;
- info_offsets [i] = p - buf;
+
+ method = cfg->method_to_register;
name = NULL;
if (method->wrapper_type) {
}
g_assert ((p - buf) < buf_size);
- }
-
- g_assert ((p - buf) < buf_size);
-
- /* Emit method info */
- sprintf (symbol, "extra_method_info");
- emit_section_change (acfg, ".text", 1);
- emit_global (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
-
- emit_bytes (acfg, buf, p - buf);
- emit_line (acfg);
+ info_offsets [i] = add_to_blob (acfg, buf, p - buf);
+ g_free (buf);
+ }
/*
* Construct a chained hash table for mapping indexes in extra_method_info to
chain_lengths [hash] ++;
max_chain_length = MAX (max_chain_length, chain_lengths [hash]);
- /* FIXME: Allocate from the mempool */
- new_entry = g_new0 (HashEntry, 1);
+ new_entry = mono_mempool_alloc0 (acfg->mempool, sizeof (HashEntry));
new_entry->key = key;
new_entry->value = value;
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
- g_assert (table_size < 65000);
emit_int32 (acfg, table_size);
- g_assert (table->len < 65000);
for (i = 0; i < table->len; ++i) {
HashEntry *entry = g_ptr_array_index (table, i);
emit_int32 (acfg, 0);
emit_int32 (acfg, 0);
} else {
- g_assert (entry->key > 0);
+ //g_assert (entry->key > 0);
emit_int32 (acfg, entry->key);
emit_int32 (acfg, entry->value);
if (entry->next)
}
static void
-emit_method_order (MonoAotCompile *acfg)
+emit_exception_info (MonoAotCompile *acfg)
{
- int i, index, len;
+ int i;
char symbol [256];
- GList *l;
+ gint32 *offsets;
+
+ offsets = g_new0 (gint32, acfg->nmethods);
+ for (i = 0; i < acfg->nmethods; ++i) {
+ if (acfg->cfgs [i]) {
+ emit_exception_debug_info (acfg, acfg->cfgs [i]);
+ offsets [i] = acfg->cfgs [i]->ex_info_offset;
+ } else {
+ offsets [i] = 0;
+ }
+ }
- sprintf (symbol, "method_order");
+ sprintf (symbol, "ex_info_offsets");
emit_section_change (acfg, ".text", 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
- /* First emit an index table */
- index = 0;
- len = 0;
- for (l = acfg->method_order; l != NULL; l = l->next) {
- i = GPOINTER_TO_UINT (l->data);
-
- if (acfg->cfgs [i]) {
- if ((index % 1024) == 0) {
- emit_int32 (acfg, i);
- }
-
- index ++;
- }
-
- len ++;
- }
- emit_int32 (acfg, 0xffffff);
-
- /* Then emit the whole method order */
- for (l = acfg->method_order; l != NULL; l = l->next) {
- i = GPOINTER_TO_UINT (l->data);
-
- if (acfg->cfgs [i]) {
- emit_int32 (acfg, i);
- }
- }
- emit_line (acfg);
-
- sprintf (symbol, "method_order_end");
- emit_section_change (acfg, ".text", 1);
- emit_global (acfg, symbol, FALSE);
- emit_label (acfg, symbol);
-}
-
-static void
-emit_exception_info (MonoAotCompile *acfg)
-{
- int i;
- char symbol [256];
-
- sprintf (symbol, "ex_info");
- emit_section_change (acfg, ".text", 1);
- emit_global (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
-
- /* To reduce size of generated assembly */
- sprintf (symbol, "ex");
- emit_label (acfg, symbol);
-
- for (i = 0; i < acfg->nmethods; ++i) {
- if (acfg->cfgs [i])
- emit_exception_debug_info (acfg, acfg->cfgs [i]);
- }
-
- sprintf (symbol, "ex_info_offsets");
- emit_section_change (acfg, ".text", 1);
- emit_global (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
-
- for (i = 0; i < acfg->nmethods; ++i) {
- if (acfg->cfgs [i]) {
- sprintf (symbol, "%se_%x_p", acfg->temp_prefix, i);
- emit_symbol_diff (acfg, symbol, "ex", 0);
- } else {
- emit_int32 (acfg, 0);
- }
- }
- emit_line (acfg);
-}
+ acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets);
+ g_free (offsets);
+}
static void
emit_unwind_info (MonoAotCompile *acfg)
{
int i;
char symbol [256];
+ gint32 *offsets;
- sprintf (symbol, "class_info");
- emit_section_change (acfg, ".text", 1);
- emit_global (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
-
+ offsets = g_new0 (gint32, acfg->image->tables [MONO_TABLE_TYPEDEF].rows);
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
- emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
+ offsets [i] = emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
sprintf (symbol, "class_info_offsets");
emit_section_change (acfg, ".text", 1);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
- for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
- sprintf (symbol, "%sK_I_%x", acfg->temp_prefix, i);
- emit_symbol_diff (acfg, symbol, "class_info", 0);
- }
- emit_line (acfg);
+ acfg->stats.offsets_size += emit_offset_table (acfg, acfg->image->tables [MONO_TABLE_TYPEDEF].rows, 10, offsets);
+ g_free (offsets);
}
typedef struct ClassNameTableEntry {
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 = mono_aot_str_hash (full_name) % table_size;
+ hash = mono_metadata_str_hash (full_name) % table_size;
g_free (full_name);
/* FIXME: Allocate from the mempool */
for (i = 0; i < acfg->got_patches->len; ++i) {
MonoJumpInfo *ji = g_ptr_array_index (acfg->got_patches, i);
- got_info_offsets [i] = p - buf;
- if (i >= first_plt_got_patch)
- acfg->plt_got_info_offsets [i - first_plt_got_patch + 1] = got_info_offsets [i];
+ p = buf;
+
encode_value (ji->type, p, &p);
encode_patch (acfg, ji, p, &p);
- }
-
- g_assert (p - buf <= buf_size);
- acfg->stats.got_info_size = p - buf;
+ g_assert (p - buf <= buf_size);
+ got_info_offsets [i] = add_to_blob (acfg, buf, p - buf);
- /* Emit got_info table */
- sprintf (symbol, "got_info");
- emit_section_change (acfg, ".text", 1);
- emit_global (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
-
- emit_bytes (acfg, buf, p - buf);
+ if (i >= first_plt_got_patch)
+ acfg->plt_got_info_offsets [i - first_plt_got_patch + 1] = got_info_offsets [i];
+ acfg->stats.got_info_size += p - buf;
+ }
/* Emit got_info_offsets table */
sprintf (symbol, "got_info_offsets");
emit_label (acfg, symbol);
/* No need to emit offsets for the got plt entries, the plt embeds them directly */
- for (i = 0; i < first_plt_got_patch; ++i)
- emit_int32 (acfg, got_info_offsets [i]);
-
- acfg->stats.got_info_offsets_size = acfg->got_patches->len * 4;
+ acfg->stats.offsets_size += emit_offset_table (acfg, first_plt_got_patch, 10, (gint32*)got_info_offsets);
}
static void
{
char symbol [256];
- /* Don't make GOT global so accesses to it don't need relocations */
- sprintf (symbol, "%s", acfg->got_symbol);
- emit_section_change (acfg, ".bss", 0);
- emit_alignment (acfg, 8);
- emit_local_symbol (acfg, symbol, "got_end", FALSE);
- emit_label (acfg, symbol);
- if (acfg->got_offset > 0)
- emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
+ if (!acfg->llvm) {
+ /* Don't make GOT global so accesses to it don't need relocations */
+ sprintf (symbol, "%s", acfg->got_symbol);
+ emit_section_change (acfg, ".bss", 0);
+ emit_alignment (acfg, 8);
+ emit_local_symbol (acfg, symbol, "got_end", FALSE);
+ emit_label (acfg, symbol);
+ if (acfg->got_offset > 0)
+ emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
- sprintf (symbol, "got_end");
- emit_label (acfg, symbol);
+ sprintf (symbol, "got_end");
+ emit_label (acfg, symbol);
+ }
sprintf (symbol, "mono_aot_got_addr");
emit_section_change (acfg, ".data", 0);
emit_pointer (acfg, acfg->got_symbol);
}
+typedef struct GlobalsTableEntry {
+ guint32 value, index;
+ struct GlobalsTableEntry *next;
+} GlobalsTableEntry;
+
+static void
+emit_globals_table (MonoAotCompile *acfg)
+{
+ int i, table_size;
+ guint32 hash;
+ GPtrArray *table;
+ char symbol [256];
+ GlobalsTableEntry *entry, *new_entry;
+
+ /*
+ * Construct a chained hash table for mapping global names to their index in
+ * the globals table.
+ */
+ table_size = g_spaced_primes_closest ((int)(acfg->globals->len * 1.5));
+ table = g_ptr_array_sized_new (table_size);
+ for (i = 0; i < table_size; ++i)
+ g_ptr_array_add (table, NULL);
+ for (i = 0; i < acfg->globals->len; ++i) {
+ char *name = g_ptr_array_index (acfg->globals, i);
+
+ hash = mono_metadata_str_hash (name) % table_size;
+
+ /* FIXME: Allocate from the mempool */
+ new_entry = g_new0 (GlobalsTableEntry, 1);
+ new_entry->value = i;
+
+ entry = g_ptr_array_index (table, hash);
+ if (entry == NULL) {
+ new_entry->index = hash;
+ g_ptr_array_index (table, hash) = new_entry;
+ } else {
+ while (entry->next)
+ entry = entry->next;
+
+ entry->next = new_entry;
+ new_entry->index = table->len;
+ g_ptr_array_add (table, new_entry);
+ }
+ }
+
+ /* Emit the table */
+ sprintf (symbol, ".Lglobals_hash");
+ emit_section_change (acfg, ".text", 0);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+
+ /* FIXME: Optimize memory usage */
+ g_assert (table_size < 65000);
+ emit_int16 (acfg, table_size);
+ for (i = 0; i < table->len; ++i) {
+ GlobalsTableEntry *entry = g_ptr_array_index (table, i);
+
+ if (entry == NULL) {
+ emit_int16 (acfg, 0);
+ emit_int16 (acfg, 0);
+ } else {
+ emit_int16 (acfg, entry->value + 1);
+ if (entry->next)
+ emit_int16 (acfg, entry->next->index);
+ else
+ emit_int16 (acfg, 0);
+ }
+ }
+
+ /* Emit the names */
+ for (i = 0; i < acfg->globals->len; ++i) {
+ char *name = g_ptr_array_index (acfg->globals, i);
+
+ sprintf (symbol, "name_%d", i);
+ emit_section_change (acfg, ".text", 1);
+ emit_label (acfg, symbol);
+ emit_string (acfg, name);
+ }
+
+ /* Emit the globals table */
+ sprintf (symbol, ".Lglobals");
+ emit_section_change (acfg, ".data", 0);
+ /* This is not a global, since it is accessed by the init function */
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+
+ sprintf (symbol, "%sglobals_hash", acfg->temp_prefix);
+ emit_pointer (acfg, symbol);
+
+ for (i = 0; i < acfg->globals->len; ++i) {
+ char *name = g_ptr_array_index (acfg->globals, i);
+
+ sprintf (symbol, "name_%d", i);
+ emit_pointer (acfg, symbol);
+
+ sprintf (symbol, "%s", name);
+ emit_pointer (acfg, symbol);
+ }
+ /* Null terminate the table */
+ emit_int32 (acfg, 0);
+ emit_int32 (acfg, 0);
+}
+
static void
emit_globals (MonoAotCompile *acfg)
{
- char *opts_str;
char *build_info;
emit_string_symbol (acfg, "mono_assembly_guid" , acfg->image->guid);
emit_string_symbol (acfg, "mono_aot_version", MONO_AOT_FILE_VERSION);
- opts_str = g_strdup_printf ("%d", acfg->opts);
- emit_string_symbol (acfg, "mono_aot_opt_flags", opts_str);
- g_free (opts_str);
-
- emit_string_symbol (acfg, "mono_aot_full_aot", acfg->aot_opts.full_aot ? "TRUE" : "FALSE");
-
if (acfg->aot_opts.bind_to_runtime_version) {
build_info = mono_get_runtime_build_info ();
emit_string_symbol (acfg, "mono_runtime_version", build_info);
* When static linking, we emit a global which will point to the symbol table.
*/
if (acfg->aot_opts.static_link) {
- int i;
char symbol [256];
char *p;
/* Emit a string holding the assembly name */
emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name);
- /* Emit the names */
- for (i = 0; i < acfg->globals->len; ++i) {
- char *name = g_ptr_array_index (acfg->globals, i);
-
- sprintf (symbol, "name_%d", i);
- emit_section_change (acfg, ".text", 1);
- emit_label (acfg, symbol);
- emit_string (acfg, name);
- }
-
- /* Emit the globals table */
- sprintf (symbol, "globals");
- emit_section_change (acfg, ".data", 0);
- /* This is not a global, since it is accessed by the init function */
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
-
- for (i = 0; i < acfg->globals->len; ++i) {
- char *name = g_ptr_array_index (acfg->globals, i);
-
- sprintf (symbol, "name_%d", i);
- emit_pointer (acfg, symbol);
-
- sprintf (symbol, "%s", name);
- emit_pointer (acfg, symbol);
- }
- /* Null terminate the table */
- emit_int32 (acfg, 0);
- emit_int32 (acfg, 0);
+ emit_globals_table (acfg);
/*
* Emit a global symbol which can be passed by an embedding app to
emit_global_inner (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
- emit_pointer (acfg, "globals");
+ sprintf (symbol, "%sglobals", acfg->temp_prefix);
+ emit_pointer (acfg, symbol);
}
}
+static void
+emit_autoreg (MonoAotCompile *acfg)
+{
+ char *symbol;
+
+ /*
+ * Emit a function into the .ctor section which will be called by the ELF
+ * loader to register this module with the runtime.
+ */
+ if (! (!acfg->use_bin_writer && acfg->aot_opts.static_link && acfg->aot_opts.autoreg))
+ return;
+
+ symbol = g_strdup_printf ("_%s_autoreg", acfg->static_linking_symbol);
+
+ arch_emit_autoreg (acfg, symbol);
+
+ g_free (symbol);
+}
+
static void
emit_mem_end (MonoAotCompile *acfg)
{
emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
emit_int32 (acfg, acfg->plt_offset);
emit_int32 (acfg, acfg->nmethods);
+ emit_int32 (acfg, acfg->flags);
+ emit_int32 (acfg, acfg->opts);
for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
emit_int32 (acfg, acfg->num_trampolines [i]);
emit_int32 (acfg, acfg->trampoline_size [i]);
}
+static void
+emit_blob (MonoAotCompile *acfg)
+{
+ char symbol [128];
+
+ sprintf (symbol, "blob");
+ emit_section_change (acfg, ".text", 1);
+ emit_global (acfg, symbol, FALSE);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+
+ emit_bytes (acfg, (guint8*)acfg->blob.data, acfg->blob.index);
+}
+
static void
emit_dwarf_info (MonoAotCompile *acfg)
{
if (!cfg)
continue;
- sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
+ // FIXME: LLVM doesn't define .Lme_...
+ if (cfg->compile_llvm)
+ continue;
+
+ sprintf (symbol, "%s", cfg->asm_symbol);
sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, symbol, symbol2, 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 ()));
method = wrapper;
}
+ /* FIXME: Some mscorlib methods don't have debug info */
+ /*
+ if (acfg->aot_opts.soft_debug && !method->wrapper_type) {
+ if (!((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
+ (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))) {
+ if (!mono_debug_lookup_method (method)) {
+ fprintf (stderr, "Method %s has no debug info, probably the .mdb file for the assembly is missing.\n", mono_method_full_name (method, TRUE));
+ exit (1);
+ }
+ }
+ }
+ */
+
/* 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, FALSE);
acfg->method_index ++;
#ifndef LD_OPTIONS
#define LD_OPTIONS ""
+#endif
+
+#ifdef ENABLE_LLVM
+#define EH_LD_OPTIONS "--eh-frame-hdr"
+#else
+#define EH_LD_OPTIONS ""
#endif
if (acfg->aot_opts.asm_only) {
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", tmp_outfile_name, acfg->tmpfname);
-#elif defined(PLATFORM_WIN32)
+#elif defined(HOST_WIN32)
command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
#else
- command = g_strdup_printf ("%sld %s -shared -o %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
+ command = g_strdup_printf ("%sld %s %s -shared -o %s %s.o", tool_prefix, EH_LD_OPTIONS, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
#endif
printf ("Executing the native linker: %s\n", command);
if (system (command) != 0) {
{
MonoImage *image = ass->image;
MonoAotCompile *acfg;
+ int i;
acfg = g_new0 (MonoAotCompile, 1);
acfg->methods = g_ptr_array_new ();
acfg->method_indexes = g_hash_table_new (NULL, NULL);
+ acfg->method_depth = 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_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
+ acfg->patch_to_got_offset_by_type = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM);
+ for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
+ acfg->patch_to_got_offset_by_type [i] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
acfg->got_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);
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->method_depth);
g_hash_table_destroy (acfg->plt_offset_to_patch);
g_hash_table_destroy (acfg->patch_to_plt_offset);
g_hash_table_destroy (acfg->patch_to_got_offset);
g_hash_table_destroy (acfg->image_hash);
g_hash_table_destroy (acfg->unwind_info_offsets);
g_hash_table_destroy (acfg->method_label_hash);
+ for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
+ g_hash_table_destroy (acfg->patch_to_got_offset_by_type [i]);
+ g_free (acfg->patch_to_got_offset_by_type);
mono_mempool_destroy (acfg->mempool);
g_free (acfg);
}
mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
{
MonoImage *image = ass->image;
- int res;
+ int i, res;
MonoAotCompile *acfg;
char *outfile_name, *tmp_outfile_name, *p;
TV_DECLARE (atv);
memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts));
acfg->aot_opts.write_symbols = TRUE;
acfg->aot_opts.ntrampolines = 1024;
+ acfg->aot_opts.nrgctx_trampolines = 1024;
+ acfg->aot_opts.nimt_trampolines = 128;
mono_aot_parse_options (aot_options, &acfg->aot_opts);
+ if (acfg->aot_opts.static_link)
+ acfg->aot_opts.autoreg = TRUE;
+
//acfg->aot_opts.print_skipped_methods = TRUE;
#ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
if (acfg->aot_opts.static_link)
acfg->aot_opts.asm_writer = TRUE;
+ if (acfg->aot_opts.soft_debug) {
+ MonoDebugOptions *opt = mini_get_debug_options ();
+
+ opt->mdb_optimizations = TRUE;
+ opt->gen_seq_points = TRUE;
+
+ if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) {
+ fprintf (stderr, "The soft-debug AOT option requires the --debug option.\n");
+ return 1;
+ }
+ }
+
+#ifdef ENABLE_LLVM
+ acfg->llvm = TRUE;
+ acfg->aot_opts.asm_writer = TRUE;
+ acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
+#endif
+
+ if (acfg->aot_opts.full_aot)
+ acfg->flags |= MONO_AOT_FILE_FLAG_FULL_AOT;
+
load_profile_files (acfg);
acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0;
#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
- acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? 1024 : 0;
+ acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? acfg->aot_opts.nrgctx_trampolines : 0;
#endif
- acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? 128 : 0;
+ acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
- acfg->got_symbol = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
+ acfg->got_symbol_base = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
acfg->plt_symbol = g_strdup_printf ("mono_aot_%s_plt", acfg->image->assembly->aname.name);
/* Get rid of characters which cannot occur in symbols */
- for (p = acfg->got_symbol; *p; ++p) {
+ for (p = acfg->got_symbol_base; *p; ++p) {
if (!(isalnum (*p) || *p == '_'))
*p = '_';
}
*p = '_';
}
+ acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
+
acfg->method_index = 1;
collect_methods (acfg);
/* PLT offset 0 is reserved for the PLT trampoline */
acfg->plt_offset = 1;
+#ifdef ENABLE_LLVM
+ llvm_acfg = acfg;
+ mono_llvm_create_aot_module (acfg->got_symbol_base);
+#endif
+
/* GOT offset 0 is reserved for the address of the current assembly */
{
MonoJumpInfo *ji;
TV_GETTIME (atv);
+#ifdef ENABLE_LLVM
+ if (acfg->llvm) {
+ if (acfg->aot_opts.asm_only) {
+ if (acfg->aot_opts.outfile)
+ acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+ else
+ acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
+ } else {
+ acfg->tmpfname = g_strdup ("temp.s");
+ }
+ }
+
+ emit_llvm_file (acfg);
+#endif
+
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, TRUE);
acfg->use_bin_writer = TRUE;
} else {
- if (acfg->aot_opts.asm_only) {
- if (acfg->aot_opts.outfile)
- acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
- else
- acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
- acfg->fp = fopen (acfg->tmpfname, "w+");
+ if (acfg->llvm) {
+ /* Append to the .s file created by llvm */
+ /* FIXME: Use multiple files instead */
+ acfg->fp = fopen (acfg->tmpfname, "a+");
} else {
- int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
- acfg->fp = fdopen (i, "w+");
+ if (acfg->aot_opts.asm_only) {
+ if (acfg->aot_opts.outfile)
+ acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+ else
+ acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
+ acfg->fp = fopen (acfg->tmpfname, "w+");
+ } else {
+ int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
+ acfg->fp = fdopen (i, "w+");
+ }
+ g_assert (acfg->fp);
}
- g_assert (acfg->fp);
-
acfg->w = img_writer_create (acfg->fp, FALSE);
tmp_outfile_name = NULL;
outfile_name = NULL;
}
- acfg->temp_prefix = img_writer_get_temp_label_prefix (acfg->w);
+ /*
+ * The prefix LLVM likes to put in front of symbol names on darwin.
+ * The mach-os specs require this for globals, but LLVM puts them in front of all
+ * symbols. We need to handle this, since we need to refer to LLVM generated
+ * symbols.
+ */
+ acfg->llvm_label_prefix = "";
+ if (acfg->llvm)
+ acfg->llvm_label_prefix = LLVM_LABEL_PREFIX;
+
+ acfg->got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->got_symbol_base);
+
+ /* Compute symbols for methods */
+ for (i = 0; i < acfg->nmethods; ++i) {
+ if (acfg->cfgs [i]) {
+ MonoCompile *cfg = acfg->cfgs [i];
+ int method_index = get_method_index (acfg, cfg->orig_method);
+
+ cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, LLVM_LABEL_PREFIX, method_index);
+ }
+ }
if (!acfg->aot_opts.nodebug)
- acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, FALSE);
+ acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE);
img_writer_emit_start (acfg->w);
if (acfg->dwarf)
- mono_dwarf_writer_emit_base_info (acfg->dwarf, arch_get_cie_program ());
+ mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_unwind_get_cie_program ());
emit_code (acfg);
emit_extra_methods (acfg);
- emit_method_order (acfg);
-
emit_trampolines (acfg);
emit_class_name_table (acfg);
emit_file_info (acfg);
+ emit_blob (acfg);
+
emit_globals (acfg);
+ emit_autoreg (acfg);
+
if (acfg->dwarf) {
emit_dwarf_info (acfg);
mono_dwarf_writer_close (acfg->dwarf);
acfg->stats.gen_time = TV_ELAPSED (atv, btv);
- 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 Offsets: %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)), (int)(acfg->nmethods * 3 * sizeof (gpointer)));
+ if (acfg->llvm)
+ g_assert (acfg->got_offset <= acfg->final_got_size);
+
+ printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT: %d Offsets: %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, (int)(acfg->got_offset * sizeof (gpointer)), acfg->stats.offsets_size);
TV_GETTIME (atv);
res = img_writer_emit_writeout (acfg->w);
printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
if (acfg->stats.ocount)
printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
+ if (acfg->llvm)
+ printf ("Methods compiled with LLVM: %d (%d%%)\n", acfg->stats.llvm_count, acfg->stats.mcount ? (acfg->stats.llvm_count * 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 ("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]);
- */
+ if (acfg->aot_opts.stats) {
+ int i;
+
+ 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);
return 0;
}
-
-/*
- * Support for emitting debug info for JITted code.
- *
- * This works as follows:
- * - the runtime writes out an xdb.s file containing DWARF debug info.
- * - the user calls a gdb macro
- * - the macro compiles and loads this shared library using add-symbol-file.
- *
- * This is based on the xdebug functionality in the Kaffe Java VM.
- *
- * We emit assembly code instead of using the ELF writer, so we can emit debug info
- * incrementally as each method is JITted, and the debugger doesn't have to call
- * into the runtime to emit the shared library, which would cause all kinds of
- * complications, like threading issues, and the fact that the ELF writer's
- * emit_writeout () function cannot be called more than once.
- */
-
-/* The recommended gdb macro is: */
-/*
- define xdb
- shell rm -f xdb.so && as --64 -o xdb.o xdb.s && ld -shared -o xdb.so xdb.o
- add-symbol-file xdb.so 0
- end
-*/
-
-static MonoDwarfWriter *xdebug_writer;
-static FILE *xdebug_fp;
-
-void
-mono_xdebug_init (void)
-{
- FILE *il_file;
- MonoImageWriter *w;
-
- unlink ("xdb.s");
- xdebug_fp = fopen ("xdb.s", "w");
-
- w = img_writer_create (xdebug_fp, FALSE);
-
- img_writer_emit_start (w);
-
- /* This file will contain the IL code for methods which don't have debug info */
- il_file = fopen ("xdb.il", "w");
-
- xdebug_writer = mono_dwarf_writer_create (w, il_file, TRUE);
-
- /* Emit something so the file has a text segment */
- img_writer_emit_section_change (w, ".text", 0);
- img_writer_emit_string (w, "");
-
- mono_dwarf_writer_emit_base_info (xdebug_writer, arch_get_cie_program ());
-}
-
-/*
- * mono_save_xdebug_info:
- *
- * 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)
-{
- if (!xdebug_writer)
- return;
-
- 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)
-{
- if (!xdebug_writer)
- return;
-
- 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
return 0;
}
-void
-mono_xdebug_init (void)
-{
-}
-
-void
-mono_save_xdebug_info (MonoCompile *cfg)
-{
-}
-
-void
-mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
-{
-}
-
#endif