#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
+#if defined(__linux__)
+#define RODATA_SECT ".rodata"
+#else
+#define RODATA_SECT ".text"
+#endif
+
#define TV_DECLARE(name) gint64 name
#define TV_GETTIME(tv) tv = mono_100ns_ticks ()
#define TV_ELAPSED(start,end) (((end) - (start)) / 10)
GHashTable *method_depth;
MonoCompile **cfgs;
int cfgs_size;
- GHashTable *patch_to_plt_offset;
- GHashTable *plt_offset_to_patch;
+ GHashTable *patch_to_plt_entry;
+ GHashTable *plt_offset_to_entry;
GHashTable *patch_to_got_offset;
GHashTable **patch_to_got_offset_by_type;
GPtrArray *got_patches;
MonoDynamicStream blob;
} MonoAotCompile;
+typedef struct {
+ int plt_offset;
+ char *symbol;
+ MonoJumpInfo *ji;
+} MonoPltEntry;
+
#define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
#define mono_acfg_unlock(acfg) LeaveCriticalSection (&((acfg)->mutex))
static void
emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
{
- img_writer_emit_section_change (acfg->w, ".text", 1);
+ img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
emit_global (acfg, name, FALSE);
img_writer_emit_label (acfg->w, name);
img_writer_emit_string (acfg->w, value);
* one.
*/
+/*
+ * X86 design:
+ * - similar to the PPC32 design, we reserve EBX to hold the GOT pointer.
+ */
+
#ifdef MONO_ARCH_AOT_SUPPORTED
/*
* arch_emit_got_offset:
arch_emit_plt_entry (MonoAotCompile *acfg, int index)
{
#if defined(TARGET_X86)
- if (index == 0) {
- /* It is filled up during loading by the AOT loader. */
- emit_zero_bytes (acfg, 16);
- } else {
- /* Need to make sure this is 9 bytes long */
- emit_byte (acfg, '\xe9');
- emit_symbol_diff (acfg, acfg->plt_symbol, ".", -4);
- emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
- }
+ guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
+
+ /* jmp *<offset>(%ebx) */
+ emit_byte (acfg, 0xff);
+ emit_byte (acfg, 0xa3);
+ emit_int32 (acfg, offset);
+ /* Used by mono_aot_get_plt_info_offset */
+ emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
#elif defined(TARGET_AMD64)
/*
* We can't emit jumps because they are 32 bits only so they can't be patched.
#else
*tramp_size = 9 * 4;
#endif
+#elif defined(TARGET_X86)
+ guint8 buf [128];
+ guint8 *code;
+
+ /* Similar to the PPC code above */
+
+ /* FIXME: Could this clobber the register needed by get_vcall_slot () ? */
+
+ /* We clobber ECX, since EAX is used as MONO_ARCH_MONITOR_OBJECT_REG */
+#ifdef MONO_ARCH_MONITOR_OBJECT_REG
+ g_assert (MONO_ARCH_MONITOR_OBJECT_REG != X86_ECX);
+#endif
+
+ code = buf;
+ /* Load mscorlib got address */
+ x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
+ /* Push trampoline argument */
+ x86_push_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
+ /* Load generic trampoline address */
+ x86_mov_reg_membase (code, X86_ECX, X86_ECX, offset * sizeof (gpointer), 4);
+ /* Branch to generic trampoline */
+ x86_jump_reg (code, X86_ECX);
+
+ emit_bytes (acfg, buf, code - buf);
+
+ *tramp_size = 17;
+ g_assert (code - buf == *tramp_size);
#else
g_assert_not_reached ();
#endif
amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
emit_bytes (acfg, buf, code - buf);
+ /* jump <method> */
+ emit_byte (acfg, '\xe9');
+ emit_symbol_diff (acfg, call_target, ".", -4);
+#elif defined(TARGET_X86)
+ guint8 buf [32];
+ guint8 *code;
+ int this_pos = 4;
+
+ code = buf;
+
+ x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
+
+ emit_bytes (acfg, buf, code - buf);
+
/* jump <method> */
emit_byte (acfg, '\xe9');
emit_symbol_diff (acfg, call_target, ".", -4);
#elif defined(TARGET_ARM)
guint8 buf [128];
guint8 *code;
- int this_pos = 0;
code = buf;
- if (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret))
- this_pos = 1;
-
- ARM_ADD_REG_IMM8 (code, this_pos, this_pos, sizeof (MonoObject));
+ ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (MonoObject));
emit_bytes (acfg, buf, code - buf);
/* jump to method */
#elif defined(TARGET_POWERPC)
int this_pos = 3;
- if (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret))
- this_pos = 4;
-
g_assert (!acfg->use_bin_writer);
fprintf (acfg->fp, "\n\taddi %d, %d, %d\n", this_pos, this_pos, (int)sizeof (MonoObject));
*tramp_size = 9 * 4;
#endif
+#elif defined(TARGET_X86)
+ guint8 buf [128];
+ guint8 *code;
+
+ /* Similar to the PPC code above */
+
+ g_assert (MONO_ARCH_RGCTX_REG != X86_ECX);
+
+ code = buf;
+ /* Load mscorlib got address */
+ x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
+ /* Load arg */
+ x86_mov_reg_membase (code, MONO_ARCH_RGCTX_REG, X86_ECX, offset * sizeof (gpointer), 4);
+ /* Branch to the target address */
+ x86_jump_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
+
+ emit_bytes (acfg, buf, code - buf);
+
+ *tramp_size = 15;
+ g_assert (code - buf == *tramp_size);
#else
g_assert_not_reached ();
#endif
/* FIXME: Optimize this, i.e. use binary search etc. */
/* Maybe move the body into a separate function (slower, but much smaller) */
- /* R10 is a free register */
+ /* R11 is a free register */
labels [0] = code;
- amd64_alu_membase_imm (code, X86_CMP, AMD64_R10, 0, 0);
+ amd64_alu_membase_imm (code, X86_CMP, AMD64_R11, 0, 0);
labels [1] = code;
amd64_branch8 (code, X86_CC_Z, FALSE, 0);
/* Check key */
- amd64_alu_membase_reg (code, X86_CMP, AMD64_R10, 0, MONO_ARCH_IMT_REG);
+ amd64_alu_membase_reg (code, X86_CMP, AMD64_R11, 0, MONO_ARCH_IMT_REG);
labels [2] = code;
amd64_branch8 (code, X86_CC_Z, FALSE, 0);
/* Loop footer */
- amd64_alu_reg_imm (code, X86_ADD, AMD64_R10, 2 * sizeof (gpointer));
+ amd64_alu_reg_imm (code, X86_ADD, AMD64_R11, 2 * sizeof (gpointer));
amd64_jump_code (code, labels [0]);
/* Match */
mono_amd64_patch (labels [2], code);
- amd64_mov_reg_membase (code, AMD64_R10, AMD64_R10, sizeof (gpointer), 8);
- amd64_jump_membase (code, AMD64_R10, 0);
+ amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, sizeof (gpointer), 8);
+ amd64_jump_membase (code, AMD64_R11, 0);
/* No match */
/* FIXME: */
mono_amd64_patch (labels [1], code);
x86_breakpoint (code);
- /* mov <OFFSET>(%rip), %r10 */
+ amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 12345678, 8);
+
+ /* mov <OFFSET>(%rip), %r11 */
emit_byte (acfg, '\x4d');
emit_byte (acfg, '\x8b');
- emit_byte (acfg, '\x15');
+ emit_byte (acfg, '\x1d');
emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
emit_bytes (acfg, buf, code - buf);
*tramp_size = code - buf + 7;
+#elif defined(TARGET_X86)
+ guint8 *buf, *code;
+ guint8 *labels [3];
+
+ code = buf = g_malloc (256);
+
+ /* Allocate a temporary stack slot */
+ x86_push_reg (code, X86_EAX);
+ /* Save EAX */
+ x86_push_reg (code, X86_EAX);
+
+ /* Load mscorlib got address */
+ x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
+ /* Load arg */
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, offset * sizeof (gpointer), 4);
+
+ labels [0] = code;
+ x86_alu_membase_imm (code, X86_CMP, X86_EAX, 0, 0);
+ labels [1] = code;
+ x86_branch8 (code, X86_CC_Z, FALSE, 0);
+
+ /* Check key */
+ x86_alu_membase_reg (code, X86_CMP, X86_EAX, 0, MONO_ARCH_IMT_REG);
+ labels [2] = code;
+ x86_branch8 (code, X86_CC_Z, FALSE, 0);
+
+ /* Loop footer */
+ x86_alu_reg_imm (code, X86_ADD, X86_EAX, 2 * sizeof (gpointer));
+ x86_jump_code (code, labels [0]);
+
+ /* Match */
+ mono_x86_patch (labels [2], code);
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, sizeof (gpointer), 4);
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, 4);
+ /* Save the target address to the temporary stack location */
+ x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
+ /* Restore EAX */
+ x86_pop_reg (code, X86_EAX);
+ /* Jump to the target address */
+ x86_ret (code);
+
+ /* No match */
+ /* FIXME: */
+ mono_x86_patch (labels [1], code);
+ x86_breakpoint (code);
+
+ emit_bytes (acfg, buf, code - buf);
+
+ *tramp_size = code - buf;
#elif defined(TARGET_ARM)
guint8 buf [128];
guint8 *code, *code2, *labels [16];
return 0;
}
+static G_GNUC_UNUSED char*
+patch_to_string (MonoJumpInfo *patch_info)
+{
+ GString *str;
+
+ str = g_string_new ("");
+
+ g_string_append_printf (str, "%s(", get_patch_name (patch_info->type));
+
+ switch (patch_info->type) {
+ case MONO_PATCH_INFO_VTABLE:
+ mono_type_get_desc (str, &patch_info->data.klass->byval_arg, TRUE);
+ break;
+ default:
+ break;
+ }
+ g_string_append_printf (str, ")");
+ return g_string_free (str, FALSE);
+}
+
/*
* is_plt_patch:
*
}
}
-static int
-get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+/*
+ * get_plt_symbol:
+ *
+ * Return the symbol identifying the plt entry PLT_OFFSET.
+ */
+static char*
+get_plt_symbol (MonoAotCompile *acfg, int plt_offset, MonoJumpInfo *patch_info)
{
- int res = -1;
+#ifdef __MACH__
+ /*
+ * The Apple linker reorganizes object files, so it doesn't like branches to local
+ * labels, since those have no relocations.
+ */
+ return g_strdup_printf ("%sp_%d", acfg->llvm_label_prefix, plt_offset);
+#else
+ return g_strdup_printf ("%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, plt_offset);
+#endif
+}
- if (is_plt_patch (patch_info)) {
- int idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info));
+/*
+ * get_plt_entry:
+ *
+ * Return a PLT entry which belongs to the method identified by PATCH_INFO.
+ */
+static MonoPltEntry*
+get_plt_entry (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+{
+ MonoPltEntry *res;
- // 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 the
- * wrapper.
- */
- idx = 0;
- }
+ if (!is_plt_patch (patch_info))
+ return NULL;
- if (idx) {
- res = idx;
- } else {
- MonoJumpInfo *new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
+ res = g_hash_table_lookup (acfg->patch_to_plt_entry, patch_info);
- g_assert (!acfg->final_got_size);
+ // 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 the
+ * wrapper.
+ */
+ res = NULL;
+ }
- 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));
- acfg->plt_offset ++;
- }
+ if (!res) {
+ MonoJumpInfo *new_ji;
+
+ g_assert (!acfg->final_got_size);
+
+ new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
+
+ res = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoPltEntry));
+ res->plt_offset = acfg->plt_offset;
+ res->ji = new_ji;
+ res->symbol = get_plt_symbol (acfg, res->plt_offset, patch_info);
+
+ g_hash_table_insert (acfg->patch_to_plt_entry, new_ji, res);
+
+ g_hash_table_insert (acfg->plt_offset_to_entry, GUINT_TO_POINTER (res->plt_offset), res);
+
+ acfg->plt_offset ++;
}
return res;
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));
+ add_method (acfg, mono_marshal_get_managed_wrapper (method, klass, 0));
}
}
return FALSE;
}
+static void add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth);
+
+static void
+add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
+{
+ add_generic_class_with_depth (acfg, klass, 0);
+}
+
/*
* add_generic_class:
*
* Add all methods of a generic class.
*/
static void
-add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
+add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth)
{
MonoMethod *method;
gpointer iter;
* FIXME: Instances which are referenced by these methods are not added,
* for example Array.Resize<int> for List<int>.Add ().
*/
- add_extra_method (acfg, method);
+ add_extra_method_with_depth (acfg, method, depth);
}
if (klass->delegate) {
while ((method = mono_class_get_methods (array_class, &iter))) {
if (strstr (method->name, name_prefix)) {
MonoMethod *m = mono_aot_get_array_helper_from_wrapper (method);
- add_extra_method (acfg, m);
+ add_extra_method_with_depth (acfg, m, depth);
}
}
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, callee_cfg->asm_symbol);
+ sprintf (direct_call_target, "%s", callee_cfg->asm_symbol);
patch_info->type = MONO_PATCH_INFO_NONE;
acfg->stats.direct_calls ++;
}
}
if (!got_only && !direct_call) {
- int plt_offset = get_plt_offset (acfg, patch_info);
- if (plt_offset != -1) {
+ MonoPltEntry *plt_entry = get_plt_entry (acfg, patch_info);
+ if (plt_entry) {
/* This patch has a PLT entry, so we must emit a call to the PLT entry */
direct_call = TRUE;
- sprintf (direct_call_target, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, plt_offset);
+ sprintf (direct_call_target, "%s", plt_entry->symbol);
/* Nullify the patch */
patch_info->type = MONO_PATCH_INFO_NONE;
method = cfg->orig_method;
code = cfg->native_code;
- header = mono_method_get_header (method);
+ header = cfg->header;
method_index = get_method_index (acfg, method);
method = cfg->orig_method;
code = cfg->native_code;
- header = mono_method_get_header (method);
+ header = cfg->header;
method_index = get_method_index (acfg, method);
/* Exception table */
if (cfg->compile_llvm) {
+ /*
+ * When using LLVM, we can't emit some data, like pc offsets, this reg/offset etc.,
+ * since the information is only available to llc. Instead, we let llc save the data
+ * into the LSDA, and read it from there at runtime.
+ */
/* The assembly might be CIL stripped so emit the data ourselves */
if (header->num_clauses)
encode_value (header->num_clauses, p, &p);
} else {
encode_value (0, p, &p);
}
+
+ /* Emit a list of nesting clauses */
+ for (i = 0; i < header->num_clauses; ++i) {
+ gint32 cindex1 = k;
+ MonoExceptionClause *clause1 = &header->clauses [cindex1];
+ gint32 cindex2 = i;
+ MonoExceptionClause *clause2 = &header->clauses [cindex2];
+
+ if (cindex1 != cindex2 && clause1->try_offset >= clause2->try_offset && clause1->handler_offset <= clause2->handler_offset)
+ encode_value (i, p, &p);
+ }
+ encode_value (-1, p, &p);
}
} else {
if (jinfo->num_clauses)
if (jinfo->has_generic_jit_info) {
MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (jinfo);
- encode_value (gi->has_this ? 1 : 0, p, &p);
- encode_value (gi->this_reg, p, &p);
- encode_value (gi->this_offset, p, &p);
+ if (!cfg->compile_llvm) {
+ encode_value (gi->has_this ? 1 : 0, p, &p);
+ encode_value (gi->this_reg, p, &p);
+ encode_value (gi->this_offset, p, &p);
+ }
/*
* Need to encode jinfo->method too, since it is not equal to 'method'
gboolean no_special_static, cant_encode;
gpointer iter = NULL;
+ if (!klass) {
+ buf_size = 16;
+
+ p = buf = g_malloc (buf_size);
+
+ /* Mark as unusable */
+ encode_value (-1, p, &p);
+
+ res = add_to_blob (acfg, buf, p - buf);
+ g_free (buf);
+
+ return res;
+ }
+
buf_size = 10240 + (klass->vtable_size * 16);
p = buf = g_malloc (buf_size);
emit_section_change (acfg, ".text", 0);
emit_global (acfg, symbol, TRUE);
-#ifdef TARGET_X86
- /* This section will be made read-write by the AOT loader */
- emit_alignment (acfg, mono_pagesize ());
-#else
emit_alignment (acfg, 16);
-#endif
emit_label (acfg, symbol);
emit_label (acfg, acfg->plt_symbol);
for (i = 0; i < acfg->plt_offset; ++i) {
char label [128];
char *debug_sym = NULL;
+ MonoPltEntry *plt_entry = NULL;
MonoJumpInfo *ji;
- sprintf (label, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, i);
+ if (i == 0) {
+ /*
+ * The first plt entry is used to transfer code to the AOT loader.
+ */
+ arch_emit_plt_entry (acfg, i);
+ continue;
+ }
+
+ plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
+ ji = plt_entry->ji;
+ sprintf (label, "%s", plt_entry->symbol);
if (acfg->llvm) {
/*
* 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);
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));
-
- if (ji) {
- switch (ji->type) {
- case MONO_PATCH_INFO_METHOD:
- debug_sym = get_debug_sym (ji->data.method, "plt_", cache);
- break;
- case MONO_PATCH_INFO_INTERNAL_METHOD:
- debug_sym = g_strdup_printf ("plt__jit_icall_%s", ji->data.name);
- break;
- case MONO_PATCH_INFO_CLASS_INIT:
- debug_sym = g_strdup_printf ("plt__class_init_%s", mono_type_get_name (&ji->data.klass->byval_arg));
- sanitize_symbol (debug_sym);
- break;
- case MONO_PATCH_INFO_RGCTX_FETCH:
- debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
- break;
- case MONO_PATCH_INFO_ICALL_ADDR: {
- char *s = get_debug_sym (ji->data.method, "", cache);
+ switch (ji->type) {
+ case MONO_PATCH_INFO_METHOD:
+ debug_sym = get_debug_sym (ji->data.method, "plt_", cache);
+ break;
+ case MONO_PATCH_INFO_INTERNAL_METHOD:
+ debug_sym = g_strdup_printf ("plt__jit_icall_%s", ji->data.name);
+ break;
+ case MONO_PATCH_INFO_CLASS_INIT:
+ debug_sym = g_strdup_printf ("plt__class_init_%s", mono_type_get_name (&ji->data.klass->byval_arg));
+ sanitize_symbol (debug_sym);
+ break;
+ case MONO_PATCH_INFO_RGCTX_FETCH:
+ debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
+ break;
+ case MONO_PATCH_INFO_ICALL_ADDR: {
+ char *s = get_debug_sym (ji->data.method, "", cache);
- debug_sym = g_strdup_printf ("plt__icall_native_%s", s);
- g_free (s);
- break;
- }
- case MONO_PATCH_INFO_JIT_ICALL_ADDR:
- debug_sym = g_strdup_printf ("plt__jit_icall_native_%s", ji->data.name);
- break;
- case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
- debug_sym = g_strdup_printf ("plt__generic_class_init");
- break;
- default:
- break;
- }
+ debug_sym = g_strdup_printf ("plt__icall_native_%s", s);
+ g_free (s);
+ break;
+ }
+ case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+ debug_sym = g_strdup_printf ("plt__jit_icall_native_%s", ji->data.name);
+ break;
+ case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+ debug_sym = g_strdup_printf ("plt__generic_class_init");
+ break;
+ default:
+ break;
+ }
- if (debug_sym) {
- emit_local_symbol (acfg, debug_sym, NULL, TRUE);
- emit_label (acfg, debug_sym);
- }
+ if (debug_sym) {
+ emit_local_symbol (acfg, debug_sym, NULL, TRUE);
+ emit_label (acfg, debug_sym);
}
}
- /*
- * The first plt entry is used to transfer code to the AOT loader.
- */
arch_emit_plt_entry (acfg, i);
if (debug_sym) {
}
static G_GNUC_UNUSED void
-emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
- guint32 code_size, int got_offset, MonoJumpInfo *ji, GSList *unwind_ops)
+emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
{
char start_symbol [256];
char symbol [256];
MonoJumpInfo *patch_info;
guint8 *buf, *p;
GPtrArray *patches;
+ char *name;
+ guint8 *code;
+ guint32 code_size;
+ MonoJumpInfo *ji;
+ GSList *unwind_ops;
+
+ name = info->name;
+ code = info->code;
+ code_size = info->code_size;
+ ji = info->ji;
+ unwind_ops = info->unwind_ops;
/* Emit code */
info_offset = add_to_blob (acfg, buf, p - buf);
- emit_section_change (acfg, ".text", 0);
+ emit_section_change (acfg, RODATA_SECT, 0);
emit_global (acfg, symbol, FALSE);
emit_label (acfg, symbol);
MonoAotTrampoline ntype;
#ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
int tramp_type;
- guint32 code_size;
- MonoJumpInfo *ji;
guint8 *code;
- GSList *unwind_ops;
#endif
if (!acfg->aot_opts.full_aot)
/* 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
+ MonoTrampInfo *info;
+
/*
* Emit the generic trampolines.
*
* method.
*/
for (tramp_type = 0; tramp_type < MONO_TRAMPOLINE_NUM; ++tramp_type) {
- code = mono_arch_create_trampoline_code_full (tramp_type, &code_size, &ji, &unwind_ops, TRUE);
-
- /* Emit trampoline code */
-
- sprintf (symbol, "generic_trampoline_%d", tramp_type);
-
- emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, unwind_ops);
+ mono_arch_create_generic_trampoline (tramp_type, &info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
}
- code = mono_arch_get_nullified_class_init_trampoline (&code_size);
- emit_trampoline (acfg, "nullified_class_init_trampoline", code, code_size, acfg->got_offset, NULL, NULL);
-#if defined(TARGET_AMD64) && defined(MONO_ARCH_MONITOR_OBJECT_REG)
- code = mono_arch_create_monitor_enter_trampoline_full (&code_size, &ji, TRUE);
- emit_trampoline (acfg, "monitor_enter_trampoline", code, code_size, acfg->got_offset, ji, NULL);
- code = mono_arch_create_monitor_exit_trampoline_full (&code_size, &ji, TRUE);
- emit_trampoline (acfg, "monitor_exit_trampoline", code, code_size, acfg->got_offset, ji, NULL);
+ mono_arch_get_nullified_class_init_trampoline (&info);
+ emit_trampoline (acfg, acfg->got_offset, info);
+#if defined(MONO_ARCH_MONITOR_OBJECT_REG)
+ mono_arch_create_monitor_enter_trampoline (&info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
+ mono_arch_create_monitor_exit_trampoline (&info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
#endif
- code = mono_arch_create_generic_class_init_trampoline_full (&code_size, &ji, TRUE);
- emit_trampoline (acfg, "generic_class_init_trampoline", code, code_size, acfg->got_offset, ji, NULL);
+ mono_arch_create_generic_class_init_trampoline (&info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
/* Emit the exception related code pieces */
- code = mono_arch_get_restore_context_full (&code_size, &ji, TRUE);
- emit_trampoline (acfg, "restore_context", code, code_size, acfg->got_offset, ji, NULL);
- code = mono_arch_get_call_filter_full (&code_size, &ji, TRUE);
- emit_trampoline (acfg, "call_filter", code, code_size, acfg->got_offset, ji, NULL);
- code = mono_arch_get_throw_exception_full (&code_size, &ji, TRUE);
- 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);
+ code = mono_arch_get_restore_context (&info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
+ code = mono_arch_get_call_filter (&info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
+ code = mono_arch_get_throw_exception (&info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
+ code = mono_arch_get_rethrow_exception (&info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
+ code = mono_arch_get_throw_corlib_exception (&info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
+
+#if defined(MONO_ARCH_HAVE_GET_TRAMPOLINES)
+ {
+ GSList *l = mono_arch_get_trampolines (TRUE);
-#if defined(TARGET_AMD64)
- code = mono_arch_get_throw_pending_exception_full (&code_size, &ji, TRUE);
- emit_trampoline (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji, NULL);
+ while (l) {
+ MonoTrampInfo *info = l->data;
+
+ emit_trampoline (acfg, acfg->got_offset, info);
+ l = l->next;
+ }
+ }
#endif
for (i = 0; i < 128; ++i) {
int offset;
offset = MONO_RGCTX_SLOT_MAKE_RGCTX (i);
- code = mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset, &code_size, &ji, TRUE);
- sprintf (symbol, "rgctx_fetch_trampoline_%u", offset);
- emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
+ code = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
offset = MONO_RGCTX_SLOT_MAKE_MRGCTX (i);
- code = mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset, &code_size, &ji, TRUE);
- sprintf (symbol, "rgctx_fetch_trampoline_%u", offset);
- emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
+ code = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
}
{
/* delegate_invoke_impl trampolines */
l = mono_arch_get_delegate_invoke_impls ();
while (l) {
- MonoAotTrampInfo *info = l->data;
+ MonoTrampInfo *info = l->data;
- emit_trampoline (acfg, info->name, info->code, info->code_size, acfg->got_offset, NULL, NULL);
+ emit_trampoline (acfg, acfg->got_offset, info);
l = l->next;
}
}
add_extra_method_with_depth (acfg, m, depth + 1);
}
}
- add_generic_class (acfg, m->klass);
+ add_generic_class_with_depth (acfg, m->klass, depth + 5);
}
if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && !strcmp (m->name, "ElementAddr"))
add_extra_method_with_depth (acfg, m, depth + 1);
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);
+ add_generic_class_with_depth (acfg, klass, depth + 5);
break;
}
default:
mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
{
MonoJumpInfo *ji = mono_mempool_alloc (llvm_acfg->mempool, sizeof (MonoJumpInfo));
- int offset;
+ MonoPltEntry *plt_entry;
ji->type = type;
ji->data.target = data;
if (!can_encode_patch (llvm_acfg, ji))
return NULL;
- offset = get_plt_offset (llvm_acfg, ji);
+ plt_entry = get_plt_entry (llvm_acfg, ji);
- return g_strdup_printf ("%sp_%d", llvm_acfg->temp_prefix, offset);
+ return g_strdup_printf (plt_entry->symbol);
}
MonoJumpInfo*
char *command, *opts;
int i;
MonoJumpInfo *patch_info;
- char *llc_target_args;
+ const char *llc_extra_args;
/*
* When using LLVM, we let llvm emit the got since the LLVM IL needs to refer
if (!is_plt_patch (patch_info))
get_got_offset (acfg, patch_info);
else
- get_plt_offset (acfg, patch_info);
+ get_plt_entry (acfg, patch_info);
}
}
}
* a lot of time, and doesn't seem to save much space.
* The following optimizations cannot be enabled:
* - 'tailcallelim'
+ * - 'jump-threading' changes our blockaddress references to int constants.
* 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");
+ opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -basiccg -prune-eh -inline -functionattrs -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -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 -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);
#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);
+#if !LLVM_CHECK_VERSION(2, 8)
+ /* LLVM 2.8 removed the -f flag ??? */
+ llc_extra_args = "-f";
+#else
+ llc_extra_args = "";
+#endif
+ command = g_strdup_printf ("llc %s %s -relocation-model=pic -unwind-tables -o %s temp.opt.bc", LLC_TARGET_ARGS, llc_extra_args, acfg->tmpfname);
printf ("Executing llc: %s\n", command);
emit_label (acfg, symbol);
sprintf (symbol, "code_offsets");
- emit_section_change (acfg, ".text", 1);
+ emit_section_change (acfg, RODATA_SECT, 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
}
sprintf (symbol, "method_info_offsets");
- emit_section_change (acfg, ".text", 1);
+ emit_section_change (acfg, RODATA_SECT, 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
return m;
}
-/*
- * mono_aot_tramp_info_create:
- *
- * Create a MonoAotTrampInfo structure from the arguments.
- */
-MonoAotTrampInfo*
-mono_aot_tramp_info_create (const char *name, guint8 *code, guint32 code_size)
-{
- MonoAotTrampInfo *info = g_new0 (MonoAotTrampInfo, 1);
-
- info->name = (char*)name;
- info->code = code;
- info->code_size = code_size;
-
- return info;
-}
-
#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
typedef struct HashEntry {
if (!cfg)
continue;
- buf_size = 512;
+ buf_size = 1024;
p = buf = g_malloc (buf_size);
nmethods ++;
/* Emit the table */
sprintf (symbol, "extra_method_table");
- emit_section_change (acfg, ".text", 0);
+ emit_section_change (acfg, RODATA_SECT, 0);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
* This is used by mono_aot_find_jit_info ().
*/
sprintf (symbol, "extra_method_info_offsets");
- emit_section_change (acfg, ".text", 0);
+ emit_section_change (acfg, RODATA_SECT, 0);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
}
sprintf (symbol, "ex_info_offsets");
- emit_section_change (acfg, ".text", 1);
+ emit_section_change (acfg, RODATA_SECT, 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
*/
sprintf (symbol, "unwind_info");
- emit_section_change (acfg, ".text", 1);
+ emit_section_change (acfg, RODATA_SECT, 1);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
emit_global (acfg, symbol, FALSE);
offsets [i] = emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
sprintf (symbol, "class_info_offsets");
- emit_section_change (acfg, ".text", 1);
+ emit_section_change (acfg, RODATA_SECT, 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
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)
+ continue;
full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
hash = mono_metadata_str_hash (full_name) % table_size;
g_free (full_name);
/* Emit the table */
sprintf (symbol, "class_name_table");
- emit_section_change (acfg, ".text", 0);
+ emit_section_change (acfg, RODATA_SECT, 0);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
*/
sprintf (symbol, "mono_image_table");
- emit_section_change (acfg, ".text", 1);
+ emit_section_change (acfg, RODATA_SECT, 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
acfg->plt_got_offset_base = acfg->got_offset;
first_plt_got_patch = acfg->got_patches->len;
for (i = 1; i < acfg->plt_offset; ++i) {
- MonoJumpInfo *patch_info = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
+ MonoPltEntry *plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
- g_ptr_array_add (acfg->got_patches, patch_info);
+ g_ptr_array_add (acfg->got_patches, plt_entry->ji);
}
acfg->got_offset += acfg->plt_offset;
*/
/* Encode info required to decode shared GOT entries */
- buf_size = acfg->got_patches->len * 64;
+ buf_size = acfg->got_patches->len * 128;
p = buf = mono_mempool_alloc (acfg->mempool, buf_size);
got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->got_patches->len * sizeof (guint32));
acfg->plt_got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->plt_offset * sizeof (guint32));
/* Emit got_info_offsets table */
sprintf (symbol, "got_info_offsets");
- emit_section_change (acfg, ".text", 1);
+ emit_section_change (acfg, RODATA_SECT, 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
/* Emit the table */
sprintf (symbol, ".Lglobals_hash");
- emit_section_change (acfg, ".text", 0);
+ emit_section_change (acfg, RODATA_SECT, 0);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
char *name = g_ptr_array_index (acfg->globals, i);
sprintf (symbol, "name_%d", i);
- emit_section_change (acfg, ".text", 1);
+ emit_section_change (acfg, RODATA_SECT, 1);
emit_label (acfg, symbol);
emit_string (acfg, name);
}
char symbol [128];
sprintf (symbol, "blob");
- emit_section_change (acfg, ".text", 1);
+ emit_section_change (acfg, RODATA_SECT, 1);
emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
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->plt_offset_to_entry = g_hash_table_new (NULL, NULL);
+ acfg->patch_to_plt_entry = 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)
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->plt_offset_to_entry);
+ g_hash_table_destroy (acfg->patch_to_plt_entry);
g_hash_table_destroy (acfg->patch_to_got_offset);
g_hash_table_destroy (acfg->method_to_cfg);
g_hash_table_destroy (acfg->token_info_hash);
acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
+ /*
+ * 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->method_index = 1;
collect_methods (acfg);
outfile_name = NULL;
}
- /*
- * 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 */