#include "mini.h"
#include "image-writer.h"
#include "dwarfwriter.h"
+#include "mini-gc.h"
#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
#ifdef TARGET_WIN32
#define SHARED_EXT ".dll"
-#elif defined(__ppc__) && defined(__APPLE__)
+#elif defined(__ppc__) && defined(TARGET_MACH)
#define SHARED_EXT ".dylib"
-#elif defined(__APPLE__) && defined(TARGET_X86) && !defined(__native_client_codegen__)
+#elif defined(TARGET_MACH) && defined(TARGET_X86) && !defined(__native_client_codegen__)
#define SHARED_EXT ".dylib"
#else
#define SHARED_EXT ".so"
gboolean log_generics;
gboolean direct_pinvoke;
gboolean direct_icalls;
+ gboolean no_direct_calls;
+ gboolean use_trampolines_page;
+ gboolean no_instances;
int nthreads;
int ntrampolines;
int nrgctx_trampolines;
int nimt_trampolines;
+ int ngsharedvt_arg_trampolines;
gboolean print_skipped_methods;
gboolean stats;
char *tool_prefix;
GHashTable *plt_entry_debug_sym_cache;
gboolean thumb_mixed, need_no_dead_strip, need_pt_gnu_stack;
GHashTable *ginst_hash;
+ gboolean global_symbols;
+ gboolean direct_method_addresses;
} MonoAotCompile;
typedef struct {
emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
{
img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
-#ifdef __APPLE__
+#ifdef TARGET_MACH
/* On apple, all symbols need to be aligned to avoid warnings from ld */
emit_alignment (acfg, 4);
#endif
#endif
#ifdef TARGET_ARM
-#ifdef __MACH__
+#ifdef TARGET_MACH
#define AOT_TARGET_STR "ARM (MACH)"
#else
#define AOT_TARGET_STR "ARM (!MACH)"
g_string_append (acfg->llc_args, "-mattr=+v6");
} else {
#ifdef ARM_FPU_VFP
- g_string_append (acfg->llc_args, " -mattr=+vfp2,+d16");
+ g_string_append (acfg->llc_args, " -mattr=+vfp2,-neon,+d16");
g_string_append (acfg->as_args, " -mfpu=vfp3");
#else
g_string_append (acfg->llc_args, " -soft-float");
mono_arch_set_target (acfg->aot_opts.mtriple);
#endif
-#ifdef __APPLE__
+#ifdef TARGET_MACH
acfg->llvm_label_prefix = "_";
acfg->need_no_dead_strip = TRUE;
#endif
#if defined(__linux__) && !defined(TARGET_ARM)
acfg->need_pt_gnu_stack = TRUE;
#endif
+
+#ifdef MONOTOUCH
+ acfg->direct_method_addresses = TRUE;
+ acfg->global_symbols = TRUE;
+#endif
}
/*
#endif
}
+/*
+ * arch_emit_specific_trampoline_pages:
+ *
+ * Emits a page full of trampolines: each trampoline uses its own address to
+ * lookup both the generic trampoline code and the data argument.
+ * This page can be remapped in process multiple times so we can get an
+ * unlimited number of trampolines.
+ * Specifically this implementation uses the following trick: two memory pages
+ * are allocated, with the first containing the data and the second containing the trampolines.
+ * To reduce trampoline size, each trampoline jumps at the start of the page where a common
+ * implementation does all the lifting.
+ * Note that the ARM single trampoline size is 8 bytes, exactly like the data that needs to be stored
+ * on the arm 32 bit system.
+ */
+static void
+arch_emit_specific_trampoline_pages (MonoAotCompile *acfg)
+{
+#if defined(TARGET_ARM)
+ guint8 buf [128];
+ guint8 *code;
+ guint8 *loop_start, *loop_branch_back, *loop_end_check, *imt_found_check;
+ int i;
+#define COMMON_TRAMP_SIZE 16
+ int count = (mono_pagesize () - COMMON_TRAMP_SIZE) / 8;
+ int imm8, rot_amount;
+
+ if (!acfg->aot_opts.use_trampolines_page)
+ return;
+
+ emit_alignment (acfg, mono_pagesize ());
+ emit_global (acfg, "specific_trampolines_page", TRUE);
+ emit_label (acfg, "specific_trampolines_page");
+
+ /* emit the generic code first, the trampoline address + 8 is in the lr register */
+ code = buf;
+ imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
+ ARM_SUB_REG_IMM (code, ARMREG_LR, ARMREG_LR, imm8, rot_amount);
+ ARM_LDR_IMM (code, ARMREG_R1, ARMREG_LR, -8);
+ ARM_LDR_IMM (code, ARMREG_PC, ARMREG_LR, -4);
+ ARM_NOP (code);
+ g_assert (code - buf == COMMON_TRAMP_SIZE);
+
+ /* Emit it */
+ emit_bytes (acfg, buf, code - buf);
+
+ for (i = 0; i < count; ++i) {
+ code = buf;
+ ARM_PUSH (code, 0x5fff);
+ ARM_BL (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 rgctx 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.
+ */
+ emit_global (acfg, "rgctx_trampolines_page", TRUE);
+ emit_label (acfg, "rgctx_trampolines_page");
+ code = buf;
+ 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, MONO_ARCH_RGCTX_REG, ARMREG_IP, -8);
+ ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, -4);
+ ARM_NOP (code);
+ 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");
+ 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));
+
+ 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);
+
+ /* The IMT method is in v5, r0 has the imt array address */
+
+ loop_start = code;
+ ARM_LDR_IMM (code, ARMREG_R1, ARMREG_R0, 0);
+ ARM_CMP_REG_REG (code, ARMREG_R1, ARMREG_V5);
+ imt_found_check = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+
+ /* End-of-loop check */
+ ARM_CMP_REG_IMM (code, ARMREG_R1, 0, 0);
+ loop_end_check = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+
+ /* Loop footer */
+ ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (gpointer) * 2);
+ loop_branch_back = code;
+ ARM_B (code, 0);
+ arm_patch (loop_branch_back, loop_start);
+
+ /* Match */
+ arm_patch (imt_found_check, code);
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 0);
+ /* Save it to the third stack slot */
+ ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
+ /* Restore the registers and branch */
+ ARM_POP (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_PC));
+
+ /* No match */
+ arm_patch (loop_end_check, code);
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
+ ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
+ ARM_POP (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_PC));
+ ARM_NOP (code);
+
+ /* Emit it */
+ g_assert (code - buf == IMT_TRAMP_SIZE);
+ 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 - IMT_TRAMP_SIZE - 8 * (i + 1));
+ g_assert (code - buf == 8);
+ emit_bytes (acfg, buf, code - buf);
+ }
+#endif
+}
+
/*
* arch_emit_specific_trampoline:
*
guint8 *code;
if (acfg->thumb_mixed && cfg->compile_llvm) {
- fprintf (acfg->fp, "add r0, r0, #%d\n", sizeof (MonoObject));
+ fprintf (acfg->fp, "add r0, r0, #%d\n", (int)sizeof (MonoObject));
fprintf (acfg->fp, "b %s\n", call_target);
fprintf (acfg->fp, ".arm\n");
return;
#endif
}
+/*
+ * arch_emit_gsharedvt_arg_trampoline:
+ *
+ * Emit code for a gsharedvt arg trampoline. OFFSET is the offset of the first of
+ * two GOT slots which contain the argument, and the code to jump to.
+ * TRAMP_SIZE is set to the size of the emitted trampoline.
+ * These kinds of trampolines cannot be enumerated statically, since there could
+ * be one trampoline per method instantiation, so we emit the same code for all
+ * trampolines, and parameterize them using two GOT slots.
+ */
+static void
+arch_emit_gsharedvt_arg_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+#if defined(TARGET_X86)
+ guint8 buf [128];
+ guint8 *code;
+
+ /* Similar to the PPC code above */
+
+ g_assert (MONO_ARCH_RGCTX_REG != X86_ECX);
+
+ code = buf;
+ /* Load mscorlib got address */
+ x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
+ /* Load arg */
+ x86_mov_reg_membase (code, X86_EAX, X86_ECX, offset * sizeof (gpointer), 4);
+ /* Branch to the target address */
+ x86_jump_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
+
+#ifdef __native_client_codegen__
+ {
+ /* emit nops to next 32 byte alignment */
+ int a = (~kNaClAlignmentMask) & ((code - buf) + kNaClAlignment - 1);
+ while (code < (buf + a)) x86_nop(code);
+ }
+#endif
+
+ emit_bytes (acfg, buf, code - buf);
+
+ *tramp_size = NACL_SIZE (15, kNaClAlignment);
+ g_assert (code - buf == *tramp_size);
+#elif defined(TARGET_ARM)
+ guint8 buf [128];
+ guint8 *code;
+
+ /* The same as mono_arch_get_gsharedvt_arg_trampoline (), but for AOT */
+ /* 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_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);
+ /* Load the addr from the GOT */
+ ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_PC, ARMREG_R1);
+ /* Branch to it */
+ ARM_BX (code, ARMREG_R1);
+
+ g_assert (code - buf == 20);
+
+ /* Emit it */
+ emit_bytes (acfg, buf, code - buf);
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) + 4);
+#else
+ g_assert_not_reached ();
+#endif
+}
+
static void
arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
{
}
} else if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR)) {
MonoGenericContainer *container = mono_type_get_generic_param_owner (&klass->byval_arg);
- g_assert (container);
+ MonoGenericParam *par = klass->byval_arg.data.generic_param;
encode_value (MONO_AOT_TYPEREF_VAR, p, &p);
encode_value (klass->byval_arg.type, p, &p);
encode_value (mono_type_get_generic_param_num (&klass->byval_arg), p, &p);
-
- encode_value (container->is_method, p, &p);
- if (container->is_method)
- encode_method_ref (acfg, container->owner.method, p, &p);
- else
- encode_klass_ref (acfg, container->owner.klass, p, &p);
+
+ encode_value (container ? 1 : 0, p, &p);
+ if (container) {
+ encode_value (container->is_method, p, &p);
+ g_assert (par->serial == 0);
+ if (container->is_method)
+ encode_method_ref (acfg, container->owner.method, p, &p);
+ else
+ encode_klass_ref (acfg, container->owner.klass, p, &p);
+ } else {
+ encode_value (par->serial, p, &p);
+ }
} else if (klass->byval_arg.type == MONO_TYPE_PTR) {
encode_value (MONO_AOT_TYPEREF_PTR, p, &p);
encode_type (acfg, &klass->byval_arg, p, &p);
encode_value (array->lobounds [i], p, &p);
break;
}
+ case MONO_TYPE_VAR:
+ case MONO_TYPE_MVAR:
+ encode_klass_ref (acfg, mono_class_from_mono_type (t), p, &p);
+ break;
default:
g_assert_not_reached ();
}
* types of method encodings.
*/
- g_assert (image_index < MONO_AOT_METHODREF_MIN);
-
/* Mark methods which can't use aot trampolines because they need the further
* processing in mono_magic_trampoline () which requires a MonoMethod*.
*/
}
break;
}
- case MONO_WRAPPER_DELEGATE_INVOKE:
+ case MONO_WRAPPER_DELEGATE_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);
+
+ encode_value (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);
* doesn't have a token since the reference is generated by the JIT
* like Nullable:Box/Unbox, or by generic sharing.
*/
-
encode_value ((MONO_AOT_METHODREF_GINST << 24), p, &p);
/* Encode the klass */
encode_klass_ref (acfg, method->klass, p, &p);
}
} else {
g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
- encode_value ((image_index << 24) | mono_metadata_token_index (token), p, &p);
+
+ if (image_index >= MONO_AOT_METHODREF_MIN) {
+ encode_value ((MONO_AOT_METHODREF_LARGE_IMAGE_INDEX << 24), p, &p);
+ encode_value (image_index, p, &p);
+ encode_value (mono_metadata_token_index (token), p, &p);
+ } else {
+ encode_value ((image_index << 24) | mono_metadata_token_index (token), p, &p);
+ }
}
*endbuf = p;
}
static char*
get_plt_symbol (MonoAotCompile *acfg, int plt_offset, MonoJumpInfo *patch_info)
{
-#ifdef __APPLE__
+#ifdef TARGET_MACH
/*
* The Apple linker reorganizes object files, so it doesn't like branches to local
* labels, since those have no relocations.
new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
+ // g_assert (mono_patch_info_equal (patch_info, new_ji));
+
res = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoPltEntry));
res->plt_offset = acfg->plt_offset;
res->ji = new_ji;
MonoClassField *field;
gboolean can_marshal = TRUE;
gpointer iter = NULL;
+ MonoMarshalType *info;
+ int i;
if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
return FALSE;
+ info = mono_marshal_load_type_info (klass);
+
/* Only allow a few field types to avoid asserts in the marshalling code */
while ((field = mono_class_get_fields (klass, &iter))) {
if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC))
if (!mono_class_from_mono_type (field->type)->enumtype && !can_marshal_struct (mono_class_from_mono_type (field->type)))
can_marshal = FALSE;
break;
+ case MONO_TYPE_SZARRAY: {
+ gboolean has_mspec = FALSE;
+
+ if (info) {
+ for (i = 0; i < info->num_fields; ++i) {
+ if (info->fields [i].field == field && info->fields [i].mspec)
+ has_mspec = TRUE;
+ }
+ }
+ if (!has_mspec)
+ can_marshal = FALSE;
+ break;
+ }
default:
can_marshal = FALSE;
break;
/* Special cases */
/* Its hard to compute whenever these can be marshalled or not */
- if (!strcmp (klass->name_space, "System.Net.NetworkInformation.MacOsStructs"))
+ if (!strcmp (klass->name_space, "System.Net.NetworkInformation.MacOsStructs") && strcmp (klass->name, "sockaddr_dl"))
return TRUE;
return can_marshal;
}
+static void
+create_gsharedvt_inst (MonoAotCompile *acfg, MonoMethod *method, MonoGenericContext *ctx)
+{
+ /* Create a vtype instantiation */
+ MonoGenericContext shared_context;
+ MonoType **args;
+ MonoGenericInst *inst;
+ MonoGenericContainer *container;
+ MonoClass **constraints;
+ int i;
+
+ memset (ctx, 0, sizeof (MonoGenericContext));
+
+ if (method->klass->generic_container) {
+ shared_context = method->klass->generic_container->context;
+ inst = shared_context.class_inst;
+
+ args = g_new0 (MonoType*, inst->type_argc);
+ for (i = 0; i < inst->type_argc; ++i) {
+ args [i] = &mono_defaults.int_class->byval_arg;
+ }
+ ctx->class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
+ }
+ if (method->is_generic) {
+ container = mono_method_get_generic_container (method);
+ shared_context = container->context;
+ inst = shared_context.method_inst;
+
+ args = g_new0 (MonoType*, inst->type_argc);
+ for (i = 0; i < container->type_argc; ++i) {
+ MonoGenericParamInfo *info = &container->type_params [i].info;
+ gboolean ref_only = FALSE;
+
+ if (info && info->constraints) {
+ constraints = info->constraints;
+
+ while (*constraints) {
+ MonoClass *cklass = *constraints;
+ if (!(cklass == mono_defaults.object_class || (cklass->image == mono_defaults.corlib && !strcmp (cklass->name, "ValueType"))))
+ /* Inflaring the method with our vtype would not be valid */
+ ref_only = TRUE;
+ constraints ++;
+ }
+ }
+
+ if (ref_only)
+ args [i] = &mono_defaults.object_class->byval_arg;
+ else
+ args [i] = &mono_defaults.int_class->byval_arg;
+ }
+ ctx->method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
+ }
+}
+
static void
add_wrappers (MonoAotCompile *acfg)
{
continue;
}
- if (klass->delegate && klass != mono_defaults.delegate_class && klass != mono_defaults.multicastdelegate_class && !klass->generic_container) {
+ if (!klass->delegate || klass == mono_defaults.delegate_class || klass == mono_defaults.multicastdelegate_class)
+ continue;
+
+ if (!klass->generic_container) {
method = mono_get_delegate_invoke (klass);
m = mono_marshal_get_delegate_invoke (method, NULL);
int j;
for (j = 0; j < cattr->num_attrs; ++j)
- if (cattr->attrs [j].ctor && !strcmp (cattr->attrs [j].ctor->klass->name, "MonoNativeFunctionWrapperAttribute"))
+ if (cattr->attrs [j].ctor && (!strcmp (cattr->attrs [j].ctor->klass->name, "MonoNativeFunctionWrapperAttribute") || !strcmp (cattr->attrs [j].ctor->klass->name, "UnmanagedFunctionPointerAttribute")))
break;
if (j < cattr->num_attrs)
add_method (acfg, mono_marshal_get_native_func_wrapper_aot (klass));
}
+ } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->generic_container) {
+ MonoGenericContext ctx;
+ MonoMethod *inst, *gshared;
+
+ /*
+ * Emit a gsharedvt version of the generic delegate-invoke wrapper
+ */
+
+ method = mono_get_delegate_invoke (klass);
+ create_gsharedvt_inst (acfg, method, &ctx);
+
+ inst = mono_class_inflate_generic_method (method, &ctx);
+
+ m = mono_marshal_get_delegate_invoke (inst, NULL);
+ g_assert (m->is_inflated);
+
+ gshared = mini_get_shared_method_full (m, FALSE, TRUE);
+ add_extra_method (acfg, gshared);
}
}
if (!klass->generic_class && !klass->rank)
return;
+ if (klass->exception_type)
+ return;
+
if (!acfg->ginst_hash)
acfg->ginst_hash = g_hash_table_new (NULL, NULL);
iter = NULL;
while ((method = mono_class_get_methods (klass, &iter))) {
- if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
+ if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, FALSE))
/* Already added */
continue;
* in Array, since a T[] could be cast to ICollection<T>.
*/
if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") &&
- (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1"))) {
+ (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1") || !strcmp (klass->name, "IReadOnlyList`1"))) {
MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
MonoClass *array_class = mono_bounded_array_class_get (tclass, 1, FALSE);
gpointer iter;
MonoGenericContext ctx;
MonoType *args [16];
+ if (acfg->aot_opts.no_instances)
+ return;
+
memset (&ctx, 0, sizeof (ctx));
for (i = 0; i < ninsts; ++i) {
MonoMethod *method;
MonoGenericContext *context;
+ if (acfg->aot_opts.no_instances)
+ return;
+
for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) {
token = MONO_TOKEN_METHOD_SPEC | (i + 1);
method = mono_get_method (acfg->image, token, NULL);
* 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))
+ if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, FALSE))
continue;
/*
// FIXME: Maybe call the wrapper directly ?
direct_callable = FALSE;
- if (acfg->aot_opts.soft_debug) {
+ if (acfg->aot_opts.soft_debug || acfg->aot_opts.no_direct_calls) {
/* Disable this so all calls go through load_method (), see the
* mini_get_debug_options ()->load_aot_jit_info_eagerly = TRUE; line in
* mono_debugger_agent_init ().
MonoMethodHeader *header;
gboolean skip, direct_call;
guint32 got_slot;
- char direct_call_target [1024];
+ const char *direct_call_target;
const char *direct_pinvoke;
if (method) {
MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
//printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
direct_call = TRUE;
- g_assert (strlen (callee_cfg->asm_symbol) < 1000);
- sprintf (direct_call_target, "%s", callee_cfg->asm_symbol);
+ direct_call_target = callee_cfg->asm_symbol;
+ patch_info->type = MONO_PATCH_INFO_NONE;
+ acfg->stats.direct_calls ++;
}
acfg->stats.all_calls ++;
direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method);
if (direct_pinvoke) {
const char*prefix;
-#if defined(__APPLE__)
+#if defined(TARGET_MACH)
prefix = "_";
#else
prefix = "";
#endif
direct_call = TRUE;
g_assert (strlen (direct_pinvoke) < 1000);
- sprintf (direct_call_target, "%s%s", prefix, direct_pinvoke);
+ direct_call_target = g_strdup_printf ("%s%s", prefix, direct_pinvoke);
}
}
}
if (plt_entry) {
/* This patch has a PLT entry, so we must emit a call to the PLT entry */
direct_call = TRUE;
- sprintf (direct_call_target, "%s", plt_entry->symbol);
+ direct_call_target = plt_entry->symbol;
/* Nullify the patch */
patch_info->type = MONO_PATCH_INFO_NONE;
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);
int method_index;
guint8 *code;
char *debug_sym = NULL;
- char symbol [128];
+ char *symbol = NULL;
int func_alignment = AOT_FUNC_ALIGNMENT;
MonoMethodHeader *header;
char *export_name;
header = cfg->header;
method_index = get_method_index (acfg, method);
+ symbol = g_strdup_printf ("%sme_%x", acfg->temp_prefix, method_index);
- /* Make the labels local */
- sprintf (symbol, "%s", cfg->asm_symbol);
+ /* Make the labels local */
emit_section_change (acfg, ".text", 0);
emit_alignment (acfg, func_alignment);
- emit_label (acfg, symbol);
+
+ if (acfg->global_symbols && acfg->need_no_dead_strip)
+ fprintf (acfg->fp, " .no_dead_strip %s\n", cfg->asm_symbol);
+
+ emit_label (acfg, cfg->asm_symbol);
- if (acfg->aot_opts.write_symbols) {
+ if (acfg->aot_opts.write_symbols && !acfg->global_symbols) {
/*
* Write a C style symbol for every method, this has two uses:
* - it works on platforms where the dwarf debugging info is not
*/
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);
}
if (cfg->verbose_level > 0)
- g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
+ g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), cfg->asm_symbol);
acfg->stats.code_size += cfg->code_len;
g_free (debug_sym);
}
- sprintf (symbol, "%sme_%x", acfg->temp_prefix, method_index);
emit_label (acfg, symbol);
+ g_free (symbol);
}
/**
case MONO_PATCH_INFO_SIGNATURE:
encode_signature (acfg, (MonoMethodSignature*)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;
default:
g_warning ("unable to handle jump info %d", patch_info->type);
g_assert_not_reached ();
if (jinfo->has_generic_jit_info) {
MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (jinfo);
+ MonoGenericSharingContext* gsctx = gi->generic_sharing_context;
guint8 *p1;
p1 = p;
* when using generic sharing.
*/
encode_method_ref (acfg, jinfo->method, p, &p);
+
+ 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;
+ context = &inflated->context;
+
+ encode_value (1, p, &p);
+ if (context->class_inst) {
+ inst = context->class_inst;
+
+ encode_value (inst->type_argc, p, &p);
+ for (i = 0; i < inst->type_argc; ++i)
+ encode_value (gsctx->var_is_vt [i], p, &p);
+ } else {
+ encode_value (0, p, &p);
+ }
+ if (context->method_inst) {
+ inst = context->method_inst;
+
+ encode_value (inst->type_argc, p, &p);
+ for (i = 0; i < inst->type_argc; ++i)
+ encode_value (gsctx->mvar_is_vt [i], p, &p);
+ } else {
+ encode_value (0, p, &p);
+ }
+ } else {
+ encode_value (0, p, &p);
+ }
}
if (jinfo->has_try_block_holes) {
/* Emit only a thumb version */
continue;
- if (!acfg->thumb_mixed)
+ if (acfg->llvm && !acfg->thumb_mixed)
emit_label (acfg, plt_entry->llvm_symbol);
if (debug_sym) {
- if (acfg->need_no_dead_strip)
+ if (acfg->need_no_dead_strip) {
+ img_writer_emit_unset_mode (acfg->w);
fprintf (acfg->fp, " .no_dead_strip %s\n", debug_sym);
+ }
emit_local_symbol (acfg, debug_sym, NULL, TRUE);
emit_label (acfg, debug_sym);
}
}
if (debug_sym) {
-#if defined(__APPLE__)
+#if defined(TARGET_MACH)
fprintf (acfg->fp, " .thumb_func %s\n", debug_sym);
fprintf (acfg->fp, " .no_dead_strip %s\n", debug_sym);
#endif
emit_label (acfg, symbol);
}
+/*
+ * emit_trampoline_full:
+ *
+ * If EMIT_TINFO is TRUE, emit additional information which can be used to create a MonoJitInfo for this trampoline by
+ * create_jit_info_for_trampoline ().
+ */
static G_GNUC_UNUSED void
-emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
+emit_trampoline_full (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info, gboolean emit_tinfo)
{
char start_symbol [256];
+ char end_symbol [256];
char symbol [256];
guint32 buf_size, info_offset;
MonoJumpInfo *patch_info;
emit_symbol_size (acfg, start_symbol, ".");
+ if (emit_tinfo) {
+ sprintf (end_symbol, "%snamede_%s", acfg->temp_prefix, name);
+ emit_label (acfg, end_symbol);
+ }
+
/* Emit info */
/* Sort relocations */
emit_int32 (acfg, info_offset);
+ if (emit_tinfo) {
+ guint8 *encoded;
+ guint32 encoded_len;
+ guint32 uw_offset;
+
+ /*
+ * Emit additional information which can be used to reconstruct a partial MonoTrampInfo.
+ */
+ encoded = mono_unwind_ops_encode (info->unwind_ops, &encoded_len);
+ uw_offset = get_unwind_info_offset (acfg, encoded, encoded_len);
+ g_free (encoded);
+
+ emit_symbol_diff (acfg, end_symbol, start_symbol, 0);
+ emit_int32 (acfg, uw_offset);
+ }
+
/* Emit debug info */
if (unwind_ops) {
char symbol2 [256];
}
}
+static G_GNUC_UNUSED void
+emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
+{
+ emit_trampoline_full (acfg, got_offset, info, FALSE);
+}
+
static void
emit_trampolines (MonoAotCompile *acfg)
{
* method.
*/
for (tramp_type = 0; tramp_type < MONO_TRAMPOLINE_NUM; ++tramp_type) {
- mono_arch_create_generic_trampoline (tramp_type, &info, TRUE);
+ /* we overload the boolean here to indicate the slightly different trampoline needed, see mono_arch_create_generic_trampoline() */
+ mono_arch_create_generic_trampoline (tramp_type, &info, acfg->aot_opts.use_trampolines_page? 2: TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
}
mono_arch_get_throw_corlib_exception (&info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+ mono_arch_get_gsharedvt_trampoline (&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);
+ }
+#endif
+
#if defined(MONO_ARCH_HAVE_GET_TRAMPOLINES)
{
GSList *l = mono_arch_get_trampolines (TRUE);
case MONO_AOT_TRAMP_IMT_THUNK:
sprintf (symbol, "imt_thunks");
break;
+ case MONO_AOT_TRAMP_GSHAREDVT_ARG:
+ sprintf (symbol, "gsharedvt_arg_trampolines");
+ break;
default:
g_assert_not_reached ();
}
arch_emit_imt_thunk (acfg, tramp_got_offset, &tramp_size);
tramp_got_offset += 1;
break;
+ case MONO_AOT_TRAMP_GSHAREDVT_ARG:
+ arch_emit_gsharedvt_arg_trampoline (acfg, tramp_got_offset, &tramp_size);
+ tramp_got_offset += 2;
+ break;
default:
g_assert_not_reached ();
}
emit_label (acfg, end_symbol);
}
+ arch_emit_specific_trampoline_pages (acfg);
+
/* Reserve some entries at the end of the GOT for our use */
acfg->num_trampoline_got_entries = tramp_got_offset - acfg->got_offset;
}
opts->asm_writer = TRUE;
} else if (str_begins_with (arg, "nodebug")) {
opts->nodebug = TRUE;
+ } else if (str_begins_with (arg, "nopagetrampolines")) {
+ opts->use_trampolines_page = FALSE;
} else if (str_begins_with (arg, "ntrampolines=")) {
opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
} else if (str_begins_with (arg, "nrgctx-trampolines=")) {
opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines="));
} else if (str_begins_with (arg, "nimt-trampolines=")) {
opts->nimt_trampolines = atoi (arg + strlen ("nimt-trampolines="));
+ } else if (str_begins_with (arg, "ngsharedvt-trampolines=")) {
+ opts->ngsharedvt_arg_trampolines = atoi (arg + strlen ("ngsharedvt-trampolines="));
} else if (str_begins_with (arg, "autoreg")) {
opts->autoreg = TRUE;
} else if (str_begins_with (arg, "tool-prefix=")) {
opts->direct_pinvoke = TRUE;
} else if (str_begins_with (arg, "direct-icalls")) {
opts->direct_icalls = TRUE;
+#if defined(TARGET_ARM)
+ } else if (str_begins_with (arg, "iphone-abi")) {
+ // older full-aot users did depend on this.
+#endif
+ } else if (str_begins_with (arg, "no-direct-calls")) {
+ opts->no_direct_calls = TRUE;
} else if (str_begins_with (arg, "print-skipped")) {
opts->print_skipped_methods = TRUE;
} else if (str_begins_with (arg, "stats")) {
opts->stats = TRUE;
+ } else if (str_begins_with (arg, "no-instances")) {
+ opts->no_instances = TRUE;
} else if (str_begins_with (arg, "log-generics")) {
opts->log_generics = TRUE;
} else if (str_begins_with (arg, "mtriple=")) {
} else if (str_begins_with (arg, "info")) {
printf ("AOT target setup: %s.\n", AOT_TARGET_STR);
exit (0);
+ } else if (str_begins_with (arg, "gc-maps")) {
+ mini_gc_enable_gc_maps_for_aot ();
} else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) {
printf ("Supported options for --aot:\n");
printf (" outfile=\n");
printf (" ntrampolines=\n");
printf (" nrgctx-trampolines=\n");
printf (" nimt-trampolines=\n");
+ printf (" ngsharedvt-trampolines=\n");
printf (" autoreg\n");
printf (" tool-prefix=\n");
printf (" readonly-value=\n");
printf (" soft-debug\n");
+ printf (" gc-maps\n");
printf (" print-skipped\n");
+ printf (" no-instances\n");
printf (" stats\n");
printf (" info\n");
printf (" help/?\n");
}
}
+ if (opts->use_trampolines_page) {
+ opts->ntrampolines = 0;
+ opts->nrgctx_trampolines = 0;
+ opts->nimt_trampolines = 0;
+ }
g_strfreev (args);
}
}
static gboolean
-can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+can_encode_method (MonoAotCompile *acfg, MonoMethod *method)
{
- switch (patch_info->type) {
- case MONO_PATCH_INFO_METHOD:
- case MONO_PATCH_INFO_METHODCONST: {
- MonoMethod *method = patch_info->data.method;
-
if (method->wrapper_type) {
switch (method->wrapper_type) {
case MONO_WRAPPER_NONE:
case MONO_WRAPPER_REMOTING_INVOKE:
case MONO_WRAPPER_UNKNOWN:
case MONO_WRAPPER_WRITE_BARRIER:
+ case MONO_WRAPPER_DELEGATE_INVOKE:
break;
case MONO_WRAPPER_MANAGED_TO_MANAGED:
case MONO_WRAPPER_CASTCLASS: {
}
}
}
- break;
+ return TRUE;
+}
+
+static gboolean
+can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+{
+ switch (patch_info->type) {
+ case MONO_PATCH_INFO_METHOD:
+ case MONO_PATCH_INFO_METHODCONST: {
+ MonoMethod *method = patch_info->data.method;
+
+ return can_encode_method (acfg, method);
}
case MONO_PATCH_INFO_VTABLE:
case MONO_PATCH_INFO_CLASS_INIT:
case MONO_PATCH_INFO_RGCTX_FETCH: {
MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
+ if (!can_encode_method (acfg, entry->method))
+ return FALSE;
if (!can_encode_patch (acfg, entry->data))
return FALSE;
break;
*/
cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
- //printf ("F: %s\n", mono_method_full_name (method, TRUE));
+ if (acfg->aot_opts.print_skipped_methods)
+ printf ("Skip (gshared failure): %s (%s)\n", mono_method_full_name (method, TRUE), cfg->exception_message);
InterlockedIncrement (&acfg->stats.genericcount);
return;
}
* encountered.
*/
depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
- if (depth < 32) {
+ if (!acfg->aot_opts.no_instances && depth < 32) {
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
switch (patch_info->type) {
case MONO_PATCH_INFO_METHOD: {
MonoMethod *m = patch_info->data.method;
if (m->is_inflated) {
if (!(mono_class_generic_sharing_enabled (m->klass) &&
- mono_method_is_generic_sharable_impl (m, FALSE)) &&
+ mono_method_is_generic_sharable_impl_full (m, FALSE, FALSE, FALSE)) &&
!method_has_type_vars (m)) {
if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
if (acfg->aot_opts.full_aot)
plt_entry = get_plt_entry (llvm_acfg, ji);
plt_entry->llvm_used = TRUE;
-#if defined(__APPLE__)
+#if defined(TARGET_MACH)
return g_strdup_printf (plt_entry->llvm_symbol + strlen (llvm_acfg->llvm_label_prefix));
#else
return g_strdup_printf (plt_entry->llvm_symbol);
static void
emit_llvm_file (MonoAotCompile *acfg)
{
- char *command, *opts;
+ char *command, *opts, *tempbc;
int i;
MonoJumpInfo *patch_info;
*/
if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
/* For the generic + rgctx trampolines */
- acfg->final_got_size += 200;
+ acfg->final_got_size += 400;
/* For the specific trampolines */
for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype)
acfg->final_got_size += acfg->num_trampolines [ntype] * 2;
}
- mono_llvm_emit_aot_module ("temp.bc", acfg->final_got_size);
+ tempbc = g_strdup_printf ("%s.bc", acfg->tmpfname);
+ mono_llvm_emit_aot_module (tempbc, acfg->final_got_size);
+ g_free (tempbc);
/*
* FIXME: Experiment with adding optimizations, the -std-compile-opts set takes
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");
#if 1
- command = g_strdup_printf ("%sopt -f %s -o temp.opt.bc temp.bc", acfg->aot_opts.llvm_path, opts);
+ command = g_strdup_printf ("%sopt -f %s -o %s.opt.bc %s.bc", acfg->aot_opts.llvm_path, opts, acfg->tmpfname, acfg->tmpfname);
printf ("Executing opt: %s\n", command);
if (system (command) != 0) {
exit (1);
g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
unlink (acfg->tmpfname);
- command = g_strdup_printf ("%sllc %s -disable-gnu-eh-frame -enable-mono-eh-frame -o %s temp.opt.bc", acfg->aot_opts.llvm_path, acfg->llc_args->str, 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);
printf ("Executing llc: %s\n", command);
method = cfg->orig_method;
/* Emit unbox trampoline */
- if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+ if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
sprintf (symbol, "ut_%d", get_method_index (acfg, method));
emit_section_change (acfg, ".text", 0);
}
}
+#ifdef MONOTOUCH
+ if (acfg->direct_method_addresses) {
+ acfg->flags |= MONO_AOT_FILE_FLAG_DIRECT_METHOD_ADDRESSES;
+
+ sprintf (symbol, "method_addresses");
+ emit_section_change (acfg, RODATA_SECT, 1);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+
+ for (i = 0; i < acfg->nmethods; ++i) {
+ if (acfg->cfgs [i]) {
+ emit_pointer (acfg, acfg->cfgs [i]->asm_symbol);
+ } else {
+ emit_pointer (acfg, NULL);
+ }
+ }
+
+ /* Empty */
+ sprintf (symbol, "code_offsets");
+ emit_section_change (acfg, RODATA_SECT, 1);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+ } else {
+ sprintf (symbol, "code_offsets");
+ emit_section_change (acfg, RODATA_SECT, 1);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+
+ acfg->stats.offsets_size += acfg->nmethods * 4;
+
+ sprintf (end_symbol, "methods");
+ for (i = 0; i < acfg->nmethods; ++i) {
+ if (acfg->cfgs [i]) {
+ emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
+ } else {
+ emit_int32 (acfg, 0xffffffff);
+ }
+ }
+ }
+#else
sprintf (symbol, "code_offsets");
emit_section_change (acfg, RODATA_SECT, 1);
emit_alignment (acfg, 8);
emit_int32 (acfg, 0xffffffff);
}
}
+#endif
emit_line (acfg);
/* Emit a sorted table mapping methods to their unbox trampolines */
method = cfg->orig_method;
- if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+ if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
index = get_method_index (acfg, method);
sprintf (symbol, "ut_%d", index);
emit_int32 (acfg, index);
- emit_symbol_diff (acfg, symbol, end_symbol, 0);
+ if (acfg->direct_method_addresses)
+ emit_pointer (acfg, symbol);
+ else
+ emit_symbol_diff (acfg, symbol, end_symbol, 0);
/* Make sure the table is sorted by index */
g_assert (index > prev_index);
prev_index = index;
sprintf (symbol, "name_%d", i);
emit_section_change (acfg, RODATA_SECT, 1);
-#ifdef __APPLE__
+#ifdef TARGET_MACH
emit_alignment (acfg, 4);
#endif
emit_label (acfg, symbol);
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
emit_pointer (acfg, "extra_method_info_offsets");
emit_pointer (acfg, "extra_method_table");
emit_pointer (acfg, "got_info_offsets");
emit_pointer (acfg, "specific_trampolines");
emit_pointer (acfg, "static_rgctx_trampolines");
emit_pointer (acfg, "imt_thunks");
+ emit_pointer (acfg, "gsharedvt_arg_trampolines");
} else {
emit_pointer (acfg, NULL);
emit_pointer (acfg, NULL);
emit_pointer (acfg, NULL);
+ emit_pointer (acfg, NULL);
}
if (acfg->thumb_mixed) {
emit_pointer (acfg, "thumb_end");
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;
+#if defined (TARGET_ARM) && defined (TARGET_MACH)
+ {
+ MonoType t;
+ int align = 0;
- t.type = MONO_TYPE_R8;
- mono_type_size (&t, &align);
+ memset (&t, 0, sizeof (MonoType));
+ t.type = MONO_TYPE_R8;
+ mono_type_size (&t, &align);
- emit_int32 (acfg, align);
+ emit_int32 (acfg, align);
- t.type = MONO_TYPE_I8;
- mono_type_size (&t, &align);
+ memset (&t, 0, sizeof (MonoType));
+ t.type = MONO_TYPE_I8;
+ mono_type_size (&t, &align);
- emit_int32 (acfg, align);
- }
+ emit_int32 (acfg, align);
+ }
#else
emit_int32 (acfg, __alignof__ (double));
emit_int32 (acfg, __alignof__ (gint64));
* mono_aot_register_module (). The symbol points to a pointer to the the file info
* structure.
*/
-#if defined(__APPLE__) && !defined(__native_client_codegen__)
+#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);
{
#ifdef EMIT_DWARF_INFO
int i;
- char symbol [128], symbol2 [128];
+ char symbol2 [128];
/* DIEs for methods */
for (i = 0; i < acfg->nmethods; ++i) {
if (cfg->compile_llvm)
continue;
- sprintf (symbol, "%s", cfg->asm_symbol);
sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
- mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, symbol, symbol2, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
+ 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 ()));
}
#endif
}
static void
collect_methods (MonoAotCompile *acfg)
{
- int i;
+ int mindex, i;
MonoImage *image = acfg->image;
/* Collect methods */
acfg->method_index ++;
}
+ /* gsharedvt methods */
+ for (mindex = 0; mindex < image->tables [MONO_TABLE_METHOD].rows; ++mindex) {
+ MonoMethod *method;
+ guint32 token = MONO_TOKEN_METHOD_DEF | (mindex + 1);
+
+ if (!(acfg->opts & MONO_OPT_GSHAREDVT))
+ continue;
+
+ method = mono_get_method (acfg->image, token, NULL);
+ if (!method)
+ continue;
+ if (method->is_generic || method->klass->generic_container) {
+ /* Create a vtype instantiation */
+ MonoGenericContext ctx;
+ MonoMethod *inflated, *gshared;
+
+ create_gsharedvt_inst (acfg, method, &ctx);
+
+ inflated = mono_class_inflate_generic_method (method, &ctx);
+ gshared = mini_get_shared_method_full (inflated, FALSE, TRUE);
+ add_extra_method (acfg, gshared);
+ }
+ }
+
add_generic_instances (acfg);
if (acfg->aot_opts.full_aot)
#define LD_OPTIONS "-m elf64ppc"
#elif defined(sparc) && SIZEOF_VOID_P == 8
#define AS_OPTIONS "-xarch=v9"
-#elif defined(TARGET_X86) && defined(__APPLE__) && !defined(__native_client_codegen__)
+#elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
#define AS_OPTIONS "-arch i386 -W"
#else
#define AS_OPTIONS ""
#if defined(sparc)
command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
-#elif defined(__ppc__) && defined(__APPLE__)
+#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(__APPLE__) && !defined(__native_client_codegen__)
+#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);
#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);
}
g_free (command);
- unlink (objfile);
+
/*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, SHARED_EXT);
printf ("Stripping the binary: %s\n", com);
system (com);
g_free (com);*/
-#if defined(TARGET_ARM) && !defined(__APPLE__)
+#if defined(TARGET_ARM) && !defined(TARGET_MACH)
/*
* 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.
rename (tmp_outfile_name, outfile_name);
+#if defined(TARGET_MACH)
+ command = g_strdup_printf ("dsymutil %s", outfile_name);
+ printf ("Generating debug symbols: %s\n", command);
+ if (system (command) != 0) {
+ return 1;
+ }
+#endif
+
+ if (!acfg->aot_opts.save_temps)
+ unlink (objfile);
+
g_free (tmp_outfile_name);
g_free (outfile_name);
g_free (objfile);
acfg->aot_opts.ntrampolines = 1024;
acfg->aot_opts.nrgctx_trampolines = 1024;
acfg->aot_opts.nimt_trampolines = 128;
+ acfg->aot_opts.ngsharedvt_arg_trampolines = 128;
acfg->aot_opts.llvm_path = g_strdup ("");
+#if MONOTOUCH
+ acfg->aot_opts.use_trampolines_page = TRUE;
+#endif
mono_aot_parse_options (aot_options, &acfg->aot_opts);
acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? acfg->aot_opts.nrgctx_trampolines : 0;
#endif
acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+ if (acfg->opts & MONO_OPT_GSHAREDVT)
+ acfg->num_trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = acfg->aot_opts.full_aot ? acfg->aot_opts.ngsharedvt_arg_trampolines : 0;
+#endif
acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
if (COMPILE_LLVM (cfg))
cfg->asm_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, cfg->llvm_method_name);
+ else if (acfg->global_symbols)
+ cfg->asm_symbol = get_debug_sym (cfg->method, "", acfg->method_label_hash);
else
cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, acfg->llvm_label_prefix, method_index);
}
*/
sprintf (symbol, "thumb_end");
emit_section_change (acfg, ".text", 0);
+ emit_alignment (acfg, 8);
emit_label (acfg, symbol);
emit_zero_bytes (acfg, 16);
g_assert (acfg->got_offset <= acfg->final_got_size);
printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT: %d Offsets: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.unwind_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, (int)(acfg->got_offset * sizeof (gpointer)), acfg->stats.offsets_size);
+ printf ("Compiled: %d/%d (%d%%), 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,
+ 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 are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
+ if (acfg->stats.abscount)
+ printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
+ if (acfg->stats.lmfcount)
+ 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);
TV_GETTIME (btv);
acfg->stats.link_time = TV_ELAPSED (atv, btv);
- printf ("Compiled %d out of %d methods (%d%%)\n", acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100);
- if (acfg->stats.genericcount)
- printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
- if (acfg->stats.abscount)
- printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
- if (acfg->stats.lmfcount)
- printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
- if (acfg->stats.ocount)
- printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
- if (acfg->llvm)
- printf ("Methods compiled with LLVM: %d (%d%%)\n", acfg->stats.llvm_count, acfg->stats.mcount ? (acfg->stats.llvm_count * 100) / acfg->stats.mcount : 100);
- printf ("Methods without GOT slots: %d (%d%%)\n", acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100);
- printf ("Direct calls: %d (%d%%)\n", acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
-
if (acfg->aot_opts.stats) {
int i;