#ifdef TARGET_WIN32
#define SHARED_EXT ".dll"
-#elif defined(__ppc__) && defined(__MACH__)
+#elif defined(__ppc__) && defined(__APPLE__)
#define SHARED_EXT ".dylib"
#elif defined(__APPLE__) && defined(TARGET_X86) && !defined(__native_client_codegen__)
#define SHARED_EXT ".dylib"
char *tool_prefix;
gboolean autoreg;
char *mtriple;
+ char *llvm_path;
} MonoAotOptions;
typedef struct MonoAotStats {
GPtrArray *extra_methods;
GPtrArray *image_table;
GPtrArray *globals;
- GList *method_order;
+ GPtrArray *method_order;
guint32 *plt_got_info_offsets;
guint32 got_offset, plt_offset, plt_got_offset_base;
guint32 final_got_size;
MonoClass **typespec_classes;
GString *llc_args;
GString *as_args;
+ gboolean thumb_mixed, need_no_dead_strip, need_pt_gnu_stack;
} MonoAotCompile;
typedef struct {
int plt_offset;
- char *symbol;
+ char *symbol, *llvm_symbol, *debug_sym;
MonoJumpInfo *ji;
+ gboolean jit_used, llvm_used;
} MonoPltEntry;
#define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
{
img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
- emit_global (acfg, name, FALSE);
+#ifdef __APPLE__
+ /* On apple, all symbols need to be aligned to avoid warnings from ld */
+ emit_alignment (acfg, 4);
+#endif
img_writer_emit_label (acfg->w, name);
img_writer_emit_string (acfg->w, value);
}
#else
#define AOT_FUNC_ALIGNMENT 16
#endif
-#if defined(TARGET_X86) && defined(__native_client_codegen__)
+#if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__native_client_codegen__)
#undef AOT_FUNC_ALIGNMENT
#define AOT_FUNC_ALIGNMENT 32
#endif
#define PPC_LDX_OP "lwzx"
#endif
+#ifdef TARGET_AMD64
+#define AOT_TARGET_STR "AMD64"
+#endif
+
+#ifdef TARGET_ARM
+#ifdef __MACH__
+#define AOT_TARGET_STR "ARM (MACH)"
+#else
+#define AOT_TARGET_STR "ARM (!MACH)"
+#endif
+#endif
+
+#ifdef TARGET_POWERPC64
+#ifdef __mono_ilp32__
+#define AOT_TARGET_STR "POWERPC64 (mono ilp32)"
+#else
+#define AOT_TARGET_STR "POWERPC64 (!mono ilp32)"
+#endif
+#else
+#ifdef TARGET_POWERPC
+#ifdef __mono_ilp32__
+#define AOT_TARGET_STR "POWERPC (mono ilp32)"
+#else
+#define AOT_TARGET_STR "POWERPC (!mono ilp32)"
+#endif
+#endif
+#endif
+
+#ifdef TARGET_WIN32
+#define AOT_TARGET_STR "WIN32"
+#endif
+
+#ifdef TARGET_X86
+#ifdef __native_client_codegen__
+#define AOT_TARGET_STR "X86 (native client codegen)"
+#else
+#define AOT_TARGET_STR "X86 (!native client codegen)"
+#endif
+#endif
+
+#ifndef AOT_TARGET_STR
+#define AOT_TARGET_STR ""
+#endif
+
static void
arch_init (MonoAotCompile *acfg)
{
#ifdef TARGET_ARM
if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "darwin")) {
g_string_append (acfg->llc_args, "-mattr=+v6");
- acfg->llvm_label_prefix = "_";
} else {
#ifdef ARM_FPU_VFP
g_string_append (acfg->llc_args, " -mattr=+vfp2,+d16");
g_string_append (acfg->llc_args, " -soft-float");
#endif
}
+ if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "thumb"))
+ acfg->thumb_mixed = TRUE;
if (acfg->aot_opts.mtriple)
mono_arch_set_target (acfg->aot_opts.mtriple);
#endif
+
+#ifdef __APPLE__
+ acfg->llvm_label_prefix = "_";
+ acfg->need_no_dead_strip = TRUE;
+#endif
+
+#if defined(__linux__) && !defined(TARGET_ARM)
+ acfg->need_pt_gnu_stack = TRUE;
+#endif
}
/*
{
#if defined(TARGET_X86)
guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
-
-#ifdef __native_client_codegen__
+#if defined(__default_codegen__)
+ /* 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(__native_client_codegen__)
const guint8 kSizeOfNaClJmp = 11;
guint8 bytes[kSizeOfNaClJmp];
guint8 *pbytes = &bytes[0];
emit_byte (acfg, 0x68); /* hide data in a push */
emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
-#else
- /* 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]);
-#endif /* __native_client_codegen__ */
+#endif /*__native_client_codegen__*/
#elif defined(TARGET_AMD64)
+#if defined(__default_codegen__)
/*
* We can't emit jumps because they are 32 bits only so they can't be patched.
* So we make indirect calls through GOT entries which are patched by the AOT
emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4);
/* Used by mono_aot_get_plt_info_offset */
emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+#elif defined(__native_client_codegen__)
+ guint8 buf [256];
+ guint8 *buf_aligned = ALIGN_TO(buf, kNaClAlignment);
+ guint8 *code = buf_aligned;
+
+ /* mov <OFFSET>(%rip), %r11d */
+ emit_byte (acfg, '\x45');
+ emit_byte (acfg, '\x8b');
+ emit_byte (acfg, '\x1d');
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4);
+
+ amd64_jump_reg (code, AMD64_R11);
+ /* This should be constant for the plt patch */
+ g_assert ((size_t)(code-buf_aligned) == 10);
+ emit_bytes (acfg, buf_aligned, code - buf_aligned);
+
+ /* Hide data in a push imm32 so it passes validation */
+ emit_byte (acfg, 0x68); /* push */
+ emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+ emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#endif /*__native_client_codegen__*/
#elif defined(TARGET_ARM)
guint8 buf [256];
guint8 *code;
- /* FIXME:
- * - optimize OP_AOTCONST implementation
- * - optimize the PLT entries
- * - optimize SWITCH AOT implementation
- */
code = buf;
- if (acfg->use_bin_writer && FALSE) {
- /* FIXME: mono_arch_patch_plt_entry () needs to decode this */
- /* We only emit 1 relocation since we implement it ourselves anyway */
- img_writer_emit_reloc (acfg->w, R_ARM_ALU_PC_G0_NC, acfg->got_symbol, ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) - 8);
- /* FIXME: A 2 instruction encoding is sufficient in most cases */
- ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_PC, 0, 0);
- ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_IP, 0, 0);
- ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, 0);
- emit_bytes (acfg, buf, code - buf);
- /* Used by mono_aot_get_plt_info_offset */
- emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
- } else {
- ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
- ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
- emit_bytes (acfg, buf, code - buf);
- emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) - 4);
- /* Used by mono_aot_get_plt_info_offset */
- emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
- }
- /*
- * The plt_got_info_offset is computed automatically by
- * mono_aot_get_plt_info_offset (), so no need to save it here.
- */
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
+ ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
+ emit_bytes (acfg, buf, code - buf);
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) - 4);
+ /* Used by mono_aot_get_plt_info_offset */
+ emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
#elif defined(TARGET_POWERPC)
guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
#endif
}
+static void
+arch_emit_llvm_plt_entry (MonoAotCompile *acfg, int index)
+{
+#if defined(TARGET_ARM)
+#if 0
+ /* LLVM calls the PLT entries using bl, so emit a stub */
+ /* FIXME: Too much overhead on every call */
+ fprintf (acfg->fp, ".thumb_func\n");
+ fprintf (acfg->fp, "bx pc\n");
+ fprintf (acfg->fp, "nop\n");
+ fprintf (acfg->fp, ".arm\n");
+#endif
+ /* 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 */
+ 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");
+ 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]);
+#else
+ g_assert_not_reached ();
+#endif
+}
+
/*
* arch_emit_specific_trampoline:
*
* - all the trampolines should be of the same length.
*/
#if defined(TARGET_AMD64)
+#if defined(__default_codegen__)
/* This should be exactly 16 bytes long */
*tramp_size = 16;
/* call *<offset>(%rip) */
emit_byte (acfg, '\x15');
emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
/* This should be relative to the start of the trampoline */
- emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4 + 19);
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset+1) * sizeof (gpointer)) + 7);
emit_zero_bytes (acfg, 5);
+#elif defined(__native_client_codegen__)
+ guint8 buf [256];
+ guint8 *buf_aligned = ALIGN_TO(buf, kNaClAlignment);
+ guint8 *code = buf_aligned;
+ guint8 *call_start;
+ size_t call_len;
+ int got_offset;
+
+ /* Emit this call in 'code' so we can find out how long it is. */
+ amd64_call_reg (code, AMD64_R11);
+ call_start = mono_arch_nacl_skip_nops (buf_aligned);
+ call_len = code - call_start;
+
+ /* The tramp_size is twice the NaCl alignment because it starts with */
+ /* a call which needs to be aligned to the end of the boundary. */
+ *tramp_size = kNaClAlignment*2;
+ {
+ /* Emit nops to align call site below which is 7 bytes plus */
+ /* the length of the call sequence emitted above. */
+ /* Note: this requires the specific trampoline starts on a */
+ /* kNaclAlignedment aligned address, which it does because */
+ /* it's its own function that is aligned. */
+ guint8 nop_buf[256];
+ guint8 *nopbuf_aligned = ALIGN_TO (nop_buf, kNaClAlignment);
+ guint8 *nopbuf_end = mono_arch_nacl_pad (nopbuf_aligned, kNaClAlignment - 7 - (call_len));
+ emit_bytes (acfg, nopbuf_aligned, nopbuf_end - nopbuf_aligned);
+ }
+ /* The trampoline is stored at the offset'th pointer, the -4 is */
+ /* present because RIP relative addressing starts at the end of */
+ /* the current instruction, while the label "." is relative to */
+ /* the beginning of the current asm location, which in this case */
+ /* is not the mov instruction, but the offset itself, due to the */
+ /* way the bytes and ints are emitted here. */
+ got_offset = (offset * sizeof(gpointer)) - 4;
+
+ /* mov <OFFSET>(%rip), %r11d */
+ emit_byte (acfg, '\x45');
+ emit_byte (acfg, '\x8b');
+ emit_byte (acfg, '\x1d');
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", got_offset);
+
+ /* naclcall %r11 */
+ emit_bytes (acfg, call_start, call_len);
+
+ /* The arg is stored at the offset+1 pointer, relative to beginning */
+ /* of trampoline: 7 for mov, plus the call length, and 1 for push. */
+ got_offset = ((offset + 1) * sizeof(gpointer)) + 7 + call_len + 1;
+
+ /* We can't emit this data directly, hide in a "push imm32" */
+ emit_byte (acfg, '\x68'); /* push */
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", got_offset);
+ emit_alignment (acfg, kNaClAlignment);
+#endif /*__native_client_codegen__*/
#elif defined(TARGET_ARM)
guint8 buf [128];
guint8 *code;
* CALL_TARGET is the symbol pointing to the native code of METHOD.
*/
static void
-arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, const char *call_target)
+arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *method, const char *call_target)
{
#if defined(TARGET_AMD64)
guint8 buf [32];
guint8 buf [128];
guint8 *code;
+ if (acfg->thumb_mixed && cfg->compile_llvm) {
+ fprintf (acfg->fp, "add r0, r0, #%d\n", sizeof (MonoObject));
+ fprintf (acfg->fp, "b %s\n", call_target);
+ fprintf (acfg->fp, ".arm\n");
+ return;
+ }
+
code = buf;
ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (MonoObject));
img_writer_emit_reloc (acfg->w, R_ARM_JUMP24, call_target, -8);
emit_bytes (acfg, buf, 4);
} else {
- fprintf (acfg->fp, "\n\tb %s\n", call_target);
+ if (acfg->thumb_mixed && cfg->compile_llvm)
+ fprintf (acfg->fp, "\n\tbx %s\n", call_target);
+ else
+ fprintf (acfg->fp, "\n\tb %s\n", call_target);
}
#elif defined(TARGET_POWERPC)
int this_pos = 3;
arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
{
#if defined(TARGET_AMD64)
+#if defined(__default_codegen__)
/* This should be exactly 13 bytes long */
*tramp_size = 13;
emit_byte (acfg, '\xff');
emit_byte (acfg, '\x25');
emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4);
+#elif defined(__native_client_codegen__)
+ guint8 buf [128];
+ guint8 *buf_aligned = ALIGN_TO(buf, kNaClAlignment);
+ guint8 *code = buf_aligned;
+
+ /* mov <OFFSET>(%rip), %r10d */
+ emit_byte (acfg, '\x45');
+ emit_byte (acfg, '\x8b');
+ emit_byte (acfg, '\x15');
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
+
+ /* mov <OFFSET>(%rip), %r11d */
+ emit_byte (acfg, '\x45');
+ emit_byte (acfg, '\x8b');
+ emit_byte (acfg, '\x1d');
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4);
+
+ /* nacljmp *%r11 */
+ amd64_jump_reg (code, AMD64_R11);
+ emit_bytes (acfg, buf_aligned, code - buf_aligned);
+
+ emit_alignment (acfg, kNaClAlignment);
+ *tramp_size = kNaClAlignment;
+#endif /*__native_client_codegen__*/
+
#elif defined(TARGET_ARM)
guint8 buf [128];
guint8 *code;
{
#if defined(TARGET_AMD64)
guint8 *buf, *code;
+#if defined(__native_client_codegen__)
+ guint8 *buf_alloc;
+#endif
guint8 *labels [3];
+ guint8 mov_buf[3];
+ guint8 *mov_buf_ptr = mov_buf;
+ const int kSizeOfMove = 7;
+#if defined(__default_codegen__)
code = buf = g_malloc (256);
+#elif defined(__native_client_codegen__)
+ buf_alloc = g_malloc (256 + kNaClAlignment + kSizeOfMove);
+ buf = ((guint)buf_alloc + kNaClAlignment) & ~kNaClAlignmentMask;
+ /* The RIP relative move below is emitted first */
+ buf += kSizeOfMove;
+ code = buf;
+#endif
/* FIXME: Optimize this, i.e. use binary search etc. */
/* Maybe move the body into a separate function (slower, but much smaller) */
- /* R11 is a free register */
+ /* MONO_ARCH_IMT_SCRATCH_REG is a free register */
labels [0] = code;
- amd64_alu_membase_imm (code, X86_CMP, AMD64_R11, 0, 0);
+ amd64_alu_membase_imm (code, X86_CMP, MONO_ARCH_IMT_SCRATCH_REG, 0, 0);
labels [1] = code;
- amd64_branch8 (code, X86_CC_Z, FALSE, 0);
+ amd64_branch8 (code, X86_CC_Z, 0, FALSE);
/* Check key */
- amd64_alu_membase_reg (code, X86_CMP, AMD64_R11, 0, MONO_ARCH_IMT_REG);
+ amd64_alu_membase_reg_size (code, X86_CMP, MONO_ARCH_IMT_SCRATCH_REG, 0, MONO_ARCH_IMT_REG, sizeof (gpointer));
labels [2] = code;
- amd64_branch8 (code, X86_CC_Z, FALSE, 0);
+ amd64_branch8 (code, X86_CC_Z, 0, FALSE);
/* Loop footer */
- amd64_alu_reg_imm (code, X86_ADD, AMD64_R11, 2 * sizeof (gpointer));
+ amd64_alu_reg_imm (code, X86_ADD, MONO_ARCH_IMT_SCRATCH_REG, 2 * sizeof (gpointer));
amd64_jump_code (code, labels [0]);
/* Match */
mono_amd64_patch (labels [2], code);
- amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, sizeof (gpointer), 8);
- amd64_jump_membase (code, AMD64_R11, 0);
+ amd64_mov_reg_membase (code, MONO_ARCH_IMT_SCRATCH_REG, MONO_ARCH_IMT_SCRATCH_REG, sizeof (gpointer), sizeof (gpointer));
+ amd64_jump_membase (code, MONO_ARCH_IMT_SCRATCH_REG, 0);
/* No match */
/* FIXME: */
mono_amd64_patch (labels [1], code);
x86_breakpoint (code);
- 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, '\x1d');
+ /* mov <OFFSET>(%rip), MONO_ARCH_IMT_SCRATCH_REG */
+ amd64_emit_rex (mov_buf_ptr, sizeof(gpointer), MONO_ARCH_IMT_SCRATCH_REG, 0, AMD64_RIP);
+ *(mov_buf_ptr)++ = (unsigned char)0x8b; /* mov opcode */
+ x86_address_byte (mov_buf_ptr, 0, MONO_ARCH_IMT_SCRATCH_REG & 0x7, 5);
+ emit_bytes (acfg, mov_buf, mov_buf_ptr - mov_buf);
emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
emit_bytes (acfg, buf, code - buf);
- *tramp_size = code - buf + 7;
+ *tramp_size = code - buf + kSizeOfMove;
+#if defined(__native_client_codegen__)
+ /* The tramp will be padded to the next kNaClAlignment bundle. */
+ *tramp_size = ALIGN_TO ((*tramp_size), kNaClAlignment);
+#endif
+
+#if defined(__default_codegen__)
+ g_free (buf);
+#elif defined(__native_client_codegen__)
+ g_free (buf_alloc);
+#endif
+
#elif defined(TARGET_X86)
guint8 *buf, *code;
#ifdef __native_client_codegen__
#endif
guint8 *labels [3];
-#ifdef __native_client_codegen__
+#if defined(__default_codegen__)
+ code = buf = g_malloc (256);
+#elif defined(__native_client_codegen__)
buf_alloc = g_malloc (256 + kNaClAlignment);
code = buf = ((guint)buf_alloc + kNaClAlignment) & ~kNaClAlignmentMask;
-#else
- code = buf = g_malloc (256);
#endif
/* Allocate a temporary stack slot */
emit_bytes (acfg, buf, code - buf);
*tramp_size = code - buf;
+
+#if defined(__default_codegen__)
+ g_free (buf);
+#elif defined(__native_client_codegen__)
+ g_free (buf_alloc);
+#endif
+
#elif defined(TARGET_ARM)
guint8 buf [128];
guint8 *code, *code2, *labels [16];
return add_stream_data (&acfg->blob, (char*)data, data_len);
}
+static guint32
+add_to_blob_aligned (MonoAotCompile *acfg, const guint8 *data, guint32 data_len, guint32 align)
+{
+ char buf [4] = {0};
+ guint32 count;
+
+ if (acfg->blob.alloc_size == 0)
+ stream_init (&acfg->blob);
+
+ count = acfg->blob.index % align;
+
+ /* we assume the stream data will be aligned */
+ if (count)
+ add_stream_data (&acfg->blob, buf, 4 - count);
+
+ return add_stream_data (&acfg->blob, (char*)data, data_len);
+}
+
/*
* emit_offset_table:
*
break;
}
case MONO_WRAPPER_UNKNOWN:
- if (strcmp (method->name, "FastMonitorEnter") == 0)
+ if (strcmp (method->name, "FastMonitorEnter") == 0) {
encode_value (MONO_AOT_WRAPPER_MONO_ENTER, p, &p);
- else if (strcmp (method->name, "FastMonitorExit") == 0)
+ } else if (strcmp (method->name, "FastMonitorExit") == 0) {
encode_value (MONO_AOT_WRAPPER_MONO_EXIT, p, &p);
- else
+ } else if (strcmp (method->name, "PtrToStructure") == 0) {
+ encode_value (MONO_AOT_WRAPPER_PTR_TO_STRUCTURE, p, &p);
+ encode_klass_ref (acfg, method->klass, p, &p);
+ } else if (strcmp (method->name, "StructureToPtr") == 0) {
+ encode_value (MONO_AOT_WRAPPER_STRUCTURE_TO_PTR, p, &p);
+ encode_klass_ref (acfg, method->klass, p, &p);
+ } else {
g_assert_not_reached ();
+ }
break;
case MONO_WRAPPER_SYNCHRONIZED:
case MONO_WRAPPER_MANAGED_TO_NATIVE:
g_assert_not_reached ();
}
break;
+ case MONO_WRAPPER_CASTCLASS:
+ if (!strcmp (method->name, "__castclass_with_cache")) {
+ encode_value (MONO_AOT_WRAPPER_CASTCLASS_WITH_CACHE, p, &p);
+ } else if (!strcmp (method->name, "__isinst_with_cache")) {
+ encode_value (MONO_AOT_WRAPPER_ISINST_WITH_CACHE, p, &p);
+ } else {
+ g_assert_not_reached ();
+ }
+ break;
default:
g_assert_not_reached ();
}
static char*
get_plt_symbol (MonoAotCompile *acfg, int plt_offset, MonoJumpInfo *patch_info)
{
-#ifdef __MACH__
+#ifdef __APPLE__
/*
* The Apple linker reorganizes object files, so it doesn't like branches to local
* labels, since those have no relocations.
res->plt_offset = acfg->plt_offset;
res->ji = new_ji;
res->symbol = get_plt_symbol (acfg, res->plt_offset, patch_info);
+ res->llvm_symbol = g_strdup_printf ("%s_llvm", res->symbol);
g_hash_table_insert (acfg->patch_to_plt_entry, new_ji, res);
index = acfg->method_index;
add_method_with_index (acfg, method, index, extra);
- /* FIXME: Fix quadratic behavior */
- acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (index));
+ g_ptr_array_add (acfg->method_order, GUINT_TO_POINTER (index));
g_hash_table_insert (acfg->method_depth, method, GUINT_TO_POINTER (depth));
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 ();
}
+
+ /* castclass_with_check wrapper */
+ add_method (acfg, mono_marshal_get_castclass_with_cache ());
+ /* isinst_with_check wrapper */
+ add_method (acfg, mono_marshal_get_isinst_with_cache ());
}
/*
token = MONO_TOKEN_TYPE_DEF | (i + 1);
klass = mono_class_get (acfg->image, token);
+ if (!klass) {
+ mono_loader_clear_error ();
+ continue;
+ }
+
if (klass->delegate && klass != mono_defaults.delegate_class && klass != mono_defaults.multicastdelegate_class && !klass->generic_container) {
method = mono_get_delegate_invoke (klass);
token = MONO_TOKEN_TYPE_DEF | (i + 1);
klass = mono_class_get (acfg->image, token);
+ if (!klass) {
+ mono_loader_clear_error ();
+ continue;
+ }
+
if (klass->valuetype && !klass->generic_container && can_marshal_struct (klass)) {
add_method (acfg, mono_marshal_get_struct_to_ptr (klass));
add_method (acfg, mono_marshal_get_ptr_to_struct (klass));
add_generic_class_with_depth (acfg, klass, 0);
}
+static gboolean
+check_type_depth (MonoType *t, int depth)
+{
+ int i;
+
+ if (depth > 8)
+ return TRUE;
+
+ switch (t->type) {
+ case MONO_TYPE_GENERICINST: {
+ MonoGenericClass *gklass = t->data.generic_class;
+ MonoGenericInst *ginst = gklass->context.class_inst;
+
+ if (ginst) {
+ for (i = 0; i < ginst->type_argc; ++i) {
+ if (check_type_depth (ginst->type_argv [i], depth + 1))
+ return TRUE;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
/*
* add_generic_class:
*
if (!klass->generic_class && !klass->rank)
return;
+ if (check_type_depth (&klass->byval_arg, 0))
+ return;
+
iter = NULL;
while ((method = mono_class_get_methods (klass, &iter))) {
if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
* FIXME: Instances which are referenced by these methods are not added,
* for example Array.Resize<int> for List<int>.Add ().
*/
- add_extra_method_with_depth (acfg, method, depth);
+ add_extra_method_with_depth (acfg, method, depth + 1);
}
if (klass->delegate) {
token = MONO_TOKEN_TYPE_SPEC | (i + 1);
klass = mono_class_get (acfg->image, token);
- if (!klass || klass->rank)
+ if (!klass || klass->rank) {
+ mono_loader_clear_error ();
continue;
+ }
add_generic_class (acfg, klass, FALSE);
}
/* Add types of args/locals */
for (i = 0; i < acfg->methods->len; ++i) {
- int j;
+ int j, depth;
method = g_ptr_array_index (acfg->methods, i);
+ depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
+
sig = mono_method_signature (method);
if (sig) {
for (j = 0; j < sig->param_count; ++j)
if (sig->params [j]->type == MONO_TYPE_GENERICINST)
- add_generic_class (acfg, mono_class_from_mono_type (sig->params [j]), FALSE);
+ add_generic_class_with_depth (acfg, mono_class_from_mono_type (sig->params [j]), depth + 1);
}
header = mono_method_get_header (method);
if (header) {
for (j = 0; j < header->num_locals; ++j)
if (header->locals [j]->type == MONO_TYPE_GENERICINST)
- add_generic_class (acfg, mono_class_from_mono_type (header->locals [j]), FALSE);
+ add_generic_class_with_depth (acfg, mono_class_from_mono_type (header->locals [j]), depth + 1);
}
}
add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (get_method, &ctx), TRUE, TRUE));
}
}
+
+ /* Same for CompareExchange<T> */
+ {
+ MonoGenericContext ctx;
+ MonoType *args [16];
+ MonoMethod *cas_method;
+ MonoClass *interlocked_klass = mono_class_from_name (mono_defaults.corlib, "System.Threading", "Interlocked");
+ gpointer iter = NULL;
+
+ while ((cas_method = mono_class_get_methods (interlocked_klass, &iter))) {
+ if (!strcmp (cas_method->name, "CompareExchange") && cas_method->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 (cas_method, &ctx), TRUE, TRUE));
+ }
+ }
+ }
}
}
/* Nullify the patch */
patch_info->type = MONO_PATCH_INFO_NONE;
+ plt_entry->jit_used = TRUE;
}
}
debug_sym = get_debug_sym (method, "", acfg->method_label_hash);
sprintf (symbol, "%sme_%x", acfg->temp_prefix, method_index);
+ if (acfg->need_no_dead_strip)
+ fprintf (acfg->fp, " .no_dead_strip %s\n", debug_sym);
emit_local_symbol (acfg, debug_sym, symbol, TRUE);
emit_label (acfg, debug_sym);
}
break;
case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
+ case MONO_PATCH_INFO_CASTCLASS_CACHE:
break;
case MONO_PATCH_INFO_METHOD_REL:
encode_value ((gint)patch_info->data.offset, p, &p);
MonoMethod *method;
GList *l;
int pindex, buf_size, n_patches;
- guint8 *code;
GPtrArray *patches;
MonoJumpInfo *patch_info;
MonoMethodHeader *header;
guint32 first_got_offset;
method = cfg->orig_method;
- code = cfg->native_code;
header = mono_method_get_header (method);
method_index = get_method_index (acfg, method);
seq_points = cfg->seq_point_info;
- buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (seq_points ? (seq_points->len * 64) : 0);
+ buf_size = header->num_clauses * 256 + debug_info_size + 2048 + (seq_points ? (seq_points->len * 64) : 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);
+ 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);
encode_value (flags, p, &p);
}
}
-
g_assert (debug_info_size < buf_size);
encode_value (debug_info_size, p, &p);
g_free (debug_info);
}
+ /* GC Map */
+ if (cfg->gc_map) {
+ encode_value (cfg->gc_map_size, p, &p);
+ /* The GC map requires 4 bytes of alignment */
+ while ((gsize)p % 4)
+ p ++;
+ memcpy (p, cfg->gc_map, cfg->gc_map_size);
+ p += cfg->gc_map_size;
+ }
+
acfg->stats.ex_info_size += p - buf;
g_assert (p - buf < buf_size);
/* Emit info */
- cfg->ex_info_offset = add_to_blob (acfg, buf, p - buf);
+ /* The GC Map requires 4 byte alignment */
+ cfg->ex_info_offset = add_to_blob_aligned (acfg, buf, p - buf, cfg->gc_map ? 4 : 1);
g_free (buf);
}
gpointer iter = NULL;
if (!klass) {
+ mono_loader_clear_error ();
+
buf_size = 16;
p = buf = g_malloc (buf_size);
return res;
}
+static char*
+get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cache)
+{
+ char *debug_sym = NULL;
+
+ 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;
+ }
+
+ return debug_sym;
+}
+
/*
* Calls made from AOTed code are routed through a table of jumps similar to the
- * ELF PLT (Program Linkage Table). The differences are the following:
- * - the ELF PLT entries make an indirect jump though the GOT so they expect the
- * GOT pointer to be in EBX. We want to avoid this, so our table contains direct
- * jumps. This means the jumps need to be patched when the address of the callee is
- * known. Initially the PLT entries jump to code which transfers control to the
- * AOT runtime through the first PLT entry.
+ * ELF PLT (Program Linkage Table). Initially the PLT entries jump to code which transfers
+ * control to the AOT runtime through a trampoline.
*/
static void
emit_plt (MonoAotCompile *acfg)
sprintf (symbol, "plt");
emit_section_change (acfg, ".text", 0);
- emit_global (acfg, symbol, TRUE);
- emit_alignment (acfg, 16);
+ emit_alignment (acfg, NACL_SIZE(16, kNaClAlignment));
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;
- if (i == 0) {
+ if (i == 0)
/*
- * The first plt entry is used to transfer code to the AOT loader.
+ * The first plt entry is unused.
*/
- 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) {
/*
*/
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);
+
+ if (acfg->thumb_mixed && !callee_cfg->compile_llvm) {
+ /* LLVM calls the PLT entries using bl, so emit a stub */
+ 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");
+ 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);
+ }
continue;
}
}
- emit_label (acfg, label);
+ if (acfg->aot_opts.write_symbols)
+ plt_entry->debug_sym = get_plt_entry_debug_sym (acfg, ji, cache);
+ debug_sym = plt_entry->debug_sym;
- if (acfg->aot_opts.write_symbols) {
- 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;
+ if (acfg->thumb_mixed && !plt_entry->jit_used)
+ /* Emit only a thumb version */
+ continue;
+
+ if (!acfg->thumb_mixed)
+ emit_label (acfg, plt_entry->llvm_symbol);
+
+ if (debug_sym) {
+ if (acfg->need_no_dead_strip)
+ fprintf (acfg->fp, " .no_dead_strip %s\n", debug_sym);
+ emit_local_symbol (acfg, debug_sym, NULL, TRUE);
+ emit_label (acfg, debug_sym);
+ }
+
+ emit_label (acfg, plt_entry->symbol);
+
+ arch_emit_plt_entry (acfg, i);
+
+ if (debug_sym)
+ emit_symbol_size (acfg, debug_sym, ".");
+ }
+
+ if (acfg->thumb_mixed) {
+ /* Make sure the ARM symbols don't alias the thumb ones */
+ emit_zero_bytes (acfg, 16);
+
+ /*
+ * Emit a separate set of PLT entries using thumb2 which is called by LLVM generated
+ * code.
+ */
+ for (i = 0; i < acfg->plt_offset; ++i) {
+ char *debug_sym = NULL;
+ MonoPltEntry *plt_entry = NULL;
+ MonoJumpInfo *ji;
+
+ if (i == 0)
+ continue;
+
+ plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
+ ji = plt_entry->ji;
+
+ if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer)
+ continue;
+
+ /* Skip plt entries not actually called by LLVM code */
+ if (!plt_entry->llvm_used)
+ continue;
+
+ if (acfg->aot_opts.write_symbols) {
+ if (plt_entry->debug_sym)
+ debug_sym = g_strdup_printf ("%s_thumb", plt_entry->debug_sym);
}
if (debug_sym) {
+#if defined(__APPLE__)
+ fprintf (acfg->fp, " .thumb_func %s\n", debug_sym);
+ fprintf (acfg->fp, " .no_dead_strip %s\n", debug_sym);
+#endif
emit_local_symbol (acfg, debug_sym, NULL, TRUE);
emit_label (acfg, debug_sym);
}
- }
+ fprintf (acfg->fp, "\n.thumb_func\n");
- arch_emit_plt_entry (acfg, i);
+ emit_label (acfg, plt_entry->llvm_symbol);
- if (debug_sym) {
- emit_symbol_size (acfg, debug_sym, ".");
- g_free (debug_sym);
+ arch_emit_llvm_plt_entry (acfg, i);
+
+ if (debug_sym) {
+ emit_symbol_size (acfg, debug_sym, ".");
+ g_free (debug_sym);
+ }
}
}
emit_symbol_size (acfg, acfg->plt_symbol, ".");
sprintf (symbol, "plt_end");
- emit_global (acfg, symbol, TRUE);
emit_label (acfg, symbol);
g_hash_table_destroy (cache);
emit_trampolines (MonoAotCompile *acfg)
{
char symbol [256];
+ char end_symbol [256];
int i, tramp_got_offset;
MonoAotTrampoline ntype;
#ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
int tramp_type;
- guint8 *code;
#endif
if (!acfg->aot_opts.full_aot)
emit_trampoline (acfg, acfg->got_offset, info);
/* Emit the exception related code pieces */
- code = mono_arch_get_restore_context (&info, TRUE);
+ mono_arch_get_restore_context (&info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
- code = mono_arch_get_call_filter (&info, TRUE);
+ mono_arch_get_call_filter (&info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
- code = mono_arch_get_throw_exception (&info, TRUE);
+ mono_arch_get_throw_exception (&info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
- code = mono_arch_get_rethrow_exception (&info, TRUE);
+ mono_arch_get_rethrow_exception (&info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
- code = mono_arch_get_throw_corlib_exception (&info, TRUE);
+ mono_arch_get_throw_corlib_exception (&info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
#if defined(MONO_ARCH_HAVE_GET_TRAMPOLINES)
int offset;
offset = MONO_RGCTX_SLOT_MAKE_RGCTX (i);
- code = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
+ 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 (offset, &info, TRUE);
+ mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
}
g_assert_not_reached ();
}
- emit_global (acfg, symbol, TRUE);
+ sprintf (end_symbol, "%s_e", symbol);
+
+ if (acfg->aot_opts.write_symbols)
+ emit_local_symbol (acfg, symbol, end_symbol, TRUE);
+
emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
emit_label (acfg, symbol);
acfg->trampoline_size [ntype] = tramp_size;
}
}
+
+ emit_label (acfg, end_symbol);
}
/* Reserve some entries at the end of the GOT for our use */
opts->save_temps = TRUE;
} else if (str_begins_with (arg, "write-symbols")) {
opts->write_symbols = TRUE;
+ } else if (str_begins_with (arg, "no-write-symbols")) {
+ opts->write_symbols = FALSE;
} else if (str_begins_with (arg, "metadata-only")) {
opts->metadata_only = TRUE;
} else if (str_begins_with (arg, "bind-to-runtime-version")) {
opts->stats = TRUE;
} else if (str_begins_with (arg, "mtriple=")) {
opts->mtriple = g_strdup (arg + strlen ("mtriple="));
+ } else if (str_begins_with (arg, "llvm-path=")) {
+ opts->llvm_path = g_strdup (arg + strlen ("llvm-path="));
+ } else if (str_begins_with (arg, "info")) {
+ printf ("AOT target setup: %s.\n", AOT_TARGET_STR);
+ exit (0);
+ } else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) {
+ printf ("Supported options for --aot:\n");
+ printf (" outfile=\n");
+ printf (" save-temps\n");
+ printf (" keep-temps\n");
+ printf (" write-symbols\n");
+ printf (" metadata-only\n");
+ printf (" bind-to-runtime-version\n");
+ printf (" full\n");
+ printf (" threads=\n");
+ printf (" static\n");
+ printf (" asmonly\n");
+ printf (" asmwriter\n");
+ printf (" nodebug\n");
+ printf (" ntrampolines=\n");
+ printf (" nrgctx-trampolines=\n");
+ printf (" nimt-trampolines=\n");
+ printf (" autoreg\n");
+ printf (" tool-prefix=\n");
+ printf (" soft-debug\n");
+ printf (" print-skipped\n");
+ printf (" stats\n");
+ printf (" info\n");
+ printf (" help/?\n");
+ exit (0);
} else {
fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
exit (1);
return TRUE;
else
return FALSE;
+ case MONO_WRAPPER_CASTCLASS:
+ if (!strcmp (method->name, "__castclass_with_cache"))
+ return TRUE;
+ else if (!strcmp (method->name, "__isinst_with_cache"))
+ return TRUE;
+ else
+ return FALSE;
default:
//printf ("Skip (wrapper call): %d -> %s\n", patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
return FALSE;
return;
}
if (cfg->exception_type != MONO_EXCEPTION_NONE) {
+ //printf ("E: %s\n", mono_method_full_name (method, TRUE));
/* Let the exception happen at runtime */
return;
}
int file_index, res, method_index, i;
char ver [256];
guint32 token;
- GList *unordered;
+ GList *unordered, *l;
+ gboolean found;
file_index = 0;
while (TRUE) {
token = mono_method_get_token (method);
method_index = mono_metadata_token_index (token) - 1;
- if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index))) {
- acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+ found = FALSE;
+ for (i = 0; i < acfg->method_order->len; ++i) {
+ if (g_ptr_array_index (acfg->method_order, i) == GUINT_TO_POINTER (method_index)) {
+ found = TRUE;
+ break;
+ }
}
+ if (!found)
+ g_ptr_array_add (acfg->method_order, GUINT_TO_POINTER (method_index));
} else {
//printf ("No method found matching '%s'.\n", name);
}
/* Add missing methods */
unordered = NULL;
- for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
- if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (i)))
- unordered = g_list_prepend (unordered, GUINT_TO_POINTER (i));
+ for (method_index = 0; method_index < acfg->image->tables [MONO_TABLE_METHOD].rows; ++method_index) {
+ found = FALSE;
+ for (i = 0; i < acfg->method_order->len; ++i) {
+ if (g_ptr_array_index (acfg->method_order, i) == GUINT_TO_POINTER (method_index)) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found)
+ unordered = g_list_prepend (unordered, GUINT_TO_POINTER (method_index));
}
unordered = g_list_reverse (unordered);
- if (acfg->method_order)
- g_list_last (acfg->method_order)->next = unordered;
- else
- acfg->method_order = unordered;
+ for (l = unordered; l; l = l->next)
+ g_ptr_array_add (acfg->method_order, l->data);
}
/* Used by the LLVM backend */
char*
mono_aot_get_method_name (MonoCompile *cfg)
{
- return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
+ if (llvm_acfg->aot_opts.static_link)
+ /* Include the assembly name too to avoid duplicate symbol errors */
+ return g_strdup_printf ("%s_%s", llvm_acfg->image->assembly->aname.name, get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash));
+ else
+ return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
}
char*
return NULL;
plt_entry = get_plt_entry (llvm_acfg, ji);
+ plt_entry->llvm_used = TRUE;
- return g_strdup_printf (plt_entry->symbol);
+#if defined(__APPLE__)
+ return g_strdup_printf (plt_entry->llvm_symbol + strlen (llvm_acfg->llvm_label_prefix));
+#else
+ return g_strdup_printf (plt_entry->llvm_symbol);
+#endif
}
MonoJumpInfo*
* 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 -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");
+ 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 -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");
#if 1
- command = g_strdup_printf ("opt -f %s -o temp.opt.bc temp.bc", opts);
+ command = g_strdup_printf ("%sopt -f %s -o temp.opt.bc temp.bc", acfg->aot_opts.llvm_path, opts);
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 (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");
unlink (acfg->tmpfname);
- command = g_strdup_printf ("llc %s -relocation-model=pic -unwind-tables -disable-gnu-eh-frame -enable-mono-eh-frame -o %s temp.opt.bc", acfg->llc_args->str, acfg->tmpfname);
+ command = g_strdup_printf ("%sllc %s -unwind-tables -disable-gnu-eh-frame -enable-mono-eh-frame -o %s temp.opt.bc", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname);
printf ("Executing llc: %s\n", command);
static void
emit_code (MonoAotCompile *acfg)
{
- int i;
+ int oindex, i;
char symbol [256];
char end_symbol [256];
- GList *l;
#if defined(TARGET_POWERPC64)
sprintf (symbol, ".Lgot_addr");
*/
sprintf (symbol, "methods");
emit_section_change (acfg, ".text", 0);
- emit_global (acfg, symbol, TRUE);
emit_alignment (acfg, 8);
if (acfg->llvm) {
for (i = 0; i < acfg->nmethods; ++i) {
* Emit some padding so the local symbol for the first method doesn't have the
* same address as 'methods'.
*/
+#if defined(__default_codegen__)
emit_zero_bytes (acfg, 16);
+#elif defined(__native_client_codegen__)
+ {
+ const int kPaddingSize = 16;
+ guint8 pad_buffer[kPaddingSize];
+ mono_arch_nacl_pad (pad_buffer, kPaddingSize);
+ emit_bytes (acfg, pad_buffer, kPaddingSize);
+ }
+#endif
- for (l = acfg->method_order; l != NULL; l = l->next) {
+ for (oindex = 0; oindex < acfg->method_order->len; ++oindex) {
MonoCompile *cfg;
MonoMethod *method;
- i = GPOINTER_TO_UINT (l->data);
+ i = GPOINTER_TO_UINT (g_ptr_array_index (acfg->method_order, oindex));
cfg = acfg->cfgs [i];
/* Emit unbox trampoline */
if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
- char call_target [256];
-
if (!method->wrapper_type && !method->is_inflated) {
g_assert (method->token);
sprintf (symbol, "ut_%d", mono_metadata_token_index (method->token) - 1);
emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
#endif
emit_global (acfg, symbol, TRUE);
- emit_label (acfg, symbol);
- sprintf (call_target, "%s", cfg->asm_symbol);
+ if (acfg->thumb_mixed && cfg->compile_llvm)
+ fprintf (acfg->fp, "\n.thumb_func\n");
+
+ emit_label (acfg, symbol);
- arch_emit_unbox_trampoline (acfg, cfg->orig_method, call_target);
+ arch_emit_unbox_trampoline (acfg, cfg, cfg->orig_method, cfg->asm_symbol);
}
if (cfg->compile_llvm)
sprintf (symbol, "methods_end");
emit_section_change (acfg, ".text", 0);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
+ /*
+ * Add .no_dead_strip directives for all LLVM methods to prevent the OSX linker
+ * from optimizing them away, since it doesn't see that code_offsets references them.
+ * JITted methods don't need this since they are referenced using assembler local
+ * symbols.
+ * FIXME: This is why write-symbols doesn't work on OSX ?
+ */
+ if (acfg->llvm && acfg->need_no_dead_strip) {
+ fprintf (acfg->fp, "\n");
+ for (i = 0; i < acfg->nmethods; ++i) {
+ if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm)
+ fprintf (acfg->fp, ".no_dead_strip %s\n", acfg->cfgs [i]->asm_symbol);
+ }
+ }
+
sprintf (symbol, "code_offsets");
emit_section_change (acfg, RODATA_SECT, 1);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
static void
emit_info (MonoAotCompile *acfg)
{
- int i;
+ int oindex, i;
char symbol [256];
- GList *l;
gint32 *offsets;
offsets = g_new0 (gint32, acfg->nmethods);
- for (l = acfg->method_order; l != NULL; l = l->next) {
- i = GPOINTER_TO_UINT (l->data);
+ for (oindex = 0; oindex < acfg->method_order->len; ++oindex) {
+ i = GPOINTER_TO_UINT (g_ptr_array_index (acfg->method_order, oindex));
if (acfg->cfgs [i]) {
emit_method_info (acfg, acfg->cfgs [i]);
sprintf (symbol, "method_info_offsets");
emit_section_change (acfg, RODATA_SECT, 1);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
case MONO_TYPE_GENERICINST:
return ((hash << 5) - hash) ^ 0;
+ default:
+ return hash;
}
- return hash;
}
/*
name = NULL;
if (method->wrapper_type) {
+ gboolean encode_ref = FALSE;
+
/*
* We encode some wrappers using their name, since encoding them
- * directly would be difficult. This also avoids creating the wrapper
- * methods at runtime, since they are not needed anyway.
+ * directly would be difficult. This works because at runtime, we only need to
+ * check whenever a method ref matches an existing MonoMethod. The downside is
+ * that the method names are large, so we use the binary encoding if possible.
*/
switch (method->wrapper_type) {
case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
case MONO_WRAPPER_SYNCHRONIZED:
- /* encode_method_ref () can handle these */
+ encode_ref = TRUE;
break;
+ case MONO_WRAPPER_MANAGED_TO_NATIVE:
+ /* Skip JIT icall wrappers */
+ if (!strstr (method->name, "__icall_wrapper"))
+ encode_ref = TRUE;
+ break;
+ case MONO_WRAPPER_UNKNOWN:
+ if (!strcmp (method->name, "PtrToStructure") || !strcmp (method->name, "StructureToPtr"))
+ encode_ref = TRUE;
+ break;
case MONO_WRAPPER_RUNTIME_INVOKE:
if (mono_marshal_method_from_wrapper (method) != method && !strstr (method->name, "virtual"))
/* Direct wrapper, encode normally */
- break;
- /* Fall through */
+ encode_ref = TRUE;
+ break;
default:
- name = mono_aot_wrapper_name (method);
break;
}
+
+ if (!encode_ref)
+ name = mono_aot_wrapper_name (method);
}
if (name) {
/* Emit the table */
sprintf (symbol, "extra_method_table");
emit_section_change (acfg, RODATA_SECT, 0);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
*/
sprintf (symbol, "extra_method_info_offsets");
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, RODATA_SECT, 1);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
emit_section_change (acfg, RODATA_SECT, 1);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
- emit_global (acfg, symbol, FALSE);
for (i = 0; i < acfg->unwind_ops->len; ++i) {
guint32 index = GPOINTER_TO_UINT (g_ptr_array_index (acfg->unwind_ops, i));
acfg->stats.unwind_info_size += (p - buf) + unwind_info_len;
}
-
- /*
- * Emit a reference to the mono_eh_frame table created by our modified LLVM compiler.
- */
- if (acfg->llvm) {
- sprintf (symbol, "mono_eh_frame_addr");
- emit_section_change (acfg, ".data", 0);
- emit_global (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
- emit_pointer (acfg, "mono_eh_frame");
- }
}
static void
sprintf (symbol, "class_info_offsets");
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)
+ if (!klass) {
+ mono_loader_clear_error ();
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, RODATA_SECT, 0);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
* So we emit it at once, and reference its elements by an index.
*/
- sprintf (symbol, "mono_image_table");
+ sprintf (symbol, "image_table");
emit_section_change (acfg, RODATA_SECT, 1);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
/* Emit got_info_offsets table */
sprintf (symbol, "got_info_offsets");
emit_section_change (acfg, RODATA_SECT, 1);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
sprintf (symbol, "got_end");
emit_label (acfg, symbol);
}
-
- sprintf (symbol, "mono_aot_got_addr");
- emit_section_change (acfg, ".data", 0);
- emit_global (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
- emit_pointer (acfg, acfg->got_symbol);
}
typedef struct GlobalsTableEntry {
} GlobalsTableEntry;
static void
-emit_globals_table (MonoAotCompile *acfg)
+emit_globals (MonoAotCompile *acfg)
{
int i, table_size;
guint32 hash;
char symbol [256];
GlobalsTableEntry *entry, *new_entry;
+ if (!acfg->aot_opts.static_link)
+ return;
+
+ /*
+ * When static linking, we emit a table containing our globals.
+ */
+
/*
* Construct a chained hash table for mapping global names to their index in
* the globals table.
sprintf (symbol, "name_%d", i);
emit_section_change (acfg, RODATA_SECT, 1);
+#ifdef __APPLE__
+ emit_alignment (acfg, 4);
+#endif
emit_label (acfg, symbol);
emit_string (acfg, name);
}
/* Emit the globals table */
- sprintf (symbol, ".Lglobals");
+ sprintf (symbol, "globals");
emit_section_change (acfg, ".data", 0);
/* This is not a global, since it is accessed by the init function */
emit_alignment (acfg, 8);
emit_int32 (acfg, 0);
}
-static void
-emit_globals (MonoAotCompile *acfg)
-{
- char *build_info;
-
- emit_string_symbol (acfg, "mono_assembly_guid" , acfg->image->guid);
-
- emit_string_symbol (acfg, "mono_aot_version", MONO_AOT_FILE_VERSION);
-
- if (acfg->aot_opts.bind_to_runtime_version) {
- build_info = mono_get_runtime_build_info ();
- emit_string_symbol (acfg, "mono_runtime_version", build_info);
- g_free (build_info);
- } else {
- emit_string_symbol (acfg, "mono_runtime_version", "");
- }
-
- /*
- * When static linking, we emit a global which will point to the symbol table.
- */
- if (acfg->aot_opts.static_link) {
- char symbol [256];
- char *p;
-
- /* Emit a string holding the assembly name */
- emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name);
-
- emit_globals_table (acfg);
-
- /*
- * Emit a global symbol which can be passed by an embedding app to
- * mono_aot_register_module ().
- */
-#if defined(__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
-
- /* Get rid of characters which cannot occur in symbols */
- p = symbol;
- for (p = symbol; *p; ++p) {
- if (!(isalnum (*p) || *p == '_'))
- *p = '_';
- }
- acfg->static_linking_symbol = g_strdup (symbol);
- emit_global_inner (acfg, symbol, FALSE);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
- sprintf (symbol, "%sglobals", acfg->temp_prefix);
- emit_pointer (acfg, symbol);
- }
-}
-
static void
emit_autoreg (MonoAotCompile *acfg)
{
sprintf (symbol, "mem_end");
emit_section_change (acfg, ".text", 1);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
}
static void
emit_file_info (MonoAotCompile *acfg)
{
- char symbol [128];
+ char symbol [256];
int i;
int gc_name_offset;
const char *gc_name;
+ char *build_info;
+
+ emit_string_symbol (acfg, "assembly_guid" , acfg->image->guid);
+
+ if (acfg->aot_opts.bind_to_runtime_version) {
+ build_info = mono_get_runtime_build_info ();
+ emit_string_symbol (acfg, "runtime_version", build_info);
+ g_free (build_info);
+ } else {
+ emit_string_symbol (acfg, "runtime_version", "");
+ }
+
+ /* Emit a string holding the assembly name */
+ emit_string_symbol (acfg, "assembly_name", acfg->image->assembly->aname.name);
/*
* The managed allocators are GC specific, so can't use an AOT image created by one GC
emit_section_change (acfg, ".data", 0);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
- emit_global (acfg, symbol, FALSE);
+ if (!acfg->aot_opts.static_link)
+ emit_global (acfg, symbol, FALSE);
/* The data emitted here must match MonoAotFileInfo. */
+
+ emit_int32 (acfg, MONO_AOT_FILE_VERSION);
+ emit_int32 (acfg, 0);
+
+ /*
+ * We emit pointers to our data structures instead of emitting global symbols which
+ * point to them, to reduce the number of globals, and because using globals leads to
+ * various problems (i.e. arm/thumb).
+ */
+ emit_pointer (acfg, acfg->got_symbol);
+ emit_pointer (acfg, "methods");
+ if (acfg->llvm) {
+ /*
+ * Emit a reference to the mono_eh_frame table created by our modified LLVM compiler.
+ */
+ emit_pointer (acfg, "mono_eh_frame");
+ } else {
+ emit_pointer (acfg, NULL);
+ }
+ emit_pointer (acfg, "blob");
+ emit_pointer (acfg, "class_name_table");
+ emit_pointer (acfg, "class_info_offsets");
+ emit_pointer (acfg, "method_info_offsets");
+ emit_pointer (acfg, "ex_info_offsets");
+ emit_pointer (acfg, "code_offsets");
+ emit_pointer (acfg, "extra_method_info_offsets");
+ emit_pointer (acfg, "extra_method_table");
+ emit_pointer (acfg, "got_info_offsets");
+ emit_pointer (acfg, "methods_end");
+ emit_pointer (acfg, "unwind_info");
+ emit_pointer (acfg, "mem_end");
+ emit_pointer (acfg, "image_table");
+ emit_pointer (acfg, "plt");
+ emit_pointer (acfg, "plt_end");
+ emit_pointer (acfg, "assembly_guid");
+ emit_pointer (acfg, "runtime_version");
+ if (acfg->num_trampoline_got_entries) {
+ emit_pointer (acfg, "specific_trampolines");
+ emit_pointer (acfg, "static_rgctx_trampolines");
+ emit_pointer (acfg, "imt_thunks");
+ } else {
+ emit_pointer (acfg, NULL);
+ emit_pointer (acfg, NULL);
+ emit_pointer (acfg, NULL);
+ }
+ if (acfg->thumb_mixed) {
+ emit_pointer (acfg, "thumb_end");
+ } else {
+ emit_pointer (acfg, NULL);
+ }
+ if (acfg->aot_opts.static_link) {
+ emit_pointer (acfg, "globals");
+ } else {
+ emit_pointer (acfg, NULL);
+ }
+ emit_pointer (acfg, "assembly_name");
+
emit_int32 (acfg, acfg->plt_got_offset_base);
emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
emit_int32 (acfg, acfg->plt_offset);
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]);
+
+#if defined (TARGET_ARM) && defined (__APPLE__)
+ {
+ MonoType t;
+ int align = 0;
+
+ t.type = MONO_TYPE_R8;
+ mono_type_size (&t, &align);
+
+ emit_int32 (acfg, align);
+
+ t.type = MONO_TYPE_I8;
+ mono_type_size (&t, &align);
+
+ emit_int32 (acfg, align);
+ }
+#else
+ emit_int32 (acfg, __alignof__ (double));
+ emit_int32 (acfg, __alignof__ (gint64));
+#endif
+
+ if (acfg->aot_opts.static_link) {
+ char *p;
+
+ /*
+ * Emit a global symbol which can be passed by an embedding app to
+ * mono_aot_register_module (). The symbol points to a pointer to the the file info
+ * structure.
+ */
+#if defined(__APPLE__) && !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
+
+ /* Get rid of characters which cannot occur in symbols */
+ p = symbol;
+ for (p = symbol; *p; ++p) {
+ if (!(isalnum (*p) || *p == '_'))
+ *p = '_';
+ }
+ acfg->static_linking_symbol = g_strdup (symbol);
+ emit_global_inner (acfg, symbol, FALSE);
+ emit_label (acfg, symbol);
+ emit_pointer (acfg, "mono_aot_file_info");
+ }
}
static void
sprintf (symbol, "blob");
emit_section_change (acfg, RODATA_SECT, 1);
- emit_global (acfg, symbol, FALSE);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
#endif
#ifdef __native_client_codegen__
+#if defined(TARGET_AMD64)
+#define AS_NAME "nacl64-as"
+#else
#define AS_NAME "nacl-as"
+#endif
#else
#define AS_NAME "as"
#endif
#if defined(sparc)
command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
-#elif defined(__ppc__) && defined(__MACH__)
+#elif defined(__ppc__) && defined(__APPLE__)
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);
system (com);
g_free (com);*/
-#if defined(TARGET_ARM) && !defined(__MACH__)
+#if defined(TARGET_ARM) && !defined(__APPLE__)
/*
* gas generates 'mapping symbols' each time code and data is mixed, which
* happens a lot in emit_and_reloc_code (), so we need to get rid of them.
acfg->unwind_info_offsets = g_hash_table_new (NULL, NULL);
acfg->unwind_ops = g_ptr_array_new ();
acfg->method_label_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ acfg->method_order = g_ptr_array_new ();
InitializeCriticalSection (&acfg->mutex);
return acfg;
acfg->aot_opts.ntrampolines = 1024;
acfg->aot_opts.nrgctx_trampolines = 1024;
acfg->aot_opts.nimt_trampolines = 128;
+ acfg->aot_opts.llvm_path = g_strdup ("");
mono_aot_parse_options (aot_options, &acfg->aot_opts);
acfg->llvm = TRUE;
acfg->aot_opts.asm_writer = TRUE;
acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
+
+ if (acfg->aot_opts.soft_debug) {
+ fprintf (stderr, "The 'soft-debug' option is not supported when compiling with LLVM.\n");
+ exit (1);
+ }
}
if (acfg->aot_opts.full_aot)
arch_init (acfg);
- acfg->got_symbol_base = g_strdup_printf ("%smono_aot_%s_got", acfg->llvm_label_prefix, acfg->image->assembly->aname.name);
+ acfg->got_symbol_base = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
acfg->plt_symbol = g_strdup_printf ("%smono_aot_%s_plt", acfg->llvm_label_prefix, acfg->image->assembly->aname.name);
/* Get rid of characters which cannot occur in symbols */
if (acfg->dwarf)
mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_unwind_get_cie_program ());
+ if (acfg->thumb_mixed) {
+ char symbol [256];
+ /*
+ * This global symbol marks the end of THUMB code, and the beginning of ARM
+ * code generated by our JIT.
+ */
+ sprintf (symbol, "thumb_end");
+ emit_section_change (acfg, ".text", 0);
+ emit_label (acfg, symbol);
+ emit_zero_bytes (acfg, 16);
+
+ fprintf (acfg->fp, ".arm\n");
+ }
+
emit_code (acfg);
emit_info (acfg);
emit_mem_end (acfg);
+ if (acfg->need_pt_gnu_stack) {
+ /* This is required so the .so doesn't have an executable stack */
+ /* The bin writer already emits this */
+ if (!acfg->use_bin_writer)
+ fprintf (acfg->fp, "\n.section .note.GNU-stack,\"\",@progbits\n");
+ }
+
TV_GETTIME (btv);
acfg->stats.gen_time = TV_ELAPSED (atv, btv);