#if defined(__linux__) || defined(__native_client_codegen__)
#define RODATA_SECT ".rodata"
+#elif defined(TARGET_MACH)
+#define RODATA_SECT ".section __TEXT, __const"
#else
#define RODATA_SECT ".text"
#endif
#define SHARED_EXT ".dylib"
#elif defined(TARGET_MACH) && defined(TARGET_X86) && !defined(__native_client_codegen__)
#define SHARED_EXT ".dylib"
+#elif defined(TARGET_MACH) && defined(TARGET_AMD64) && !defined(__native_client_codegen__)
+#define SHARED_EXT ".dylib"
#else
#define SHARED_EXT ".so"
#endif
gboolean asm_only;
gboolean asm_writer;
gboolean nodebug;
+ gboolean dwarf_debug;
gboolean soft_debug;
gboolean log_generics;
gboolean direct_pinvoke;
gboolean no_direct_calls;
gboolean use_trampolines_page;
gboolean no_instances;
+ gboolean gnu_asm;
int nthreads;
int ntrampolines;
int nrgctx_trampolines;
int nimt_trampolines;
int ngsharedvt_arg_trampolines;
+ int nrgctx_fetch_trampolines;
gboolean print_skipped_methods;
gboolean stats;
char *tool_prefix;
GHashTable *method_depth;
MonoCompile **cfgs;
int cfgs_size;
- GHashTable *patch_to_plt_entry;
+ GHashTable **patch_to_plt_entry;
GHashTable *plt_offset_to_entry;
GHashTable *patch_to_got_offset;
GHashTable **patch_to_got_offset_by_type;
guint32 final_got_size;
/* Number of GOT entries reserved for trampolines */
guint32 num_trampoline_got_entries;
+ guint32 tramp_page_size;
guint32 num_trampolines [MONO_AOT_TRAMP_NUM];
guint32 trampoline_got_offset_base [MONO_AOT_TRAMP_NUM];
guint32 trampoline_size [MONO_AOT_TRAMP_NUM];
+ guint32 tramp_page_code_offsets [MONO_AOT_TRAMP_NUM];
MonoAotOptions aot_opts;
guint32 nmethods;
char *static_linking_symbol;
CRITICAL_SECTION mutex;
gboolean use_bin_writer;
+ gboolean gas_line_numbers;
MonoImageWriter *w;
MonoDwarfWriter *dwarf;
FILE *fp;
+ char *tmpbasename;
char *tmpfname;
GSList *cie_program;
GHashTable *unwind_info_offsets;
char *got_symbol_base;
char *got_symbol;
char *plt_symbol;
+ char *methods_symbol;
GHashTable *method_label_hash;
const char *temp_prefix;
+ const char *user_symbol_prefix;
const char *llvm_label_prefix;
guint32 label_generator;
gboolean llvm;
GHashTable *plt_entry_debug_sym_cache;
gboolean thumb_mixed, need_no_dead_strip, need_pt_gnu_stack;
GHashTable *ginst_hash;
+ GHashTable *dwarf_ln_filenames;
gboolean global_symbols;
-#ifdef MONOTOUCH
gboolean direct_method_addresses;
-#endif
+ int objc_selector_index, objc_selector_index_2;
+ GPtrArray *objc_selectors;
+ GHashTable *objc_selector_to_index;
} MonoAotCompile;
typedef struct {
img_writer_emit_pointer (acfg->w, target);
}
+static inline void
+emit_pointer_2 (MonoAotCompile *acfg, const char *prefix, const char *target)
+{
+ if (prefix [0] != '\0') {
+ char *s = g_strdup_printf ("%s%s", prefix, target);
+ img_writer_emit_pointer (acfg->w, s);
+ g_free (s);
+ } else {
+ img_writer_emit_pointer (acfg->w, target);
+ }
+}
+
static inline void
emit_int16 (MonoAotCompile *acfg, int value)
{
*endbuf = p;
}
+static void
+emit_unset_mode (MonoAotCompile *acfg)
+{
+ img_writer_emit_unset_mode (acfg->w);
+}
+
+static G_GNUC_UNUSED void
+emit_set_thumb_mode (MonoAotCompile *acfg)
+{
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, ".code 16\n");
+}
+
+static G_GNUC_UNUSED void
+emit_set_arm_mode (MonoAotCompile *acfg)
+{
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, ".code 32\n");
+}
+
/* ARCHITECTURE SPECIFIC CODE */
#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_POWERPC)
* symbols.
*/
acfg->llvm_label_prefix = "";
+ acfg->user_symbol_prefix = "";
+
+#if defined(TARGET_AMD64)
+ g_string_append (acfg->llc_args, " -march=x86-64");
+#endif
#ifdef TARGET_ARM
if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "darwin")) {
#endif
#ifdef TARGET_MACH
+ acfg->user_symbol_prefix = "_";
acfg->llvm_label_prefix = "_";
acfg->need_no_dead_strip = TRUE;
+ acfg->aot_opts.gnu_asm = TRUE;
#endif
#if defined(__linux__) && !defined(TARGET_ARM)
* calling code.
*/
static void
-arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
+arch_emit_direct_call (MonoAotCompile *acfg, const char *target, gboolean external, MonoJumpInfo *ji, int *call_size)
{
#if defined(TARGET_X86) || defined(TARGET_AMD64)
/* Need to make sure this is exactly 5 bytes long */
- if (FALSE && !acfg->use_bin_writer) {
- img_writer_emit_unset_mode (acfg->w);
+ if (external && !acfg->use_bin_writer) {
+ emit_unset_mode (acfg);
fprintf (acfg->fp, "call %s\n", target);
} else {
emit_byte (acfg, '\xe8');
img_writer_emit_reloc (acfg->w, R_ARM_CALL, target, -8);
emit_bytes (acfg, buf, 4);
} else {
- img_writer_emit_unset_mode (acfg->w);
+ emit_unset_mode (acfg);
fprintf (acfg->fp, "bl %s\n", target);
}
*call_size = 4;
if (acfg->use_bin_writer) {
g_assert_not_reached ();
} else {
- img_writer_emit_unset_mode (acfg->w);
+ emit_unset_mode (acfg);
fprintf (acfg->fp, "bl %s\n", target);
*call_size = 4;
}
{
#if defined(TARGET_POWERPC64)
g_assert (!acfg->use_bin_writer);
- img_writer_emit_unset_mode (acfg->w);
+ emit_unset_mode (acfg);
/*
* The ppc32 code doesn't seem to work on ppc64, the assembler complains about
* unsupported relocations. So we store the got address into the .Lgot_addr
*code_size = 16;
#elif defined(TARGET_POWERPC)
g_assert (!acfg->use_bin_writer);
- img_writer_emit_unset_mode (acfg->w);
+ emit_unset_mode (acfg);
fprintf (acfg->fp, ".L%d:\n", acfg->label_generator);
fprintf (acfg->fp, "lis 0, (%s + 4 - .L%d)@h\n", acfg->got_symbol, acfg->label_generator);
fprintf (acfg->fp, "ori 0, 0, (%s + 4 - .L%d)@l\n", acfg->got_symbol, acfg->label_generator);
#endif
+/*
+ * arch_emit_objc_selector_ref:
+ *
+ * Emit the implementation of OP_OBJC_GET_SELECTOR, which itself implements @selector(foo:) in objective-c.
+ */
+static void
+arch_emit_objc_selector_ref (MonoAotCompile *acfg, guint8 *code, int index, int *code_size)
+{
+#if defined(TARGET_ARM)
+ char symbol1 [256];
+ char symbol2 [256];
+ int lindex = acfg->objc_selector_index_2 ++;
+
+ /* Emit ldr.imm/b */
+ emit_bytes (acfg, code, 8);
+
+ sprintf (symbol1, "L_OBJC_SELECTOR_%d", lindex);
+ sprintf (symbol2, "L_OBJC_SELECTOR_REFERENCES_%d", index);
+
+ emit_label (acfg, symbol1);
+ img_writer_emit_unset_mode (acfg->w);
+ fprintf (acfg->fp, ".long %s-(%s+12)", symbol2, symbol1);
+
+ *code_size = 12;
+#else
+ g_assert_not_reached ();
+#endif
+}
+
/*
* arch_emit_plt_entry:
*
/* The GOT address is guaranteed to be in r30 by OP_LOAD_GOTADDR */
g_assert (!acfg->use_bin_writer);
- img_writer_emit_unset_mode (acfg->w);
+ emit_unset_mode (acfg);
fprintf (acfg->fp, "lis 11, %d@h\n", offset);
fprintf (acfg->fp, "ori 11, 11, %d@l\n", offset);
fprintf (acfg->fp, "add 11, 11, 30\n");
/* LLVM calls the PLT entries using bl, so these have to be thumb2 */
/* The caller already transitioned to thumb */
/* The code below should be 12 bytes long */
+ /* clang has trouble encoding these instructions, so emit the binary */
+#if 0
fprintf (acfg->fp, "ldr ip, [pc, #8]\n");
/* thumb can't encode ld pc, [pc, ip] */
fprintf (acfg->fp, "add ip, pc, ip\n");
fprintf (acfg->fp, "ldr ip, [ip, #0]\n");
fprintf (acfg->fp, "bx ip\n");
+#endif
+ emit_set_thumb_mode (acfg);
+ fprintf (acfg->fp, ".4byte 0xc008f8df\n");
+ fprintf (acfg->fp, ".2byte 0x44fc\n");
+ fprintf (acfg->fp, ".4byte 0xc000f8dc\n");
+ fprintf (acfg->fp, ".2byte 0x4760\n");
emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) + 4);
emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+ emit_unset_mode (acfg);
+ emit_set_arm_mode (acfg);
#else
g_assert_not_reached ();
#endif
#define COMMON_TRAMP_SIZE 16
int count = (mono_pagesize () - COMMON_TRAMP_SIZE) / 8;
int imm8, rot_amount;
+ char symbol [128];
if (!acfg->aot_opts.use_trampolines_page)
return;
+ acfg->tramp_page_size = mono_pagesize ();
+
+ sprintf (symbol, "%sspecific_trampolines_page", acfg->user_symbol_prefix);
emit_alignment (acfg, mono_pagesize ());
- emit_global (acfg, "specific_trampolines_page", TRUE);
- emit_label (acfg, "specific_trampolines_page");
+ emit_global (acfg, symbol, TRUE);
+ emit_label (acfg, symbol);
/* emit the generic code first, the trampoline address + 8 is in the lr register */
code = buf;
* subtracts 4096 to get to the data page and loads the values
* We again fit the generic trampiline in 16 bytes.
*/
- emit_global (acfg, "rgctx_trampolines_page", TRUE);
- emit_label (acfg, "rgctx_trampolines_page");
+ sprintf (symbol, "%srgctx_trampolines_page", acfg->user_symbol_prefix);
+ emit_global (acfg, symbol, TRUE);
+ emit_label (acfg, symbol);
code = buf;
imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
g_assert (code - buf == 8);
emit_bytes (acfg, buf, code - buf);
}
+
+ /*
+ * gsharedvt arg trampolines: see arch_emit_gsharedvt_arg_trampoline ()
+ */
+ sprintf (symbol, "%sgsharedvt_arg_trampolines_page", acfg->user_symbol_prefix);
+ emit_global (acfg, symbol, TRUE);
+ emit_label (acfg, symbol);
+ code = buf;
+ ARM_PUSH (code, (1 << ARMREG_R0) | (1 << ARMREG_R1) | (1 << ARMREG_R2) | (1 << ARMREG_R3));
+ imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
+ ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_IP, -8);
+ ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, -4);
+ g_assert (code - buf == COMMON_TRAMP_SIZE);
+ /* Emit it */
+ emit_bytes (acfg, buf, code - buf);
+
+ for (i = 0; i < count; ++i) {
+ code = buf;
+ ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_PC);
+ ARM_B (code, 0);
+ arm_patch (code - 4, code - COMMON_TRAMP_SIZE - 8 * (i + 1));
+ g_assert (code - buf == 8);
+ emit_bytes (acfg, buf, code - buf);
+ }
+
/* now the imt trampolines: each specific trampolines puts in the ip register
* the instruction pointer address, so the generic trampoline at the start of the page
* subtracts 4096 to get to the data page and loads the values
* We again fit the generic trampiline in 16 bytes.
*/
#define IMT_TRAMP_SIZE 72
- emit_global (acfg, "imt_trampolines_page", TRUE);
- emit_label (acfg, "imt_trampolines_page");
+ sprintf (symbol, "%simt_trampolines_page", acfg->user_symbol_prefix);
+ emit_global (acfg, symbol, TRUE);
+ emit_label (acfg, symbol);
code = buf;
/* Need at least two free registers, plus a slot for storing the pc */
ARM_PUSH (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_R2));
* in the second got slot of every aot image. The caller already computed
* the address of its got and placed it into r30.
*/
- img_writer_emit_unset_mode (acfg->w);
+ emit_unset_mode (acfg);
/* Load mscorlib got address */
fprintf (acfg->fp, "%s 0, %d(30)\n", PPC_LD_OP, (int)sizeof (gpointer));
/* Load generic trampoline address */
fprintf (acfg->fp, "add r0, r0, #%d\n", (int)sizeof (MonoObject));
fprintf (acfg->fp, "b %s\n", call_target);
fprintf (acfg->fp, ".arm\n");
+ fprintf (acfg->fp, ".align 2\n");
return;
}
* in the second got slot of every aot image. The caller already computed
* the address of its got and placed it into r30.
*/
- img_writer_emit_unset_mode (acfg->w);
+ emit_unset_mode (acfg);
/* Load mscorlib got address */
fprintf (acfg->fp, "%s 0, %d(30)\n", PPC_LD_OP, (int)sizeof (gpointer));
/* Load rgctx */
/* Similar to arch_emit_specific_trampoline () */
*tramp_size = 24;
code = buf;
- ARM_PUSH (code, (1 << ARMREG_R0) | (1 << ARMREG_R1) | (1 << ARMREG_R2) | (1 << ARMREG_R3) | (1 << ARMREG_LR));
+ ARM_PUSH (code, (1 << ARMREG_R0) | (1 << ARMREG_R1) | (1 << ARMREG_R2) | (1 << ARMREG_R3));
ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 8);
/* Load the arg value from the GOT */
- ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_PC, ARMREG_R1);
+ ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R1);
/* Load the addr from the GOT */
ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_PC, ARMREG_R1);
/* Branch to it */
{
#if defined(TARGET_POWERPC) && defined(__mono_ilp32__)
/* Based on code generated by gcc */
- img_writer_emit_unset_mode (acfg->w);
+ emit_unset_mode (acfg);
fprintf (acfg->fp,
#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE)
encode_klass_ref (acfg, method->klass, p, &p);
else if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER)
encode_method_ref (acfg, info->d.synchronized_inner.method, p, &p);
+ else if (info->subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR)
+ encode_method_ref (acfg, info->d.array_accessor.method, p, &p);
break;
}
case MONO_WRAPPER_MANAGED_TO_NATIVE: {
case MONO_WRAPPER_RUNTIME_INVOKE: {
WrapperInfo *info = mono_marshal_get_wrapper_info (method);
- if (info) {
- encode_value (info->subtype, p, &p);
- if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL)
- encode_method_ref (acfg, info->d.runtime_invoke.method, p, &p);
- } else {
- MonoMethodSignature *sig;
-
- encode_value (0, p, &p);
-
- sig = mono_method_signature (method);
- encode_signature (acfg, sig, p, &p);
- }
+ g_assert (info);
+ encode_value (info->subtype, p, &p);
+ if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL)
+ encode_method_ref (acfg, info->d.runtime_invoke.method, p, &p);
+ else if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL)
+ encode_signature (acfg, info->d.runtime_invoke.sig, p, &p);
break;
}
- case MONO_WRAPPER_DELEGATE_INVOKE: {
+ case MONO_WRAPPER_DELEGATE_INVOKE:
+ case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
+ case MONO_WRAPPER_DELEGATE_END_INVOKE: {
if (method->is_inflated) {
/* These wrappers are identified by their class */
encode_value (1, p, &p);
encode_klass_ref (acfg, method->klass, p, &p);
} else {
MonoMethodSignature *sig = mono_method_signature (method);
+ WrapperInfo *info = mono_marshal_get_wrapper_info (method);
encode_value (0, p, &p);
+ if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE)
+ encode_value (info ? info->subtype : 0, p, &p);
encode_signature (acfg, sig, p, &p);
}
break;
}
- case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
- case MONO_WRAPPER_DELEGATE_END_INVOKE: {
- MonoMethodSignature *sig = mono_method_signature (method);
- encode_signature (acfg, sig, p, &p);
- break;
- }
case MONO_WRAPPER_NATIVE_TO_MANAGED: {
WrapperInfo *info = mono_marshal_get_wrapper_info (method);
if (!is_plt_patch (patch_info))
return NULL;
- res = g_hash_table_lookup (acfg->patch_to_plt_entry, patch_info);
+ if (!acfg->patch_to_plt_entry [patch_info->type])
+ acfg->patch_to_plt_entry [patch_info->type] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
+ res = g_hash_table_lookup (acfg->patch_to_plt_entry [patch_info->type], patch_info);
// 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)) {
else
res->llvm_symbol = g_strdup_printf ("%s_llvm", res->symbol);
- g_hash_table_insert (acfg->patch_to_plt_entry, new_ji, res);
+ g_hash_table_insert (acfg->patch_to_plt_entry [new_ji->type], new_ji, res);
g_hash_table_insert (acfg->plt_offset_to_entry, GUINT_TO_POINTER (res->plt_offset), res);
+ //g_assert (mono_patch_info_equal (patch_info, new_ji));
+ //mono_print_ji (patch_info); printf ("\n");
+ //g_hash_table_print_stats (acfg->patch_to_plt_entry);
+
acfg->plt_offset ++;
}
return add_method_full (acfg, method, FALSE, 0);
}
-static void
-add_extra_method (MonoAotCompile *acfg, MonoMethod *method)
-{
- add_method_full (acfg, method, TRUE, 0);
-}
-
static void
add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth)
{
+ if (mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE))
+ method = mini_get_shared_method (method);
+
if (acfg->aot_opts.log_generics)
printf ("%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
add_method_full (acfg, method, TRUE, depth);
}
+static void
+add_extra_method (MonoAotCompile *acfg, MonoMethod *method)
+{
+ add_extra_method_with_depth (acfg, method, 0);
+}
+
static void
add_jit_icall_wrapper (gpointer key, gpointer value, gpointer user_data)
{
* so there is only one wrapper of a given type, or inlining their contents into their
* callers.
*/
-
- /*
- * FIXME: This depends on the fact that different wrappers have different
- * names.
- */
-
for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
MonoMethod *method;
guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
(method->flags & METHOD_ATTRIBUTE_ABSTRACT))
skip = TRUE;
- if (method->is_generic || method->klass->generic_container)
- skip = TRUE;
-
/* Skip methods which can not be handled by get_runtime_invoke () */
sig = mono_method_signature (method);
if (!sig)
if ((sig->ret->type == MONO_TYPE_PTR) ||
(sig->ret->type == MONO_TYPE_TYPEDBYREF))
skip = TRUE;
+ if (mono_class_is_open_constructed_type (sig->ret))
+ skip = TRUE;
for (j = 0; j < sig->param_count; j++) {
if (sig->params [j]->type == MONO_TYPE_TYPEDBYREF)
skip = TRUE;
+ if (mono_class_is_open_constructed_type (sig->params [j]))
+ skip = TRUE;
}
#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
- if (!method->klass->contextbound) {
+ if (!mono_class_is_contextbound (method->klass)) {
MonoDynCallInfo *info = mono_arch_dyn_call_prepare (sig);
gboolean has_nullable = FALSE;
}
if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
-#ifdef MONO_ARCH_HAVE_TLS_GET
MonoMethodDesc *desc;
MonoMethod *orig_method;
int nallocators;
-#endif
/* Runtime invoke wrappers */
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);
-
/* stelemref */
add_method (acfg, mono_marshal_get_stelemref ());
-#ifdef MONO_ARCH_HAVE_TLS_GET
- /* Managed Allocators */
- nallocators = mono_gc_get_managed_allocator_types ();
- for (i = 0; i < nallocators; ++i) {
- m = mono_gc_get_managed_allocator_by_type (i);
- if (m)
- add_method (acfg, m);
- }
+ if (MONO_ARCH_HAVE_TLS_GET) {
+ /* Managed Allocators */
+ nallocators = mono_gc_get_managed_allocator_types ();
+ for (i = 0; i < nallocators; ++i) {
+ m = mono_gc_get_managed_allocator_by_type (i);
+ if (m)
+ add_method (acfg, m);
+ }
+
+ /* Monitor Enter/Exit */
+ desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
+ orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
+ /* This is a v4 method */
+ if (orig_method) {
+ method = mono_monitor_get_fast_path (orig_method);
+ if (method)
+ add_method (acfg, method);
+ }
+ mono_method_desc_free (desc);
- /* Monitor Enter/Exit */
- desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
- orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
- /* This is a v4 method */
- if (orig_method) {
+ desc = mono_method_desc_new ("Monitor:Exit(object)", FALSE);
+ orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
+ g_assert (orig_method);
+ mono_method_desc_free (desc);
method = mono_monitor_get_fast_path (orig_method);
if (method)
- add_method (acfg, method);
+ add_method (acfg, method);
}
- mono_method_desc_free (desc);
-
- desc = mono_method_desc_new ("Monitor:Exit(object)", FALSE);
- orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
- g_assert (orig_method);
- mono_method_desc_free (desc);
- method = mono_monitor_get_fast_path (orig_method);
- if (method)
- add_method (acfg, method);
-#endif
/* Stelemref wrappers */
- /* There is only a constant number of these, iterating over all types should handle them all */
- for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
- MonoClass *klass;
-
- token = MONO_TOKEN_TYPE_DEF | (i + 1);
- klass = mono_class_get (acfg->image, token);
- if (klass)
- add_method (acfg, mono_marshal_get_virtual_stelemref (mono_array_class_get (klass, 1)));
- else
- mono_loader_clear_error ();
+ {
+ MonoMethod **wrappers;
+ int nwrappers;
+
+ wrappers = mono_marshal_get_virtual_stelemref_wrappers (&nwrappers);
+ for (i = 0; i < nwrappers; ++i)
+ add_method (acfg, wrappers [i]);
+ g_free (wrappers);
}
/* castclass_with_check wrapper */
}
}
#endif
+
+ /* JIT icall wrappers */
+ /* FIXME: locking - this is "safe" as full-AOT threads don't mutate the icall hash*/
+ g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
}
/*
MonoMethod *inst, *gshared;
/*
- * Emit a gsharedvt version of the generic delegate-invoke wrapper
+ * Emit gsharedvt versions of the generic delegate-invoke wrappers
*/
-
+ /* Invoke */
method = mono_get_delegate_invoke (klass);
create_gsharedvt_inst (acfg, method, &ctx);
gshared = mini_get_shared_method_full (m, FALSE, TRUE);
add_extra_method (acfg, gshared);
+
+ /* begin-invoke */
+ method = mono_get_delegate_begin_invoke (klass);
+ create_gsharedvt_inst (acfg, method, &ctx);
+
+ inst = mono_class_inflate_generic_method (method, &ctx);
+
+ m = mono_marshal_get_delegate_begin_invoke (inst);
+ g_assert (m->is_inflated);
+
+ gshared = mini_get_shared_method_full (m, FALSE, TRUE);
+ add_extra_method (acfg, gshared);
+
+ /* end-invoke */
+ method = mono_get_delegate_end_invoke (klass);
+ create_gsharedvt_inst (acfg, method, &ctx);
+
+ inst = mono_class_inflate_generic_method (method, &ctx);
+
+ m = mono_marshal_get_delegate_end_invoke (inst);
+ g_assert (m->is_inflated);
+
+ gshared = mini_get_shared_method_full (m, FALSE, TRUE);
+ add_extra_method (acfg, gshared);
+
+ }
+ }
+
+ /* array access wrappers */
+ for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
+ MonoClass *klass;
+
+ token = MONO_TOKEN_TYPE_SPEC | (i + 1);
+ klass = mono_class_get (acfg->image, token);
+
+ if (!klass) {
+ mono_loader_clear_error ();
+ continue;
+ }
+
+ if (klass->rank && MONO_TYPE_IS_PRIMITIVE (&klass->element_class->byval_arg)) {
+ MonoMethod *m, *wrapper;
+
+ /* Add runtime-invoke wrappers too */
+
+ m = mono_class_get_method_from_name (klass, "Get", -1);
+ g_assert (m);
+ wrapper = mono_marshal_get_array_accessor_wrapper (m);
+ add_extra_method (acfg, wrapper);
+ add_extra_method (acfg, mono_marshal_get_runtime_invoke (wrapper, FALSE));
+
+ m = mono_class_get_method_from_name (klass, "Set", -1);
+ g_assert (m);
+ wrapper = mono_marshal_get_array_accessor_wrapper (m);
+ add_extra_method (acfg, wrapper);
+ add_extra_method (acfg, mono_marshal_get_runtime_invoke (wrapper, FALSE));
}
}
token = MONO_TOKEN_METHOD_DEF | (i + 1);
method = mono_get_method (acfg->image, token, NULL);
- if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !method->is_generic)
- add_method (acfg, mono_marshal_get_synchronized_wrapper (method));
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
+ if (method->is_generic) {
+ // FIXME:
+ } else if (method->klass->generic_container) {
+ MonoGenericContext ctx;
+ MonoMethod *inst, *gshared, *m;
+
+ /*
+ * Create a generic wrapper for a generic instance, and AOT that.
+ */
+ create_gsharedvt_inst (acfg, method, &ctx);
+ inst = mono_class_inflate_generic_method (method, &ctx);
+ m = mono_marshal_get_synchronized_wrapper (inst);
+ g_assert (m->is_inflated);
+ gshared = mini_get_shared_method_full (m, FALSE, TRUE);
+ add_method (acfg, gshared);
+ } else {
+ add_method (acfg, mono_marshal_get_synchronized_wrapper (method));
+ }
+ }
}
/* pinvoke wrappers */
continue;
}
- if (klass->valuetype && !klass->generic_container && can_marshal_struct (klass)) {
+ if (klass->valuetype && !klass->generic_container && can_marshal_struct (klass) &&
+ !(klass->nested_in && strstr (klass->nested_in->name, "<PrivateImplementationDetails>") == klass->nested_in->name)) {
add_method (acfg, mono_marshal_get_struct_to_ptr (klass));
add_method (acfg, mono_marshal_get_ptr_to_struct (klass));
}
return TRUE;
}
}
+ if (klass->generic_container)
+ return TRUE;
+ return FALSE;
+}
+
+static gboolean
+is_vt_inst (MonoGenericInst *inst)
+{
+ int i;
+
+ for (i = 0; i < inst->type_argc; ++i) {
+ MonoType *t = inst->type_argv [i];
+ if (t->type == MONO_TYPE_VALUETYPE)
+ return TRUE;
+ }
return FALSE;
}
MonoMethod *method;
MonoClassField *field;
gpointer iter;
+ gboolean use_gsharedvt = FALSE;
if (!acfg->ginst_hash)
acfg->ginst_hash = g_hash_table_new (NULL, NULL);
g_hash_table_insert (acfg->ginst_hash, klass, klass);
+ /*
+ * Use gsharedvt for generic collections with vtype arguments to avoid code blowup.
+ * Enable this only for some classes since gsharedvt might not support all methods.
+ */
+ if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->image == mono_defaults.corlib && klass->generic_class && klass->generic_class->context.class_inst && is_vt_inst (klass->generic_class->context.class_inst) && (!strcmp (klass->name, "Dictionary`2") || !strcmp (klass->name, "List`1")))
+ use_gsharedvt = TRUE;
+
iter = NULL;
while ((method = mono_class_get_methods (klass, &iter))) {
- if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, FALSE))
+ if ((acfg->opts & MONO_OPT_GSHAREDVT) && method->is_inflated && mono_method_get_context (method)->method_inst) {
+ /*
+ * This is partial sharing, and we can't handle it yet
+ */
+ continue;
+ }
+
+ if (mono_method_is_generic_sharable_full (method, FALSE, FALSE, use_gsharedvt))
/* Already added */
continue;
for (j = 0; j < header->num_locals; ++j)
if (header->locals [j]->type == MONO_TYPE_GENERICINST)
add_generic_class_with_depth (acfg, mono_class_from_mono_type (header->locals [j]), depth + 1, "local");
+ } else {
+ mono_loader_clear_error ();
}
}
* If the method is fully sharable, it was already added in place of its
* generic definition.
*/
- if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, FALSE))
+ if (mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE))
continue;
/*
}
}
}
+
+ /* Same for Volatile.Read/Write<T> */
+ {
+ MonoGenericContext ctx;
+ MonoType *args [16];
+ MonoMethod *m;
+ MonoClass *volatile_klass = mono_class_from_name (mono_defaults.corlib, "System.Threading", "Volatile");
+ gpointer iter = NULL;
+
+ if (volatile_klass) {
+ while ((m = mono_class_get_methods (volatile_klass, &iter))) {
+ if ((!strcmp (m->name, "Read") || !strcmp (m->name, "Write")) && m->is_generic) {
+ 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 (m, &ctx), TRUE, TRUE));
+ }
+ }
+ }
+ }
}
}
direct_callable = FALSE;
}
+ if (callee_cfg->method->wrapper_type == MONO_WRAPPER_ALLOC)
+ /* sgen does some initialization when the allocator method is created */
+ direct_callable = FALSE;
+
if (direct_callable)
return TRUE;
}
return import;
}
+static gint
+compare_lne (MonoDebugLineNumberEntry *a, MonoDebugLineNumberEntry *b)
+{
+ if (a->native_offset == b->native_offset)
+ return a->il_offset - b->il_offset;
+ else
+ return a->native_offset - b->native_offset;
+}
+
+/*
+ * compute_line_numbers:
+ *
+ * Returns a sparse array of size CODE_SIZE containing MonoDebugSourceLocation* entries for the native offsets which have a corresponding line number
+ * entry.
+ */
+static MonoDebugSourceLocation**
+compute_line_numbers (MonoMethod *method, int code_size, MonoDebugMethodJitInfo *debug_info)
+{
+ MonoDebugMethodInfo *minfo;
+ MonoDebugLineNumberEntry *ln_array;
+ MonoDebugSourceLocation *loc;
+ int i, prev_line, prev_il_offset;
+ int *native_to_il_offset = NULL;
+ MonoDebugSourceLocation **res;
+ gboolean first;
+
+ minfo = mono_debug_lookup_method (method);
+ if (!minfo)
+ return NULL;
+ // FIXME: This seems to happen when two methods have the same cfg->method_to_register
+ if (debug_info->code_size != code_size)
+ return NULL;
+
+ g_assert (code_size);
+
+ /* Compute the native->IL offset mapping */
+
+ ln_array = g_new0 (MonoDebugLineNumberEntry, debug_info->num_line_numbers);
+ memcpy (ln_array, debug_info->line_numbers, debug_info->num_line_numbers * sizeof (MonoDebugLineNumberEntry));
+
+ qsort (ln_array, debug_info->num_line_numbers, sizeof (MonoDebugLineNumberEntry), (gpointer)compare_lne);
+
+ native_to_il_offset = g_new0 (int, code_size + 1);
+
+ for (i = 0; i < debug_info->num_line_numbers; ++i) {
+ int j;
+ MonoDebugLineNumberEntry *lne = &ln_array [i];
+
+ if (i == 0) {
+ for (j = 0; j < lne->native_offset; ++j)
+ native_to_il_offset [j] = -1;
+ }
+
+ if (i < debug_info->num_line_numbers - 1) {
+ MonoDebugLineNumberEntry *lne_next = &ln_array [i + 1];
+
+ for (j = lne->native_offset; j < lne_next->native_offset; ++j)
+ native_to_il_offset [j] = lne->il_offset;
+ } else {
+ for (j = lne->native_offset; j < code_size; ++j)
+ native_to_il_offset [j] = lne->il_offset;
+ }
+ }
+ g_free (ln_array);
+
+ /* Compute the native->line number mapping */
+ res = g_new0 (MonoDebugSourceLocation*, code_size);
+ prev_il_offset = -1;
+ prev_line = -1;
+ first = TRUE;
+ for (i = 0; i < code_size; ++i) {
+ int il_offset = native_to_il_offset [i];
+
+ if (il_offset == -1 || il_offset == prev_il_offset)
+ continue;
+ prev_il_offset = il_offset;
+ loc = mono_debug_symfile_lookup_location (minfo, il_offset);
+ if (!(loc && loc->source_file))
+ continue;
+ if (loc->row == prev_line) {
+ mono_debug_symfile_free_location (loc);
+ continue;
+ }
+ prev_line = loc->row;
+ //printf ("D: %s:%d il=%x native=%x\n", loc->source_file, loc->row, il_offset, i);
+ if (first)
+ /* This will cover the prolog too */
+ res [0] = loc;
+ else
+ res [i] = loc;
+ first = FALSE;
+ }
+ return res;
+}
+
+static int
+get_file_index (MonoAotCompile *acfg, const char *source_file)
+{
+ int findex;
+
+ // FIXME: Free these
+ if (!acfg->dwarf_ln_filenames)
+ acfg->dwarf_ln_filenames = g_hash_table_new (g_str_hash, g_str_equal);
+ findex = GPOINTER_TO_INT (g_hash_table_lookup (acfg->dwarf_ln_filenames, source_file));
+ if (!findex) {
+ findex = g_hash_table_size (acfg->dwarf_ln_filenames) + 1;
+ g_hash_table_insert (acfg->dwarf_ln_filenames, g_strdup (source_file), GINT_TO_POINTER (findex));
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, ".file %d \"%s\"\n", findex, mono_dwarf_escape_path (source_file));
+ }
+ return findex;
+}
+
/*
* emit_and_reloc_code:
*
* since trampolines are needed to make PTL work.
*/
static void
-emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, guint32 code_len, MonoJumpInfo *relocs, gboolean got_only)
+emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, guint32 code_len, MonoJumpInfo *relocs, gboolean got_only, MonoDebugMethodJitInfo *debug_info)
{
int i, pindex, start_index, method_index;
GPtrArray *patches;
MonoJumpInfo *patch_info;
MonoMethodHeader *header;
- gboolean skip, direct_call;
+ MonoDebugSourceLocation **locs = NULL;
+ gboolean skip, direct_call, external_call;
guint32 got_slot;
- const char *direct_call_target;
+ const char *direct_call_target = 0;
const char *direct_pinvoke;
if (method) {
method_index = get_method_index (acfg, method);
}
+ if (acfg->gas_line_numbers && method && debug_info) {
+ locs = compute_line_numbers (method, code_len, debug_info);
+ if (!locs) {
+ int findex = get_file_index (acfg, "<unknown>");
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, ".loc %d %d 0\n", findex, 1);
+ }
+ }
+
/* Collect and sort relocations */
patches = g_ptr_array_new ();
for (patch_info = relocs; patch_info; patch_info = patch_info->next)
break;
}
-#ifdef MONO_ARCH_AOT_SUPPORTED
+ if (locs && locs [i]) {
+ MonoDebugSourceLocation *loc = locs [i];
+ int findex;
+
+ findex = get_file_index (acfg, loc->source_file);
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, ".loc %d %d 0\n", findex, loc->row);
+ mono_debug_symfile_free_location (loc);
+ }
+
skip = FALSE;
+#ifdef MONO_ARCH_AOT_SUPPORTED
if (patch_info && (patch_info->ip.i == i) && (pindex < patches->len)) {
start_index = pindex;
patch_info->type = MONO_PATCH_INFO_NONE;
break;
}
+ case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
+ int code_size, index;
+ char *selector = (void*)patch_info->data.target;
+
+ if (!acfg->objc_selector_to_index)
+ acfg->objc_selector_to_index = g_hash_table_new (g_str_hash, g_str_equal);
+ if (!acfg->objc_selectors)
+ acfg->objc_selectors = g_ptr_array_new ();
+ index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->objc_selector_to_index, selector));
+ if (index)
+ index --;
+ else {
+ index = acfg->objc_selector_index;
+ g_ptr_array_add (acfg->objc_selectors, (void*)patch_info->data.target);
+ g_hash_table_insert (acfg->objc_selector_to_index, selector, GUINT_TO_POINTER (index + 1));
+ acfg->objc_selector_index ++;
+ }
+
+ arch_emit_objc_selector_ref (acfg, code + i, index, &code_size);
+ i += code_size - 1;
+ skip = TRUE;
+ patch_info->type = MONO_PATCH_INFO_NONE;
+ break;
+ }
default: {
/*
* If this patch is a call, try emitting a direct call instead of
* the same assembly and requires no initialization.
*/
direct_call = FALSE;
+ external_call = FALSE;
if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
if (!got_only && is_direct_callable (acfg, method, patch_info)) {
MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
else
direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method);
if (direct_pinvoke) {
- const char*prefix;
-#if defined(TARGET_MACH)
- prefix = "_";
-#else
- prefix = "";
-#endif
direct_call = TRUE;
g_assert (strlen (direct_pinvoke) < 1000);
- direct_call_target = g_strdup_printf ("%s%s", prefix, direct_pinvoke);
+ direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, direct_pinvoke);
}
}
+ } else if (patch_info->type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
+ const char *sym = mono_lookup_jit_icall_symbol (patch_info->data.name);
+ if (!got_only && sym && acfg->aot_opts.direct_icalls) {
+ /* Call to a C function implementing a jit icall */
+ direct_call = TRUE;
+ external_call = TRUE;
+ g_assert (strlen (sym) < 1000);
+ direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, sym);
+ }
+ } else if (patch_info->type == MONO_PATCH_INFO_INTERNAL_METHOD) {
+ MonoJitICallInfo *info = mono_find_jit_icall_by_name (patch_info->data.name);
+ const char *sym = mono_lookup_jit_icall_symbol (patch_info->data.name);
+ if (!got_only && sym && acfg->aot_opts.direct_icalls && info->func == info->wrapper) {
+ /* Call to a jit icall without a wrapper */
+ direct_call = TRUE;
+ external_call = TRUE;
+ g_assert (strlen (sym) < 1000);
+ direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, sym);
+ }
}
if (direct_call) {
if (direct_call) {
int call_size;
- arch_emit_direct_call (acfg, direct_call_target, &call_size);
+ arch_emit_direct_call (acfg, direct_call_target, external_call, patch_info, &call_size);
i += call_size - 1;
} else {
int code_size;
/* Try to emit multiple bytes at once */
if (pindex < patches->len && patch_info->ip.i > i) {
- emit_bytes (acfg, code + i, patch_info->ip.i - i);
- i = patch_info->ip.i - 1;
+ int limit;
+
+ for (limit = i + 1; limit < patch_info->ip.i; ++limit) {
+ if (locs && locs [limit])
+ break;
+ }
+
+ emit_bytes (acfg, code + i, limit - i);
+ i = limit - 1;
} else {
emit_bytes (acfg, code + i, 1);
}
}
}
+
+ g_free (locs);
}
/*
* sanitize_symbol:
*
- * Modify SYMBOL so it only includes characters permissible in symbols.
+ * Return a modified version of S which only includes characters permissible in symbols.
*/
-static void
-sanitize_symbol (char *symbol)
+static char*
+sanitize_symbol (MonoAotCompile *acfg, char *s)
{
- int i, len = strlen (symbol);
+ gboolean process = FALSE;
+ int i, len;
+ GString *gs;
+ char *res;
+ if (!s)
+ return s;
+
+ len = strlen (s);
for (i = 0; i < len; ++i)
- if (!isalnum (symbol [i]) && (symbol [i] != '_'))
- symbol [i] = '_';
+ if (!(s [i] <= 0x7f && (isalnum (s [i]) || s [i] == '_')))
+ process = TRUE;
+ if (!process)
+ return s;
+
+ gs = g_string_sized_new (len);
+ for (i = 0; i < len; ++i) {
+ guint8 c = s [i];
+ if (c <= 0x7f && (isalnum (c) || c == '_')) {
+ g_string_append_c (gs, c);
+ } else if (c > 0x7f) {
+ /* multi-byte utf8 */
+ g_string_append_printf (gs, "_0x%x", c);
+ i ++;
+ c = s [i];
+ while (c >> 6 == 0x2) {
+ g_string_append_printf (gs, "%x", c);
+ i ++;
+ c = s [i];
+ }
+ g_string_append_printf (gs, "_");
+ i --;
+ } else {
+ g_string_append_c (gs, '_');
+ }
+ }
+
+ res = mono_mempool_strdup (acfg->mempool, gs->str);
+ g_string_free (gs, TRUE);
+ return res;
}
static char*
char *name1, *name2, *cached;
int i, j, len, count;
+#ifdef TARGET_MACH
+ // This is so that we don't accidentally create a local symbol (which starts with 'L')
+ if (!prefix || !*prefix)
+ prefix = "_";
+#endif
+
name1 = mono_method_full_name (method, TRUE);
len = strlen (name1);
name2 = malloc (strlen (prefix) + len + 16);
acfg->cfgs [method_index]->got_offset = acfg->got_offset;
- emit_and_reloc_code (acfg, method, code, cfg->code_len, cfg->patch_info, FALSE);
+ emit_and_reloc_code (acfg, method, code, cfg->code_len, cfg->patch_info, FALSE, mono_debug_find_method (cfg->jit_info->d.method, mono_domain_get ()));
emit_line (acfg);
encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
break;
case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
+ case MONO_PATCH_INFO_JIT_TLS_ID:
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
case MONO_PATCH_INFO_CASTCLASS_CACHE:
break;
case MONO_PATCH_INFO_METHOD_JUMP:
case MONO_PATCH_INFO_ICALL_ADDR:
case MONO_PATCH_INFO_METHOD_RGCTX:
+ case MONO_PATCH_INFO_METHOD_CODE_SLOT:
encode_method_ref (acfg, patch_info->data.method, p, &p);
break;
case MONO_PATCH_INFO_INTERNAL_METHOD:
}
encode_value (offset, p, &p);
- g_assert (entry->info_type < 256);
+ g_assert ((int)entry->info_type < 256);
g_assert (entry->data->type < 256);
encode_value ((entry->in_mrgctx ? 1 : 0) | (entry->info_type << 1) | (entry->data->type << 9), p, &p);
encode_patch (acfg, entry->data, p, &p);
case MONO_PATCH_INFO_SIGNATURE:
encode_signature (acfg, (MonoMethodSignature*)patch_info->data.target, p, &p);
break;
+ case MONO_PATCH_INFO_TLS_OFFSET:
+ encode_value (GPOINTER_TO_INT (patch_info->data.target), p, &p);
+ break;
case MONO_PATCH_INFO_GSHAREDVT_CALL:
encode_signature (acfg, (MonoMethodSignature*)patch_info->data.gsharedvt->sig, p, &p);
encode_method_ref (acfg, patch_info->data.gsharedvt->method, p, &p);
break;
+ case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
+ MonoGSharedVtMethodInfo *info = patch_info->data.gsharedvt_method;
+ int i;
+
+ encode_method_ref (acfg, info->method, p, &p);
+ encode_value (info->entries->len, p, &p);
+ for (i = 0; i < info->entries->len; ++i) {
+ MonoRuntimeGenericContextInfoTemplate *template = g_ptr_array_index (info->entries, i);
+
+ encode_value (template->info_type, p, &p);
+ switch (mini_rgctx_info_type_to_patch_info_type (template->info_type)) {
+ case MONO_PATCH_INFO_CLASS:
+ encode_klass_ref (acfg, mono_class_from_mono_type (template->data), p, &p);
+ break;
+ case MONO_PATCH_INFO_FIELD:
+ encode_field_info (acfg, template->data, p, &p);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ break;
+ }
default:
g_warning ("unable to handle jump info %d", patch_info->type);
g_assert_not_reached ();
seq_points = cfg->seq_point_info;
- buf_size = header->num_clauses * 256 + debug_info_size + 2048 + (seq_points ? (seq_points->len * 64) : 0) + cfg->gc_map_size;
+ buf_size = header->num_clauses * 256 + debug_info_size + 2048 + (seq_points ? (seq_points->len * 128) : 0) + cfg->gc_map_size;
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) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 0) | (cfg->compile_llvm ? 16 : 0) | (jinfo->has_try_block_holes ? 32 : 0) | (cfg->gc_map ? 64 : 0) | (jinfo->has_arch_eh_info ? 128 : 0);
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);
+ guint8 *buf2, *p2;
+ int len;
+
+ buf2 = g_malloc (4096);
+ p2 = buf2;
+ encode_klass_ref (acfg, ei->data.catch_class, p2, &p2);
+ len = p2 - buf2;
+ g_assert (len < 4096);
+ encode_value (len, p, &p);
+ memcpy (p, buf2, len);
+ p += p2 - buf2;
+ g_free (buf2);
} else {
encode_value (0, p, &p);
}
}
}
+ if (jinfo->has_try_block_holes) {
+ MonoTryBlockHoleTableJitInfo *table = mono_jit_info_get_try_block_hole_table_info (jinfo);
+ for (i = 0; i < table->num_holes; ++i) {
+ MonoTryBlockHoleJitInfo *hole = &table->holes [i];
+ encode_value (hole->clause, p, &p);
+ encode_value (hole->length, p, &p);
+ encode_value (hole->offset, p, &p);
+ }
+ }
+
+ if (jinfo->has_arch_eh_info) {
+ MonoArchEHJitInfo *eh_info;
+
+ eh_info = mono_jit_info_get_arch_eh_info (jinfo);
+ encode_value (eh_info->stack_size, p, &p);
+ }
+
if (jinfo->has_generic_jit_info) {
MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (jinfo);
MonoGenericSharingContext* gsctx = gi->generic_sharing_context;
guint8 *p1;
+ guint8 *buf2, *p2;
+ int len;
p1 = p;
encode_value (gi->nlocs, p, &p);
* Need to encode jinfo->method too, since it is not equal to 'method'
* when using generic sharing.
*/
- encode_method_ref (acfg, jinfo->method, p, &p);
+ buf2 = g_malloc (4096);
+ p2 = buf2;
+ encode_method_ref (acfg, jinfo->d.method, p2, &p2);
+ len = p2 - buf2;
+ g_assert (len < 4096);
+ encode_value (len, p, &p);
+ memcpy (p, buf2, len);
+ p += p2 - buf2;
+ g_free (buf2);
if (gsctx && (gsctx->var_is_vt || gsctx->mvar_is_vt)) {
MonoMethodInflated *inflated;
MonoGenericContext *context;
MonoGenericInst *inst;
- g_assert (jinfo->method->is_inflated);
- inflated = (MonoMethodInflated*)jinfo->method;
+ g_assert (jinfo->d.method->is_inflated);
+ inflated = (MonoMethodInflated*)jinfo->d.method;
context = &inflated->context;
encode_value (1, p, &p);
}
}
- if (jinfo->has_try_block_holes) {
- MonoTryBlockHoleTableJitInfo *table = mono_jit_info_get_try_block_hole_table_info (jinfo);
- for (i = 0; i < table->num_holes; ++i) {
- MonoTryBlockHoleJitInfo *hole = &table->holes [i];
- encode_value (hole->clause, p, &p);
- encode_value (hole->length, p, &p);
- encode_value (hole->offset, p, &p);
- }
- }
-
- if (jinfo->has_arch_eh_info) {
- MonoArchEHJitInfo *eh_info;
-
- eh_info = mono_jit_info_get_arch_eh_info (jinfo);
- encode_value (eh_info->stack_size, p, &p);
- }
-
if (seq_points) {
int il_offset, native_offset, last_il_offset, last_native_offset, j;
last_il_offset = il_offset;
last_native_offset = native_offset;
+ encode_value (sp->flags, p, &p);
encode_value (sp->next_len, p, &p);
for (j = 0; j < sp->next_len; ++j)
encode_value (sp->next [j], p, &p);
get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cache)
{
char *debug_sym = NULL;
+ char *s;
switch (ji->type) {
case MONO_PATCH_INFO_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);
+ s = mono_type_get_name (&ji->data.klass->byval_arg);
+ debug_sym = g_strdup_printf ("plt__class_init_%s", s);
+ g_free (s);
break;
case MONO_PATCH_INFO_RGCTX_FETCH:
debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
break;
}
- return debug_sym;
+ return sanitize_symbol (acfg, debug_sym);
}
/*
if (callee_cfg) {
if (acfg->thumb_mixed && !callee_cfg->compile_llvm) {
/* LLVM calls the PLT entries using bl, so emit a stub */
+ emit_set_thumb_mode (acfg);
fprintf (acfg->fp, "\n.thumb_func\n");
emit_label (acfg, plt_entry->llvm_symbol);
fprintf (acfg->fp, "bx pc\n");
fprintf (acfg->fp, "nop\n");
- fprintf (acfg->fp, ".arm\n");
+ emit_set_arm_mode (acfg);
fprintf (acfg->fp, "b %s\n", callee_cfg->asm_symbol);
} else {
fprintf (acfg->fp, "\n.set %s, %s\n", plt_entry->llvm_symbol, callee_cfg->asm_symbol);
if (debug_sym) {
if (acfg->need_no_dead_strip) {
- img_writer_emit_unset_mode (acfg->w);
+ emit_unset_mode (acfg);
fprintf (acfg->fp, " .no_dead_strip %s\n", debug_sym);
}
emit_local_symbol (acfg, debug_sym, NULL, TRUE);
MonoJumpInfo *ji;
GSList *unwind_ops;
+ g_assert (info);
+
name = info->name;
code = info->code;
code_size = info->code_size;
/* Emit code */
- sprintf (start_symbol, "%s", name);
+ sprintf (start_symbol, "%s%s", acfg->user_symbol_prefix, name);
emit_section_change (acfg, ".text", 0);
emit_global (acfg, start_symbol, TRUE);
* The code should access everything through the GOT, so we pass
* TRUE here.
*/
- emit_and_reloc_code (acfg, NULL, code, code_size, ji, TRUE);
+ emit_and_reloc_code (acfg, NULL, code, code_size, ji, TRUE, NULL);
emit_symbol_size (acfg, start_symbol, ".");
encode_patch_list (acfg, patches, patches->len, got_offset, p, &p);
g_assert (p - buf < buf_size);
- sprintf (symbol, "%s_p", name);
+ sprintf (symbol, "%s%s_p", acfg->user_symbol_prefix, name);
info_offset = add_to_blob (acfg, buf, p - buf);
*/
for (tramp_type = 0; tramp_type < MONO_TRAMPOLINE_NUM; ++tramp_type) {
/* we overload the boolean here to indicate the slightly different trampoline needed, see mono_arch_create_generic_trampoline() */
+#ifdef DISABLE_REMOTING
+ if (tramp_type == MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING)
+ continue;
+#endif
+#ifndef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
+ if (tramp_type == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD)
+ continue;
+#endif
mono_arch_create_generic_trampoline (tramp_type, &info, acfg->aot_opts.use_trampolines_page? 2: TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
}
#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
mono_arch_get_gsharedvt_trampoline (&info, TRUE);
- emit_trampoline_full (acfg, acfg->got_offset, info, TRUE);
+ if (info) {
+ emit_trampoline_full (acfg, acfg->got_offset, info, TRUE);
- /* Create a separate out trampoline for more information in stack traces */
- info->name = g_strdup ("gsharedvt_out_trampoline");
- emit_trampoline_full (acfg, acfg->got_offset, info, TRUE);
+ /* Create a separate out trampoline for more information in stack traces */
+ info->name = g_strdup ("gsharedvt_out_trampoline");
+ emit_trampoline_full (acfg, acfg->got_offset, info, TRUE);
+ }
#endif
#if defined(MONO_ARCH_HAVE_GET_TRAMPOLINES)
}
#endif
- for (i = 0; i < 128; ++i) {
+ for (i = 0; i < acfg->aot_opts.nrgctx_fetch_trampolines; ++i) {
int offset;
offset = MONO_RGCTX_SLOT_MAKE_RGCTX (i);
emit_trampoline (acfg, acfg->got_offset, info);
}
+#ifdef MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE
+ mono_arch_create_general_rgctx_lazy_fetch_trampoline (&info, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
+#endif
+
{
GSList *l;
}
emit_label (acfg, end_symbol);
+ emit_int32 (acfg, 0);
}
arch_emit_specific_trampoline_pages (acfg);
opts->asm_writer = TRUE;
} else if (str_begins_with (arg, "nodebug")) {
opts->nodebug = TRUE;
+ } else if (str_begins_with (arg, "dwarfdebug")) {
+ opts->dwarf_debug = TRUE;
} else if (str_begins_with (arg, "nopagetrampolines")) {
opts->use_trampolines_page = FALSE;
} else if (str_begins_with (arg, "ntrampolines=")) {
printf (" asmonly\n");
printf (" asmwriter\n");
printf (" nodebug\n");
+ printf (" dwarfdebug\n");
printf (" ntrampolines=\n");
printf (" nrgctx-trampolines=\n");
printf (" nimt-trampolines=\n");
opts->ntrampolines = 0;
opts->nrgctx_trampolines = 0;
opts->nimt_trampolines = 0;
+ opts->ngsharedvt_arg_trampolines = 0;
}
g_strfreev (args);
}
case MONO_WRAPPER_UNKNOWN:
case MONO_WRAPPER_WRITE_BARRIER:
case MONO_WRAPPER_DELEGATE_INVOKE:
+ case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
+ case MONO_WRAPPER_DELEGATE_END_INVOKE:
+ case MONO_WRAPPER_SYNCHRONIZED:
break;
case MONO_WRAPPER_MANAGED_TO_MANAGED:
case MONO_WRAPPER_CASTCLASS: {
{
switch (patch_info->type) {
case MONO_PATCH_INFO_METHOD:
- case MONO_PATCH_INFO_METHODCONST: {
+ case MONO_PATCH_INFO_METHODCONST:
+ case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
MonoMethod *method = patch_info->data.method;
return can_encode_method (acfg, method);
* does not need to support them by creating a fake GOT etc.
*/
cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
+ mono_loader_clear_error ();
+
if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
if (acfg->aot_opts.print_skipped_methods)
printf ("Skip (gshared failure): %s (%s)\n", mono_method_full_name (method, TRUE), cfg->exception_message);
mono_destroy_compile (cfg);
return;
}
+ cfg->method_index = index;
/* Nullify patches which need no aot processing */
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
MonoMethod *m = patch_info->data.method;
if (m->is_inflated) {
if (!(mono_class_generic_sharing_enabled (m->klass) &&
- mono_method_is_generic_sharable_impl_full (m, FALSE, FALSE, FALSE)) &&
+ mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) &&
!method_has_type_vars (m)) {
if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
if (acfg->aot_opts.full_aot)
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))
+ if (klass->generic_class && !mini_class_is_generic_sharable (klass))
add_generic_class_with_depth (acfg, klass, depth + 5, "vtable");
break;
}
#endif
}
+int
+mono_aot_get_method_index (MonoMethod *method)
+{
+ g_assert (llvm_acfg);
+ return get_method_index (llvm_acfg, method);
+}
+
MonoJumpInfo*
mono_aot_patch_info_dup (MonoJumpInfo* ji)
{
}
- tempbc = g_strdup_printf ("%s.bc", acfg->tmpfname);
+ tempbc = g_strdup_printf ("%s.bc", acfg->tmpbasename);
mono_llvm_emit_aot_module (tempbc, acfg->final_got_size);
g_free (tempbc);
* - 'prune-eh' and 'functionattrs' depend on 'basiccg'.
* 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.
+ * then removing tailcallelim + the global opts.
+ * strip-dead-prototypes deletes unused intrinsics definitions.
*/
opts = g_strdup ("-instcombine -simplifycfg");
- opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -domfrontier -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -iv-users -indvars -loop-deletion -loop-simplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -domtree -memdep -dse -adce -simplifycfg -preverify -domtree -verify");
+ //opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -domfrontier -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -iv-users -indvars -loop-deletion -loop-simplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -domtree -memdep -dse -adce -simplifycfg -preverify -domtree -verify");
+ opts = g_strdup ("-targetlibinfo -no-aa -basicaa -notti -instcombine -simplifycfg -sroa -domtree -early-cse -lazy-value-info -correlated-propagation -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop-idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt -sccp -instcombine -lazy-value-info -correlated-propagation -domtree -memdep -dse -adce -simplifycfg -instcombine -strip-dead-prototypes -preverify -domtree -verify");
#if 1
- command = g_strdup_printf ("%sopt -f %s -o %s.opt.bc %s.bc", acfg->aot_opts.llvm_path, opts, acfg->tmpfname, acfg->tmpfname);
+ command = g_strdup_printf ("%sopt -f %s -o \"%s.opt.bc\" \"%s.bc\"", acfg->aot_opts.llvm_path, opts, acfg->tmpbasename, acfg->tmpbasename);
printf ("Executing opt: %s\n", command);
if (system (command) != 0) {
exit (1);
if (acfg->aot_opts.mtriple)
g_string_append_printf (acfg->llc_args, " -mtriple=%s", acfg->aot_opts.mtriple);
+#if defined(TARGET_MACH) && defined(TARGET_ARM)
+ /* ios requires PIC code now */
+ g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
+#else
if (llvm_acfg->aot_opts.static_link)
g_string_append_printf (acfg->llc_args, " -relocation-model=static");
else
g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
+#endif
unlink (acfg->tmpfname);
- command = g_strdup_printf ("%sllc %s -disable-gnu-eh-frame -enable-mono-eh-frame -o %s %s.opt.bc", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname, acfg->tmpfname);
+ command = g_strdup_printf ("%sllc %s -disable-gnu-eh-frame -enable-mono-eh-frame -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname, acfg->tmpbasename);
printf ("Executing llc: %s\n", command);
{
int oindex, i, prev_index;
char symbol [256];
- char end_symbol [256];
#if defined(TARGET_POWERPC64)
sprintf (symbol, ".Lgot_addr");
* code_offsets array. It is also used to compute the memory ranges occupied by
* AOT code, so it must be equal to the address of the first emitted method.
*/
- sprintf (symbol, "methods");
emit_section_change (acfg, ".text", 0);
emit_alignment (acfg, 8);
if (acfg->llvm) {
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm) {
- fprintf (acfg->fp, "\n.set methods, %s\n", acfg->cfgs [i]->asm_symbol);
+ acfg->methods_symbol = g_strdup (acfg->cfgs [i]->asm_symbol);
break;
}
}
- if (i == acfg->nmethods)
- /* No LLVM compiled methods */
- emit_label (acfg, symbol);
- } else {
+ }
+ if (!acfg->methods_symbol) {
+ sprintf (symbol, "methods");
emit_label (acfg, symbol);
+ acfg->methods_symbol = g_strdup (symbol);
}
/*
emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
#endif
- if (acfg->thumb_mixed && cfg->compile_llvm)
+ if (acfg->thumb_mixed && cfg->compile_llvm) {
+ emit_set_thumb_mode (acfg);
fprintf (acfg->fp, "\n.thumb_func\n");
+ }
emit_label (acfg, symbol);
arch_emit_unbox_trampoline (acfg, cfg, cfg->orig_method, cfg->asm_symbol);
+
+ if (acfg->thumb_mixed && cfg->compile_llvm) {
+ emit_set_arm_mode (acfg);
+ }
}
if (cfg->compile_llvm)
emit_section_change (acfg, ".text", 0);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ /* To distinguish it from the next symbol */
+ emit_int32 (acfg, 0);
/*
* Add .no_dead_strip directives for all LLVM methods to prevent the OSX linker
if (acfg->direct_method_addresses) {
acfg->flags |= MONO_AOT_FILE_FLAG_DIRECT_METHOD_ADDRESSES;
+ /*
+ * To work around linker issues, we emit a table of branches, and disassemble them at runtime.
+ * This is PIE code, and the linker can update it if needed.
+ */
sprintf (symbol, "method_addresses");
- emit_section_change (acfg, RODATA_SECT, 1);
+ emit_section_change (acfg, ".text", 1);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ emit_local_symbol (acfg, symbol, "method_addresses_end", TRUE);
+ emit_unset_mode (acfg);
+ if (acfg->need_no_dead_strip)
+ fprintf (acfg->fp, " .no_dead_strip %s\n", symbol);
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
- emit_pointer (acfg, acfg->cfgs [i]->asm_symbol);
+ if (acfg->thumb_mixed && acfg->cfgs [i]->compile_llvm)
+ fprintf (acfg->fp, "\tblx %s\n", acfg->cfgs [i]->asm_symbol);
+ else
+ fprintf (acfg->fp, "\tbl %s\n", acfg->cfgs [i]->asm_symbol);
} else {
- emit_pointer (acfg, NULL);
+ fprintf (acfg->fp, "\tbl method_addresses\n");
}
}
+ sprintf (symbol, "method_addresses_end");
+ emit_label (acfg, symbol);
+
/* Empty */
sprintf (symbol, "code_offsets");
emit_section_change (acfg, RODATA_SECT, 1);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ emit_int32 (acfg, 0);
} else {
sprintf (symbol, "code_offsets");
emit_section_change (acfg, RODATA_SECT, 1);
acfg->stats.offsets_size += acfg->nmethods * 4;
- sprintf (end_symbol, "methods");
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
- emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
+ emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, acfg->methods_symbol, 0);
} else {
emit_int32 (acfg, 0xffffffff);
}
acfg->stats.offsets_size += acfg->nmethods * 4;
- sprintf (end_symbol, "methods");
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
- emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
+ emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, acfg->methods_symbol, 0);
} else {
emit_int32 (acfg, 0xffffffff);
}
/* Emit a sorted table mapping methods to their unbox trampolines */
sprintf (symbol, "unbox_trampolines");
- emit_section_change (acfg, RODATA_SECT, 1);
+ if (acfg->direct_method_addresses)
+ emit_section_change (acfg, ".text", 0);
+ else
+ emit_section_change (acfg, RODATA_SECT, 0);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
- sprintf (end_symbol, "methods");
prev_index = -1;
for (i = 0; i < acfg->nmethods; ++i) {
MonoCompile *cfg;
sprintf (symbol, "ut_%d", index);
emit_int32 (acfg, index);
- emit_symbol_diff (acfg, symbol, end_symbol, 0);
+ if (acfg->direct_method_addresses) {
+ emit_unset_mode (acfg);
+ if (acfg->thumb_mixed && cfg->compile_llvm)
+ fprintf (acfg->fp, "\n\tblx %s\n", symbol);
+ else
+ fprintf (acfg->fp, "\n\tbl %s\n", symbol);
+ } else {
+ emit_symbol_diff (acfg, symbol, acfg->methods_symbol, 0);
+ }
/* Make sure the table is sorted by index */
g_assert (index > prev_index);
prev_index = index;
}
sprintf (symbol, "unbox_trampolines_end");
emit_label (acfg, symbol);
+ emit_int32 (acfg, 0);
}
static void
#undef mix
#undef final
-/*
- * mono_aot_wrapper_name:
- *
- * Return a string which uniqely identifies the given wrapper method.
- */
-char*
-mono_aot_wrapper_name (MonoMethod *method)
-{
- char *name, *tmpsig, *klass_desc;
-
- tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
-
- switch (method->wrapper_type) {
- case MONO_WRAPPER_RUNTIME_INVOKE:
- if (!strcmp (method->name, "runtime_invoke_dynamic"))
- name = g_strdup_printf ("(wrapper runtime-invoke-dynamic)");
- else
- name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
- break;
- default:
- klass_desc = mono_type_full_name (&method->klass->byval_arg);
- name = g_strdup_printf ("%s:%s (%s)", klass_desc, method->name, tmpsig);
- g_free (klass_desc);
- break;
- }
-
- g_free (tmpsig);
-
- return name;
-}
-
/*
* mono_aot_get_array_helper_from_wrapper;
*
value = get_method_index (acfg, method);
hash = mono_aot_method_hash (method) % table_size;
+ //printf ("X: %s %d\n", mono_method_full_name (method, 1), hash);
chain_lengths [hash] ++;
max_chain_length = MAX (max_chain_length, chain_lengths [hash]);
gc_name = mono_gc_get_gc_name ();
gc_name_offset = add_to_blob (acfg, (guint8*)gc_name, strlen (gc_name) + 1);
- sprintf (symbol, "mono_aot_file_info");
+ sprintf (symbol, "%smono_aot_file_info", acfg->user_symbol_prefix);
emit_section_change (acfg, ".data", 0);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
* various problems (i.e. arm/thumb).
*/
emit_pointer (acfg, acfg->got_symbol);
- emit_pointer (acfg, "methods");
+ emit_pointer (acfg, acfg->methods_symbol);
if (acfg->llvm) {
/*
* Emit a reference to the mono_eh_frame table created by our modified LLVM compiler.
emit_pointer (acfg, "method_info_offsets");
emit_pointer (acfg, "ex_info_offsets");
emit_pointer (acfg, "code_offsets");
-#ifdef MONOTOUCH
- emit_pointer (acfg, "method_addresses");
-#endif
+ if (acfg->direct_method_addresses)
+ emit_pointer (acfg, "method_addresses");
+ else
+ emit_pointer (acfg, NULL);
emit_pointer (acfg, "extra_method_info_offsets");
emit_pointer (acfg, "extra_method_table");
emit_pointer (acfg, "got_info_offsets");
emit_int32 (acfg, acfg->trampoline_got_offset_base [i]);
for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
emit_int32 (acfg, acfg->trampoline_size [i]);
+ emit_int32 (acfg, acfg->aot_opts.nrgctx_fetch_trampolines);
#if defined (TARGET_ARM) && defined (TARGET_MACH)
{
memset (&t, 0, sizeof (MonoType));
t.type = MONO_TYPE_R8;
mono_type_size (&t, &align);
-
emit_int32 (acfg, align);
memset (&t, 0, sizeof (MonoType));
emit_int32 (acfg, __alignof__ (double));
emit_int32 (acfg, __alignof__ (gint64));
#endif
+ emit_int32 (acfg, MONO_TRAMPOLINE_NUM);
+ emit_int32 (acfg, acfg->tramp_page_size);
+ for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+ emit_int32 (acfg, acfg->tramp_page_code_offsets [i]);
if (acfg->aot_opts.static_link) {
char *p;
* mono_aot_register_module (). The symbol points to a pointer to the the file info
* structure.
*/
-#if defined(TARGET_MACH) && !defined(__native_client_codegen__)
- sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name);
-#else
- sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name);
-#endif
+ sprintf (symbol, "%smono_aot_module_%s_info", acfg->user_symbol_prefix, acfg->image->assembly->aname.name);
/* Get rid of characters which cannot occur in symbols */
p = symbol;
}
acfg->static_linking_symbol = g_strdup (symbol);
emit_global_inner (acfg, symbol, FALSE);
+ emit_alignment (acfg, sizeof (gpointer));
emit_label (acfg, symbol);
- emit_pointer (acfg, "mono_aot_file_info");
+ emit_pointer_2 (acfg, acfg->user_symbol_prefix, "mono_aot_file_info");
}
}
emit_bytes (acfg, (guint8*)acfg->blob.data, acfg->blob.index);
}
+static void
+emit_objc_selectors (MonoAotCompile *acfg)
+{
+ int i;
+
+ if (!acfg->objc_selectors || acfg->objc_selectors->len == 0)
+ return;
+
+ /*
+ * From
+ * cat > foo.m << EOF
+ * void *ret ()
+ * {
+ * return @selector(print:);
+ * }
+ * EOF
+ */
+
+ img_writer_emit_unset_mode (acfg->w);
+ g_assert (acfg->fp);
+ fprintf (acfg->fp, ".section __DATA,__objc_selrefs,literal_pointers,no_dead_strip\n");
+ fprintf (acfg->fp, ".align 2\n");
+ for (i = 0; i < acfg->objc_selectors->len; ++i) {
+ fprintf (acfg->fp, "L_OBJC_SELECTOR_REFERENCES_%d:\n", i);
+ fprintf (acfg->fp, ".long L_OBJC_METH_VAR_NAME_%d\n", i);
+ }
+ fprintf (acfg->fp, ".section __TEXT,__cstring,cstring_literals\n");
+ for (i = 0; i < acfg->objc_selectors->len; ++i) {
+ fprintf (acfg->fp, "L_OBJC_METH_VAR_NAME_%d:\n", i);
+ fprintf (acfg->fp, ".asciz \"%s\"\n", (char*)g_ptr_array_index (acfg->objc_selectors, i));
+ }
+
+ fprintf (acfg->fp, ".section __DATA,__objc_imageinfo,regular,no_dead_strip\n");
+ fprintf (acfg->fp, ".align 2\n");
+ fprintf (acfg->fp, "L_OBJC_IMAGE_INFO:\n");
+ fprintf (acfg->fp, ".long 0\n");
+ fprintf (acfg->fp, ".long 16\n");
+}
+
static void
emit_dwarf_info (MonoAotCompile *acfg)
{
sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
- mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, cfg->asm_symbol, symbol2, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
+ mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, cfg->asm_symbol, symbol2, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->d.method, mono_domain_get ()));
}
#endif
}
method = mono_get_method (acfg->image, token, NULL);
if (!method)
continue;
+ /*
+ if (strcmp (method->name, "gshared2"))
+ continue;
+ */
+ /*
+ if (!strstr (method->klass->image->name, "mini"))
+ continue;
+ */
if (method->is_generic || method->klass->generic_container) {
- /* Create a vtype instantiation */
- MonoGenericContext ctx;
- MonoMethod *inflated, *gshared;
-
- create_gsharedvt_inst (acfg, method, &ctx);
+ MonoMethod *gshared;
- inflated = mono_class_inflate_generic_method (method, &ctx);
- gshared = mini_get_shared_method_full (inflated, FALSE, TRUE);
+ gshared = mini_get_shared_method_full (method, TRUE, TRUE);
add_extra_method (acfg, gshared);
}
}
char *outfile_name, *tmp_outfile_name;
const char *tool_prefix = acfg->aot_opts.tool_prefix ? acfg->aot_opts.tool_prefix : "";
-#if defined(TARGET_AMD64)
+#if defined(TARGET_AMD64) && !defined(TARGET_MACH)
#define AS_OPTIONS "--64"
#elif defined(TARGET_POWERPC64)
#define AS_OPTIONS "-a64 -mppc64"
#else
#define AS_NAME "nacl-as"
#endif
+#elif defined(TARGET_OSX)
+#define AS_NAME "clang -c -x assembler"
#else
#define AS_NAME "as"
#endif
#define LD_OPTIONS ""
#endif
-#define EH_LD_OPTIONS ""
+#if defined(sparc)
+#define LD_NAME "ld -shared -G"
+#elif defined(__ppc__) && defined(TARGET_MACH)
+#define LD_NAME "gcc -dynamiclib"
+#elif defined(TARGET_AMD64) && defined(TARGET_MACH)
+#define LD_NAME "clang --shared"
+#elif defined(HOST_WIN32)
+#define LD_NAME "gcc -shared --dll"
+#elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
+#define LD_NAME "clang -m32 -dynamiclib"
+#endif
if (acfg->aot_opts.asm_only) {
printf ("Output file: '%s'.\n", acfg->tmpfname);
tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
-#if defined(sparc)
- command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
-#elif defined(__ppc__) && defined(TARGET_MACH)
- command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
-#elif defined(HOST_WIN32)
- command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
-#elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
- command = g_strdup_printf ("gcc -m32 -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
+#ifdef LD_NAME
+ command = g_strdup_printf ("%s -o %s %s.o", LD_NAME, tmp_outfile_name, acfg->tmpfname);
#else
- command = g_strdup_printf ("%sld %s %s -shared -o %s %s.o", tool_prefix, EH_LD_OPTIONS, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
+ command = g_strdup_printf ("%sld %s -shared -o %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
#endif
printf ("Executing the native linker: %s\n", command);
if (system (command) != 0) {
#if defined(TARGET_MACH)
command = g_strdup_printf ("dsymutil %s", outfile_name);
- printf ("Generating debug symbols: %s\n", command);
+ printf ("Executing dsymutil: %s\n", command);
if (system (command) != 0) {
return 1;
}
acfg->method_indexes = g_hash_table_new (NULL, NULL);
acfg->method_depth = g_hash_table_new (NULL, NULL);
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_plt_entry = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM);
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_hash_table_destroy (acfg->method_indexes);
g_hash_table_destroy (acfg->method_depth);
g_hash_table_destroy (acfg->plt_offset_to_entry);
- g_hash_table_destroy (acfg->patch_to_plt_entry);
+ for (i = 0; i < MONO_PATCH_INFO_NUM; ++i) {
+ if (acfg->patch_to_plt_entry [i])
+ g_hash_table_destroy (acfg->patch_to_plt_entry [i]);
+ }
+ g_free (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);
int i, res;
MonoAotCompile *acfg;
char *outfile_name, *tmp_outfile_name, *p;
+ char llvm_stats_msg [256];
TV_DECLARE (atv);
TV_DECLARE (btv);
+#if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED) || (!defined(MONO_EXTENSIONS) && !defined(MONOTOUCH))
+ if (opts & MONO_OPT_GSHAREDVT) {
+ fprintf (stderr, "-O=gsharedvt not supported on this platform.\n");
+ exit (1);
+ }
+#endif
+
printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
acfg = acfg_create (ass, opts);
acfg->aot_opts.ntrampolines = 1024;
acfg->aot_opts.nrgctx_trampolines = 1024;
acfg->aot_opts.nimt_trampolines = 128;
+ acfg->aot_opts.nrgctx_fetch_trampolines = 128;
acfg->aot_opts.ngsharedvt_arg_trampolines = 128;
acfg->aot_opts.llvm_path = g_strdup ("");
-#if MONOTOUCH
+#ifdef MONOTOUCH
acfg->aot_opts.use_trampolines_page = TRUE;
#endif
opt->mdb_optimizations = TRUE;
opt->gen_seq_points = TRUE;
- if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) {
+ if (!mono_debug_enabled ()) {
fprintf (stderr, "The soft-debug AOT option requires the --debug option.\n");
return 1;
}
acfg->method_index = 1;
+ // FIXME:
+ /*
+ if (acfg->aot_opts.full_aot)
+ mono_set_partial_sharing_supported (TRUE);
+ */
+
collect_methods (acfg);
acfg->cfgs_size = acfg->methods->len + 32;
ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
ji->type = MONO_PATCH_INFO_GC_CARD_TABLE_ADDR;
get_got_offset (acfg, ji);
+
+ ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
+ ji->type = MONO_PATCH_INFO_JIT_TLS_ID;
+ get_got_offset (acfg, ji);
}
TV_GETTIME (atv);
#ifdef ENABLE_LLVM
if (acfg->llvm) {
if (acfg->aot_opts.asm_only) {
- if (acfg->aot_opts.outfile)
+ 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->tmpbasename = g_strdup (acfg->tmpfname);
+ } else {
+ acfg->tmpbasename = g_strdup_printf ("%s", acfg->image->name);
+ acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
+ }
} else {
- acfg->tmpfname = g_strdup ("temp.s");
+ acfg->tmpbasename = g_strdup_printf ("%s", "temp");
+ acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
}
emit_llvm_file (acfg);
int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
acfg->fp = fdopen (i, "w+");
}
- if (acfg->fp == 0) {
- fprintf (stderr, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));
- return 1;
- }
+ }
+ if (acfg->fp == 0) {
+ fprintf (stderr, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));
+ return 1;
}
acfg->w = img_writer_create (acfg->fp, FALSE);
}
}
- if (!acfg->aot_opts.nodebug)
- acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE);
+ if (acfg->aot_opts.dwarf_debug && acfg->aot_opts.asm_only && acfg->aot_opts.gnu_asm) {
+ /*
+ * CLANG supports GAS .file/.loc directives, so emit line number information this way
+ */
+ acfg->gas_line_numbers = TRUE;
+ }
+
+ if (!acfg->aot_opts.nodebug || acfg->aot_opts.dwarf_debug) {
+ if (acfg->aot_opts.dwarf_debug && !mono_debug_enabled ()) {
+ fprintf (stderr, "The dwarf AOT option requires the --debug option.\n");
+ return 1;
+ }
+ acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE, !acfg->gas_line_numbers);
+ }
img_writer_emit_start (acfg->w);
if (acfg->dwarf)
- mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_unwind_get_cie_program ());
+ mono_dwarf_writer_emit_base_info (acfg->dwarf, g_path_get_basename (acfg->image->name), mono_unwind_get_cie_program ());
if (acfg->thumb_mixed) {
char symbol [256];
emit_blob (acfg);
+ emit_objc_selectors (acfg);
+
emit_globals (acfg);
emit_autoreg (acfg);
if (acfg->llvm)
g_assert (acfg->got_offset <= acfg->final_got_size);
+ if (acfg->llvm)
+ sprintf (llvm_stats_msg, ", LLVM: %d (%d%%)", acfg->stats.llvm_count, acfg->stats.mcount ? (acfg->stats.llvm_count * 100) / acfg->stats.mcount : 100);
+ else
+ strcpy (llvm_stats_msg, "");
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);
- printf ("Compiled: %d/%d (%d%%), No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n",
+ printf ("Compiled: %d/%d (%d%%)%s, No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n",
acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100,
+ llvm_stats_msg,
acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100,
acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
if (acfg->stats.genericcount)
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);
TV_GETTIME (atv);
res = img_writer_emit_writeout (acfg->w);