int nthreads;
int ntrampolines;
gboolean print_skipped_methods;
+ char *tool_prefix;
} MonoAotOptions;
typedef struct MonoAotStats {
/* The IMT method is in v5 */
- /* Only IP is available, but we need at least two free registers */
- ARM_PUSH1 (code, ARMREG_R1);
+ /* 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));
labels [0] = code;
/* Load the parameter from the GOT */
- ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
- ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP);
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
+ ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R0);
labels [1] = code;
- ARM_LDR_IMM (code, ARMREG_R1, ARMREG_IP, 0);
+ ARM_LDR_IMM (code, ARMREG_R1, ARMREG_R0, 0);
ARM_CMP_REG_REG (code, ARMREG_R1, ARMREG_V5);
labels [2] = code;
ARM_B_COND (code, ARMCOND_EQ, 0);
ARM_B_COND (code, ARMCOND_EQ, 0);
/* Loop footer */
- ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_IP, sizeof (gpointer) * 2);
+ ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (gpointer) * 2);
labels [4] = code;
ARM_B (code, 0);
arm_patch (labels [4], labels [1]);
/* Match */
arm_patch (labels [2], code);
- ARM_POP1 (code, ARMREG_R1);
- ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, 4);
- ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, 0);
+ 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 (labels [3], code);
/* Fixup offset */
code2 = labels [0];
- ARM_LDR_IMM (code2, ARMREG_IP, ARMREG_PC, (code - (labels [0] + 8)));
+ ARM_LDR_IMM (code2, ARMREG_R0, ARMREG_PC, (code - (labels [0] + 8)));
emit_bytes (acfg, buf, code - buf);
emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) + (code - (labels [0] + 8)) - 4);
add_extra_method (acfg, method);
}
+ if (klass->delegate) {
+ method = mono_get_delegate_invoke (klass);
+
+ method = mono_marshal_get_delegate_invoke (method, NULL);
+
+ add_method (acfg, method);
+ }
+
/*
* For ICollection<T>, where T is a vtype, add instances of the helper methods
* in Array, since a T[] could be cast to ICollection<T>.
}
}
+static void
+add_array_wrappers (MonoAotCompile *acfg, MonoClass *klass)
+{
+ int i;
+
+ mono_class_setup_methods (klass);
+ for (i = 0; i < klass->method.count; ++i) {
+ if (klass->methods [i]->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED)
+ add_extra_method (acfg, klass->methods [i]);
+ }
+}
+
/*
* add_generic_instances:
*
add_generic_class (acfg, mono_class_from_mono_type (header->locals [j]));
}
}
+
+ if (acfg->image == mono_defaults.corlib) {
+ /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
+ MonoClass *klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
+
+ if (klass) {
+ MonoGenericContext ctx;
+ MonoType *args [16];
+
+ memset (&ctx, 0, sizeof (ctx));
+
+ args [0] = &mono_defaults.byte_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.sbyte_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.int16_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.uint16_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.int32_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.uint32_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.int64_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.uint64_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+ }
+
+ /* Add GenericEqualityComparer<T> instances for primitive types */
+ klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericEqualityComparer`1");
+
+ if (klass) {
+ MonoGenericContext ctx;
+ MonoType *args [16];
+
+ memset (&ctx, 0, sizeof (ctx));
+
+ args [0] = &mono_defaults.byte_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.sbyte_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.int16_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.uint16_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.int32_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.uint32_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.int64_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+ args [0] = &mono_defaults.uint64_class->byval_arg;
+ ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+ add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+ }
+
+ /* Emit the array wrapper methods for arrays of primitive types */
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.byte_class, 1));
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.sbyte_class, 1));
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int16_class, 1));
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.uint16_class, 1));
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int32_class, 1));
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.uint32_class, 1));
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int64_class, 1));
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.single_class, 1));
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.double_class, 1));
+ /* These are not handled by generic sharing */
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.object_class, 1));
+ add_array_wrappers (acfg, mono_array_class_get (mono_defaults.string_class, 1));
+
+ /* Add instances of Array.GetGenericValueImpl */
+ {
+ MonoGenericContext ctx;
+ MonoType *args [16];
+ MonoMethod *method;
+
+ memset (&ctx, 0, sizeof (ctx));
+
+ /*
+ * managed-to-native wrappers are not shared, so have to generate
+ * these for ref types too.
+ */
+ klass = mono_array_class_get (mono_defaults.int_class, 1)->parent;
+ method = mono_class_get_method_from_name (klass, "GetGenericValueImpl", 2);
+
+ if (method) {
+ /* String */
+ args [0] = &mono_defaults.string_class->byval_arg;
+ ctx.method_inst = mono_metadata_get_generic_inst (1, args);
+ add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (method, &ctx), TRUE, TRUE));
+ }
+ }
+ }
+}
+
+/*
+ * is_direct_callable:
+ *
+ * Return whenever the method identified by JI is directly callable without
+ * going through the PLT.
+ */
+static gboolean
+is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patch_info)
+{
+ if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
+ MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
+ if (callee_cfg) {
+ gboolean direct_callable = TRUE;
+
+ if (direct_callable && !(!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
+ direct_callable = FALSE;
+ if ((callee_cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && (!method || method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED))
+ // FIXME: Maybe call the wrapper directly ?
+ direct_callable = FALSE;
+
+ if (direct_callable)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
/*
* the same assembly and requires no initialization.
*/
direct_call = FALSE;
- if (!got_only && (patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == method->klass->image)) {
- MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
- if (callee_cfg) {
- gboolean direct_callable = TRUE;
-
- if (direct_callable && !(!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
- direct_callable = FALSE;
- if ((callee_cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
- // FIXME: Maybe call the wrapper directly ?
- direct_callable = FALSE;
- if (direct_callable) {
- //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
- direct_call = TRUE;
- sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
- patch_info->type = MONO_PATCH_INFO_NONE;
- acfg->stats.direct_calls ++;
- }
+ if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
+ if (!got_only && is_direct_callable (acfg, method, patch_info)) {
+ MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
+ //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
+ direct_call = TRUE;
+ sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
+ patch_info->type = MONO_PATCH_INFO_NONE;
+ acfg->stats.direct_calls ++;
}
acfg->stats.all_calls ++;
}
}
+/*
+ * sanitize_symbol:
+ *
+ * Modify SYMBOL so it only includes characters permissible in symbols.
+ */
+static void
+sanitize_symbol (char *symbol)
+{
+ int i, len = strlen (symbol);
+
+ for (i = 0; i < len; ++i)
+ if (!isalnum (symbol [i]) && (symbol [i] != '_'))
+ symbol [i] = '_';
+}
+
static char*
get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
{
use_unwind_ops = cfg->unwind_ops != NULL;
#endif
- flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0);
+ flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0);
encode_value (jinfo->code_size, p, &p);
encode_value (flags, p, &p);
}
/* Exception table */
- if (header->num_clauses) {
- for (k = 0; k < header->num_clauses; ++k) {
- MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+ if (jinfo->num_clauses)
+ encode_value (jinfo->num_clauses, p, &p);
- encode_value (ei->exvar_offset, p, &p);
+ for (k = 0; k < jinfo->num_clauses; ++k) {
+ MonoJitExceptionInfo *ei = &jinfo->clauses [k];
- if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
- encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+ encode_value (ei->exvar_offset, p, &p);
- encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
- encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
- encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+ encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+ else {
+ if (ei->data.catch_class) {
+ encode_value (1, p, &p);
+ encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+ } else {
+ encode_value (0, p, &p);
+ }
}
+
+ encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
+ encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
+ encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
}
if (jinfo->has_generic_jit_info) {
emit_label (acfg, label);
if (acfg->aot_opts.write_symbols) {
- MonoJumpInfo *patch_info = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
+ MonoJumpInfo *ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
+ char *debug_sym = NULL;
- if (patch_info && patch_info->type == MONO_PATCH_INFO_METHOD) {
- char *debug_sym = get_debug_sym (patch_info->data.method, "plt_", cache);
+ if (ji) {
+ switch (ji->type) {
+ case MONO_PATCH_INFO_METHOD:
+ debug_sym = get_debug_sym (ji->data.method, "plt_", cache);
+ break;
+ case MONO_PATCH_INFO_INTERNAL_METHOD:
+ debug_sym = g_strdup_printf ("plt__jit_icall_%s", ji->data.name);
+ break;
+ case MONO_PATCH_INFO_CLASS_INIT:
+ debug_sym = g_strdup_printf ("plt__class_init_%s", mono_type_get_name (&ji->data.klass->byval_arg));
+ sanitize_symbol (debug_sym);
+ break;
+ case MONO_PATCH_INFO_RGCTX_FETCH:
+ debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
+ break;
+ case MONO_PATCH_INFO_ICALL_ADDR: {
+ char *s = get_debug_sym (ji->data.method, "", cache);
+
+ 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;
+ }
- emit_local_symbol (acfg, debug_sym, NULL, TRUE);
- emit_label (acfg, debug_sym);
+ if (debug_sym) {
+ emit_local_symbol (acfg, debug_sym, NULL, TRUE);
+ emit_label (acfg, debug_sym);
+ }
}
}
opts->nodebug = TRUE;
} else if (str_begins_with (arg, "ntrampolines=")) {
opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
+ } else if (str_begins_with (arg, "tool-prefix=")) {
+ opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
} else {
fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
exit (1);
}
break;
}
+ case MONO_PATCH_INFO_VTABLE: {
+ MonoClass *klass = patch_info->data.klass;
+
+ if (klass->generic_class && !mono_generic_context_is_sharable (&klass->generic_class->context, FALSE))
+ add_generic_class (acfg, klass);
+ break;
+ }
default:
break;
}
char symbol [256];
/* Don't make GOT global so accesses to it don't need relocations */
- sprintf (symbol, acfg->got_symbol);
+ sprintf (symbol, "%s", acfg->got_symbol);
emit_section_change (acfg, ".bss", 0);
emit_alignment (acfg, 8);
emit_local_symbol (acfg, symbol, "got_end", FALSE);
emit_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->nmethods);
for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
emit_int32 (acfg, acfg->num_trampolines [i]);
{
char *command, *objfile;
char *outfile_name, *tmp_outfile_name;
+ const char *tool_prefix = acfg->aot_opts.tool_prefix ? acfg->aot_opts.tool_prefix : "";
#if defined(TARGET_AMD64)
#define AS_OPTIONS "--64"
} else {
objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
}
- command = g_strdup_printf ("as %s %s -o %s", AS_OPTIONS, acfg->tmpfname, objfile);
+ command = g_strdup_printf ("%sas %s %s -o %s", tool_prefix, AS_OPTIONS, acfg->tmpfname, objfile);
printf ("Executing the native assembler: %s\n", command);
if (system (command) != 0) {
g_free (command);
#elif defined(PLATFORM_WIN32)
command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
#else
- command = g_strdup_printf ("ld %s -shared -o %s %s.o", LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
+ command = g_strdup_printf ("%sld %s -shared -o %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
#endif
printf ("Executing the native linker: %s\n", command);
if (system (command) != 0) {
* 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.
*/
- command = g_strdup_printf ("strip --strip-symbol=\\$a --strip-symbol=\\$d %s", tmp_outfile_name);
+ command = g_strdup_printf ("%sstrip --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
printf ("Stripping the binary: %s\n", command);
if (system (command) != 0) {
g_free (tmp_outfile_name);