* - 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>
#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;
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 *method_label_hash;
const char *temp_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
* 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
}
+static void
+arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
+{
+#if defined(TARGET_POWERPC) && defined(__mono_ilp32__)
+ /* Based on code generated by gcc */
+ img_writer_emit_unset_mode (acfg->w);
+
+ 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
+
+
+ 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
+#endif
+}
+
/*
* arch_get_cie_program:
*
*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_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;
+ g_assert (!acfg->final_got_size);
+
got_offset = acfg->got_offset;
acfg->got_offset ++;
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 (!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));
}
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));
}
}
}
}
/*
- * 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));
}
}
}
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));
}
}
}
/* Make the labels local */
sprintf (symbol, "%sm_%x", acfg->temp_prefix, method_index);
+ 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) {
- for (k = 0; k < header->num_clauses; ++k) {
- MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+ if (jinfo->num_clauses)
+ encode_value (jinfo->num_clauses, p, &p);
- encode_value (ei->exvar_offset, p, &p);
+ for (k = 0; k < jinfo->num_clauses; ++k) {
+ MonoJitExceptionInfo *ei = &jinfo->clauses [k];
- if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
- encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+ encode_value (ei->flags, p, &p);
+ encode_value (ei->exvar_offset, p, &p);
- encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
- encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
- encode_value ((gint)((guint8*)ei->handler_start - code), 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_value ((gint)((guint8*)ei->handler_start - code), p, &p);
}
if (jinfo->has_generic_jit_info) {
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, "%sp_%d", 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, .Lm_%x\n", label, get_method_index (acfg, callee_cfg->orig_method));
+ continue;
+ }
+ }
+
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) {
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, "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);
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);
+ 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;
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);
+}
-static void
-emit_code (MonoAotCompile *acfg)
+char*
+mono_aot_get_method_name (MonoCompile *cfg)
{
- int i;
- char symbol [256];
- GList *l;
+ guint32 method_index = get_method_index (llvm_acfg, cfg->orig_method);
-#if defined(TARGET_POWERPC64)
- sprintf (symbol, ".Lgot_addr");
- emit_section_change (acfg, ".text", 0);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
- emit_pointer (acfg, acfg->got_symbol);
-#endif
+ /* LLVM converts these to .Lm_%x */
+ return g_strdup_printf ("m_%x", method_index);
+}
- sprintf (symbol, "methods");
- emit_section_change (acfg, ".text", 0);
- emit_global (acfg, symbol, TRUE);
- emit_alignment (acfg, 8);
+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 (".Lp_%d", 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;
+
+ /*
+ * 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;
+
+ 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'
+ */
+ opts = g_strdup ("-instcombine -simplifycfg");
+#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);
+
+ //command = g_strdup_printf ("llc -march=arm -mtriple=arm-linux-gnueabi -f -relocation-model=pic -unwind-tables temp.bc");
+ command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables -o temp.s temp.opt.bc");
+ printf ("Executing llc: %s\n", command);
+
+ if (system (command) != 0) {
+ exit (1);
+ }
+}
+#endif
+
+static void
+emit_code (MonoAotCompile *acfg)
+{
+ int i;
+ char symbol [256];
+ GList *l;
+
+#if defined(TARGET_POWERPC64)
+ sprintf (symbol, ".Lgot_addr");
+ emit_section_change (acfg, ".text", 0);
+ emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ emit_pointer (acfg, acfg->got_symbol);
+#endif
+
+ if (!acfg->llvm) {
+ sprintf (symbol, "methods");
+ emit_section_change (acfg, ".text", 0);
+ emit_global (acfg, symbol, TRUE);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+ }
/*
* Emit some padding so the local symbol for the first method doesn't have the
for (l = acfg->method_order; l != NULL; l = l->next) {
i = GPOINTER_TO_UINT (l->data);
- if (acfg->cfgs [i])
- emit_method_code (acfg, acfg->cfgs [i]);
+ if (acfg->cfgs [i]) {
+ if (acfg->cfgs [i]->compile_llvm)
+ acfg->stats.llvm_count ++;
+ else
+ emit_method_code (acfg, acfg->cfgs [i]);
+ }
}
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;
+
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
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:
+ 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;
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 */
+ /* This is a hack to work around the fact that these wrappers get assigned to some random class */
name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
break;
default:
klass_desc = mono_type_full_name (&method->klass->byval_arg);
-
name = g_strdup_printf ("%s:%s (%s)", klass_desc, method->name, tmpsig);
+ 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;
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)
-{
- int i, index, len;
- char symbol [256];
- GList *l;
-
- sprintf (symbol, "method_order");
- 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];
+ gint32 *offsets;
- 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);
-
+ offsets = g_new0 (gint32, acfg->nmethods);
for (i = 0; i < acfg->nmethods; ++i) {
- if (acfg->cfgs [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, "ex_info_offsets");
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
{
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;
+ // FIXME: LLVM doesn't define .Lme_...
+ if (cfg->compile_llvm)
+ continue;
+
sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
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);
}
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;
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;
/* 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);
+#endif
+
/* GOT offset 0 is reserved for the address of the current assembly */
{
MonoJumpInfo *ji;
TV_GETTIME (atv);
+#ifdef ENABLE_LLVM
+ 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->tmpfname = g_strdup ("temp.s");
+ 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;
acfg->temp_prefix = img_writer_get_temp_label_prefix (acfg->w);
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);
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);
* 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.
+ * GDB 7.0 and later has a JIT interface.
*/
+#define USE_GDB_JIT_INTERFACE
+
/* The recommended gdb macro is: */
/*
define xdb
end
*/
+/*
+ * GDB JIT interface definitions.
+ *
+ * http://sources.redhat.com/gdb/onlinedocs/gdb_30.html
+ */
+typedef enum
+{
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry
+{
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const char *symfile_addr;
+ guint64 symfile_size;
+};
+
+struct jit_descriptor
+{
+ guint32 version;
+ /* This type should be jit_actions_t, but we use guint32
+ to be explicit about the bitwidth. */
+ guint32 action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+};
+
+
+#ifdef _MSC_VER
+#define MONO_NOINLINE __declspec (noinline)
+#else
+#define MONO_NOINLINE __attribute__((noinline))
+#endif
+
+/* GDB puts a breakpoint in this function. */
+void MONO_NOINLINE __jit_debug_register_code(void);
+
+#if defined(ENABLE_LLVM) && ((LLVM_MAJOR_VERSION == 2 && LLVM_MINOR_VERSION >= 7) || LLVM_MAJOR_VERSION > 2)
+/* LLVM already defines these */
+extern struct jit_descriptor __jit_debug_descriptor;
+#else
+
+/* Make sure to specify the version statically, because the
+ debugger may check the version before we can set it. */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+void MONO_NOINLINE __jit_debug_register_code(void) { };
+#endif
+
+static MonoImageWriter *xdebug_w;
static MonoDwarfWriter *xdebug_writer;
-static FILE *xdebug_fp;
+static FILE *xdebug_fp, *il_file;
+static gboolean use_gdb_interface, save_symfiles;
+static int il_file_line_index;
+static GHashTable *xdebug_syms;
void
-mono_xdebug_init (void)
+mono_xdebug_init (char *options)
{
- FILE *il_file;
MonoImageWriter *w;
+ char **args, **ptr;
+
+ args = g_strsplit (options, ",", -1);
+ for (ptr = args; ptr && *ptr; ptr ++) {
+ char *arg = *ptr;
+
+ if (!strcmp (arg, "gdb"))
+ use_gdb_interface = TRUE;
+ if (!strcmp (arg, "save-symfiles"))
+ save_symfiles = TRUE;
+ }
+
+ /* This file will contain the IL code for methods which don't have debug info */
+ il_file = fopen ("xdb.il", "w");
+
+ if (use_gdb_interface)
+ return;
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);
+ xdebug_writer = mono_dwarf_writer_create (w, il_file, 0, TRUE);
/* Emit something so the file has a text segment */
img_writer_emit_section_change (w, ".text", 0);
mono_dwarf_writer_emit_base_info (xdebug_writer, arch_get_cie_program ());
}
+static void
+xdebug_begin_emit (MonoImageWriter **out_w, MonoDwarfWriter **out_dw)
+{
+ MonoImageWriter *w;
+ MonoDwarfWriter *dw;
+
+ w = img_writer_create (NULL, TRUE);
+
+ img_writer_emit_start (w);
+
+ /* This file will contain the IL code for methods which don't have debug info */
+ if (!il_file)
+ il_file = fopen ("xdb.il", "w");
+
+ dw = mono_dwarf_writer_create (w, il_file, il_file_line_index, FALSE);
+
+ mono_dwarf_writer_emit_base_info (dw, arch_get_cie_program ());
+
+ *out_w = w;
+ *out_dw = dw;
+}
+
+static void
+xdebug_end_emit (MonoImageWriter *w, MonoDwarfWriter *dw, MonoMethod *method)
+{
+ guint8 *img;
+ guint32 img_size;
+ struct jit_code_entry *entry;
+
+ il_file_line_index = mono_dwarf_writer_get_il_file_line_index (dw);
+ mono_dwarf_writer_close (dw);
+
+ img_writer_emit_writeout (w);
+
+ img = img_writer_get_output (w, &img_size);
+
+ img_writer_destroy (w);
+
+ if (FALSE) {
+ /* Save the symbol files to help debugging */
+ FILE *fp;
+ char *file_name;
+ static int file_counter;
+
+ file_counter ++;
+ file_name = g_strdup_printf ("xdb-%d.o", file_counter);
+ //printf ("%s -> %s\n", mono_method_full_name (method, TRUE), file_name);
+
+ fp = fopen (file_name, "w");
+ fwrite (img, img_size, 1, fp);
+ fclose (fp);
+ g_free (file_name);
+ }
+
+ /* Register the image with GDB */
+
+ entry = g_malloc (sizeof (struct jit_code_entry));
+
+ entry->symfile_addr = (const char*)img;
+ entry->symfile_size = img_size;
+
+ entry->next_entry = __jit_debug_descriptor.first_entry;
+ if (__jit_debug_descriptor.first_entry)
+ __jit_debug_descriptor.first_entry->prev_entry = entry;
+ __jit_debug_descriptor.first_entry = entry;
+
+ __jit_debug_descriptor.relevant_entry = entry;
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+
+ __jit_debug_register_code ();
+}
+
+/*
+ * mono_xdebug_flush:
+ *
+ * This could be called from inside gdb to flush the debugging information not yet
+ * registered with gdb.
+ */
+void
+mono_xdebug_flush (void)
+{
+ if (xdebug_w)
+ xdebug_end_emit (xdebug_w, xdebug_writer, NULL);
+
+ xdebug_begin_emit (&xdebug_w, &xdebug_writer);
+}
+
+static int xdebug_method_count;
+
/*
* mono_save_xdebug_info:
*
void
mono_save_xdebug_info (MonoCompile *cfg)
{
- if (!xdebug_writer)
- return;
+ if (use_gdb_interface) {
+ mono_loader_lock ();
+
+ if (!xdebug_syms)
+ xdebug_syms = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ /*
+ * gdb is not designed to handle 1000s of symbol files (one per method). So we
+ * group them into groups of 100.
+ */
+ if ((xdebug_method_count % 100) == 0)
+ mono_xdebug_flush ();
+
+ xdebug_method_count ++;
+
+ 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 ()));
+
+#if 0
+ /*
+ * Emit a symbol for the code by emitting it at the beginning of the text
+ * segment, and setting the text segment to have an absolute address.
+ * This symbol can be used to set breakpoints in gdb.
+ * FIXME: This doesn't work when multiple methods are emitted into the same file.
+ */
+ sym = get_debug_sym (cfg->jit_info->method, "", xdebug_syms);
+ img_writer_emit_section_change (w, ".text", 0);
+ if (!xdebug_text_addr) {
+ xdebug_text_addr = cfg->jit_info->code_start;
+ img_writer_set_section_addr (w, (gssize)xdebug_text_addr);
+ }
+ img_writer_emit_global_with_size (w, sym, cfg->jit_info->code_size, TRUE);
+ img_writer_emit_label (w, sym);
+ img_writer_emit_bytes (w, cfg->jit_info->code_start, cfg->jit_info->code_size);
+ g_free (sym);
+#endif
+
+ mono_loader_unlock ();
+ } else {
+ 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_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 ();
+ }
}
/*
void
mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
{
- if (!xdebug_writer)
- return;
+ if (use_gdb_interface) {
+ MonoImageWriter *w;
+ MonoDwarfWriter *dw;
- 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 ();
+ mono_loader_lock ();
+
+ xdebug_begin_emit (&w, &dw);
+
+ mono_dwarf_writer_emit_trampoline (dw, tramp_name, NULL, NULL, code, code_size, unwind_info);
+
+ xdebug_end_emit (w, dw, NULL);
+
+ mono_loader_unlock ();
+ } else {
+ 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
}
void
-mono_xdebug_init (void)
+mono_xdebug_init (char *options)
{
}