2008-08-29 Geoff Norton <gnorton@novell.com>
[mono.git] / mono / mini / mini.c
index 5f3bf348f03cd79c61ed005ab6a7537b4eba56a5..ce23ded4aa5a8bde7b43886e687416bad25f983d 100644 (file)
@@ -59,6 +59,7 @@
 #include <mono/metadata/security-core-clr.h>
 #include <mono/metadata/verify.h>
 #include <mono/metadata/verify-internals.h>
+#include <mono/metadata/mempool-internals.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
@@ -173,9 +174,7 @@ static __thread gpointer mono_jit_tls MONO_TLS_FAST;
 
 MonoTraceSpec *mono_jit_trace_calls = NULL;
 gboolean mono_break_on_exc = FALSE;
-#ifndef DISABLE_AOT
 gboolean mono_compile_aot = FALSE;
-#endif
 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
 gboolean mono_aot_only = FALSE;
 /* Whenever to use IMT */
@@ -195,8 +194,6 @@ static int mini_verbose = 0;
 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
 static CRITICAL_SECTION jit_mutex;
 
-static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL;
-
 static MonoCodeManager *global_codeman = NULL;
 
 /* FIXME: Make this static again */
@@ -950,7 +947,7 @@ mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
  *
  *   Return whenever BB1 and BB2 are linked in the CFG.
  */
-static gboolean
+gboolean
 mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
 {
        int i;
@@ -1168,8 +1165,8 @@ split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
        }
 }
 
-static guint32
-reverse_branch_op (guint32 opcode)
+guint32
+mono_reverse_branch_op (guint32 opcode)
 {
        static const int reverse_map [] = {
                CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
@@ -1928,6 +1925,8 @@ mono_op_imm_to_op (int opcode)
                return OP_ISUB;
        case OP_LSUB_IMM:
                return OP_LSUB;
+       case OP_IMUL_IMM:
+               return OP_IMUL;
        case OP_AND_IMM:
 #if SIZEOF_VOID_P == 4
                return OP_IAND;
@@ -2150,6 +2149,13 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
                        printf ("  Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
                }
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+               if (cfg->opt & MONO_OPT_SSA) {
+                       if (mono_type_is_float (type))
+                               inst->flags = MONO_INST_VOLATILE;
+               }
+#endif
+
                /* Allocate a dummy MonoInst for the first vreg */
                MONO_INST_NEW (cfg, tree, OP_LOCAL);
                tree->dreg = inst->dreg + 1;
@@ -4924,48 +4930,12 @@ get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, int context_u
        }
 }
 
-gpointer
-mini_create_rgctx_lazy_fetch_trampoline (guint32 offset)
-{
-       static gboolean inited = FALSE;
-       static int num_trampolines = 0;
-
-       gpointer tramp, ptr;
-
-       mono_jit_lock ();
-       if (rgctx_lazy_fetch_trampoline_hash)
-               tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
-       else
-               tramp = NULL;
-       mono_jit_unlock ();
-       if (tramp)
-               return tramp;
-
-       tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset);
-       ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
-
-       mono_jit_lock ();
-       if (!rgctx_lazy_fetch_trampoline_hash)
-               rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL);
-       g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
-       mono_jit_unlock ();
-
-       if (!inited) {
-               mono_counters_register ("RGCTX num lazy fetch trampolines",
-                               MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
-               inited = TRUE;
-       }
-       num_trampolines++;
-
-       return ptr;
-}
-
 static MonoInst*
 get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
        MonoInst *rgc_ptr, guint32 slot, const unsigned char *ip)
 {
        MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
-       guint8 *tramp = mini_create_rgctx_lazy_fetch_trampoline (slot);
+       guint8 *tramp = mono_create_rgctx_lazy_fetch_trampoline (slot);
        int temp;
        MonoInst *field;
 
@@ -6361,11 +6331,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                        generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
                                        NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
                                        temp = mono_emit_jit_icall (cfg, bblock,
-                                               mono_helper_compile_generic_method_wo_context, iargs, ip);
+                                               mono_helper_compile_generic_method, iargs, ip);
                                } else {
                                        NEW_METHODCONST (cfg, iargs [1], cmethod);
-                                       NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
-                                       NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
+                                       NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
                                        temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method,
                                                iargs, ip);
                                }
@@ -8045,7 +8014,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
                                        call->inst.opcode = OP_TRAMPCALL_VTABLE;
-                                       call->fptr = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
+                                       call->fptr = mono_create_generic_class_init_trampoline ();
 
                                        call->inst.inst_left = vtable;
 
@@ -8624,7 +8593,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
                                        MonoInst *load;
                                        NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
-                                       MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+                                       MONO_INST_NEW (cfg, ins, CEE_STIND_REF);
                                        ins->inst_left = load;
                                        ins->inst_right = sp [2];
                                        MONO_ADD_INS (bblock, ins);
@@ -9458,10 +9427,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else {
                                        NEW_METHODCONST (cfg, argconst, cmethod);
                                }
-                               if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
-                                       temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
-                               else
-                                       temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
+                               temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
                                NEW_TEMPLOAD (cfg, *sp, temp);
                                sp ++;
                                
@@ -9738,8 +9704,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                for (i = 0; i < header->num_clauses; ++i) {
                                        MonoExceptionClause *clause = &header->clauses [i];
-                                       if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
+                                       if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
                                                handler_offset = clause->handler_offset;
+                                               break;
+                                       }
                                }
 
                                bblock->flags |= BB_EXCEPTION_UNSAFE;
@@ -10115,7 +10083,7 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
        wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
        g_free (name);
 
-       trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper, TRUE));
+       trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
        mono_register_jit_icall_wrapper (callinfo, trampoline);
 
        callinfo->trampoline = trampoline;
@@ -10151,19 +10119,6 @@ typedef struct {
        GSList *slots;
 } StackSlotInfo;
 
-static inline GSList*
-g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
-                                                gpointer  data)
-{
-  GSList *new_list;
-
-  new_list = mono_mempool_alloc (mp, sizeof (GSList));
-  new_list->data = data;
-  new_list->next = list;
-
-  return new_list;
-}
-
 static gint 
 compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
 {
@@ -10992,8 +10947,8 @@ mono_destroy_compile (MonoCompile *cfg)
        mono_mempool_destroy (cfg->mempool);
        g_list_free (cfg->ldstr_list);
        g_hash_table_destroy (cfg->token_info_hash);
-
-       g_free (cfg->reverse_inst_list);
+       if (cfg->abs_patches)
+               g_hash_table_destroy (cfg->abs_patches);
 
        g_free (cfg->varinfo);
        g_free (cfg->vars);
@@ -11230,7 +11185,7 @@ mono_create_tls_get (MonoCompile *cfg, int offset)
                return NULL;
        
        MONO_INST_NEW (cfg, ins, OP_TLS_GET);
-       ins->dreg = mono_regstate_next_int (cfg->rs);
+       ins->dreg = cfg->new_ir ? mono_alloc_preg (cfg) : mono_regstate_next_int (cfg->rs);
        ins->inst_offset = offset;
        return ins;
 #else
@@ -11307,6 +11262,11 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
                res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
                memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
                break;
+       case MONO_PATCH_INFO_RGCTX_FETCH:
+               res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
+               memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
+               res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
+               break;
        default:
                break;
        }
@@ -11330,16 +11290,16 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_CLASS:
        case MONO_PATCH_INFO_IID:
        case MONO_PATCH_INFO_ADJUSTED_IID:
-               return (ji->type << 8) | (gssize)ji->data.klass;
-       case MONO_PATCH_INFO_FIELD:
-       case MONO_PATCH_INFO_SFLDA:
-               return (ji->type << 8) | (gssize)ji->data.field;
+       case MONO_PATCH_INFO_CLASS_INIT:
        case MONO_PATCH_INFO_METHODCONST:
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_METHOD_JUMP:
-               return (ji->type << 8) | (gssize)ji->data.method;
        case MONO_PATCH_INFO_IMAGE:
-               return (ji->type << 8) | (gssize)ji->data.image;                
+       case MONO_PATCH_INFO_INTERNAL_METHOD:
+       case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+       case MONO_PATCH_INFO_FIELD:
+       case MONO_PATCH_INFO_SFLDA:
+               return (ji->type << 8) | (gssize)ji->data.target;
        default:
                return (ji->type << 8);
        }
@@ -11372,7 +11332,7 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
                        return 0;
                break;
        default:
-               if (ji1->data.name != ji2->data.name)
+               if (ji1->data.target != ji2->data.target)
                        return 0;
                break;
        }
@@ -11412,18 +11372,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = mono_icall_get_wrapper (mi);
                break;
        }
-       case MONO_PATCH_INFO_METHOD_JUMP: {
-               GSList *list;
-
-               /* get the trampoline to the method from the domain */
-               target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
-               if (!domain->jump_target_hash)
-                       domain->jump_target_hash = g_hash_table_new (NULL, NULL);
-               list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
-               list = g_slist_prepend (list, ip);
-               g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
+       case MONO_PATCH_INFO_METHOD_JUMP:
+               target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
                break;
-       }
        case MONO_PATCH_INFO_METHOD:
                if (patch_info->data.method == method) {
                        target = code;
@@ -11431,7 +11382,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                        /* get the trampoline to the method from the domain */
                        if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
                                target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
-                                       patch_info->data.method, FALSE);
+                                       patch_info->data.method);
                        } else {
                                target = mono_create_jit_trampoline (patch_info->data.method);
                        }
@@ -11559,11 +11510,40 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
                target = mono_thread_interruption_request_flag ();
                break;
+       case MONO_PATCH_INFO_METHOD_RGCTX:
+               target = mono_method_lookup_rgctx (mono_class_vtable (domain, patch_info->data.method->klass), mini_method_get_context (patch_info->data.method)->method_inst);
+               break;
        case MONO_PATCH_INFO_BB_OVF:
        case MONO_PATCH_INFO_EXC_OVF:
        case MONO_PATCH_INFO_GOT_OFFSET:
        case MONO_PATCH_INFO_NONE:
                break;
+       case MONO_PATCH_INFO_RGCTX_FETCH: {
+               MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
+               guint32 slot = -1;
+
+               switch (entry->data->type) {
+               case MONO_PATCH_INFO_CLASS:
+                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
+                       break;
+               case MONO_PATCH_INFO_METHOD:
+               case MONO_PATCH_INFO_METHODCONST:
+                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
+                       break;
+               case MONO_PATCH_INFO_FIELD:
+                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
+                       break;
+               default:
+                       g_assert_not_reached ();
+                       break;
+               }
+
+               target = mono_create_rgctx_lazy_fetch_trampoline (slot);
+               break;
+       }
+       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+               target = mono_create_generic_class_init_trampoline ();
+               break;
        default:
                g_assert_not_reached ();
        }
@@ -11645,672 +11625,6 @@ decompose_pass (MonoCompile *cfg) {
        }
 }
 
-static void
-nullify_basic_block (MonoBasicBlock *bb) 
-{
-       bb->in_count = 0;
-       bb->out_count = 0;
-       bb->in_bb = NULL;
-       bb->out_bb = NULL;
-       bb->next_bb = NULL;
-       bb->code = bb->last_ins = NULL;
-       bb->cil_code = NULL;
-}
-
-static void 
-replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
-{
-       int i;
-
-       for (i = 0; i < bb->out_count; i++) {
-               MonoBasicBlock *ob = bb->out_bb [i];
-               if (ob == orig) {
-                       if (!repl) {
-                               if (bb->out_count > 1) {
-                                       bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
-                               }
-                               bb->out_count--;
-                       } else {
-                               bb->out_bb [i] = repl;
-                       }
-               }
-       }
-}
-
-static void 
-replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
-{
-       int i;
-
-       for (i = 0; i < bb->in_count; i++) {
-               MonoBasicBlock *ib = bb->in_bb [i];
-               if (ib == orig) {
-                       if (!repl) {
-                               if (bb->in_count > 1) {
-                                       bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
-                               }
-                               bb->in_count--;
-                       } else {
-                               bb->in_bb [i] = repl;
-                       }
-               }
-       }
-}
-
-static void
-replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
-       MonoInst *ins;
-       
-       for (ins = bb->code; ins != NULL; ins = ins->next) {
-               switch (ins->opcode) {
-               case OP_BR:
-                       if (ins->inst_target_bb == orig)
-                               ins->inst_target_bb = repl;
-                       break;
-               case OP_CALL_HANDLER:
-                       if (ins->inst_target_bb == orig)
-                               ins->inst_target_bb = repl;
-                       break;
-               case OP_SWITCH: {
-                       int i;
-                       int n = GPOINTER_TO_INT (ins->klass);
-                       for (i = 0; i < n; i++ ) {
-                               if (ins->inst_many_bb [i] == orig)
-                                       ins->inst_many_bb [i] = repl;
-                       }
-                       break;
-               }
-               default:
-                       if (MONO_IS_COND_BRANCH_OP (ins)) {
-                               if (ins->inst_true_bb == orig)
-                                       ins->inst_true_bb = repl;
-                               if (ins->inst_false_bb == orig)
-                                       ins->inst_false_bb = repl;
-                       } else if (MONO_IS_JUMP_TABLE (ins)) {
-                               int i;
-                               MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (ins);
-                               for (i = 0; i < table->table_size; i++ ) {
-                                       if (table->table [i] == orig)
-                                               table->table [i] = repl;
-                               }
-                       }
-
-                       break;
-               }
-       }
-}
-
-/**
-  * Check if a bb is useless (is just made of NOPs and ends with an
-  * unconditional branch, or nothing).
-  * If it is so, unlink it from the CFG and nullify it, and return TRUE.
-  * Otherwise, return FALSE;
-  */
-static gboolean
-remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
-       MonoBasicBlock *target_bb = NULL;
-       MonoInst *inst;
-
-       /* Do not touch handlers */
-       if (bb->region != -1) {
-               bb->not_useless = TRUE;
-               return FALSE;
-       }
-       
-       MONO_BB_FOR_EACH_INS (bb, inst) {
-               switch (inst->opcode) {
-               case OP_NOP:
-                       break;
-               case OP_BR:
-                       target_bb = inst->inst_target_bb;
-                       break;
-               default:
-                       bb->not_useless = TRUE;
-                       return FALSE;
-               }
-       }
-       
-       if (target_bb == NULL) {
-               if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
-                       target_bb = bb->next_bb;
-               } else {
-                       /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
-                       return FALSE;
-               }
-       }
-       
-       /* Do not touch BBs following a switch (they are the "default" branch) */
-       if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == OP_SWITCH)) {
-               return FALSE;
-       }
-       
-       /* Do not touch BBs following the entry BB and jumping to something that is not */
-       /* thiry "next" bb (the entry BB cannot contain the branch) */
-       if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
-               return FALSE;
-       }
-
-       /* 
-        * Do not touch BBs following a try block as the code in 
-        * mini_method_compile needs them to compute the length of the try block.
-        */
-       if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
-               return FALSE;
-       
-       /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
-       if ((target_bb != NULL) && (target_bb != bb)) {
-               int i;
-
-               if (cfg->verbose_level > 1) {
-                       printf ("remove_block_if_useless, removed BB%d\n", bb->block_num);
-               }
-               
-               /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
-               while (bb->in_count) {
-                       MonoBasicBlock *in_bb = bb->in_bb [0];
-                       mono_unlink_bblock (cfg, in_bb, bb);
-                       link_bblock (cfg, in_bb, target_bb);
-                       replace_out_block_in_code (in_bb, bb, target_bb);
-               }
-               
-               mono_unlink_bblock (cfg, bb, target_bb);
-               
-               if ((previous_bb != cfg->bb_entry) &&
-                               (previous_bb->region == bb->region) &&
-                               ((previous_bb->last_ins == NULL) ||
-                               ((previous_bb->last_ins->opcode != OP_BR) &&
-                               (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
-                               (previous_bb->last_ins->opcode != OP_SWITCH)))) {
-                       for (i = 0; i < previous_bb->out_count; i++) {
-                               if (previous_bb->out_bb [i] == target_bb) {
-                                       MonoInst *jump;
-                                       MONO_INST_NEW (cfg, jump, OP_BR);
-                                       MONO_ADD_INS (previous_bb, jump);
-                                       jump->cil_code = previous_bb->cil_code;
-                                       jump->inst_target_bb = target_bb;
-                                       break;
-                               }
-                       }
-               }
-               
-               previous_bb->next_bb = bb->next_bb;
-               nullify_basic_block (bb);
-               
-               return TRUE;
-       } else {
-               return FALSE;
-       }
-}
-
-void
-mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *bbn) 
-{
-       MonoInst *inst;
-       MonoBasicBlock *prev_bb;
-       int i;
-
-       bb->has_array_access |= bbn->has_array_access;
-       bb->extended |= bbn->extended;
-
-       mono_unlink_bblock (cfg, bb, bbn);
-       for (i = 0; i < bbn->out_count; ++i)
-               mono_link_bblock (cfg, bb, bbn->out_bb [i]);
-       while (bbn->out_count)
-               mono_unlink_bblock (cfg, bbn, bbn->out_bb [0]);
-
-       /* Handle the branch at the end of the bb */
-       for (inst = bb->code; inst != NULL; inst = inst->next) {
-               if (inst->opcode == OP_CALL_HANDLER) {
-                       g_assert (inst->inst_target_bb == bbn);
-                       NULLIFY_INS (inst);
-               }
-               if (MONO_IS_JUMP_TABLE (inst)) {
-                       int i;
-                       MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (inst);
-                       for (i = 0; i < table->table_size; i++ ) {
-                               /* Might be already NULL from a previous merge */
-                               if (table->table [i])
-                                       g_assert (table->table [i] == bbn);
-                               table->table [i] = NULL;
-                       }
-                       /* Can't nullify this as later instructions depend on it */
-               }
-       }
-       if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
-               g_assert (bb->last_ins->inst_false_bb == bbn);
-               bb->last_ins->inst_false_bb = NULL;
-               bb->extended = TRUE;
-       } else if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
-               NULLIFY_INS (bb->last_ins);
-       }
-
-       if (bb->last_ins) {
-               if (bbn->code) {
-                       bb->last_ins->next = bbn->code;
-                       bbn->code->prev = bb->last_ins;
-                       bb->last_ins = bbn->last_ins;
-               }
-       } else {
-               bb->code = bbn->code;
-               bb->last_ins = bbn->last_ins;
-       }
-       for (prev_bb = cfg->bb_entry; prev_bb && prev_bb->next_bb != bbn; prev_bb = prev_bb->next_bb)
-               ;
-       if (prev_bb) {
-               prev_bb->next_bb = bbn->next_bb;
-       } else {
-               /* bbn might not be in the bb list yet */
-               if (bb->next_bb == bbn)
-                       bb->next_bb = bbn->next_bb;
-       }
-       nullify_basic_block (bbn);
-}
-
-static void
-move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
-{
-       MonoBasicBlock *bbn, *next;
-
-       next = bb->next_bb;
-
-       /* Find the previous */
-       for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
-               ;
-       if (bbn->next_bb) {
-               bbn->next_bb = bb->next_bb;
-       }
-
-       /* Find the last */
-       for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
-               ;
-       bbn->next_bb = bb;
-       bb->next_bb = NULL;
-
-       /* Add a branch */
-       if (next && (!bb->last_ins || ((bb->last_ins->opcode != OP_NOT_REACHED) && (bb->last_ins->opcode != OP_BR) && (bb->last_ins->opcode != OP_BR_REG) && (!MONO_IS_COND_BRANCH_OP (bb->last_ins))))) {
-               MonoInst *ins;
-
-               MONO_INST_NEW (cfg, ins, OP_BR);
-               MONO_ADD_INS (bb, ins);
-               link_bblock (cfg, bb, next);
-               ins->inst_target_bb = next;
-       }               
-}
-
-/*
- * mono_remove_block:
- *
- *   Remove BB from the control flow graph
- */
-void
-mono_remove_bblock (MonoCompile *cfg, MonoBasicBlock *bb) 
-{
-       MonoBasicBlock *tmp_bb;
-
-       for (tmp_bb = cfg->bb_entry; tmp_bb && tmp_bb->next_bb != bb; tmp_bb = tmp_bb->next_bb)
-               ;
-
-       g_assert (tmp_bb);
-       tmp_bb->next_bb = bb->next_bb;
-}
-
-/* checks that a and b represent the same instructions, conservatively,
- * it can return FALSE also for two trees that are equal.
- * FIXME: also make sure there are no side effects.
- */
-static int
-same_trees (MonoInst *a, MonoInst *b)
-{
-       int arity;
-       if (a->opcode != b->opcode)
-               return FALSE;
-       arity = mono_burg_arity [a->opcode];
-       if (arity == 1) {
-               if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
-                       return TRUE;
-               return same_trees (a->inst_left, b->inst_left);
-       } else if (arity == 2) {
-               return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
-       } else if (arity == 0) {
-               switch (a->opcode) {
-               case OP_ICONST:
-                       return a->inst_c0 == b->inst_c0;
-               default:
-                       return FALSE;
-               }
-       }
-       return FALSE;
-}
-
-static int
-get_unsigned_condbranch (int opcode)
-{
-       switch (opcode) {
-       case CEE_BLE: return CEE_BLE_UN;
-       case CEE_BLT: return CEE_BLT_UN;
-       case CEE_BGE: return CEE_BGE_UN;
-       case CEE_BGT: return CEE_BGT_UN;
-       }
-       g_assert_not_reached ();
-       return 0;
-}
-
-static int
-tree_is_unsigned (MonoInst* ins) {
-       switch (ins->opcode) {
-       case OP_ICONST:
-               return (int)ins->inst_c0 >= 0;
-       /* array lengths are positive as are string sizes */
-       case CEE_LDLEN:
-       case OP_STRLEN:
-               return TRUE;
-       case CEE_CONV_U1:
-       case CEE_CONV_U2:
-       case CEE_CONV_U4:
-       case CEE_CONV_OVF_U1:
-       case CEE_CONV_OVF_U2:
-       case CEE_CONV_OVF_U4:
-               return TRUE;
-       case CEE_LDIND_U1:
-       case CEE_LDIND_U2:
-       case CEE_LDIND_U4:
-               return TRUE;
-       default:
-               return FALSE;
-       }
-}
-
-/* check if an unsigned compare can be used instead of two signed compares
- * for (val < 0 || val > limit) conditionals.
- * Returns TRUE if the optimization has been applied.
- * Note that this can't be applied if the second arg is not positive...
- */
-static int
-try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
-{
-       MonoBasicBlock *truet, *falset;
-       MonoInst *cmp_inst = bb->last_ins->inst_left;
-       MonoInst *condb;
-       if (!cmp_inst->inst_right->inst_c0 == 0)
-               return FALSE;
-       truet = bb->last_ins->inst_true_bb;
-       falset = bb->last_ins->inst_false_bb;
-       if (falset->in_count != 1)
-               return FALSE;
-       condb = falset->last_ins;
-       /* target bb must have one instruction */
-       if (!condb || (condb != falset->code))
-               return FALSE;
-       if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
-                       || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
-                       && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
-               if (!tree_is_unsigned (condb->inst_left->inst_right))
-                       return FALSE;
-               condb->opcode = get_unsigned_condbranch (condb->opcode);
-               /* change the original condbranch to just point to the new unsigned check */
-               bb->last_ins->opcode = OP_BR;
-               bb->last_ins->inst_target_bb = falset;
-               replace_out_block (bb, truet, NULL);
-               replace_in_block (truet, bb, NULL);
-               return TRUE;
-       }
-       return FALSE;
-}
-
-/*
- * Optimizes the branches on the Control Flow Graph
- *
- */
-void
-mono_optimize_branches (MonoCompile *cfg)
-{
-       int i, changed = FALSE;
-       MonoBasicBlock *bb, *bbn;
-       guint32 niterations;
-
-       /*
-        * Some crazy loops could cause the code below to go into an infinite
-        * loop, see bug #53003 for an example. To prevent this, we put an upper
-        * bound on the number of iterations.
-        */
-       if (cfg->num_bblocks > 1000)
-               niterations = cfg->num_bblocks * 2;
-       else
-               niterations = 1000;
-       
-       do {
-               MonoBasicBlock *previous_bb;
-               changed = FALSE;
-               niterations --;
-
-               /* we skip the entry block (exit is handled specially instead ) */
-               for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
-                       /* dont touch code inside exception clauses */
-                       if (bb->region != -1)
-                               continue;
-
-                       if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
-                               changed = TRUE;
-                               continue;
-                       }
-
-                       if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
-                               if (cfg->verbose_level > 2)
-                                       g_print ("nullify block triggered %d\n", bbn->block_num);
-
-                               bb->next_bb = bbn->next_bb;
-
-                               for (i = 0; i < bbn->out_count; i++)
-                                       replace_in_block (bbn->out_bb [i], bbn, NULL);
-
-                               nullify_basic_block (bbn);                      
-                               changed = TRUE;
-                       }
-
-                       if (bb->out_count == 1) {
-                               bbn = bb->out_bb [0];
-
-                               /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
-                               if (bb->last_ins && (bb->last_ins->opcode != OP_BR) && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
-                                       if (!cfg->new_ir) {
-                                               MonoInst *pop;
-                                               MONO_INST_NEW (cfg, pop, CEE_POP);
-                                               pop->inst_left = bb->last_ins->inst_left->inst_left;
-                                               mono_add_ins_to_end (bb, pop);
-                                               MONO_INST_NEW (cfg, pop, CEE_POP);
-                                               pop->inst_left = bb->last_ins->inst_left->inst_right;
-                                               mono_add_ins_to_end (bb, pop);
-                                       }
-                                       bb->last_ins->opcode = OP_BR;
-                                       bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
-                                       changed = TRUE;
-                                       if (cfg->verbose_level > 2)
-                                               g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
-                               }
-
-                               if (bb->region == bbn->region && bb->next_bb == bbn) {
-                                       /* the block are in sequence anyway ... */
-
-                                       /* branches to the following block can be removed */
-                                       if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
-                                               bb->last_ins->opcode = OP_NOP;
-                                               changed = TRUE;
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
-                                       }
-
-                                       if (bbn->in_count == 1 && !bb->extended) {
-                                               if (bbn != cfg->bb_exit) {
-                                                       if (cfg->verbose_level > 2)
-                                                               g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
-                                                       mono_merge_basic_blocks (cfg, bb, bbn);
-                                                       changed = TRUE;
-                                                       continue;
-                                               }
-
-                                               //mono_print_bb_code (bb);
-                                       }
-                               }
-                       }
-
-                       if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
-                               if (cfg->verbose_level > 2) {
-                                       g_print ("nullify block triggered %d\n", bbn->block_num);
-                               }
-                               bb->next_bb = bbn->next_bb;
-
-                               for (i = 0; i < bbn->out_count; i++)
-                                       replace_in_block (bbn->out_bb [i], bbn, NULL);
-
-                               nullify_basic_block (bbn);                      
-                               changed = TRUE;
-                               continue;
-                       }
-
-                       if (bb->out_count == 1) {
-                               bbn = bb->out_bb [0];
-
-                               if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
-                                       bbn = bb->last_ins->inst_target_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
-                                           bbn->code->inst_target_bb->region == bb->region) {
-                                               
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("branch to branch triggered %d -> %d -> %d\n", bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
-
-                                               replace_in_block (bbn, bb, NULL);
-                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
-                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
-                                               bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
-                                               changed = TRUE;
-                                               continue;
-                                       }
-                               }
-                       } else if (bb->out_count == 2) {
-                               if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
-                                       int branch_result;
-                                       MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
-
-                                       if (cfg->new_ir) {
-                                               if (bb->last_ins->flags & MONO_INST_CFOLD_TAKEN)
-                                                       branch_result = BRANCH_TAKEN;
-                                               else if (bb->last_ins->flags & MONO_INST_CFOLD_NOT_TAKEN)
-                                                       branch_result = BRANCH_NOT_TAKEN;
-                                               else
-                                                       branch_result = BRANCH_UNDEF;
-                                       }
-                                       else
-                                               branch_result = mono_eval_cond_branch (bb->last_ins);
-
-                                       if (branch_result == BRANCH_TAKEN) {
-                                               taken_branch_target = bb->last_ins->inst_true_bb;
-                                               untaken_branch_target = bb->last_ins->inst_false_bb;
-                                       } else if (branch_result == BRANCH_NOT_TAKEN) {
-                                               taken_branch_target = bb->last_ins->inst_false_bb;
-                                               untaken_branch_target = bb->last_ins->inst_true_bb;
-                                       }
-                                       if (taken_branch_target) {
-                                               /* if mono_eval_cond_branch () is ever taken to handle 
-                                                * non-constant values to compare, issue a pop here.
-                                                */
-                                               bb->last_ins->opcode = OP_BR;
-                                               bb->last_ins->inst_target_bb = taken_branch_target;
-                                               if (!bb->extended)
-                                                       mono_unlink_bblock (cfg, bb, untaken_branch_target);
-                                               changed = TRUE;
-                                               continue;
-                                       }
-                                       bbn = bb->last_ins->inst_true_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
-                                           bbn->code->inst_target_bb->region == bb->region) {
-                                               if (cfg->verbose_level > 2)             
-                                                       g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
-                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
-                                                                bbn->code->opcode);
-
-                                               /* 
-                                                * Unlink, then relink bblocks to avoid various
-                                                * tricky situations when the two targets of the branch
-                                                * are equal, or will become equal after the change.
-                                                */
-                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
-                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
-                                               bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
-
-                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
-                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
-                                               changed = TRUE;
-                                               continue;
-                                       }
-
-                                       bbn = bb->last_ins->inst_false_bb;
-                                       if (bbn && bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
-                                           bbn->code->inst_target_bb->region == bb->region) {
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
-                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
-                                                                bbn->code->opcode);
-
-                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
-                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
-                                               bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
-
-                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
-                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
-                                               changed = TRUE;
-                                               continue;
-                                       }
-
-                                       bbn = bb->last_ins->inst_false_bb;
-                                       /*
-                                        * If bb is an extended bb, it could contain an inside branch to bbn.
-                                        * FIXME: Enable the optimization if that is not true.
-                                        * If bblocks_linked () is true, then merging bb and bbn
-                                        * would require addition of an extra branch at the end of bbn 
-                                        * slowing down loops.
-                                        */
-                                       if (cfg->new_ir && bbn && bb->region == bbn->region && bbn->in_count == 1 && cfg->enable_extended_bblocks && bbn != cfg->bb_exit && !bb->extended && !bbn->out_of_line && !mono_bblocks_linked (bbn, bb)) {
-                                               g_assert (bbn->in_bb [0] == bb);
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("merge false branch target triggered BB%d -> BB%d\n", bb->block_num, bbn->block_num);
-                                               mono_merge_basic_blocks (cfg, bb, bbn);
-                                               changed = TRUE;
-                                               continue;
-                                       }
-                               }
-
-                               /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
-                               if (bb->last_ins && bb->last_ins->opcode == CEE_BLT && !cfg->new_ir && bb->last_ins->inst_left->inst_right->opcode == OP_ICONST) {
-                                       if (try_unsigned_compare (cfg, bb)) {
-                                               /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
-                                               changed = TRUE;
-                                               continue;
-                                       }
-                               }
-
-                               if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
-                                       if (bb->last_ins->inst_false_bb && bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
-                                               /* Reverse the branch */
-                                               bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
-                                               bbn = bb->last_ins->inst_false_bb;
-                                               bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
-                                               bb->last_ins->inst_true_bb = bbn;
-
-                                               move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("cbranch to throw block triggered %d.\n", 
-                                                                        bb->block_num);
-                                       }
-                               }
-                       }
-               }
-       } while (changed && (niterations > 0));
-}
-
 static void
 mono_compile_create_vars (MonoCompile *cfg)
 {
@@ -12497,7 +11811,7 @@ mini_select_instructions (MonoCompile *cfg)
                                bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
                                bb->last_ins->inst_false_bb = tmp;
 
-                               bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+                               bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
                        } else {                        
                                MonoInst *ins;
 
@@ -12753,6 +12067,11 @@ mono_codegen (MonoCompile *cfg)
                switch (patch_info->type) {
                case MONO_PATCH_INFO_ABS: {
                        MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
+
+                       /*
+                        * Change patches of type MONO_PATCH_INFO_ABS into patches describing the 
+                        * absolute address.
+                        */
                        if (info) {
                                //printf ("TEST %s %p\n", info->name, patch_info->data.target);
                                // FIXME: CLEAN UP THIS MESS.
@@ -12778,19 +12097,33 @@ mono_codegen (MonoCompile *cfg)
                                        }
                                }
                        }
-                       else {
+                       
+                       if (patch_info->type == MONO_PATCH_INFO_ABS && !cfg->new_ir) {
                                MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
                                if (vtable) {
                                        patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
                                        patch_info->data.klass = vtable->klass;
-                               } else {
-                                       MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
-                                       if (klass) {
-                                               patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
-                                               patch_info->data.klass = klass;
+                               }
+                       }
+
+                       if (patch_info->type == MONO_PATCH_INFO_ABS) {
+                               MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
+                               if (klass) {
+                                       patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
+                                       patch_info->data.klass = klass;
+                               }
+                       }
+
+                       if (patch_info->type == MONO_PATCH_INFO_ABS) {
+                               if (cfg->abs_patches) {
+                                       MonoJumpInfo *abs_ji = g_hash_table_lookup (cfg->abs_patches, patch_info->data.target);
+                                       if (abs_ji) {
+                                               patch_info->type = abs_ji->type;
+                                               patch_info->data.target = abs_ji->data.target;
                                        }
                                }
                        }
+
                        break;
                }
                case MONO_PATCH_INFO_SWITCH: {
@@ -12818,6 +12151,20 @@ mono_codegen (MonoCompile *cfg)
                        patch_info->data.table->table = (MonoBasicBlock**)table;
                        break;
                }
+               case MONO_PATCH_INFO_METHOD_JUMP: {
+                       GSList *list;
+                       MonoDomain *domain = cfg->domain;
+                       unsigned char *ip = cfg->native_code + patch_info->ip.i;
+
+                       mono_domain_lock (domain);
+                       if (!domain->jump_target_hash)
+                               domain->jump_target_hash = g_hash_table_new (NULL, NULL);
+                       list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
+                       list = g_slist_prepend (list, ip);
+                       g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
+                       mono_domain_unlock (domain);
+                       break;
+               }
                default:
                        /* do nothing */
                        break;
@@ -12874,135 +12221,6 @@ if (valgrind_register){
 #endif
 }
 
-void
-mono_remove_critical_edges (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb;
-       MonoBasicBlock *previous_bb;
-       
-       if (cfg->verbose_level > 3) {
-               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-                       int i;
-                       printf ("remove_critical_edges, BEFORE BB%d (in:", bb->block_num);
-                       for (i = 0; i < bb->in_count; i++) {
-                               printf (" %d", bb->in_bb [i]->block_num);
-                       }
-                       printf (") (out:");
-                       for (i = 0; i < bb->out_count; i++) {
-                               printf (" %d", bb->out_bb [i]->block_num);
-                       }
-                       printf (")");
-                       if (bb->last_ins != NULL) {
-                               printf (" ");
-                               mono_print_tree (bb->last_ins);
-                       }
-                       printf ("\n");
-               }
-       }
-       
-       for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
-               if (bb->in_count > 1) {
-                       int in_bb_index;
-                       for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
-                               MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
-                               if (in_bb->out_count > 1) {
-                                       MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-                                       new_bb->block_num = cfg->num_bblocks++;
-//                                     new_bb->real_offset = bb->real_offset;
-                                       new_bb->region = bb->region;
-                                       
-                                       /* Do not alter the CFG while altering the BB list */
-                                       if (previous_bb->region == bb->region) {
-                                               if (previous_bb != cfg->bb_entry) {
-                                                       /* If previous_bb "followed through" to bb, */
-                                                       /* keep it linked with a OP_BR */
-                                                       if ((previous_bb->last_ins == NULL) ||
-                                                                       ((previous_bb->last_ins->opcode != OP_BR) &&
-                                                                       (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
-                                                                       (previous_bb->last_ins->opcode != OP_SWITCH))) {
-                                                               int i;
-                                                               /* Make sure previous_bb really falls through bb */
-                                                               for (i = 0; i < previous_bb->out_count; i++) {
-                                                                       if (previous_bb->out_bb [i] == bb) {
-                                                                               MonoInst *jump;
-                                                                               MONO_INST_NEW (cfg, jump, OP_BR);
-                                                                               MONO_ADD_INS (previous_bb, jump);
-                                                                               jump->cil_code = previous_bb->cil_code;
-                                                                               jump->inst_target_bb = bb;
-                                                                               break;
-                                                                       }
-                                                               }
-                                                       }
-                                               } else {
-                                                       /* We cannot add any inst to the entry BB, so we must */
-                                                       /* put a new BB in the middle to hold the OP_BR */
-                                                       MonoInst *jump;
-                                                       MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-                                                       new_bb_after_entry->block_num = cfg->num_bblocks++;
-//                                                     new_bb_after_entry->real_offset = bb->real_offset;
-                                                       new_bb_after_entry->region = bb->region;
-                                                       
-                                                       MONO_INST_NEW (cfg, jump, OP_BR);
-                                                       MONO_ADD_INS (new_bb_after_entry, jump);
-                                                       jump->cil_code = bb->cil_code;
-                                                       jump->inst_target_bb = bb;
-                                                       
-                                                       previous_bb->next_bb = new_bb_after_entry;
-                                                       previous_bb = new_bb_after_entry;
-                                                       
-                                                       if (cfg->verbose_level > 2) {
-                                                               printf ("remove_critical_edges, added helper BB%d jumping to BB%d\n", new_bb_after_entry->block_num, bb->block_num);
-                                                       }
-                                               }
-                                       }
-                                       
-                                       /* Insert new_bb in the BB list */
-                                       previous_bb->next_bb = new_bb;
-                                       new_bb->next_bb = bb;
-                                       previous_bb = new_bb;
-                                       
-                                       /* Setup in_bb and out_bb */
-                                       new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
-                                       new_bb->in_bb [0] = in_bb;
-                                       new_bb->in_count = 1;
-                                       new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
-                                       new_bb->out_bb [0] = bb;
-                                       new_bb->out_count = 1;
-                                       
-                                       /* Relink in_bb and bb to (from) new_bb */
-                                       replace_out_block (in_bb, bb, new_bb);
-                                       replace_out_block_in_code (in_bb, bb, new_bb);
-                                       replace_in_block (bb, in_bb, new_bb);
-                                       
-                                       if (cfg->verbose_level > 2) {
-                                               printf ("remove_critical_edges, removed critical edge from BB%d to BB%d (added BB%d)\n", in_bb->block_num, bb->block_num, new_bb->block_num);
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       if (cfg->verbose_level > 3) {
-               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-                       int i;
-                       printf ("remove_critical_edges, AFTER BB%d (in:", bb->block_num);
-                       for (i = 0; i < bb->in_count; i++) {
-                               printf (" %d", bb->in_bb [i]->block_num);
-                       }
-                       printf (") (out:");
-                       for (i = 0; i < bb->out_count; i++) {
-                               printf (" %d", bb->out_bb [i]->block_num);
-                       }
-                       printf (")");
-                       if (bb->last_ins != NULL) {
-                               printf (" ");
-                               mono_print_tree (bb->last_ins);
-                       }
-                       printf ("\n");
-               }
-       }
-}
-
 static MonoGenericInst*
 get_object_generic_inst (int type_argc)
 {
@@ -13099,10 +12317,16 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->verbose_level = mini_verbose;
        cfg->compile_aot = compile_aot;
        cfg->skip_visibility = method->skip_visibility;
+       cfg->orig_method = method;
        if (try_generic_shared)
                cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
 
+       if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) {
+               cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
+               return cfg;
+       }
+
        /* The debugger has no liveness information, so avoid sharing registers/stack slots */
        if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
                cfg->disable_reuse_registers = TRUE;
@@ -13327,7 +12551,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                                        g_print ("found unreachable code in BB%d\n", bbn->block_num);
                                /* There may exist unreachable branches to this bb */
                                bb->next_bb = bbn->next_bb;
-                               nullify_basic_block (bbn);                      
+                               mono_nullify_basic_block (bbn);                 
                        } else {
                                bb = bb->next_bb;
                        }
@@ -13598,7 +12822,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                                        bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
                                        bb->last_ins->inst_false_bb = tmp;
 
-                                       bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+                                       bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
                                } else {                        
                                        MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
                                        inst->opcode = OP_BR;
@@ -15036,6 +14260,32 @@ mini_get_debug_options (void)
 {
        return &debug_options;
 }
+static void
+mini_create_jit_domain_info (MonoDomain *domain)
+{
+       MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
+
+       domain->runtime_info = info;
+}
+
+static void
+delete_jump_list (gpointer key, gpointer value, gpointer user_data)
+{
+       g_slist_free (value);
+}
+
+static void
+mini_free_jit_domain_info (MonoDomain *domain)
+{
+       MonoJitDomainInfo *info = jit_domain_info (domain);
+
+       if (info->jump_target_got_slot_hash) {
+               g_hash_table_foreach (info->jump_target_got_slot_hash, delete_jump_list, NULL);
+               g_hash_table_destroy (info->jump_target_got_slot_hash);
+       }
+       g_free (domain->runtime_info);
+}
 
 MonoDomain *
 mini_init (const char *filename, const char *runtime_version)
@@ -15104,6 +14354,8 @@ mini_init (const char *filename, const char *runtime_version)
        mono_install_jump_trampoline (mono_create_jump_trampoline);
        mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
        mono_install_delegate_trampoline (mono_create_delegate_trampoline);
+       mono_install_create_domain_hook (mini_create_jit_domain_info);
+       mono_install_free_domain_hook (mini_free_jit_domain_info);
 #endif
 #define JIT_INVOKE_WORKS
 #ifdef JIT_INVOKE_WORKS
@@ -15317,12 +14569,9 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
        register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
        register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
-       register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
        register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
        register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
-       register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
-       register_icall (mono_helper_compile_generic_method_wo_context, "compile_generic_method_wo_context",
-               "ptr object ptr ptr", FALSE);
+       register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
        register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
        register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
        register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
@@ -15332,19 +14581,26 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
        register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
        register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
+       register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
        register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
 #endif
 
+       mono_generic_sharing_init ();
+
+       if (mono_compile_aot)
+               /* 
+                * Avoid running managed code when AOT compiling, since the platform
+                * might only support aot-only execution.
+                */
+               mono_runtime_set_no_exec (TRUE);
+
 #define JIT_RUNTIME_WORKS
 #ifdef JIT_RUNTIME_WORKS
        mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
        mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
+       mono_thread_attach (domain);
 #endif
 
-       mono_generic_sharing_init ();
-
-       mono_thread_attach (domain);
-       
        mono_profiler_runtime_initialized ();
        
        MONO_PROBE_VES_INIT_END ();