Merge pull request #3240 from alexanderkyte/aot_compiler_leaks
[mono.git] / mono / mini / mini.c
index 94062ec4b84ef71dcc6d6b01c97042e268f4f217..fff5ece8d5512e319ffe7c3a70bbaf25e5ba2b24 100644 (file)
@@ -58,6 +58,7 @@
 #include <mono/utils/mono-hwcap.h>
 #include <mono/utils/dtrace.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
 #include <mono/io-layer/io-layer.h>
 
 #include "mini.h"
@@ -95,211 +96,9 @@ MonoBackend *current_backend;
 gpointer
 mono_realloc_native_code (MonoCompile *cfg)
 {
-#if defined(__default_codegen__)
        return g_realloc (cfg->native_code, cfg->code_size);
-#elif defined(__native_client_codegen__)
-       guint old_padding;
-       gpointer native_code;
-       guint alignment_check;
-
-       /* Save the old alignment offset so we can re-align after the realloc. */
-       old_padding = (guint)(cfg->native_code - cfg->native_code_alloc);
-       cfg->code_size = NACL_BUNDLE_ALIGN_UP (cfg->code_size);
-
-       cfg->native_code_alloc = g_realloc ( cfg->native_code_alloc,
-                                                                                cfg->code_size + kNaClAlignment );
-
-       /* Align native_code to next nearest kNaClAlignment byte. */
-       native_code = (guint)cfg->native_code_alloc + kNaClAlignment;
-       native_code = (guint)native_code & ~kNaClAlignmentMask;
-
-       /* Shift the data to be 32-byte aligned again. */
-       memmove (native_code, cfg->native_code_alloc + old_padding, cfg->code_size);
-
-       alignment_check = (guint)native_code & kNaClAlignmentMask;
-       g_assert (alignment_check == 0);
-       return native_code;
-#else
-       g_assert_not_reached ();
-       return cfg->native_code;
-#endif
-}
-
-#ifdef __native_client_codegen__
-
-/* Prevent instructions from straddling a 32-byte alignment boundary.   */
-/* Instructions longer than 32 bytes must be aligned internally.        */
-/* IN: pcode, instlen                                                   */
-/* OUT: pcode                                                           */
-void mono_nacl_align_inst(guint8 **pcode, int instlen) {
-  int space_in_block;
-
-  space_in_block = kNaClAlignment - ((uintptr_t)(*pcode) & kNaClAlignmentMask);
-
-  if (G_UNLIKELY (instlen >= kNaClAlignment)) {
-    g_assert_not_reached();
-  } else if (instlen > space_in_block) {
-    *pcode = mono_arch_nacl_pad(*pcode, space_in_block);
-  }
-}
-
-/* Move emitted call sequence to the end of a kNaClAlignment-byte block.  */
-/* IN: start    pointer to start of call sequence                         */
-/* IN: pcode    pointer to end of call sequence (current "IP")            */
-/* OUT: start   pointer to the start of the call sequence after padding   */
-/* OUT: pcode   pointer to the end of the call sequence after padding     */
-void mono_nacl_align_call(guint8 **start, guint8 **pcode) {
-  const size_t MAX_NACL_CALL_LENGTH = kNaClAlignment;
-  guint8 copy_of_call[MAX_NACL_CALL_LENGTH];
-  guint8 *temp;
-
-  const size_t length = (size_t)((*pcode)-(*start));
-  g_assert(length < MAX_NACL_CALL_LENGTH);
-
-  memcpy(copy_of_call, *start, length);
-  temp = mono_nacl_pad_call(*start, (guint8)length);
-  memcpy(temp, copy_of_call, length);
-  (*start) = temp;
-  (*pcode) = temp + length;
-}
-
-/* mono_nacl_pad_call(): Insert padding for Native Client call instructions */
-/*    code     pointer to buffer for emitting code                          */
-/*    ilength  length of call instruction                                   */
-guint8 *mono_nacl_pad_call(guint8 *code, guint8 ilength) {
-  int freeSpaceInBlock = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
-  int padding = freeSpaceInBlock - ilength;
-
-  if (padding < 0) {
-    /* There isn't enough space in this block for the instruction. */
-    /* Fill this block and start a new one.                        */
-    code = mono_arch_nacl_pad(code, freeSpaceInBlock);
-    freeSpaceInBlock = kNaClAlignment;
-    padding = freeSpaceInBlock - ilength;
-  }
-  g_assert(ilength > 0);
-  g_assert(padding >= 0);
-  g_assert(padding < kNaClAlignment);
-  if (0 == padding) return code;
-  return mono_arch_nacl_pad(code, padding);
-}
-
-guint8 *mono_nacl_align(guint8 *code) {
-  int padding = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
-  if (padding != kNaClAlignment) code = mono_arch_nacl_pad(code, padding);
-  return code;
-}
-
-void mono_nacl_fix_patches(const guint8 *code, MonoJumpInfo *ji)
-{
-#ifndef USE_JUMP_TABLES
-  MonoJumpInfo *patch_info;
-  for (patch_info = ji; patch_info; patch_info = patch_info->next) {
-    unsigned char *ip = patch_info->ip.i + code;
-    ip = mono_arch_nacl_skip_nops(ip);
-    patch_info->ip.i = ip - code;
-  }
-#endif
-}
-#endif  /* __native_client_codegen__ */
-
-#ifdef USE_JUMP_TABLES
-
-#define DEFAULT_JUMPTABLE_CHUNK_ELEMENTS 128
-
-typedef struct MonoJumpTableChunk {
-       guint32 total;
-       guint32 active;
-       struct MonoJumpTableChunk *previous;
-       /* gpointer entries[total]; */
-} MonoJumpTableChunk;
-
-static MonoJumpTableChunk* g_jumptable;
-#define mono_jumptable_lock() mono_os_mutex_lock (&jumptable_mutex)
-#define mono_jumptable_unlock() mono_os_mutex_unlock (&jumptable_mutex)
-static mono_mutex_t jumptable_mutex;
-
-static  MonoJumpTableChunk*
-mono_create_jumptable_chunk (guint32 max_entries)
-{
-       guint32 size = sizeof (MonoJumpTableChunk) + max_entries * sizeof(gpointer);
-       MonoJumpTableChunk *chunk = (MonoJumpTableChunk*) g_new0 (guchar, size);
-       chunk->total = max_entries;
-       return chunk;
-}
-
-void
-mono_jumptable_init (void)
-{
-       if (g_jumptable == NULL) {
-               mono_os_mutex_init_recursive (&jumptable_mutex);
-               g_jumptable = mono_create_jumptable_chunk (DEFAULT_JUMPTABLE_CHUNK_ELEMENTS);
-       }
-}
-
-gpointer*
-mono_jumptable_add_entry (void)
-{
-       return mono_jumptable_add_entries (1);
-}
-
-gpointer*
-mono_jumptable_add_entries (guint32 entries)
-{
-       guint32 index;
-       gpointer *result;
-
-       mono_jumptable_init ();
-       mono_jumptable_lock ();
-       index = g_jumptable->active;
-       if (index + entries >= g_jumptable->total) {
-               /*
-                * Grow jumptable, by adding one more chunk.
-                * We cannot realloc jumptable, as there could be pointers
-                * to existing jump table entries in the code, so instead
-                * we just add one more chunk.
-                */
-               guint32 max_entries = entries;
-               MonoJumpTableChunk *new_chunk;
-
-               if (max_entries < DEFAULT_JUMPTABLE_CHUNK_ELEMENTS)
-                       max_entries = DEFAULT_JUMPTABLE_CHUNK_ELEMENTS;
-               new_chunk = mono_create_jumptable_chunk (max_entries);
-               /* Link old jumptable, so that we could free it up later. */
-               new_chunk->previous = g_jumptable;
-               g_jumptable = new_chunk;
-               index = 0;
-       }
-       g_jumptable->active = index + entries;
-       result = (gpointer*)((guchar*)g_jumptable + sizeof(MonoJumpTableChunk)) + index;
-       mono_jumptable_unlock();
-
-       return result;
-}
-
-void
-mono_jumptable_cleanup (void)
-{
-       if (g_jumptable) {
-               MonoJumpTableChunk *current = g_jumptable, *prev;
-               while (current != NULL) {
-                       prev = current->previous;
-                       g_free (current);
-                       current = prev;
-               }
-               g_jumptable = NULL;
-               mono_os_mutex_destroy (&jumptable_mutex);
-       }
 }
 
-gpointer*
-mono_jumptable_get_entry (guint8 *code_ptr)
-{
-       return mono_arch_jumptable_entry_from_code (code_ptr);
-}
-
-#endif /* USE_JUMP_TABLES */
-
 typedef struct {
        MonoExceptionClause *clause;
        MonoBasicBlock *basic_block;
@@ -1370,7 +1169,7 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_
                vars = g_list_prepend (vars, vmv);
        }
 
-       vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
+       vars = g_list_sort (vars, compare_by_interval_start_pos_func);
 
        /* Sanity check */
        /*
@@ -2087,28 +1886,59 @@ mono_verify_cfg (MonoCompile *cfg)
                mono_verify_bblock (bb);
 }
 
+// This will free many fields in cfg to save
+// memory. Note that this must be safe to call
+// multiple times. It must be idempotent. 
+void
+mono_empty_compile (MonoCompile *cfg)
+{
+       mono_free_loop_info (cfg);
+
+       // These live in the mempool, and so must be freed
+       // first
+       for (GSList *l = cfg->headers_to_free; l; l = l->next) {
+               mono_metadata_free_mh ((MonoMethodHeader *)l->data);
+       }
+       cfg->headers_to_free = NULL;
+
+       if (cfg->mempool) {
+       //mono_mempool_stats (cfg->mempool);
+               mono_mempool_destroy (cfg->mempool);
+               cfg->mempool = NULL;
+       }
+
+       g_free (cfg->varinfo);
+       cfg->varinfo = NULL;
+
+       g_free (cfg->vars);
+       cfg->vars = NULL;
+
+       if (cfg->rs) {
+               mono_regstate_free (cfg->rs);
+               cfg->rs = NULL;
+       }
+}
+
 void
 mono_destroy_compile (MonoCompile *cfg)
 {
-       GSList *l;
+       mono_empty_compile (cfg);
 
        if (cfg->header)
                mono_metadata_free_mh (cfg->header);
-       //mono_mempool_stats (cfg->mempool);
-       mono_free_loop_info (cfg);
-       if (cfg->rs)
-               mono_regstate_free (cfg->rs);
+
        if (cfg->spvars)
                g_hash_table_destroy (cfg->spvars);
        if (cfg->exvars)
                g_hash_table_destroy (cfg->exvars);
-       for (l = cfg->headers_to_free; l; l = l->next)
-               mono_metadata_free_mh ((MonoMethodHeader *)l->data);
+
        g_list_free (cfg->ldstr_list);
-       g_hash_table_destroy (cfg->token_info_hash);
+
+       if (cfg->token_info_hash)
+               g_hash_table_destroy (cfg->token_info_hash);
+
        if (cfg->abs_patches)
                g_hash_table_destroy (cfg->abs_patches);
-       mono_mempool_destroy (cfg->mempool);
 
        mono_debug_free_method (cfg);
 
@@ -2429,12 +2259,6 @@ mono_postprocess_patches (MonoCompile *cfg)
                        MonoJumpList *jlist;
                        MonoDomain *domain = cfg->domain;
                        unsigned char *ip = cfg->native_code + patch_info->ip.i;
-#if defined(__native_client__) && defined(__native_client_codegen__)
-                       /* When this jump target gets evaluated, the method */
-                       /* will be installed in the dynamic code section,   */
-                       /* not at the location of cfg->native_code.         */
-                       ip = nacl_inverse_modify_patch_target (cfg->native_code) + patch_info->ip.i;
-#endif
 
                        mono_domain_lock (domain);
                        jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, patch_info->data.method);
@@ -2472,15 +2296,6 @@ mono_codegen (MonoCompile *cfg)
        else
                code_domain = cfg->domain;
 
-#if defined(__native_client_codegen__) && defined(__native_client__)
-       void *code_dest;
-
-       /* This keeps patch targets from being transformed during
-        * ordinary method compilation, for local branches and jumps.
-        */
-       nacl_allow_target_modification (FALSE);
-#endif
-
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
                cfg->spill_count = 0;
                /* we reuse dfn here */
@@ -2527,18 +2342,13 @@ mono_codegen (MonoCompile *cfg)
                }
        }
 
-#ifdef __native_client_codegen__
-       mono_nacl_fix_patches (cfg->native_code, cfg->patch_info);
-#endif
        mono_arch_emit_exceptions (cfg);
 
        max_epilog_size = 0;
 
        /* we always allocate code in cfg->domain->code_mp to increase locality */
        cfg->code_size = cfg->code_len + max_epilog_size;
-#ifdef __native_client_codegen__
-       cfg->code_size = NACL_BUNDLE_ALIGN_UP (cfg->code_size);
-#endif
+
        /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
 
 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
@@ -2561,9 +2371,7 @@ mono_codegen (MonoCompile *cfg)
        } else {
                code = (guint8 *)mono_domain_code_reserve (code_domain, cfg->code_size + cfg->thunk_area + unwindlen);
        }
-#if defined(__native_client_codegen__) && defined(__native_client__)
-       nacl_allow_target_modification (TRUE);
-#endif
+
        if (cfg->thunk_area) {
                cfg->thunks_offset = cfg->code_size + unwindlen;
                cfg->thunks = code + cfg->thunks_offset;
@@ -2572,17 +2380,7 @@ mono_codegen (MonoCompile *cfg)
 
        g_assert (code);
        memcpy (code, cfg->native_code, cfg->code_len);
-#if defined(__default_codegen__)
        g_free (cfg->native_code);
-#elif defined(__native_client_codegen__)
-       if (cfg->native_code_alloc) {
-               g_free (cfg->native_code_alloc);
-               cfg->native_code_alloc = 0;
-       }
-       else if (cfg->native_code) {
-               g_free (cfg->native_code);
-       }
-#endif /* __native_client_codegen__ */
        cfg->native_code = code;
        code = cfg->native_code + cfg->code_len;
   
@@ -2624,20 +2422,6 @@ mono_codegen (MonoCompile *cfg)
        mono_arch_save_unwind_info (cfg);
 #endif
 
-#if defined(__native_client_codegen__) && defined(__native_client__)
-       if (!cfg->compile_aot) {
-               if (cfg->method->dynamic) {
-                       code_dest = nacl_code_manager_get_code_dest(cfg->dynamic_info->code_mp, cfg->native_code);
-               } else {
-                       code_dest = nacl_domain_get_code_dest(cfg->domain, cfg->native_code);
-               }
-       }
-#endif
-
-#if defined(__native_client_codegen__)
-       mono_nacl_fix_patches (cfg->native_code, cfg->patch_info);
-#endif
-
 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
        {
                MonoJumpInfo *ji;
@@ -2667,7 +2451,11 @@ mono_codegen (MonoCompile *cfg)
                }
        }
 #else
-       mono_arch_patch_code (cfg, cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
+       mono_arch_patch_code (cfg, cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors, &cfg->error);
+       if (!is_ok (&cfg->error)) {
+               mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
+               return;
+       }
 #endif
 
        if (cfg->method->dynamic) {
@@ -3139,10 +2927,25 @@ is_open_method (MonoMethod *method)
        return FALSE;
 }
 
+static void mono_insert_nop_in_empty_bb (MonoCompile *cfg)
+{
+       MonoBasicBlock *bb;
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               if (bb->code)
+                       continue;
+               MonoInst *nop;
+               MONO_INST_NEW (cfg, nop, OP_NOP);
+               MONO_ADD_INS (bb, nop);
+       }
+}
 static void
 mono_create_gc_safepoint (MonoCompile *cfg, MonoBasicBlock *bblock)
 {
        MonoInst *poll_addr, *ins;
+
+       if (cfg->disable_gc_safe_points)
+               return;
+
        if (cfg->verbose_level > 1)
                printf ("ADDING SAFE POINT TO BB %d\n", bblock->block_num);
 
@@ -3228,8 +3031,7 @@ mono_insert_safepoints (MonoCompile *cfg)
 
                if (info && info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER &&
                        (info->d.icall.func == mono_thread_interruption_checkpoint ||
-                       info->d.icall.func == mono_threads_finish_blocking ||
-                       info->d.icall.func == mono_threads_reset_blocking_start)) {
+                       info->d.icall.func == mono_threads_exit_gc_safe_region_unbalanced)) {
                        /* These wrappers are called from the wrapper for the polling function, leading to potential stack overflow */
                        if (cfg->verbose_level > 1)
                                printf ("SKIPPING SAFEPOINTS for wrapper %s\n", cfg->method->name);
@@ -3470,7 +3272,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        cfg->disable_omit_fp = debug_options.disable_omit_fp;
        cfg->skip_visibility = method->skip_visibility;
        cfg->orig_method = method;
-       cfg->gen_seq_points = debug_options.gen_seq_points_compact_data || debug_options.gen_sdb_seq_points;
+       cfg->gen_seq_points = !debug_options.no_seq_points_compact_data || debug_options.gen_sdb_seq_points;
        cfg->gen_sdb_seq_points = debug_options.gen_sdb_seq_points;
        cfg->llvm_only = (flags & JIT_FLAG_LLVM_ONLY) != 0;
        cfg->backend = current_backend;
@@ -3482,6 +3284,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                cfg->gen_sdb_seq_points = FALSE;
        }
 #endif
+       if (cfg->method->wrapper_type == MONO_WRAPPER_ALLOC) {
+               /* We can't have seq points inside gc critical regions */
+               cfg->gen_seq_points = FALSE;
+               cfg->gen_sdb_seq_points = FALSE;
+       }
        /* coop / nacl requires loop detection to happen */
 #if defined(__native_client_codegen__)
        cfg->opt |= MONO_OPT_LOOP;
@@ -3592,6 +3399,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                                        //g_free (nm);
                                }
                                if (cfg->llvm_only) {
+                                       g_free (cfg->exception_message);
                                        cfg->disable_aot = TRUE;
                                        return cfg;
                                }
@@ -3645,6 +3453,17 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
 
        mini_gc_init_cfg (cfg);
 
+       if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+               /* These wrappers are using linkonce linkage, so they can't access GOT slots */
+               if ((info && (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG))) {
+                       cfg->disable_gc_safe_points = TRUE;
+                       /* This is safe, these wrappers only store to the stack */
+                       cfg->gen_write_barriers = FALSE;
+               }
+       }
+
        if (COMPILE_LLVM (cfg)) {
                cfg->opt |= MONO_OPT_ABCREM;
        }
@@ -3728,6 +3547,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        MONO_TIME_TRACK (mono_jit_stats.jit_method_to_ir, i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, NULL, NULL, 0, FALSE));
        mono_cfg_dump_ir (cfg, "method-to-ir");
 
+       if (cfg->gdump_ctx != NULL) {
+               /* workaround for graph visualization, as it doesn't handle empty basic blocks properly */
+               mono_insert_nop_in_empty_bb (cfg);
+               mono_cfg_dump_ir (cfg, "mono_insert_nop_in_empty_bb");
+       }
+
        if (i < 0) {
                if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
                        if (compile_aot) {
@@ -3806,6 +3631,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                mono_cfg_dump_ir (cfg, "local_cprop");
        }
 
+       if (cfg->flags & MONO_CFG_HAS_TYPE_CHECK) {
+               MONO_TIME_TRACK (mono_jit_stats.jit_decompose_typechecks, mono_decompose_typechecks (cfg));
+               if (cfg->gdump_ctx != NULL) {
+                       /* workaround for graph visualization, as it doesn't handle empty basic blocks properly */
+                       mono_insert_nop_in_empty_bb (cfg);
+               }
+               mono_cfg_dump_ir (cfg, "decompose_typechecks");
+       }
+
        /*
         * Should be done after cprop which can do strength reduction on
         * some of these ops, after propagating immediates.
@@ -4301,7 +4135,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                                mono_lookup_pinvoke_call (method, NULL, NULL);
                }
                nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
-               code = mono_get_addr_from_ftnptr (mono_compile_method (nm));
+               gpointer compiled_method = mono_compile_method_checked (nm, error);
+               return_val_if_nok (error, NULL);
+               code = mono_get_addr_from_ftnptr (compiled_method);
                jinfo = mono_jit_info_table_find (target_domain, (char *)code);
                if (!jinfo)
                        jinfo = mono_jit_info_table_find (mono_domain_get (), (char *)code);
@@ -4315,7 +4151,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
                if (method->klass->parent == mono_defaults.multicastdelegate_class) {
                        if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
-                               MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
+                               MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
                                g_assert (mi);
                                /*
                                 * We need to make sure this wrapper
@@ -4331,15 +4167,21 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                        } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
                                if (mono_llvm_only) {
                                        nm = mono_marshal_get_delegate_invoke (method, NULL);
-                                       return mono_get_addr_from_ftnptr (mono_compile_method (nm));
+                                       gpointer compiled_ptr = mono_compile_method_checked (nm, error);
+                                       mono_error_assert_ok (error);
+                                       return mono_get_addr_from_ftnptr (compiled_ptr);
                                }
                                return mono_create_delegate_trampoline (target_domain, method->klass);
                        } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
                                nm = mono_marshal_get_delegate_begin_invoke (method);
-                               return mono_get_addr_from_ftnptr (mono_compile_method (nm));
+                               gpointer compiled_ptr = mono_compile_method_checked (nm, error);
+                               mono_error_assert_ok (error);
+                               return mono_get_addr_from_ftnptr (compiled_ptr);
                        } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
                                nm = mono_marshal_get_delegate_end_invoke (method);
-                               return mono_get_addr_from_ftnptr (mono_compile_method (nm));
+                               gpointer compiled_ptr = mono_compile_method_checked (nm, error);
+                               mono_error_assert_ok (error);
+                               return mono_get_addr_from_ftnptr (compiled_ptr);
                        }
                }
 
@@ -4387,13 +4229,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        if (mono_aot_only) {
                char *fullname = mono_method_full_name (method, TRUE);
-               char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
-
-               ex = mono_get_exception_execution_engine (msg);
-               mono_error_set_exception_instance (error, ex);
+               mono_error_set_execution_engine (error, "Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
                g_free (fullname);
-               g_free (msg);
-               
+
                return NULL;
        }
 
@@ -4509,10 +4347,6 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                        patch_info.data.method = method;
                        g_hash_table_remove (domain_jit_info (target_domain)->jump_target_hash, method);
 
-#if defined(__native_client_codegen__) && defined(__native_client__)
-                       /* These patches are applied after a method has been installed, no target munging is needed. */
-                       nacl_allow_target_modification (FALSE);
-#endif
 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
                        for (tmp = jlist->list; tmp; tmp = tmp->next) {
                                gpointer target = mono_resolve_patch_target (NULL, target_domain, (guint8 *)tmp->data, &patch_info, TRUE, error);
@@ -4521,11 +4355,11 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                                mono_arch_patch_code_new (NULL, target_domain, (guint8 *)tmp->data, &patch_info, target);
                        }
 #else
-                       for (tmp = jlist->list; tmp; tmp = tmp->next)
-                               mono_arch_patch_code (NULL, NULL, target_domain, tmp->data, &patch_info, TRUE);
-#endif
-#if defined(__native_client_codegen__) && defined(__native_client__)
-                       nacl_allow_target_modification (TRUE);
+                       for (tmp = jlist->list; tmp; tmp = tmp->next) {
+                               mono_arch_patch_code (NULL, NULL, target_domain, tmp->data, &patch_info, TRUE, error);
+                               if (!is_ok (error))
+                                       break;
+                       }
 #endif
                }
        }