+ MonoJitInfo *jinfo;
+ MonoMemPool *mp;
+ GPtrArray *patches;
+ int i, pindex, got_index;
+ gboolean non_got_patches, keep_patches = TRUE;
+ gboolean has_clauses;
+ char *p;
+
+ p = (char*)info;
+ code_len = decode_value (p, &p);
+ used_int_regs = decode_value (p, &p);
+
+ if (!use_loaded_code) {
+ guint8 *code2;
+ code2 = mono_code_manager_reserve (domain->code_mp, code_len);
+ memcpy (code2, code, code_len);
+ mono_arch_flush_icache (code2, code_len);
+ code = code2;
+ }
+
+ if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
+ char *full_name = mono_method_full_name (method, TRUE);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name, code, code + code_len, info);
+ g_free (full_name);
+ }
+
+ /* Exception table */
+ has_clauses = decode_value (p, &p);
+ if (has_clauses) {
+ MonoMethodHeader *header = mono_method_get_header (method);
+ jinfo =
+ mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses));
+ jinfo->num_clauses = header->num_clauses;
+
+ for (i = 0; i < header->num_clauses; ++i) {
+ MonoExceptionClause *ec = &header->clauses [i];
+ MonoJitExceptionInfo *ei = &jinfo->clauses [i];
+
+ ei->flags = ec->flags;
+ ei->exvar_offset = decode_value (p, &p);
+
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+ ei->data.filter = code + decode_value (p, &p);
+ else
+ ei->data.catch_class = ec->data.catch_class;
+
+ ei->try_start = code + decode_value (p, &p);
+ ei->try_end = code + decode_value (p, &p);
+ ei->handler_start = code + decode_value (p, &p);
+ }
+ }
+ else
+ jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
+
+ if (aot_module->opts & MONO_OPT_SHARED)
+ used_strings = decode_value (p, &p);
+ else
+ used_strings = 0;
+
+ for (i = 0; i < used_strings; i++) {
+ guint token = decode_value (p, &p);
+ mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
+ }
+
+ if (aot_module->opts & MONO_OPT_SHARED)
+ keep_patches = FALSE;
+
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ got_index = decode_value (p, &p);
+ keep_patches = FALSE;
+#endif
+
+ if (*p) {
+ MonoImage *image;
+ gpointer *table;
+ int i;
+ guint32 last_offset, buf_len;
+
+ if (keep_patches)
+ mp = domain->mp;
+ else
+ mp = mono_mempool_new ();
+
+ /* First load the type + offset table */
+ last_offset = 0;
+ patches = g_ptr_array_new ();
+ while (*p) {
+ MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
+
+#if defined(MONO_ARCH_HAVE_PIC_AOT)
+ ji->type = *p;
+ p ++;
+#else
+ guint8 b1, b2;
+
+ b1 = *(guint8*)p;
+ b2 = *((guint8*)p + 1);
+ p += 2;
+
+ ji->type = b1 >> 2;
+
+ if (((b1 & (1 + 2)) == 3) && (b2 == 255))
+ ji->ip.i = decode_value (p, &p);
+ else
+ ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
+
+ ji->ip.i += last_offset;
+ last_offset = ji->ip.i;
+#endif
+ //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
+
+ ji->next = patch_info;
+ patch_info = ji;
+
+ g_ptr_array_add (patches, ji);
+ }
+
+ /* Null terminated array */
+ p ++;
+
+ /* Then load the other data */
+ for (pindex = 0; pindex < patches->len; ++pindex) {
+ MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
+
+ switch (ji->type) {
+ case MONO_PATCH_INFO_CLASS:
+ case MONO_PATCH_INFO_IID:
+ case MONO_PATCH_INFO_VTABLE:
+ case MONO_PATCH_INFO_CLASS_INIT:
+ ji->data.klass = decode_klass_info (aot_module, p, &p);
+ if (!ji->data.klass)
+ goto cleanup;
+ break;
+ case MONO_PATCH_INFO_IMAGE:
+ ji->data.image = load_image (aot_module, decode_value (p, &p));
+ if (!ji->data.image)
+ goto cleanup;
+ break;
+ case MONO_PATCH_INFO_METHOD:
+ case MONO_PATCH_INFO_METHODCONST:
+ case MONO_PATCH_INFO_METHOD_JUMP: {
+ guint32 image_index, token, value;
+
+ value = decode_value (p, &p);
+ image_index = value >> 24;
+ token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
+
+ image = load_image (aot_module, image_index);
+ if (!image)
+ goto cleanup;
+ ji->data.method = mono_get_method (image, token, NULL);
+ g_assert (ji->data.method);
+ mono_class_init (ji->data.method->klass);
+
+ break;
+ }
+ case MONO_PATCH_INFO_WRAPPER: {
+ guint32 wrapper_type;
+
+ wrapper_type = decode_value (p, &p);
+
+ switch (wrapper_type) {
+ case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
+ guint32 image_index, token, value;
+
+ value = decode_value (p, &p);
+ image_index = value >> 24;
+ token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
+
+ image = load_image (aot_module, image_index);
+ if (!image)
+ goto cleanup;
+ ji->data.method = mono_get_method (image, token, NULL);
+ g_assert (ji->data.method);
+ mono_class_init (ji->data.method->klass);
+
+ ji->type = MONO_PATCH_INFO_METHOD;
+ ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
+ break;
+ }
+ case MONO_WRAPPER_PROXY_ISINST: {
+ MonoClass *klass = decode_klass_info (aot_module, p, &p);
+ if (!klass)
+ goto cleanup;
+ ji->type = MONO_PATCH_INFO_METHOD;
+ ji->data.method = mono_marshal_get_proxy_cancast (klass);
+ break;
+ }
+ case MONO_WRAPPER_LDFLD:
+ case MONO_WRAPPER_STFLD:
+ case MONO_WRAPPER_LDFLD_REMOTE:
+ case MONO_WRAPPER_STFLD_REMOTE:
+ case MONO_WRAPPER_ISINST: {
+ MonoClass *klass = decode_klass_info (aot_module, p, &p);
+ if (!klass)
+ goto cleanup;
+ ji->type = MONO_PATCH_INFO_METHOD;
+ if (wrapper_type == MONO_WRAPPER_LDFLD)
+ ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
+ else if (wrapper_type == MONO_WRAPPER_STFLD)
+ ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
+ else if (wrapper_type == MONO_WRAPPER_LDFLD_REMOTE)
+ ji->data.method = mono_marshal_get_ldfld_remote_wrapper (klass);
+ else
+ ji->data.method = mono_marshal_get_isinst (klass);
+ break;
+ }
+ case MONO_WRAPPER_STELEMREF:
+ ji->type = MONO_PATCH_INFO_METHOD;
+ ji->data.method = mono_marshal_get_stelemref ();
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ break;
+ }
+ case MONO_PATCH_INFO_FIELD:
+ case MONO_PATCH_INFO_SFLDA:
+ ji->data.field = decode_field_info (aot_module, p, &p);
+ if (!ji->data.field)
+ goto cleanup;
+ break;
+ case MONO_PATCH_INFO_INTERNAL_METHOD:
+ ji->data.name = aot_module->icall_table [decode_value (p, &p)];
+ g_assert (ji->data.name);
+ break;
+ case MONO_PATCH_INFO_SWITCH:
+ ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
+ ji->data.table->table_size = decode_value (p, &p);
+ table = g_new (gpointer, ji->data.table->table_size);
+ ji->data.table->table = (MonoBasicBlock**)table;
+ for (i = 0; i < ji->data.table->table_size; i++)
+ table [i] = (gpointer)(gssize)decode_value (p, &p);
+ break;
+ case MONO_PATCH_INFO_R4: {
+ guint32 val;
+
+ ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
+ val = decode_value (p, &p);
+ *(float*)ji->data.target = *(float*)&val;
+ break;
+ }
+ case MONO_PATCH_INFO_R8: {
+ guint32 val [2];
+
+ ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
+
+ val [0] = decode_value (p, &p);
+ val [1] = decode_value (p, &p);
+ *(double*)ji->data.target = *(double*)val;
+ break;
+ }
+ case MONO_PATCH_INFO_LDSTR:
+ image = load_image (aot_module, decode_value (p, &p));
+ if (!image)
+ goto cleanup;
+ ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
+ break;
+ case MONO_PATCH_INFO_DECLSEC:
+ case MONO_PATCH_INFO_LDTOKEN:
+ case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+ image = load_image (aot_module, decode_value (p, &p));
+ if (!image)
+ goto cleanup;
+ ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
+ break;
+ case MONO_PATCH_INFO_EXC_NAME:
+ ji->data.klass = decode_klass_info (aot_module, p, &p);
+ if (!ji->data.klass)
+ goto cleanup;
+ ji->data.name = ji->data.klass->name;
+ break;
+ case MONO_PATCH_INFO_METHOD_REL:
+ ji->data.offset = decode_value (p, &p);
+ break;
+ default:
+ g_warning ("unhandled type %d", ji->type);
+ g_assert_not_reached ();
+ }
+ }
+
+ buf_len = decode_value (p, &p);
+ mono_debug_add_aot_method (domain, method, code, p, buf_len);
+
+#if MONO_ARCH_HAVE_PIC_AOT
+ mono_arch_flush_icache (code, code_len);
+
+ if (non_got_patches)
+ make_writable (code, code_len);
+
+ /* Do this outside the lock to avoid deadlocks */
+ LeaveCriticalSection (&aot_mutex);
+ non_got_patches = FALSE;
+ for (pindex = 0; pindex < patches->len; ++pindex) {
+ MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
+
+ if (is_got_patch (ji->type)) {
+ aot_module->got [got_index] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
+ got_index ++;
+ ji->type = MONO_PATCH_INFO_NONE;
+ }
+ else
+ non_got_patches = TRUE;
+ }
+ if (non_got_patches) {
+ make_writable (code, code_len);
+ mono_arch_patch_code (method, domain, code, patch_info, TRUE);
+ }
+ EnterCriticalSection (&aot_mutex);
+#else
+ if (use_loaded_code)
+ /* disable write protection */
+ make_writable (code, code_len);
+
+ /* Do this outside the lock to avoid deadlocks */
+ LeaveCriticalSection (&aot_mutex);
+ mono_arch_patch_code (method, domain, code, patch_info, TRUE);
+ EnterCriticalSection (&aot_mutex);
+
+#endif
+ g_ptr_array_free (patches, TRUE);
+
+ if (!keep_patches)
+ mono_mempool_destroy (mp);
+ }
+
+ mono_jit_stats.methods_aot++;
+
+ {
+ jinfo->code_size = code_len;
+ jinfo->used_regs = used_int_regs;
+ jinfo->method = method;
+ jinfo->code_start = code;
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ jinfo->domain_neutral = 0;
+#else
+ jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
+#endif
+
+ return jinfo;
+ }
+
+ cleanup:
+ g_ptr_array_free (patches, TRUE);
+
+ /* FIXME: The space in domain->mp is wasted */
+ if (aot_module->opts & MONO_OPT_SHARED)
+ /* No need to cache patches */
+ mono_mempool_destroy (mp);
+
+ return NULL;
+}
+
+MonoJitInfo*
+mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
+{
+ MonoJitInfo *info;
+
+ EnterCriticalSection (&aot_mutex);
+ info = mono_aot_get_method_inner (domain, method);
+ LeaveCriticalSection (&aot_mutex);
+
+ /* Do this outside the lock */
+ if (info) {
+ mono_jit_info_table_add (domain, info);
+ return info;
+ }
+ else
+ return NULL;
+}
+
+gboolean
+mono_aot_is_got_entry (guint8 *code, guint8 *addr)
+{
+ MonoJitInfo *ji;
+ MonoAssembly *ass;
+ MonoAotModule *aot_module;
+
+ ji = mono_jit_info_table_find (mono_domain_get (), code);
+ if (!ji)
+ return FALSE;
+
+ ass = ji->method->klass->image->assembly;
+
+ if (!aot_modules)
+ return FALSE;
+ aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
+ if (!aot_module || !aot_module->got)
+ return FALSE;
+
+ return ((addr >= (guint8*)(aot_module->got)) && (addr < (guint8*)(aot_module->got + aot_module->got_size)));
+}
+
+/*****************************************************/
+/* AOT COMPILER */
+/*****************************************************/
+
+static void
+emit_section_change (FILE *fp, const char *section_name, int subsection_index)
+{
+#if defined(sparc)
+ /* For solaris as, GNU as should accept the same */
+ fprintf (fp, ".section \"%s\"\n", section_name);
+#elif defined(__ppc__) && defined(__MACH__)
+ /* This needs to be made more precise on mach. */
+ fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
+#else
+ fprintf (fp, "%s %d\n", section_name, subsection_index);
+#endif
+}
+
+static void
+emit_symbol_type (FILE *fp, const char *name, gboolean func)
+{
+ const char *stype;
+
+ if (func)
+ stype = "function";
+ else
+ stype = "object";
+
+#if defined(sparc)
+ fprintf (fp, "\t.type %s,#%s\n", name, stype);
+#elif !(defined(__ppc__) && defined(__MACH__))
+ fprintf (fp, "\t.type %s,@%s\n", name, stype);
+#elif defined(__x86_64__) || defined(__i386__)
+ fprintf (fp, "\t.type %s,@%s\n", name, stype);
+#endif
+}
+
+static void
+emit_global (FILE *fp, const char *name, gboolean func)
+{
+#if defined(__ppc__) && defined(__MACH__)
+ // mach-o always uses a '_' prefix.
+ fprintf (fp, "\t.globl _%s\n", name);
+#else
+ fprintf (fp, "\t.globl %s\n", name);
+#endif
+
+ emit_symbol_type (fp, name, func);
+}
+
+static void
+emit_label (FILE *fp, const char *name)
+{
+#if defined(__ppc__) && defined(__MACH__)
+ // mach-o always uses a '_' prefix.
+ fprintf (fp, "_%s:\n", name);
+#else
+ fprintf (fp, "%s:\n", name);
+#endif
+}
+
+static void
+emit_string_symbol (FILE *fp, const char *name, const char *value)
+{
+ emit_section_change (fp, ".text", 1);
+ emit_global(fp, name, FALSE);
+ emit_label(fp, name);
+ fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
+}
+
+#if defined(__ppc__) && defined(__MACH__)
+static int
+ilog2(register int value)
+{
+ int count = -1;
+ while (value & ~0xf) count += 4, value >>= 4;
+ while (value) count++, value >>= 1;
+ return count;
+}
+#endif
+
+static void
+emit_alignment(FILE *fp, int size)
+{
+#if defined(__ppc__) && defined(__MACH__)
+ // the mach-o assembler specifies alignments as powers of 2.
+ fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
+#elif defined(__powerpc__)
+ /* ignore on linux/ppc */
+#else
+ fprintf (fp, "\t.align %d\n", size);
+#endif
+}
+
+G_GNUC_UNUSED static void
+emit_pointer (FILE *fp, const char *target)
+{
+ emit_alignment (fp, sizeof (gpointer));
+#if defined(__x86_64__)
+ fprintf (fp, "\t.quad %s\n", target);
+#elif defined(sparc) && SIZEOF_VOID_P == 8
+ fprintf (fp, "\t.xword %s\n", target);
+#else
+ fprintf (fp, "\t.long %s\n", target);
+#endif
+}
+
+static guint32
+mono_get_field_token (MonoClassField *field)
+{
+ MonoClass *klass = field->parent;