* Author:
* Dietmar Maurer (dietmar@ximian.com)
* Zoltan Varga (vargaz@gmail.com)
+ * Johan Lorensson (lateralusx.github@gmail.com)
*
* (C) 2002 Ximian, Inc.
* Copyright 2003-2011 Novell, Inc
#include <mono/utils/mono-rand.h>
#include <mono/utils/json.h>
#include <mono/utils/mono-threads-coop.h>
+#include <mono/profiler/mono-profiler-aot.h>
+#include <mono/utils/w32api.h>
#include "aot-compiler.h"
#include "seq-points.h"
#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
+// Use MSVC toolchain, Clang for MSVC using MSVC codegen and linker, when compiling for AMD64
+// targeting WIN32 platforms running AOT compiler on WIN32 platform with VS installation.
+#if defined(TARGET_AMD64) && defined(TARGET_WIN32) && defined(HOST_WIN32) && defined(_MSC_VER)
+#define TARGET_X86_64_WIN32_MSVC
+#endif
+
+#if defined(TARGET_X86_64_WIN32_MSVC)
+#define TARGET_WIN32_MSVC
+#endif
+
#if defined(__linux__) || defined(__native_client_codegen__)
#define RODATA_SECT ".rodata"
#elif defined(TARGET_MACH)
#define RODATA_SECT ".section __TEXT, __const"
+#elif defined(TARGET_WIN32_MSVC)
+#define RODATA_SECT ".rdata"
#else
#define RODATA_SECT ".text"
#endif
#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
#define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
+typedef struct {
+ char *name;
+ MonoImage *image;
+} ImageProfileData;
+
+typedef struct ClassProfileData ClassProfileData;
+
+typedef struct {
+ int argc;
+ ClassProfileData **argv;
+ MonoGenericInst *inst;
+} GInstProfileData;
+
+struct ClassProfileData {
+ ImageProfileData *image;
+ char *ns, *name;
+ GInstProfileData *inst;
+ MonoClass *klass;
+};
+
+typedef struct {
+ ClassProfileData *klass;
+ int id;
+ char *name;
+ int param_count;
+ char *signature;
+ GInstProfileData *inst;
+ MonoMethod *method;
+} MethodProfileData;
+
+typedef struct {
+ GHashTable *images, *classes, *ginsts, *methods;
+} ProfileData;
+
/* predefined values for static readonly fields without needed to run the .cctor */
typedef struct _ReadOnlyValue ReadOnlyValue;
struct _ReadOnlyValue {
char *outfile;
char *llvm_outfile;
char *data_outfile;
+ GList *profile_files;
gboolean save_temps;
gboolean write_symbols;
gboolean metadata_only;
int nrgctx_fetch_trampolines;
gboolean print_skipped_methods;
gboolean stats;
+ gboolean verbose;
char *tool_prefix;
char *ld_flags;
char *mtriple;
char *instances_logfile_path;
char *logfile;
gboolean dump_json;
+ gboolean profile_only;
} MonoAotOptions;
typedef enum {
int objc_selector_index, objc_selector_index_2;
GPtrArray *objc_selectors;
GHashTable *objc_selector_to_index;
+ GList *profile_data;
+ GHashTable *profile_methods;
FILE *logfile;
FILE *instances_logfile;
FILE *data_outfile;
static void
add_gsharedvt_wrappers (MonoAotCompile *acfg, MonoMethodSignature *sig, gboolean gsharedvt_in, gboolean gsharedvt_out);
+static void
+add_profile_instances (MonoAotCompile *acfg, ProfileData *data);
+
static void
aot_printf (MonoAotCompile *acfg, const gchar *format, ...)
{
#endif
+static inline gboolean
+link_shared_library (MonoAotCompile *acfg)
+{
+ return !acfg->aot_opts.static_link && !acfg->aot_opts.asm_only;
+}
+
+static inline gboolean
+add_to_global_symbol_table (MonoAotCompile *acfg)
+{
+#ifdef TARGET_WIN32_MSVC
+ return acfg->aot_opts.no_dlsym || link_shared_library (acfg);
+#else
+ return acfg->aot_opts.no_dlsym;
+#endif
+}
+
static void
emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
{
- if (acfg->aot_opts.no_dlsym) {
+ if (add_to_global_symbol_table (acfg))
g_ptr_array_add (acfg->globals, g_strdup (name));
+
+ if (acfg->aot_opts.no_dlsym) {
mono_img_writer_emit_local_symbol (acfg->w, name, NULL, func);
} else {
emit_global_inner (acfg, name, func);
#define EMIT_DWARF_INFO 1
#endif
+#ifdef TARGET_WIN32_MSVC
+#undef EMIT_DWARF_INFO
+#endif
+
#if defined(TARGET_ARM)
#define AOT_FUNC_ALIGNMENT 4
#else
#define PPC_LDX_OP "lwzx"
#endif
-#ifdef TARGET_AMD64
+#ifdef TARGET_X86_64_WIN32_MSVC
+#define AOT_TARGET_STR "AMD64 (WIN32) (MSVC codegen)"
+#elif TARGET_AMD64
#define AOT_TARGET_STR "AMD64"
#endif
#elif defined(TARGET_POWERPC)
{
guint8 buf [32];
- guint8 *code;
emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
code = buf;
MonoClass *klass = field->parent;
int i;
- for (i = 0; i < klass->field.count; ++i) {
+ int fcount = mono_class_get_field_count (klass);
+ for (i = 0; i < fcount; ++i) {
if (field == &klass->fields [i])
- return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
+ return MONO_TOKEN_FIELD_DEF | (mono_class_get_first_field_idx (klass) + 1 + i);
}
g_assert_not_reached ();
* information.
*/
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
guint32 token;
g_assert (klass->type_token);
encode_value (MONO_AOT_TYPEREF_TYPESPEC_TOKEN, p, &p);
encode_value (token, p, &p);
} else {
- MonoClass *gclass = klass->generic_class->container_class;
- MonoGenericInst *inst = klass->generic_class->context.class_inst;
+ MonoClass *gclass = mono_class_get_generic_class (klass)->container_class;
+ MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst;
static int count = 0;
guint8 *p1 = p;
/*
* The encoding of generic instances is large so emit them only once.
*/
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
guint32 token;
g_assert (klass->type_token);
case MONO_WRAPPER_PROXY_ISINST:
case MONO_WRAPPER_LDFLD:
case MONO_WRAPPER_LDFLDA:
- case MONO_WRAPPER_STFLD:
- case MONO_WRAPPER_ISINST: {
+ case MONO_WRAPPER_STFLD: {
g_assert (info);
encode_klass_ref (acfg, info->d.proxy.klass, p, &p);
break;
MonoMarshalType *info;
int i;
- if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ if (mono_class_is_auto_layout (klass))
return FALSE;
info = mono_marshal_load_type_info (klass);
memset (ctx, 0, sizeof (MonoGenericContext));
- if (method->klass->generic_container) {
- shared_context = method->klass->generic_container->context;
+ if (mono_class_is_gtd (method->klass)) {
+ shared_context = mono_class_get_generic_container (method->klass)->context;
inst = shared_context.class_inst;
args = g_new0 (MonoType*, inst->type_argc);
/* stelemref */
add_method (acfg, mono_marshal_get_stelemref ());
- if (MONO_ARCH_HAVE_TLS_GET) {
- /* Managed Allocators */
- nallocators = mono_gc_get_managed_allocator_types ();
- for (i = 0; i < nallocators; ++i) {
- if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_REGULAR)))
- add_method (acfg, m);
- if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_SLOW_PATH)))
- add_method (acfg, m);
- }
+ /* Managed Allocators */
+ nallocators = mono_gc_get_managed_allocator_types ();
+ for (i = 0; i < nallocators; ++i) {
+ if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_REGULAR)))
+ add_method (acfg, m);
+ if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_SLOW_PATH)))
+ add_method (acfg, m);
}
/* write barriers */
if (!klass->delegate || klass == mono_defaults.delegate_class || klass == mono_defaults.multicastdelegate_class)
continue;
- if (!klass->generic_container) {
+ if (!mono_class_is_gtd (klass)) {
method = mono_get_delegate_invoke (klass);
m = mono_marshal_get_delegate_invoke (method, NULL);
add_method (acfg, del_invoke);
}
}
- } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->generic_container) {
+ } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && mono_class_is_gtd (klass)) {
MonoError error;
MonoGenericContext ctx;
MonoMethod *inst, *gshared;
/* begin-invoke */
method = mono_get_delegate_begin_invoke (klass);
- create_gsharedvt_inst (acfg, method, &ctx);
+ if (method) {
+ create_gsharedvt_inst (acfg, method, &ctx);
- inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
- m = mono_marshal_get_delegate_begin_invoke (inst);
- g_assert (m->is_inflated);
+ m = mono_marshal_get_delegate_begin_invoke (inst);
+ g_assert (m->is_inflated);
- gshared = mini_get_shared_method_full (m, FALSE, TRUE);
- add_extra_method (acfg, gshared);
+ gshared = mini_get_shared_method_full (m, FALSE, TRUE);
+ add_extra_method (acfg, gshared);
+ }
/* end-invoke */
method = mono_get_delegate_end_invoke (klass);
- create_gsharedvt_inst (acfg, method, &ctx);
-
- inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ if (method) {
+ create_gsharedvt_inst (acfg, method, &ctx);
- m = mono_marshal_get_delegate_end_invoke (inst);
- g_assert (m->is_inflated);
+ inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
- gshared = mini_get_shared_method_full (m, FALSE, TRUE);
- add_extra_method (acfg, gshared);
+ m = mono_marshal_get_delegate_end_invoke (inst);
+ g_assert (m->is_inflated);
+ gshared = mini_get_shared_method_full (m, FALSE, TRUE);
+ add_extra_method (acfg, gshared);
+ }
}
}
if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
if (method->is_generic) {
// FIXME:
- } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && method->klass->generic_container) {
+ } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && mono_class_is_gtd (method->klass)) {
MonoError error;
MonoGenericContext ctx;
MonoMethod *inst, *gshared, *m;
continue;
}
- if (klass->valuetype && !klass->generic_container && can_marshal_struct (klass) &&
+ if (klass->valuetype && !mono_class_is_gtd (klass) && can_marshal_struct (klass) &&
!(klass->nested_in && strstr (klass->nested_in->name, "<PrivateImplementationDetails>") == klass->nested_in->name)) {
add_method (acfg, mono_marshal_get_struct_to_ptr (klass));
add_method (acfg, mono_marshal_get_ptr_to_struct (klass));
return TRUE;
if (klass->rank)
return has_type_vars (klass->element_class);
- if (klass->generic_class) {
- MonoGenericContext *context = &klass->generic_class->context;
+ if (mono_class_is_ginst (klass)) {
+ MonoGenericContext *context = &mono_class_get_generic_class (klass)->context;
if (context->class_inst) {
int i;
return TRUE;
}
}
- if (klass->generic_container)
+ if (mono_class_is_gtd (klass))
return TRUE;
return FALSE;
}
mono_class_init (klass);
- if (klass->generic_class && klass->generic_class->context.class_inst->is_open)
+ if (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->context.class_inst->is_open)
return;
if (has_type_vars (klass))
return;
- if (!klass->generic_class && !klass->rank)
+ if (!mono_class_is_ginst (klass) && !klass->rank)
return;
if (mono_class_has_failure (klass))
* Use gsharedvt for generic collections with vtype arguments to avoid code blowup.
* Enable this only for some classes since gsharedvt might not support all methods.
*/
- if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->image == mono_defaults.corlib && klass->generic_class && klass->generic_class->context.class_inst && is_vt_inst (klass->generic_class->context.class_inst) &&
+ if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->image == mono_defaults.corlib && mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->context.class_inst && is_vt_inst (mono_class_get_generic_class (klass)->context.class_inst) &&
(!strcmp (klass->name, "Dictionary`2") || !strcmp (klass->name, "List`1") || !strcmp (klass->name, "ReadOnlyCollection`1")))
use_gsharedvt = TRUE;
*/
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, "IReadOnlyList`1"))) {
- MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
MonoClass *array_class = mono_bounded_array_class_get (tclass, 1, FALSE);
gpointer iter;
char *name_prefix;
break;
}
g_assert (nclass);
- nclass = mono_class_inflate_generic_class_checked (nclass, mono_generic_class_get_context (klass->generic_class), &error);
+ nclass = mono_class_inflate_generic_class_checked (nclass, mono_generic_class_get_context (mono_class_get_generic_class (klass)), &error);
mono_error_assert_ok (&error); /* FIXME don't swallow the error */
add_generic_class (acfg, nclass, FALSE, "ICollection<T>");
}
/* Add an instance of GenericComparer<T> which is created dynamically by Comparer<T> */
if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) {
MonoError error;
- MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
MonoClass *icomparable, *gcomparer, *icomparable_inst;
MonoGenericContext ctx;
MonoType *args [16];
/* Add an instance of GenericEqualityComparer<T> which is created dynamically by EqualityComparer<T> */
if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "EqualityComparer`1")) {
MonoError error;
- MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
MonoClass *iface, *gcomparer, *iface_inst;
MonoGenericContext ctx;
MonoType *args [16];
/* Add an instance of EnumComparer<T> which is created dynamically by EqualityComparer<T> for enums */
if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "EqualityComparer`1")) {
MonoClass *enum_comparer;
- MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
MonoGenericContext ctx;
MonoType *args [16];
/* Add an instance of ObjectComparer<T> which is created dynamically by Comparer<T> for enums */
if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) {
MonoClass *comparer;
- MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
MonoGenericContext ctx;
MonoType *args [16];
g_free (type_argv);
}
- if (method->is_generic || method->klass->generic_container)
+ if (method->is_generic || mono_class_is_gtd (method->klass))
declaring_method = method;
else
declaring_method = mono_method_get_declaring_generic_method (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)))
+ if (direct_callable && !(!callee_cfg->has_got_slots && mono_class_is_before_field_init (callee_cfg->method->klass)))
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 ?
encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
break;
case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
- case MONO_PATCH_INFO_JIT_TLS_ID:
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
case MONO_PATCH_INFO_GC_NURSERY_START:
case MONO_PATCH_INFO_GC_NURSERY_BITS:
encode_method_ref (acfg, patch_info->data.method, p, &p);
break;
case MONO_PATCH_INFO_AOT_JIT_INFO:
+ case MONO_PATCH_INFO_GET_TLS_TRAMP:
+ case MONO_PATCH_INFO_SET_TLS_TRAMP:
encode_value (patch_info->data.index, p, &p);
break;
case MONO_PATCH_INFO_INTERNAL_METHOD:
case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
encode_signature (acfg, (MonoMethodSignature*)patch_info->data.target, p, &p);
break;
- case MONO_PATCH_INFO_TLS_OFFSET:
- encode_value (GPOINTER_TO_INT (patch_info->data.target), p, &p);
- break;
case MONO_PATCH_INFO_GSHAREDVT_CALL:
encode_signature (acfg, (MonoMethodSignature*)patch_info->data.gsharedvt->sig, p, &p);
encode_method_ref (acfg, patch_info->data.gsharedvt->method, p, &p);
encode_method_ref (acfg, patch_info->data.virt_method->method, p, &p);
break;
case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
+ case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
break;
default:
g_warning ("unable to handle jump info %d", patch_info->type);
}
mono_class_has_finalizer (klass);
+ if (mono_class_has_failure (klass))
+ cant_encode = TRUE;
- if (klass->generic_container || cant_encode) {
+ if (mono_class_is_gtd (klass) || cant_encode) {
encode_value (-1, p, &p);
} else {
+ gboolean has_nested = mono_class_get_nested_classes_property (klass) != NULL;
encode_value (klass->vtable_size, p, &p);
- encode_value ((klass->generic_container ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
+ encode_value ((mono_class_is_gtd (klass) ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (has_nested ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
if (klass->has_cctor)
encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
if (klass->has_finalize)
opts->llvm_only = TRUE;
} else if (str_begins_with (arg, "data-outfile=")) {
opts->data_outfile = g_strdup (arg + strlen ("data-outfile="));
+ } else if (str_begins_with (arg, "profile=")) {
+ opts->profile_files = g_list_append (opts->profile_files, g_strdup (arg + strlen ("profile=")));
+ } else if (!strcmp (arg, "profile-only")) {
+ opts->profile_only = TRUE;
+ } else if (!strcmp (arg, "verbose")) {
+ opts->verbose = TRUE;
} else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) {
printf ("Supported options for --aot:\n");
printf (" outfile=\n");
printf (" stats\n");
printf (" dump\n");
printf (" info\n");
+ printf (" verbose\n");
printf (" help/?\n");
exit (0);
} else {
case MONO_WRAPPER_LDFLD:
case MONO_WRAPPER_LDFLDA:
case MONO_WRAPPER_STELEMREF:
- case MONO_WRAPPER_ISINST:
case MONO_WRAPPER_PROXY_ISINST:
case MONO_WRAPPER_ALLOC:
case MONO_WRAPPER_REMOTING_INVOKE:
if (!MONO_TYPE_ISSTRUCT (t))
return TRUE;
klass = mono_class_from_mono_type (t);
- orig_ctx = &klass->generic_class->context;
+ orig_ctx = &mono_class_get_generic_class (klass)->context;
inst = orig_ctx->class_inst;
if (inst) {
if (method->wrapper_type == MONO_WRAPPER_COMINTEROP)
return;
+ if (acfg->aot_opts.profile_only && !method->is_inflated && !g_hash_table_lookup (acfg->profile_methods, method))
+ return;
+
InterlockedIncrement (&acfg->stats.mcount);
#if 0
- if (method->is_generic || method->klass->generic_container) {
+ if (method->is_generic || mono_class_is_gtd (method->klass)) {
InterlockedIncrement (&acfg->stats.genericcount);
return;
}
flags = (JitFlags)(flags | JIT_FLAG_LLVM_ONLY | JIT_FLAG_EXPLICIT_NULL_CHECKS);
if (acfg->aot_opts.no_direct_calls)
flags = (JitFlags)(flags | JIT_FLAG_NO_DIRECT_ICALLS);
+ if (acfg->aot_opts.direct_pinvoke)
+ flags = (JitFlags)(flags | JIT_FLAG_DIRECT_PINVOKE);
jit_timer = mono_time_track_start ();
cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0, index);
* encountered.
*/
depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
- if (!acfg->aot_opts.no_instances && depth < 32) {
+ if (!acfg->aot_opts.no_instances && depth < 32 && mono_aot_mode_is_full (&acfg->aot_opts)) {
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
switch (patch_info->type) {
case MONO_PATCH_INFO_RGCTX_FETCH:
if (!m)
break;
- if (m->is_inflated) {
+ if (m->is_inflated && mono_aot_mode_is_full (&acfg->aot_opts)) {
if (!(mono_class_generic_sharing_enabled (m->klass) &&
mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) &&
(!method_has_type_vars (m) || mono_method_is_generic_sharable_full (m, TRUE, TRUE, FALSE))) {
case MONO_PATCH_INFO_VTABLE: {
MonoClass *klass = patch_info->data.klass;
- if (klass->generic_class && !mini_class_is_generic_sharable (klass))
+ if (mono_class_is_ginst (klass) && !mini_class_is_generic_sharable (klass))
add_generic_class_with_depth (acfg, klass, depth + 5, "vtable");
break;
}
MonoClass *klass = patch_info->data.field->parent;
/* The .cctor needs to run at runtime. */
- if (klass->generic_class && !mono_generic_context_is_sharable_full (&klass->generic_class->context, FALSE, FALSE) && mono_class_get_cctor (klass))
+ if (mono_class_is_ginst (klass) && !mono_generic_context_is_sharable_full (&mono_class_get_generic_class (klass)->context, FALSE, FALSE) && mono_class_get_cctor (klass))
add_extra_method_with_depth (acfg, mono_class_get_cctor (klass), depth + 1);
break;
}
InterlockedIncrement (&acfg->stats.ccount);
}
-static gsize WINAPI
+static mono_thread_start_return_t WINAPI
compile_thread_main (gpointer user_data)
{
MonoDomain *domain = ((MonoDomain **)user_data) [0];
return 0;
}
-
-static void
-load_profile_files (MonoAotCompile *acfg)
-{
- FILE *infile;
- char *tmp;
- int file_index, res, method_index, i;
- char ver [256];
- guint32 token;
- GList *unordered, *l;
- gboolean found;
-
- file_index = 0;
- while (TRUE) {
- tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%d", g_get_home_dir (), acfg->image->assembly_name, file_index);
-
- if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) {
- g_free (tmp);
- break;
- }
-
- infile = fopen (tmp, "r");
- g_assert (infile);
-
- printf ("Using profile data file '%s'\n", tmp);
- g_free (tmp);
-
- file_index ++;
-
- res = fscanf (infile, "%32s\n", ver);
- if ((res != 1) || strcmp (ver, "#VER:2") != 0) {
- printf ("Profile file has wrong version or invalid.\n");
- fclose (infile);
- continue;
- }
-
- while (TRUE) {
- char name [1024];
- MonoMethodDesc *desc;
- MonoMethod *method;
-
- if (fgets (name, 1023, infile) == NULL)
- break;
-
- /* Kill the newline */
- if (strlen (name) > 0)
- name [strlen (name) - 1] = '\0';
-
- desc = mono_method_desc_new (name, TRUE);
-
- method = mono_method_desc_search_in_image (desc, acfg->image);
-
- if (method && mono_method_get_token (method)) {
- token = mono_method_get_token (method);
- method_index = mono_metadata_token_index (token) - 1;
-
- 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);
- }
- }
- fclose (infile);
- }
-
- /* Add missing methods */
- unordered = NULL;
- 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);
- for (l = unordered; l; l = l->next)
- g_ptr_array_add (acfg->method_order, l->data);
-}
/* Used by the LLVM backend */
guint32
static int
execute_system (const char * command)
{
- int status;
+ int status = 0;
-#if _WIN32
+#if HOST_WIN32
// We need an extra set of quotes around the whole command to properly handle commands
// with spaces since internally the command is called through "cmd /c.
- command = g_strdup_printf ("\"%s\"", command);
+ char * quoted_command = g_strdup_printf ("\"%s\"", command);
- int size = MultiByteToWideChar (CP_UTF8, 0 , command , -1, NULL , 0);
+ int size = MultiByteToWideChar (CP_UTF8, 0 , quoted_command , -1, NULL , 0);
wchar_t* wstr = g_malloc (sizeof (wchar_t) * size);
- MultiByteToWideChar (CP_UTF8, 0, command, -1, wstr , size);
+ MultiByteToWideChar (CP_UTF8, 0, quoted_command, -1, wstr , size);
status = _wsystem (wstr);
g_free (wstr);
- g_free (command);
+ g_free (quoted_command);
#elif defined (HAVE_SYSTEM)
status = system (command);
#else
emit_section_change (acfg, ".text", 1);
emit_alignment_code (acfg, 8);
emit_info_symbol (acfg, symbol);
- emit_local_symbol (acfg, symbol, "method_addresses_end", TRUE);
+ if (acfg->aot_opts.write_symbols)
+ emit_local_symbol (acfg, symbol, "method_addresses_end", TRUE);
emit_unset_mode (acfg);
if (acfg->need_no_dead_strip)
fprintf (acfg->fp, " .no_dead_strip %s\n", symbol);
sig = mono_method_signature (method);
- if (method->klass->generic_class)
- class_ginst = method->klass->generic_class->context.class_inst;
+ if (mono_class_is_ginst (method->klass))
+ class_ginst = mono_class_get_generic_class (method->klass)->context.class_inst;
if (method->is_inflated)
ginst = ((MonoMethodInflated*)method)->context.method_inst;
if (!method->wrapper_type) {
char *full_name;
- if (klass->generic_class)
- full_name = mono_type_full_name (&klass->generic_class->container_class->byval_arg);
+ if (mono_class_is_ginst (klass))
+ full_name = mono_type_full_name (&mono_class_get_generic_class (klass)->container_class->byval_arg);
else
full_name = mono_type_full_name (&klass->byval_arg);
#else
emit_section_change (acfg, ".bss", 0);
emit_alignment (acfg, 8);
- emit_local_symbol (acfg, symbol, "got_end", FALSE);
+ if (acfg->aot_opts.write_symbols)
+ emit_local_symbol (acfg, symbol, "got_end", FALSE);
emit_label (acfg, symbol);
if (acfg->llvm)
emit_info_symbol (acfg, "jit_got");
struct GlobalsTableEntry *next;
} GlobalsTableEntry;
+#ifdef TARGET_WIN32_MSVC
+#define DLL_ENTRY_POINT "DllMain"
+
+static void
+emit_library_info (MonoAotCompile *acfg)
+{
+ // Only include for shared libraries linked directly from generated object.
+ if (link_shared_library (acfg)) {
+ char *name = NULL;
+ char symbol [MAX_SYMBOL_SIZE];
+
+ // Ask linker to export all global symbols.
+ emit_section_change (acfg, ".drectve", 0);
+ for (guint i = 0; i < acfg->globals->len; ++i) {
+ name = (char *)g_ptr_array_index (acfg->globals, i);
+ g_assert (name != NULL);
+ sprintf_s (symbol, MAX_SYMBOL_SIZE, " /EXPORT:%s", name);
+ emit_string (acfg, symbol);
+ }
+
+ // Emit DLLMain function, needed by MSVC linker for DLL's.
+ // NOTE, DllMain should not go into exports above.
+ emit_section_change (acfg, ".text", 0);
+ emit_global (acfg, DLL_ENTRY_POINT, TRUE);
+ emit_label (acfg, DLL_ENTRY_POINT);
+
+ // Simple implementation of DLLMain, just returning TRUE.
+ // For more information about DLLMain: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
+ fprintf (acfg->fp, "movl $1, %%eax\n");
+ fprintf (acfg->fp, "ret\n");
+
+ // Inform linker about our dll entry function.
+ emit_section_change (acfg, ".drectve", 0);
+ emit_string (acfg, "/ENTRY:" DLL_ENTRY_POINT);
+ return;
+ }
+}
+
+#else
+
+static inline void
+emit_library_info (MonoAotCompile *acfg)
+{
+ return;
+}
+#endif
+
static void
emit_globals (MonoAotCompile *acfg)
{
if (!acfg->aot_opts.static_link)
return;
+
if (acfg->aot_opts.llvm_only) {
g_assert (acfg->globals->len == 0);
return;
}
*/
- if (method->is_generic || method->klass->generic_container)
+ if (method->is_generic || mono_class_is_gtd (method->klass))
/* Compile the ref shared version instead */
method = mini_get_shared_method (method);
method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
report_loader_error (acfg, &error, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (&error));
- if (method->is_generic || method->klass->generic_container) {
+ if (method->is_generic || mono_class_is_gtd (method->klass)) {
MonoMethod *gshared;
gshared = mini_get_shared_method_full (method, TRUE, TRUE);
}
}
- add_generic_instances (acfg);
+ if (mono_aot_mode_is_full (&acfg->aot_opts))
+ add_generic_instances (acfg);
if (mono_aot_mode_is_full (&acfg->aot_opts))
add_wrappers (acfg);
GPtrArray *frag;
int len, j;
GPtrArray *threads;
- HANDLE handle;
+ MonoThreadHandle *thread_handle;
gpointer *user_data;
MonoMethod **methods;
user_data [1] = acfg;
user_data [2] = frag;
- handle = mono_threads_create_thread (compile_thread_main, (gpointer) user_data, NULL, NULL);
- g_ptr_array_add (threads, handle);
+ thread_handle = mono_threads_create_thread (compile_thread_main, (gpointer) user_data, NULL, NULL);
+ g_ptr_array_add (threads, thread_handle);
}
g_free (methods);
for (i = 0; i < threads->len; ++i) {
- WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE);
+ mono_thread_info_wait_one_handle (g_ptr_array_index (threads, i), MONO_INFINITE_WAIT, FALSE);
mono_threads_close_thread_handle (g_ptr_array_index (threads, i));
}
} else {
/* Compile methods added by compile_method () or all methods if nthreads == 0 */
for (i = methods_len; i < acfg->methods->len; ++i) {
- /* This can new methods to acfg->methods */
+ /* This can add new methods to acfg->methods */
compile_method (acfg, (MonoMethod *)g_ptr_array_index (acfg->methods, i));
}
}
const char *tool_prefix = acfg->aot_opts.tool_prefix ? acfg->aot_opts.tool_prefix : "";
char *ld_flags = acfg->aot_opts.ld_flags ? acfg->aot_opts.ld_flags : g_strdup("");
-#if defined(TARGET_AMD64) && !defined(TARGET_MACH)
+#ifdef TARGET_WIN32_MSVC
+#define AS_OPTIONS "-c -x assembler"
+#elif defined(TARGET_AMD64) && !defined(TARGET_MACH)
#define AS_OPTIONS "--64"
#elif defined(TARGET_POWERPC64)
#define AS_OPTIONS "-a64 -mppc64"
#endif
#elif defined(TARGET_OSX)
#define AS_NAME "clang"
+#elif defined(TARGET_WIN32_MSVC)
+#define AS_NAME "clang.exe"
#else
#define AS_NAME "as"
#endif
+#ifdef TARGET_WIN32_MSVC
+#define AS_OBJECT_FILE_SUFFIX "obj"
+#else
+#define AS_OBJECT_FILE_SUFFIX "o"
+#endif
+
#if defined(sparc)
#define LD_NAME "ld"
#define LD_OPTIONS "-shared -G"
#elif defined(TARGET_AMD64) && defined(TARGET_MACH)
#define LD_NAME "clang"
#define LD_OPTIONS "--shared"
+#elif defined(TARGET_WIN32_MSVC)
+#define LD_NAME "link.exe"
+#define LD_OPTIONS "/DLL /MACHINE:X64 /NOLOGO"
#elif defined(TARGET_WIN32) && !defined(TARGET_ANDROID)
#define LD_NAME "gcc"
#define LD_OPTIONS "-shared"
if (acfg->aot_opts.outfile)
objfile = g_strdup_printf ("%s", acfg->aot_opts.outfile);
else
- objfile = g_strdup_printf ("%s.o", acfg->image->name);
+ objfile = g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->image->name);
} else {
- objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
+ objfile = g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname);
}
#ifdef TARGET_OSX
if (acfg->aot_opts.llvm_only)
ld_flags = g_strdup_printf ("%s %s", ld_flags, "-lstdc++");
-#ifdef LD_NAME
+#ifdef TARGET_WIN32_MSVC
+ g_assert (tmp_outfile_name != NULL);
+ g_assert (objfile != NULL);
+ command = g_strdup_printf ("\"%s%s\" %s %s /OUT:\"%s\" \"%s\"", tool_prefix, LD_NAME, LD_OPTIONS,
+ ld_flags, tmp_outfile_name, objfile);
+#elif defined(LD_NAME)
command = g_strdup_printf ("%s%s %s -o %s %s %s %s", tool_prefix, LD_NAME, LD_OPTIONS,
wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
- wrap_path (g_strdup_printf ("%s.o", acfg->tmpfname)), ld_flags);
+ wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
#else
// Default (linux)
if (acfg->aot_opts.tool_prefix) {
/* Cross compiling */
command = g_strdup_printf ("\"%sld\" %s -shared -o %s %s %s %s", tool_prefix, LD_OPTIONS,
wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
- wrap_path (g_strdup_printf ("%s.o", acfg->tmpfname)), ld_flags);
+ wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
} else {
char *args = g_strdup_printf ("%s -shared -o %s %s %s %s", LD_OPTIONS,
wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
- wrap_path (g_strdup_printf ("%s.o", acfg->tmpfname)), ld_flags);
+ wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
- if (acfg->llvm) {
+ if (acfg->aot_opts.llvm_only) {
command = g_strdup_printf ("clang++ %s", args);
} else {
command = g_strdup_printf ("\"%sld\" %s", tool_prefix, args);
}
g_free (args);
}
-
#endif
aot_printf (acfg, "Executing the native linker: %s\n", command);
if (execute_system (command) != 0) {
return 0;
}
-static void init_got_info (GotInfo *info)
+static guint8
+profread_byte (FILE *infile)
+{
+ guint8 i;
+ int res;
+
+ res = fread (&i, 1, 1, infile);
+ g_assert (res == 1);
+ return i;
+}
+
+static int
+profread_int (FILE *infile)
+{
+ int i, res;
+
+ res = fread (&i, 4, 1, infile);
+ g_assert (res == 1);
+ return i;
+}
+
+static char*
+profread_string (FILE *infile)
+{
+ int len, res;
+ char buf [1024];
+ char *pbuf;
+
+ len = profread_int (infile);
+ if (len + 1 > 1024)
+ pbuf = g_malloc (len + 1);
+ else
+ pbuf = buf;
+ res = fread (pbuf, 1, len, infile);
+ g_assert (res == len);
+ pbuf [len] = '\0';
+ if (pbuf == buf)
+ return g_strdup (buf);
+ else
+ return pbuf;
+}
+
+static void
+load_profile_file (MonoAotCompile *acfg, char *filename)
+{
+ FILE *infile;
+ char buf [1024];
+ int res, len, version;
+ char magic [32];
+
+ infile = fopen (filename, "r");
+ if (!infile) {
+ fprintf (stderr, "Unable to open file '%s': %s.\n", filename, strerror (errno));
+ exit (1);
+ }
+
+ printf ("Using profile data file '%s'\n", filename);
+
+ sprintf (magic, AOT_PROFILER_MAGIC);
+ len = strlen (magic);
+ res = fread (buf, 1, len, infile);
+ magic [len] = '\0';
+ buf [len] = '\0';
+ if ((res != len) || strcmp (buf, magic) != 0) {
+ printf ("Profile file has wrong header: '%s'.\n", buf);
+ fclose (infile);
+ exit (1);
+ }
+ guint32 expected_version = (AOT_PROFILER_MAJOR_VERSION << 16) | AOT_PROFILER_MINOR_VERSION;
+ version = profread_int (infile);
+ if (version != expected_version) {
+ printf ("Profile file has wrong version 0x%4x, expected 0x%4x.\n", version, expected_version);
+ fclose (infile);
+ exit (1);
+ }
+
+ ProfileData *data = g_new0 (ProfileData, 1);
+ data->images = g_hash_table_new (NULL, NULL);
+ data->classes = g_hash_table_new (NULL, NULL);
+ data->ginsts = g_hash_table_new (NULL, NULL);
+ data->methods = g_hash_table_new (NULL, NULL);
+
+ while (TRUE) {
+ int type = profread_byte (infile);
+ int id = profread_int (infile);
+
+ if (type == AOTPROF_RECORD_NONE)
+ break;
+
+ switch (type) {
+ case AOTPROF_RECORD_IMAGE: {
+ ImageProfileData *idata = g_new0 (ImageProfileData, 1);
+ idata->name = profread_string (infile);
+ char *mvid = profread_string (infile);
+ g_free (mvid);
+ g_hash_table_insert (data->images, GINT_TO_POINTER (id), idata);
+ break;
+ }
+ case AOTPROF_RECORD_GINST: {
+ int i;
+ int len = profread_int (infile);
+
+ GInstProfileData *gdata = g_new0 (GInstProfileData, 1);
+ gdata->argc = len;
+ gdata->argv = g_new0 (ClassProfileData*, len);
+
+ for (i = 0; i < len; ++i) {
+ int class_id = profread_int (infile);
+
+ gdata->argv [i] = g_hash_table_lookup (data->classes, GINT_TO_POINTER (class_id));
+ g_assert (gdata->argv [i]);
+ }
+ g_hash_table_insert (data->ginsts, GINT_TO_POINTER (id), gdata);
+ break;
+ }
+ case AOTPROF_RECORD_TYPE: {
+ int type = profread_byte (infile);
+
+ switch (type) {
+ case MONO_TYPE_CLASS: {
+ int image_id = profread_int (infile);
+ int ginst_id = profread_int (infile);
+ char *class_name = profread_string (infile);
+
+ ImageProfileData *image = g_hash_table_lookup (data->images, GINT_TO_POINTER (image_id));
+ g_assert (image);
+
+ char *p = strrchr (class_name, '.');
+ g_assert (p);
+ *p = '\0';
+
+ ClassProfileData *cdata = g_new0 (ClassProfileData, 1);
+ cdata->image = image;
+ cdata->ns = g_strdup (class_name);
+ cdata->name = g_strdup (p + 1);
+
+ if (ginst_id != -1) {
+ cdata->inst = g_hash_table_lookup (data->ginsts, GINT_TO_POINTER (ginst_id));
+ g_assert (cdata->inst);
+ }
+ g_free (class_name);
+
+ g_hash_table_insert (data->classes, GINT_TO_POINTER (id), cdata);
+ break;
+ }
+#if 0
+ case MONO_TYPE_SZARRAY: {
+ int elem_id = profread_int (infile);
+ // FIXME:
+ break;
+ }
+#endif
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+ }
+ case AOTPROF_RECORD_METHOD: {
+ int class_id = profread_int (infile);
+ int ginst_id = profread_int (infile);
+ int param_count = profread_int (infile);
+ char *method_name = profread_string (infile);
+ char *sig = profread_string (infile);
+
+ ClassProfileData *klass = g_hash_table_lookup (data->classes, GINT_TO_POINTER (class_id));
+ g_assert (klass);
+
+ MethodProfileData *mdata = g_new0 (MethodProfileData, 1);
+ mdata->id = id;
+ mdata->klass = klass;
+ mdata->name = method_name;
+ mdata->signature = sig;
+ mdata->param_count = param_count;
+
+ if (ginst_id != -1) {
+ mdata->inst = g_hash_table_lookup (data->ginsts, GINT_TO_POINTER (ginst_id));
+ g_assert (mdata->inst);
+ }
+ g_hash_table_insert (data->methods, GINT_TO_POINTER (id), mdata);
+ break;
+ }
+ default:
+ printf ("%d\n", type);
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ acfg->profile_data = g_list_append (acfg->profile_data, data);
+}
+
+static void
+resolve_class (ClassProfileData *cdata);
+
+static void
+resolve_ginst (GInstProfileData *inst_data)
+{
+ int i;
+
+ if (inst_data->inst)
+ return;
+
+ for (i = 0; i < inst_data->argc; ++i) {
+ resolve_class (inst_data->argv [i]);
+ if (!inst_data->argv [i]->klass)
+ return;
+ }
+ MonoType **args = g_new0 (MonoType*, inst_data->argc);
+ for (i = 0; i < inst_data->argc; ++i)
+ args [i] = &inst_data->argv [i]->klass->byval_arg;
+
+ inst_data->inst = mono_metadata_get_generic_inst (inst_data->argc, args);
+}
+
+static void
+resolve_class (ClassProfileData *cdata)
+{
+ MonoError error;
+ MonoClass *klass;
+
+ if (!cdata->image->image)
+ return;
+
+ klass = mono_class_from_name_checked (cdata->image->image, cdata->ns, cdata->name, &error);
+ if (!klass) {
+ //printf ("[%s] %s.%s\n", cdata->image->name, cdata->ns, cdata->name);
+ return;
+ }
+ if (cdata->inst) {
+ resolve_ginst (cdata->inst);
+ if (!cdata->inst->inst)
+ return;
+ MonoGenericContext ctx;
+
+ memset (&ctx, 0, sizeof (ctx));
+ ctx.class_inst = cdata->inst->inst;
+ cdata->klass = mono_class_inflate_generic_class_checked (klass, &ctx, &error);
+ } else {
+ cdata->klass = klass;
+ }
+}
+
+/*
+ * Resolve the profile data to the corresponding loaded classes/methods etc. if possible.
+ */
+static void
+resolve_profile_data (MonoAotCompile *acfg, ProfileData *data)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ int i;
+
+ if (!data)
+ return;
+
+ /* Images */
+ GPtrArray *assemblies = mono_domain_get_assemblies (mono_get_root_domain (), FALSE);
+ g_hash_table_iter_init (&iter, data->images);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ ImageProfileData *idata = (ImageProfileData*)value;
+
+ for (i = 0; i < assemblies->len; ++i) {
+ MonoAssembly *ass = g_ptr_array_index (assemblies, i);
+
+ if (!strcmp (ass->aname.name, idata->name)) {
+ idata->image = ass->image;
+ break;
+ }
+ }
+ }
+ g_ptr_array_free (assemblies, TRUE);
+
+ /* Classes */
+ g_hash_table_iter_init (&iter, data->classes);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ ClassProfileData *cdata = (ClassProfileData*)value;
+
+ if (!cdata->image->image) {
+ if (acfg->aot_opts.verbose)
+ printf ("Unable to load class '%s.%s' because its image '%s' is not loaded.\n", cdata->ns, cdata->name, cdata->image->name);
+ continue;
+ }
+
+ resolve_class (cdata);
+ /*
+ if (cdata->klass)
+ printf ("%s %s %s\n", cdata->ns, cdata->name, mono_class_full_name (cdata->klass));
+ */
+ }
+
+ /* Methods */
+ g_hash_table_iter_init (&iter, data->methods);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ MethodProfileData *mdata = (MethodProfileData*)value;
+ MonoClass *klass;
+ MonoMethod *m;
+ gpointer miter;
+
+ resolve_class (mdata->klass);
+ klass = mdata->klass->klass;
+ if (!klass) {
+ if (acfg->aot_opts.verbose)
+ printf ("Unable to load method '%s' because its class '%s.%s' is not loaded.\n", mdata->name, mdata->klass->ns, mdata->klass->name);
+ continue;
+ }
+ miter = NULL;
+ while ((m = mono_class_get_methods (klass, &miter))) {
+ MonoError error;
+
+ if (strcmp (m->name, mdata->name))
+ continue;
+ MonoMethodSignature *sig = mono_method_signature (m);
+ if (!sig)
+ continue;
+ if (sig->param_count != mdata->param_count)
+ continue;
+ if (mdata->inst) {
+ resolve_ginst (mdata->inst);
+ if (!mdata->inst->inst)
+ continue;
+ MonoGenericContext ctx;
+
+ memset (&ctx, 0, sizeof (ctx));
+ ctx.method_inst = mdata->inst->inst;
+
+ m = mono_class_inflate_generic_method_checked (m, &ctx, &error);
+ if (!m)
+ continue;
+ sig = mono_method_signature_checked (m, &error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error);
+ continue;
+ }
+ }
+ char *sig_str = mono_signature_full_name (sig);
+ gboolean match = !strcmp (sig_str, mdata->signature);
+ g_free (sig_str);
+ if (!match)
+
+ continue;
+ //printf ("%s\n", mono_method_full_name (m, 1));
+ mdata->method = m;
+ break;
+ }
+ if (!mdata->method) {
+ if (acfg->aot_opts.verbose)
+ printf ("Unable to load method '%s' from class '%s', not found.\n", mdata->name, mono_class_full_name (klass));
+ }
+ }
+}
+
+static gboolean
+inst_references_image (MonoGenericInst *inst, MonoImage *image)
+{
+ int i;
+
+ for (i = 0; i < inst->type_argc; ++i) {
+ MonoClass *k = mono_class_from_mono_type (inst->type_argv [i]);
+ if (k->image == image)
+ return TRUE;
+ if (mono_class_is_ginst (k)) {
+ MonoGenericInst *kinst = mono_class_get_context (k)->class_inst;
+ if (inst_references_image (kinst, image))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static gboolean
+is_local_inst (MonoGenericInst *inst, MonoImage *image)
+{
+ int i;
+
+ for (i = 0; i < inst->type_argc; ++i) {
+ MonoClass *k = mono_class_from_mono_type (inst->type_argv [i]);
+ if (!MONO_TYPE_IS_PRIMITIVE (inst->type_argv [i]) && k->image != image)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+add_profile_instances (MonoAotCompile *acfg, ProfileData *data)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ int count = 0;
+
+ if (!data)
+ return;
+
+ if (acfg->aot_opts.profile_only) {
+ /* Add methods referenced by the profile */
+ g_hash_table_iter_init (&iter, data->methods);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ MethodProfileData *mdata = (MethodProfileData*)value;
+ MonoMethod *m = mdata->method;
+
+ if (!m)
+ continue;
+ if (m->is_inflated)
+ continue;
+ add_extra_method (acfg, m);
+ g_hash_table_insert (acfg->profile_methods, m, m);
+ count ++;
+ }
+ }
+
+ /*
+ * Add method instances 'related' to this assembly to the AOT image.
+ */
+ g_hash_table_iter_init (&iter, data->methods);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ MethodProfileData *mdata = (MethodProfileData*)value;
+ MonoMethod *m = mdata->method;
+ MonoGenericContext *ctx;
+
+ if (!m)
+ continue;
+ if (!m->is_inflated)
+ continue;
+
+ ctx = mono_method_get_context (m);
+ /* For simplicity, add instances which reference the assembly we are compiling */
+ if (((ctx->class_inst && inst_references_image (ctx->class_inst, acfg->image)) ||
+ (ctx->method_inst && inst_references_image (ctx->method_inst, acfg->image))) &&
+ !mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) {
+ //printf ("%s\n", mono_method_full_name (m, TRUE));
+ add_extra_method (acfg, m);
+ count ++;
+ } else if (m->klass->image == acfg->image &&
+ ((ctx->class_inst && is_local_inst (ctx->class_inst, acfg->image)) ||
+ (ctx->method_inst && is_local_inst (ctx->method_inst, acfg->image))) &&
+ !mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) {
+ /* Add instances where the gtd is in the assembly and its inflated with types from this assembly or corlib */
+ //printf ("%s\n", mono_method_full_name (m, TRUE));
+ add_extra_method (acfg, m);
+ count ++;
+ }
+ /*
+ * FIXME: We might skip some instances, for example:
+ * Foo<Bar> won't be compiled when compiling Foo's assembly since it doesn't match the first case,
+ * and it won't be compiled when compiling Bar's assembly if Foo's assembly is not loaded.
+ */
+ }
+
+ printf ("Added %d methods from profile.\n", count);
+}
+
+static void
+init_got_info (GotInfo *info)
{
int i;
acfg->plt_entry_debug_sym_cache = g_hash_table_new (g_str_hash, g_str_equal);
acfg->gsharedvt_in_signatures = g_hash_table_new ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal);
acfg->gsharedvt_out_signatures = g_hash_table_new ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal);
+ acfg->profile_methods = g_hash_table_new (NULL, NULL);
mono_os_mutex_init_recursive (&acfg->mutex);
init_got_info (&acfg->got_info);
get_got_offset (acfg, TRUE, ji);
ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
- ji->type = MONO_PATCH_INFO_JIT_TLS_ID;
+ ji->type = MONO_PATCH_INFO_AOT_MODULE;
get_got_offset (acfg, FALSE, ji);
get_got_offset (acfg, TRUE, ji);
ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
- ji->type = MONO_PATCH_INFO_AOT_MODULE;
+ ji->type = MONO_PATCH_INFO_GC_NURSERY_BITS;
get_got_offset (acfg, FALSE, ji);
get_got_offset (acfg, TRUE, ji);
+ for (i = 0; i < TLS_KEY_NUM; i++) {
+ ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
+ ji->type = MONO_PATCH_INFO_GET_TLS_TRAMP;
+ ji->data.index = i;
+ get_got_offset (acfg, FALSE, ji);
+ get_got_offset (acfg, TRUE, ji);
+
+ ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
+ ji->type = MONO_PATCH_INFO_SET_TLS_TRAMP;
+ ji->data.index = i;
+ get_got_offset (acfg, FALSE, ji);
+ get_got_offset (acfg, TRUE, ji);
+ }
+
ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
- ji->type = MONO_PATCH_INFO_GC_NURSERY_BITS;
+ ji->type = MONO_PATCH_INFO_JIT_THREAD_ATTACH;
get_got_offset (acfg, FALSE, ji);
get_got_offset (acfg, TRUE, ji);
}
}
- load_profile_files (acfg);
+ if (acfg->aot_opts.profile_files) {
+ GList *l;
+
+ for (l = acfg->aot_opts.profile_files; l; l = l->next) {
+ load_profile_file (acfg, (char*)l->data);
+ }
+ }
+
+ {
+ int method_index;
+
+ for (method_index = 0; method_index < acfg->image->tables [MONO_TABLE_METHOD].rows; ++method_index) {
+ g_ptr_array_add (acfg->method_order,GUINT_TO_POINTER (method_index));
+ }
+ }
acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ntrampolines : 0;
#ifdef MONO_ARCH_GSHARED_SUPPORTED
if (!res)
return 1;
+ {
+ GList *l;
+
+ for (l = acfg->profile_data; l; l = l->next)
+ resolve_profile_data (acfg, (ProfileData*)l->data);
+ for (l = acfg->profile_data; l; l = l->next)
+ add_profile_instances (acfg, (ProfileData*)l->data);
+ }
+
acfg->cfgs_size = acfg->methods->len + 32;
acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size);
acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
else
acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
- acfg->fp = fopen (acfg->tmpfname, "w+");
+ acfg->fp = fopen (acfg->tmpfname, "w+");
} else {
int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
acfg->fp = fdopen (i, "w+");
acfg->gas_line_numbers = TRUE;
}
+#ifdef EMIT_DWARF_INFO
if ((!acfg->aot_opts.nodebug || acfg->aot_opts.dwarf_debug) && acfg->has_jitted_code) {
if (acfg->aot_opts.dwarf_debug && !mono_debug_enabled ()) {
aot_printerrf (acfg, "The dwarf AOT option requires the --debug option.\n");
}
acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, !acfg->gas_line_numbers);
}
+#endif /* EMIT_DWARF_INFO */
if (acfg->w)
mono_img_writer_emit_start (acfg->w);
emit_file_info (acfg);
+ emit_library_info (acfg);
+
if (acfg->dwarf) {
emit_dwarf_info (acfg);
mono_dwarf_writer_close (acfg->dwarf);