2007-06-05 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index da202aefb6b6d88fa9c3b28527ff9f4fb994b411..18a69edbce30ca3a7d2b7a3abfaca7675d005950 100644 (file)
 
 #include <config.h>
 #include <signal.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <math.h>
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 
 #ifdef PLATFORM_MACOSX
 #include <mach/mach.h>
@@ -86,7 +90,7 @@
 #define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
 
-#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == CEE_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
+#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == OP_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
 
 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
 
@@ -373,19 +377,19 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
  * block_num: unique ID assigned at bblock creation
  */
 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
-#define ADD_BBLOCK(cfg,bbhash,b) do {  \
-               g_hash_table_insert (bbhash, (b)->cil_code, (b));       \
+#define ADD_BBLOCK(cfg,b) do { \
+               cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
                (b)->block_num = cfg->num_bblocks++;    \
                (b)->real_offset = real_offset; \
        } while (0)
 
-#define GET_BBLOCK(cfg,bbhash,tblock,ip) do {  \
-               (tblock) = g_hash_table_lookup (bbhash, (ip));  \
+#define GET_BBLOCK(cfg,tblock,ip) do { \
+               (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
                if (!(tblock)) {        \
                        if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
                        (tblock) = NEW_BBLOCK (cfg);    \
                        (tblock)->cil_code = (ip);      \
-                       ADD_BBLOCK (cfg, (bbhash), (tblock));   \
+                       ADD_BBLOCK (cfg, (tblock));     \
                } \
        } while (0)
 
@@ -676,7 +680,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                ins->inst_i0 = cmp;     \
                MONO_ADD_INS (bblock, ins);     \
                ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
-               GET_BBLOCK (cfg, bbhash, tblock, target);               \
+               GET_BBLOCK (cfg, tblock, target);               \
                link_bblock (cfg, bblock, tblock);      \
                ins->inst_true_bb = tblock;     \
                CHECK_BBLOCK (target, ip, tblock);      \
@@ -685,7 +689,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                        ins->inst_false_bb = (next_block);      \
                        start_new_bblock = 1;   \
                } else {        \
-                       GET_BBLOCK (cfg, bbhash, tblock, ip);           \
+                       GET_BBLOCK (cfg, tblock, ip);           \
                        link_bblock (cfg, bblock, tblock);      \
                        ins->inst_false_bb = tblock;    \
                        start_new_bblock = 2;   \
@@ -718,11 +722,11 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
                MONO_ADD_INS (bblock, ins);     \
                ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
-               GET_BBLOCK (cfg, bbhash, tblock, target);               \
+               GET_BBLOCK (cfg, tblock, target);               \
                link_bblock (cfg, bblock, tblock);      \
                ins->inst_true_bb = tblock;     \
                CHECK_BBLOCK (target, ip, tblock);      \
-               GET_BBLOCK (cfg, bbhash, tblock, ip);           \
+               GET_BBLOCK (cfg, tblock, ip);           \
                link_bblock (cfg, bblock, tblock);      \
                ins->inst_false_bb = tblock;    \
                start_new_bblock = 2;   \
@@ -927,7 +931,7 @@ mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *targe
                if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
                    (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
                        if (clause->flags == type) {
-                               handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
+                               handler = cfg->cil_offset_to_bb [clause->handler_offset];
                                g_assert (handler);
                                res = g_list_append (res, handler);
                        }
@@ -1000,32 +1004,22 @@ df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
        }
 }
 
-typedef struct {
-       const guchar *code;
-       MonoBasicBlock *best;
-} PrevStruct;
-
-static void
-previous_foreach (gconstpointer key, gpointer val, gpointer data)
+static MonoBasicBlock*
+find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
 {
-       PrevStruct *p = data;
-       MonoBasicBlock *bb = val;
-       //printf ("FIDPREV %d %p  %p %p %p %p %d %d %d\n", bb->block_num, p->code, bb, p->best, bb->cil_code, p->best->cil_code,
-       //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
+       MonoBasicBlock *best = start;
+       int i;
 
-       if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
-               p->best = bb;
-}
+       for (i = 0; i < n_bblocks; ++i) {
+               if (bblocks [i]) {
+                       MonoBasicBlock *bb = bblocks [i];
 
-static MonoBasicBlock*
-find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
-       PrevStruct p;
-
-       p.code = code;
-       p.best = start;
+                       if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
+                               best = bb;
+               }
+       }
 
-       g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
-       return p.best;
+       return best;
 }
 
 static void
@@ -1450,7 +1444,7 @@ type_from_op (MonoInst *ins) {
                ins->type = STACK_R8;
                ins->opcode += unops_op_map [ins->inst_i0->type];
                return;
-       case CEE_CKFINITE:
+       case OP_CKFINITE:
                ins->type = STACK_R8;           
                return;
        case CEE_CONV_U2:
@@ -1774,7 +1768,7 @@ mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
        case CEE_BGT_UN:
        case CEE_BLE_UN:
        case CEE_BLT_UN:
-       case CEE_BR:
+       case OP_BR:
        case CEE_SWITCH:
                prev = bb->code;
                while (prev->next && prev->next != bb->last_ins)
@@ -1816,39 +1810,6 @@ mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest
        }
 }
 
-/*
- * We try to share variables when possible
- */
-static MonoInst *
-mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
-{
-       MonoInst *res;
-       int pos, vnum;
-
-       /* inlining can result in deeper stacks */ 
-       if (slot >= mono_method_get_header (cfg->method)->max_stack)
-               return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
-
-       pos = ins->type - 1 + slot * STACK_MAX;
-
-       switch (ins->type) {
-       case STACK_I4:
-       case STACK_I8:
-       case STACK_R8:
-       case STACK_PTR:
-       case STACK_MP:
-       case STACK_OBJ:
-               if ((vnum = cfg->intvars [pos]))
-                       return cfg->varinfo [vnum];
-               res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
-               cfg->intvars [pos] = res->inst_c0;
-               break;
-       default:
-               res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
-       }
-       return res;
-}
-
 /*
  * merge_stacks:
  *
@@ -2158,6 +2119,17 @@ mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs,
        cfg->patch_info = ji;
 }
 
+static void
+mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
+{
+       if (cfg->compile_aot) {
+               MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
+               jump_info_token->image = image;
+               jump_info_token->token = token;
+               g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
+       }
+}
+
 /*
  * When we add a tree of instructions, we need to ensure the instructions currently
  * on the stack are executed before (like, if we load a value from a local).
@@ -2480,7 +2452,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
        {
                int i;
                for (i = 0; i < sig->param_count; ++i) {
-                       if (sig->params [i]->type == MONO_TYPE_R4) {
+                       if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
                                MonoInst *iargs [1];
                                int temp;
                                iargs [0] = args [i + sig->hasthis];
@@ -2737,7 +2709,7 @@ handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, cons
                        int temp;       \
                        NEW_LOCLOADA (cfg, (ins), (idx));       \
                        handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
-                       MONO_INST_NEW (cfg, (ins), CEE_NOP);    \
+                       MONO_INST_NEW (cfg, (ins), OP_NOP);     \
                }       \
        } while (0)
 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
@@ -2753,7 +2725,7 @@ handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, cons
                        int temp;       \
                        NEW_ARGLOADA (cfg, (ins), (idx));       \
                        handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
-                       MONO_INST_NEW (cfg, (ins), CEE_NOP);    \
+                       MONO_INST_NEW (cfg, (ins), OP_NOP);     \
                }       \
        } while (0)
 #else
@@ -3088,7 +3060,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
                }
 #ifdef MONO_ARCH_SOFT_FLOAT
                /* this complicates things, fix later */
-               if (signature->params [i]->type == MONO_TYPE_R4)
+               if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
                        return FALSE;
 #endif
        }
@@ -3217,6 +3189,22 @@ mono_find_jit_opcode_emulation (int opcode)
                return NULL;
 }
 
+static int
+is_signed_regsize_type (MonoType *type)
+{
+       switch (type->type) {
+       case MONO_TYPE_I1:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_I4:
+#if SIZEOF_VOID_P == 8
+       /*case MONO_TYPE_I8: this requires different opcodes in inssel.brg */
+#endif
+               return TRUE;
+       default:
+               return FALSE;
+       }
+}
+
 static MonoInst*
 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -3261,7 +3249,7 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        return ins;
 #endif
                } else if (strcmp (cmethod->name, ".ctor") == 0) {
-                       MONO_INST_NEW (cfg, ins, CEE_NOP);
+                       MONO_INST_NEW (cfg, ins, OP_NOP);
                        return ins;
                } else
                        return NULL;
@@ -3309,10 +3297,26 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                store->inst_left = args [2];
                store->inst_right = load;
                return store;
+       } else if (cmethod->klass == mono_defaults.math_class) {
+               if (strcmp (cmethod->name, "Min") == 0) {
+                       if (is_signed_regsize_type (fsig->params [0])) {
+                               MONO_INST_NEW (cfg, ins, OP_MIN);
+                               ins->inst_i0 = args [0];
+                               ins->inst_i1 = args [1];
+                               return ins;
+                       }
+               } else if (strcmp (cmethod->name, "Max") == 0) {
+                       if (is_signed_regsize_type (fsig->params [0])) {
+                               MONO_INST_NEW (cfg, ins, OP_MAX);
+                               ins->inst_i0 = args [0];
+                               ins->inst_i1 = args [1];
+                               return ins;
+                       }
+               }
        } else if (cmethod->klass->image == mono_defaults.corlib) {
                if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
                                && strcmp (cmethod->klass->name, "Debugger") == 0) {
-                       MONO_INST_NEW (cfg, ins, CEE_BREAK);
+                       MONO_INST_NEW (cfg, ins, OP_BREAK);
                        return ins;
                }
                if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
@@ -3431,6 +3435,10 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        MonoBasicBlock *ebblock, *sbblock;
        int i, costs, new_locals_offset;
        MonoMethod *prev_inlined_method;
+       MonoBasicBlock **prev_cil_offset_to_bb;
+       unsigned char* prev_cil_start;
+       guint32 prev_cil_offset_to_bb_len;
+
 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
        if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
                return 0;
@@ -3472,10 +3480,16 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 
        prev_inlined_method = cfg->inlined_method;
        cfg->inlined_method = cmethod;
+       prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
+       prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
+       prev_cil_start = cfg->cil_start;
 
        costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
 
        cfg->inlined_method = prev_inlined_method;
+       cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
+       cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
+       cfg->cil_start = prev_cil_start;
 
        if ((costs >= 0 && costs < 60) || inline_allways) {
                if (cfg->verbose_level > 2)
@@ -3484,7 +3498,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                mono_jit_stats.inlined_methods++;
 
                /* always add some code to avoid block split failures */
-               MONO_INST_NEW (cfg, ins, CEE_NOP);
+               MONO_INST_NEW (cfg, ins, OP_NOP);
                MONO_ADD_INS (bblock, ins);
                ins->cil_code = ip;
 
@@ -3526,8 +3540,6 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
  * or through repeated runs where the compiler applies offline the optimizations to 
  * each method and then decides if it was worth it.
  *
- * TODO:
- * * consider using an array instead of an hash table (bb_hash)
  */
 
 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
@@ -3542,16 +3554,16 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 /* offset from br.s -> br like opcodes */
 #define BIG_BRANCH_OFFSET 13
 
-static gboolean
+static inline gboolean
 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
 {
-       MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
+       MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
        
        return b == NULL || b == bb;
 }
 
 static int
-get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
+get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
 {
        unsigned char *ip = start;
        unsigned char *target;
@@ -3589,17 +3601,17 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
                        break;
                case MonoShortInlineBrTarget:
                        target = start + cli_addr + 2 + (signed char)ip [1];
-                       GET_BBLOCK (cfg, bbhash, bblock, target);
+                       GET_BBLOCK (cfg, bblock, target);
                        ip += 2;
                        if (ip < end)
-                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               GET_BBLOCK (cfg, bblock, ip);
                        break;
                case MonoInlineBrTarget:
                        target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
-                       GET_BBLOCK (cfg, bbhash, bblock, target);
+                       GET_BBLOCK (cfg, bblock, target);
                        ip += 5;
                        if (ip < end)
-                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               GET_BBLOCK (cfg, bblock, ip);
                        break;
                case MonoInlineSwitch: {
                        guint32 n = read32 (ip + 1);
@@ -3607,11 +3619,11 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
                        ip += 5;
                        cli_addr += 5 + 4 * n;
                        target = start + cli_addr;
-                       GET_BBLOCK (cfg, bbhash, bblock, target);
+                       GET_BBLOCK (cfg, bblock, target);
                        
                        for (j = 0; j < n; ++j) {
                                target = start + cli_addr + (gint32)read32 (ip);
-                               GET_BBLOCK (cfg, bbhash, bblock, target);
+                               GET_BBLOCK (cfg, bblock, target);
                                ip += 4;
                        }
                        break;
@@ -3630,7 +3642,7 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
                        /* Find the start of the bblock containing the throw */
                        bblock = NULL;
                        while ((bb_start >= start) && !bblock) {
-                               bblock = g_hash_table_lookup (bbhash, (bb_start));
+                               bblock = cfg->cil_offset_to_bb [(bb_start) - start];
                                bb_start --;
                        }
                        if (bblock)
@@ -3760,6 +3772,13 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
 static gboolean
 can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
 {
+       if (access_klass->generic_class && member_klass->generic_class &&
+           access_klass->generic_class->container_class && member_klass->generic_class->container_class) {
+               if (can_access_member (access_klass->generic_class->container_class,
+                                      member_klass->generic_class->container_class, access_level))
+                       return TRUE;
+       }
+
        /* Partition I 8.5.3.2 */
        /* the access level values are the same for fields and methods */
        switch (access_level) {
@@ -3767,12 +3786,10 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_
                /* same compilation unit */
                return access_klass->image == member_klass->image;
        case FIELD_ATTRIBUTE_PRIVATE:
-               if (access_klass->generic_class && member_klass->generic_class && member_klass->generic_class->container_class)
-                       return member_klass->generic_class->container_class == access_klass->generic_class->container_class;
                return access_klass == member_klass;
        case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
                if (mono_class_has_parent (access_klass, member_klass) &&
-                               can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
+                   can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
                        return TRUE;
                return FALSE;
        case FIELD_ATTRIBUTE_ASSEMBLY:
@@ -3857,6 +3874,8 @@ initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, Mono
                if (newarr->inst_newa_len->opcode != OP_ICONST)
                        return NULL;
                cmethod = mini_get_method (method, token, NULL, NULL);
+               if (!cmethod)
+                       return NULL;
                if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
                        return NULL;
                switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
@@ -3911,7 +3930,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
        MonoInst *ins, **sp, **stack_start;
        MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
-       GHashTable *bbhash;
        MonoMethod *cmethod;
        MonoInst **arg_array;
        MonoMethodHeader *header;
@@ -3959,6 +3977,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        sig = mono_method_signature (method);
        num_args = sig->hasthis + sig->param_count;
        ip = (unsigned char*)header->code;
+       cfg->cil_start = ip;
        end = ip + header->code_size;
        mono_jit_stats.cil_code_size += header->code_size;
 
@@ -3969,13 +3988,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
        g_assert (!sig->has_type_parameters);
 
-       if (cfg->method == method) {
+       if (cfg->method == method)
                real_offset = 0;
-               bbhash = cfg->bb_hash;
-       } else {
+       else
                real_offset = inline_offset;
-               bbhash = g_hash_table_new (g_direct_hash, NULL);
-       }
+
+       cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
+       cfg->cil_offset_to_bb_len = header->code_size;
 
        if (cfg->verbose_level > 2)
                g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
@@ -4011,9 +4030,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                for (i = 0; i < header->num_clauses; ++i) {
                        MonoBasicBlock *try_bb;
                        MonoExceptionClause *clause = &header->clauses [i];
-                       GET_BBLOCK (cfg, bbhash, try_bb, ip + clause->try_offset);
+                       GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
                        try_bb->real_offset = clause->try_offset;
-                       GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
+                       GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
                        tblock->real_offset = clause->handler_offset;
                        tblock->flags |= BB_EXCEPTION_HANDLER;
 
@@ -4062,7 +4081,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (tblock, dummy_use);
                                
                                if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
-                                       GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
+                                       GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
                                        tblock->real_offset = clause->data.filter_offset;
                                        tblock->in_scount = 1;
                                        tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
@@ -4087,12 +4106,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        bblock = NEW_BBLOCK (cfg);
        bblock->cil_code = ip;
 
-       ADD_BBLOCK (cfg, bbhash, bblock);
+       ADD_BBLOCK (cfg, bblock);
 
        if (cfg->method == method) {
                breakpoint_id = mono_debugger_method_has_breakpoint (method);
                if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
-                       MONO_INST_NEW (cfg, ins, CEE_BREAK);
+                       MONO_INST_NEW (cfg, ins, OP_BREAK);
                        MONO_ADD_INS (bblock, ins);
                }
        }
@@ -4182,7 +4201,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
        }
 
-       if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
+       if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
                ip = err_pos;
                UNVERIFIED;
        }
@@ -4238,7 +4257,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (start_new_bblock == 2) {
                                g_assert (ip == tblock->cil_code);
                        } else {
-                               GET_BBLOCK (cfg, bbhash, tblock, ip);
+                               GET_BBLOCK (cfg, tblock, ip);
                        }
                        bblock->next_bb = tblock;
                        bblock = tblock;
@@ -4252,7 +4271,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        g_slist_free (class_inits);
                        class_inits = NULL;
                } else {
-                       if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
+                       if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
                                link_bblock (cfg, bblock, tblock);
                                if (sp != stack_start) {
                                        handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
@@ -4299,8 +4318,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                switch (*ip) {
                case CEE_NOP:
+                       MONO_INST_NEW (cfg, ins, OP_NOP);
+                       ins->cil_code = ip++;
+                       MONO_ADD_INS (bblock, ins);
+                       break;
                case CEE_BREAK:
-                       MONO_INST_NEW (cfg, ins, *ip);
+                       MONO_INST_NEW (cfg, ins, OP_BREAK);
                        ins->cil_code = ip++;
                        MONO_ADD_INS (bblock, ins);
                        break;
@@ -4571,7 +4594,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        if (stack_start != sp)
                                UNVERIFIED;
-                       MONO_INST_NEW (cfg, ins, CEE_JMP);
+                       MONO_INST_NEW (cfg, ins, OP_JMP);
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
                        cmethod = mini_get_method (method, token, NULL, generic_context);
@@ -4649,6 +4672,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
                                }
 
+                               mono_save_token_info (cfg, image, token, cmethod);
+
                                n = fsig->param_count + fsig->hasthis;
 
                                if (mono_use_security_manager) {
@@ -4739,8 +4764,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
                                this_arg_temp->cil_code = ip;
 
+                               /* Because of the PCONST below */
+                               cfg->disable_aot = TRUE;
                                NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
-                               NEW_PCONST (cfg, iargs [1], cmethod);
+                               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);
                                temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
@@ -4767,7 +4794,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* FIXME: This assumes the two methods has the same number and type of arguments */
                                /*
                                 * We implement tail calls by storing the actual arguments into the 
-                                * argument variables, then emitting a CEE_JMP. Since the actual arguments
+                                * argument variables, then emitting a OP_JMP. Since the actual arguments
                                 * can refer to the arg variables, we have to spill them.
                                 */
                                handle_loaded_temps (cfg, bblock, sp, sp + n);
@@ -4793,7 +4820,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        else
                                                MONO_ADD_INS (bblock, ins);
                                }
-                               MONO_INST_NEW (cfg, ins, CEE_JMP);
+                               MONO_INST_NEW (cfg, ins, OP_JMP);
                                ins->cil_code = ip;
                                ins->inst_p0 = cmethod;
                                ins->inst_p1 = arg_array [0];
@@ -4843,7 +4870,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ip += 5;
                                        real_offset += 5;
 
-                                       GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                       GET_BBLOCK (cfg, bblock, ip);
                                        ebblock->next_bb = bblock;
                                        link_bblock (cfg, ebblock, bblock);
 
@@ -4881,7 +4908,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ins->cil_code = ip;
                                                MONO_ADD_INS (bblock, ins);
                                        }
-                                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                                       MONO_INST_NEW (cfg, ins, OP_BR);
                                        ins->cil_code = ip;
                                        MONO_ADD_INS (bblock, ins);
                                        tblock = start_bblock->out_bb [0];
@@ -5007,7 +5034,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        g_assert (!return_var);
                                        CHECK_STACK (1);
                                        --sp;
-                                       MONO_INST_NEW (cfg, ins, CEE_NOP);
+                                       MONO_INST_NEW (cfg, ins, OP_NOP);
                                        ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
                                        if (ins->opcode == CEE_STOBJ) {
                                                NEW_RETLOADA (cfg, ins);
@@ -5024,7 +5051,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        if (sp != stack_start)
                                UNVERIFIED;
-                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                       MONO_INST_NEW (cfg, ins, OP_BR);
                        ins->cil_code = ip++;
                        ins->inst_target_bb = end_bblock;
                        MONO_ADD_INS (bblock, ins);
@@ -5033,12 +5060,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_BR_S:
                        CHECK_OPSIZE (2);
-                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                       MONO_INST_NEW (cfg, ins, OP_BR);
                        ins->cil_code = ip++;
                        MONO_ADD_INS (bblock, ins);
                        target = ip + 1 + (signed char)(*ip);
                        ++ip;
-                       GET_BBLOCK (cfg, bbhash, tblock, target);
+                       GET_BBLOCK (cfg, tblock, target);
                        link_bblock (cfg, bblock, tblock);
                        CHECK_BBLOCK (target, ip, tblock);
                        ins->inst_target_bb = tblock;
@@ -5109,12 +5136,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_BR:
                        CHECK_OPSIZE (5);
-                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                       MONO_INST_NEW (cfg, ins, OP_BR);
                        ins->cil_code = ip++;
                        MONO_ADD_INS (bblock, ins);
                        target = ip + 4 + (gint32)read32(ip);
                        ip += 4;
-                       GET_BBLOCK (cfg, bbhash, tblock, target);
+                       GET_BBLOCK (cfg, tblock, target);
                        link_bblock (cfg, bblock, tblock);
                        CHECK_BBLOCK (target, ip, tblock);
                        ins->inst_target_bb = tblock;
@@ -5197,14 +5224,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (n * sizeof (guint32));
                        target = ip + n * sizeof (guint32);
                        MONO_ADD_INS (bblock, ins);
-                       GET_BBLOCK (cfg, bbhash, tblock, target);
+                       GET_BBLOCK (cfg, tblock, target);
                        link_bblock (cfg, bblock, tblock);
                        ins->klass = GUINT_TO_POINTER (n);
                        ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
                        ins->inst_many_bb [n] = tblock;
 
                        for (i = 0; i < n; ++i) {
-                               GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
+                               GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
                                link_bblock (cfg, bblock, tblock);
                                ins->inst_many_bb [i] = tblock;
                                ip += 4;
@@ -5569,6 +5596,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MonoInst* domain_var;
                                        
                                        if (cfg->compile_aot) {
+                                               /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
                                                cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
                                        }
                                        /* avoid depending on undefined C behavior in sequence points */
@@ -5630,6 +5658,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                goto load_error;
                        fsig = mono_method_get_signature (cmethod, image, token);
 
+                       mono_save_token_info (cfg, image, token, cmethod);
+
                        if (!mono_class_init (cmethod->klass))
                                goto load_error;
 
@@ -5695,7 +5725,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ip += 5;
                                                real_offset += 5;
                                                
-                                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                               GET_BBLOCK (cfg, bblock, ip);
                                                ebblock->next_bb = bblock;
                                                link_bblock (cfg, ebblock, bblock);
 
@@ -5761,7 +5791,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 5;
                                real_offset += 5;
                        
-                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               GET_BBLOCK (cfg, bblock, ip);
                                ebblock->next_bb = bblock;
                                link_bblock (cfg, ebblock, bblock);
 
@@ -5813,7 +5843,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ip += 5;
                                        real_offset += 5;
                                
-                                       GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                       GET_BBLOCK (cfg, bblock, ip);
                                        ebblock->next_bb = bblock;
                                        link_bblock (cfg, ebblock, bblock);
        
@@ -5955,7 +5985,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 5;
                                real_offset += 5;
                        
-                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               GET_BBLOCK (cfg, bblock, ip);
                                ebblock->next_bb = bblock;
                                link_bblock (cfg, ebblock, bblock);
 
@@ -5978,7 +6008,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_THROW:
                        CHECK_STACK (1);
-                       MONO_INST_NEW (cfg, ins, *ip);
+                       MONO_INST_NEW (cfg, ins, OP_THROW);
                        --sp;
                        ins->inst_left = *sp;
                        ins->cil_code = ip++;
@@ -6050,7 +6080,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ip += 5;
                                                real_offset += 5;
 
-                                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                               GET_BBLOCK (cfg, bblock, ip);
                                                ebblock->next_bb = bblock;
                                                link_bblock (cfg, ebblock, bblock);
 
@@ -6130,7 +6160,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ip += 5;
                                                real_offset += 5;
 
-                                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                               GET_BBLOCK (cfg, bblock, ip);
                                                ebblock->next_bb = bblock;
                                                link_bblock (cfg, ebblock, bblock);
 
@@ -6431,7 +6461,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->cil_code = ip;
                                ins->inst_i0 = *sp;
                                ip += 5;
-                               MONO_INST_NEW (cfg, ins, CEE_BR);
+                               MONO_INST_NEW (cfg, ins, OP_BR);
                                ins->cil_code = ip;
                                MONO_ADD_INS (bblock, ins);
                                if (*ip == CEE_BRTRUE_S) {
@@ -6445,11 +6475,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        target = ip + 4 + (gint)(read32 (ip));
                                        ip += 4;
                                }
-                               GET_BBLOCK (cfg, bbhash, tblock, target);
+                               GET_BBLOCK (cfg, tblock, target);
                                link_bblock (cfg, bblock, tblock);
                                CHECK_BBLOCK (target, ip, tblock);
                                ins->inst_target_bb = tblock;
-                               GET_BBLOCK (cfg, bbhash, tblock, ip);
+                               GET_BBLOCK (cfg, tblock, ip);
                                link_bblock (cfg, bblock, tblock);
                                if (sp != stack_start) {
                                        handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
@@ -6700,15 +6730,27 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
-                               MonoMethod* helper = mono_marshal_get_stelemref ();
-                               MonoInst *iargs [3];
-                               handle_loaded_temps (cfg, bblock, stack_start, sp);
+                               /* storing a NULL doesn't need any of the complex checks in stelemref */
+                               if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
+                                       MonoInst *load;
+                                       NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
+                                       load->cil_code = ip;
+                                       MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+                                       ins->cil_code = ip;
+                                       ins->inst_left = load;
+                                       ins->inst_right = sp [2];
+                                       MONO_ADD_INS (bblock, ins);
+                               } else {
+                                       MonoMethod* helper = mono_marshal_get_stelemref ();
+                                       MonoInst *iargs [3];
+                                       handle_loaded_temps (cfg, bblock, stack_start, sp);
 
-                               iargs [2] = sp [2];
-                               iargs [1] = sp [1];
-                               iargs [0] = sp [0];
-                               
-                               mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+                                       iargs [2] = sp [2];
+                                       iargs [1] = sp [1];
+                                       iargs [0] = sp [0];
+
+                                       mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+                               }
                        } else {
                                NEW_LDELEMA (cfg, load, sp, klass);
                                load->cil_code = ip;
@@ -6742,24 +6784,26 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
 
-                       iargs [2] = sp [2];
-                       iargs [1] = sp [1];
-                       iargs [0] = sp [0];
+                       /* storing a NULL doesn't need any of the complex checks in stelemref */
+                       if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
+                               MonoInst *load;
+                               NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
+                               load->cil_code = ip;
+                               MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+                               ins->cil_code = ip;
+                               ins->inst_left = load;
+                               ins->inst_right = sp [2];
+                               MONO_ADD_INS (bblock, ins);
+                       } else {
+                               iargs [2] = sp [2];
+                               iargs [1] = sp [1];
+                               iargs [0] = sp [0];
                        
-                       mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
-
-                       /*
-                       MonoInst *group;
-                       NEW_GROUP (cfg, group, sp [0], sp [1]);
-                       MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
-                       ins->cil_code = ip;
-                       ins->inst_left = group;
-                       ins->inst_right = sp [2];
-                       MONO_ADD_INS (bblock, ins);
-                       */
+                               mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+                               inline_costs += 1;
+                       }
 
                        ++ip;
-                       inline_costs += 1;
                        break;
                }
                case CEE_CKFINITE: {
@@ -6772,7 +6816,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         * this check */
 
                        
-                       MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
+                       MONO_INST_NEW (cfg, ins, OP_CKFINITE);
                        ins->cil_code = ip;
                        ins->inst_left = sp [-1];
                        temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
@@ -6918,7 +6962,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ip++;
                        break;
                case CEE_ENDFINALLY:
-                       MONO_INST_NEW (cfg, ins, *ip);
+                       MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
                        MONO_ADD_INS (bblock, ins);
                        ins->cil_code = ip++;
                        start_new_bblock = 1;
@@ -7000,10 +7044,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                g_list_free (handlers);
                        } 
 
-                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                       MONO_INST_NEW (cfg, ins, OP_BR);
                        ins->cil_code = ip;
                        MONO_ADD_INS (bblock, ins);
-                       GET_BBLOCK (cfg, bbhash, tblock, target);
+                       GET_BBLOCK (cfg, tblock, target);
                        link_bblock (cfg, bblock, tblock);
                        CHECK_BBLOCK (target, ip, tblock);
                        ins->inst_target_bb = tblock;
@@ -7144,7 +7188,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (sp != stack_start)
                                        UNVERIFIED;
                                
-                               MONO_INST_NEW (cfg, ins, CEE_BR);
+                               MONO_INST_NEW (cfg, ins, OP_BR);
                                ins->cil_code = ip;
                                ins->inst_target_bb = end_bblock;
                                MONO_ADD_INS (bblock, ins);
@@ -7703,7 +7747,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        for (tmp = bb_recheck; tmp; tmp = tmp->next) {
                bblock = tmp->data;
                /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
-               tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
+               tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
                if (tblock != start_bblock) {
                        int l;
                        split_bblock (cfg, tblock, bblock);
@@ -7724,8 +7768,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->verbose_level > 2)
                                g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
                }
-       } else {
-               g_hash_table_destroy (bbhash);
        }
 
        g_slist_free (class_inits);
@@ -7745,23 +7787,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        return inline_costs;
 
  inline_failure:
-       if (cfg->method != method) 
-               g_hash_table_destroy (bbhash);
        g_slist_free (class_inits);
        dont_inline = g_list_remove (dont_inline, method);
        return -1;
 
  load_error:
-       if (cfg->method != method)
-               g_hash_table_destroy (bbhash);
        g_slist_free (class_inits);
        dont_inline = g_list_remove (dont_inline, method);
        cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
        return -1;
 
  unverified:
-       if (cfg->method != method) 
-               g_hash_table_destroy (bbhash);
        g_slist_free (class_inits);
        dont_inline = g_list_remove (dont_inline, method);
        cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
@@ -7844,9 +7880,9 @@ mono_print_tree (MonoInst *tree) {
        }
        case OP_RENAME:
        case OP_RETARG:
-       case CEE_NOP:
-       case CEE_JMP:
-       case CEE_BREAK:
+       case OP_NOP:
+       case OP_JMP:
+       case OP_BREAK:
                break;
        case OP_LOAD_MEMBASE:
        case OP_LOADI4_MEMBASE:
@@ -7857,7 +7893,7 @@ mono_print_tree (MonoInst *tree) {
        case OP_LOADI2_MEMBASE:
                printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
                break;
-       case CEE_BR:
+       case OP_BR:
        case OP_CALL_HANDLER:
                printf ("[B%d]", tree->inst_target_bb->block_num);
                break;
@@ -8134,43 +8170,32 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 #endif
 
 static gpointer
-mono_create_delegate_trampoline (MonoMethod *method, gpointer addr)
+mono_create_delegate_trampoline (MonoClass *klass)
 {
 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
+       MonoDomain *domain = mono_domain_get ();
        gpointer code, ptr;
        guint32 code_size;
-       MonoDomain *domain = mono_domain_get ();
-
-#ifndef __ia64__
-       code = mono_jit_find_compiled_method (domain, method);
-       if (code)
-               return code;
-#else
-       /* 
-        * FIXME: We should return a function descriptor here but it is not stored
-        * anywhere so it would be leaked.
-        */
-#endif
 
        mono_domain_lock (domain);
-       ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, method);
+       ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, klass);
        mono_domain_unlock (domain);
        if (ptr)
                return ptr;
 
-       code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
+    code = mono_arch_create_specific_trampoline (klass, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size);
 
        ptr = mono_create_ftnptr (domain, code);
 
        /* store trampoline address */
        mono_domain_lock (domain);
        g_hash_table_insert (domain->delegate_trampoline_hash,
-                                                         method, ptr);
+                                                         klass, ptr);
        mono_domain_unlock (domain);
 
        return ptr;
 #else
-       return addr;
+       return NULL;
 #endif
 }
 
@@ -8670,7 +8695,6 @@ void
 mono_destroy_compile (MonoCompile *cfg)
 {
        //mono_mempool_stats (cfg->mempool);
-       g_hash_table_destroy (cfg->bb_hash);
        mono_free_loop_info (cfg);
        if (cfg->rs)
                mono_regstate_free (cfg->rs);
@@ -8680,6 +8704,7 @@ mono_destroy_compile (MonoCompile *cfg)
                g_hash_table_destroy (cfg->exvars);
        mono_mempool_destroy (cfg->mempool);
        g_list_free (cfg->ldstr_list);
+       g_hash_table_destroy (cfg->token_info_hash);
 
        g_free (cfg->varinfo);
        g_free (cfg->vars);
@@ -9283,7 +9308,7 @@ replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBl
        }
        if (bb->last_ins != NULL) {
                switch (bb->last_ins->opcode) {
-               case CEE_BR:
+               case OP_BR:
                        if (bb->last_ins->inst_target_bb == orig) {
                                bb->last_ins->inst_target_bb = repl;
                        }
@@ -9356,9 +9381,9 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
        
        for (inst = bb->code; inst != NULL; inst = inst->next) {
                switch (inst->opcode) {
-               case CEE_NOP:
+               case OP_NOP:
                        break;
-               case CEE_BR:
+               case OP_BR:
                        target_bb = inst->inst_target_bb;
                        break;
                default:
@@ -9415,13 +9440,13 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
                if ((previous_bb != cfg->bb_entry) &&
                                (previous_bb->region == bb->region) &&
                                ((previous_bb->last_ins == NULL) ||
-                               ((previous_bb->last_ins->opcode != CEE_BR) &&
+                               ((previous_bb->last_ins->opcode != OP_BR) &&
                                (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
                                (previous_bb->last_ins->opcode != CEE_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, CEE_BR);
+                                       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;
@@ -9449,7 +9474,7 @@ merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
 
        /* Nullify branch at the end of bb */
        if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
-               bb->last_ins->opcode = CEE_NOP;
+               bb->last_ins->opcode = OP_NOP;
        }               
 
        if (bb->last_ins) {
@@ -9489,7 +9514,7 @@ move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
        if (next && (!bb->last_ins || (bb->last_ins->opcode != OP_NOT_REACHED))) {
                MonoInst *ins;
 
-               MONO_INST_NEW (cfg, ins, CEE_BR);
+               MONO_INST_NEW (cfg, ins, OP_BR);
                MONO_ADD_INS (bb, ins);
                link_bblock (cfg, bb, next);
                ins->inst_target_bb = next;
@@ -9590,7 +9615,7 @@ try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
                        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 = CEE_BR;
+               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);
@@ -9653,7 +9678,7 @@ optimize_branches (MonoCompile *cfg)
                        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 CEE_BR */
+                               /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
                                if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
                                        MonoInst *pop;
                                        MONO_INST_NEW (cfg, pop, CEE_POP);
@@ -9662,7 +9687,7 @@ optimize_branches (MonoCompile *cfg)
                                        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 = CEE_BR;
+                                       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)
@@ -9673,8 +9698,8 @@ optimize_branches (MonoCompile *cfg)
                                        /* the block are in sequence anyway ... */
 
                                        /* branches to the following block can be removed */
-                                       if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
-                                               bb->last_ins->opcode = CEE_NOP;
+                                       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);
@@ -9711,9 +9736,9 @@ optimize_branches (MonoCompile *cfg)
                        if (bb->out_count == 1) {
                                bbn = bb->out_bb [0];
 
-                               if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
+                               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 == CEE_BR &&
+                                       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)
@@ -9743,14 +9768,14 @@ optimize_branches (MonoCompile *cfg)
                                                /* if mono_eval_cond_branch () is ever taken to handle 
                                                 * non-constant values to compare, issue a pop here.
                                                 */
-                                               bb->last_ins->opcode = CEE_BR;
+                                               bb->last_ins->opcode = OP_BR;
                                                bb->last_ins->inst_target_bb = taken_branch_target;
                                                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 == CEE_BR &&
+                                       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", 
@@ -9775,7 +9800,7 @@ optimize_branches (MonoCompile *cfg)
                                        }
 
                                        bbn = bb->last_ins->inst_false_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+                                       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 ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
@@ -9844,11 +9869,13 @@ mono_compile_create_vars (MonoCompile *cfg)
        if (cfg->verbose_level > 2)
                g_print ("creating vars\n");
 
+       cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
+
        if (sig->hasthis)
-               mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
+               cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
 
        for (i = 0; i < sig->param_count; ++i) {
-               mono_compile_create_var (cfg, sig->params [i], OP_ARG);
+               cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
                if (sig->params [i]->byref) {
                        cfg->disable_ssa = TRUE;
                }
@@ -9983,7 +10010,7 @@ mini_select_instructions (MonoCompile *cfg)
                                bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
                        } else {                        
                                MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
-                               inst->opcode = CEE_BR;
+                               inst->opcode = OP_BR;
                                inst->inst_target_bb = bb->last_ins->inst_false_bb;
                                mono_bblock_add_inst (bb, inst);
                        }
@@ -10253,9 +10280,9 @@ remove_critical_edges (MonoCompile *cfg) {
                                        if (previous_bb->region == bb->region) {
                                                if (previous_bb != cfg->bb_entry) {
                                                        /* If previous_bb "followed through" to bb, */
-                                                       /* keep it linked with a CEE_BR */
+                                                       /* keep it linked with a OP_BR */
                                                        if ((previous_bb->last_ins == NULL) ||
-                                                                       ((previous_bb->last_ins->opcode != CEE_BR) &&
+                                                                       ((previous_bb->last_ins->opcode != OP_BR) &&
                                                                        (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
                                                                        (previous_bb->last_ins->opcode != CEE_SWITCH))) {
                                                                int i;
@@ -10263,7 +10290,7 @@ remove_critical_edges (MonoCompile *cfg) {
                                                                for (i = 0; i < previous_bb->out_count; i++) {
                                                                        if (previous_bb->out_bb [i] == bb) {
                                                                                MonoInst *jump;
-                                                                               MONO_INST_NEW (cfg, jump, CEE_BR);
+                                                                               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;
@@ -10273,14 +10300,14 @@ remove_critical_edges (MonoCompile *cfg) {
                                                        }
                                                } else {
                                                        /* We cannot add any inst to the entry BB, so we must */
-                                                       /* put a new BB in the middle to hold the CEE_BR */
+                                                       /* 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, CEE_BR);
+                                                       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;
@@ -10373,11 +10400,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->opt = opts;
        cfg->prof_options = mono_profiler_get_events ();
        cfg->run_cctors = run_cctors;
-       cfg->bb_hash = g_hash_table_new (NULL, NULL);
        cfg->domain = domain;
        cfg->verbose_level = mini_verbose;
        cfg->compile_aot = compile_aot;
        cfg->skip_visibility = method->skip_visibility;
+       cfg->token_info_hash = g_hash_table_new (NULL, NULL);
        if (!header) {
                cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
                cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
@@ -10648,22 +10675,22 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        ei->exvar_offset = exvar ? exvar->inst_offset : 0;
 
                        if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
-                               tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
+                               tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
                                g_assert (tblock);
                                ei->data.filter = cfg->native_code + tblock->native_offset;
                        } else {
                                ei->data.catch_class = ec->data.catch_class;
                        }
 
-                       tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
+                       tblock = cfg->cil_offset_to_bb [ec->try_offset];
                        g_assert (tblock);
                        ei->try_start = cfg->native_code + tblock->native_offset;
                        g_assert (tblock->native_offset);
-                       tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
+                       tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
                        g_assert (tblock);
                        ei->try_end = cfg->native_code + tblock->native_offset;
                        g_assert (tblock->native_offset);
-                       tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
+                       tblock = cfg->cil_offset_to_bb [ec->handler_offset];
                        g_assert (tblock);
                        ei->handler_start = cfg->native_code + tblock->native_offset;
                }
@@ -10705,12 +10732,9 @@ static gpointer
 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
 {
        MonoCompile *cfg;
-       GHashTable *jit_code_hash;
        gpointer code = NULL;
        MonoJitInfo *info;
 
-       jit_code_hash = target_domain->jit_code_hash;
-
        method = mono_get_inflated_method (method);
 
 #ifdef MONO_USE_AOT_COMPILER
@@ -10836,7 +10860,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        /* Check if some other thread already did the job. In this case, we can
        discard the code this thread generated. */
 
-       if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+       if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
                /* We can't use a domain specific method in another domain */
                if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
                        code = info->code_start;
@@ -10845,7 +10869,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        }
        
        if (code == NULL) {
-               g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
+               mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
                code = cfg->native_code;
        }
 
@@ -10904,7 +10928,7 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
 
        mono_domain_lock (target_domain);
 
-       if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+       if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_domain_unlock (target_domain);
@@ -10965,7 +10989,7 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
                return;
        mono_domain_lock (domain);
        g_hash_table_remove (domain->dynamic_code_hash, method);
-       g_hash_table_remove (domain->jit_code_hash, method);
+       mono_internal_hash_table_remove (&domain->jit_code_hash, method);
        g_hash_table_remove (domain->jump_trampoline_hash, method);
        mono_domain_unlock (domain);
 
@@ -11010,7 +11034,7 @@ mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
 
        mono_domain_lock (target_domain);
 
-       if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+       if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_domain_unlock (target_domain);
@@ -11524,8 +11548,13 @@ win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
        CONTEXT context;
 
        context.ContextFlags = CONTEXT_CONTROL;
-       if (GetThreadContext (win32_main_thread, &context))
+       if (GetThreadContext (win32_main_thread, &context)) {
+#ifdef _WIN64
+               mono_profiler_stat_hit ((guchar *) context.Rip, &context);
+#else
                mono_profiler_stat_hit ((guchar *) context.Eip, &context);
+#endif
+       }
 }
 #endif