2010-03-30 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / method-to-ir.c
index d762032e224810b68e2fb1ad3fe72a471606efbc..87e259d63fc861391516ae38453a44fa365fed3d 100644 (file)
@@ -464,8 +464,7 @@ mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
 static int
 mono_find_block_region (MonoCompile *cfg, int offset)
 {
-       MonoMethod *method = cfg->method;
-       MonoMethodHeader *header = mono_method_get_header (method);
+       MonoMethodHeader *header = cfg->header;
        MonoExceptionClause *clause;
        int i;
 
@@ -494,10 +493,8 @@ mono_find_block_region (MonoCompile *cfg, int offset)
 static GList*
 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
 {
-       MonoMethod *method = cfg->method;
-       MonoMethodHeader *header = mono_method_get_header (method);
+       MonoMethodHeader *header = cfg->header;
        MonoExceptionClause *clause;
-       MonoBasicBlock *handler;
        int i;
        GList *res = NULL;
 
@@ -505,11 +502,8 @@ mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *targe
                clause = &header->clauses [i];
                if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
                    (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
-                       if (clause->flags == type) {
-                               handler = cfg->cil_offset_to_bb [clause->handler_offset];
-                               g_assert (handler);
-                               res = g_list_append (res, handler);
-                       }
+                       if (clause->flags == type)
+                               res = g_list_append (res, clause);
                }
        }
        return res;
@@ -1192,7 +1186,7 @@ mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
        int pos, vnum;
 
        /* inlining can result in deeper stacks */ 
-       if (slot >= mono_method_get_header (cfg->method)->max_stack)
+       if (slot >= cfg->header->max_stack)
                return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
 
        pos = ins->type - 1 + slot * STACK_MAX;
@@ -1376,17 +1370,26 @@ mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg,
        }
 }
 
-/* 
- * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
- * stored in "klass_reg" implements the interface "klass".
- */
 static void
-mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
+mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
 {
        int ibitmap_reg = alloc_preg (cfg);
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       MonoInst *args [2];
+       MonoInst *res, *ins;
+       NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
+       MONO_ADD_INS (cfg->cbb, ins);
+       args [0] = ins;
+       if (cfg->compile_aot)
+               EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
+       else
+               EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
+       res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
+       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
+#else
        int ibitmap_byte_reg = alloc_preg (cfg);
 
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap));
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
 
        if (cfg->compile_aot) {
                int iid_reg = alloc_preg (cfg);
@@ -1407,6 +1410,17 @@ mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass
                MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
        }
+#endif
+}
+
+/* 
+ * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
+ * stored in "klass_reg" implements the interface "klass".
+ */
+static void
+mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
+{
+       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
 }
 
 /* 
@@ -1416,30 +1430,7 @@ mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass
 static void
 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
 {
-       int ibitmap_reg = alloc_preg (cfg);
-       int ibitmap_byte_reg = alloc_preg (cfg);
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap));
-
-       if (cfg->compile_aot) {
-               int iid_reg = alloc_preg (cfg);
-               int shifted_iid_reg = alloc_preg (cfg);
-               int ibitmap_byte_address_reg = alloc_preg (cfg);
-               int masked_iid_reg = alloc_preg (cfg);
-               int iid_one_bit_reg = alloc_preg (cfg);
-               int iid_bit_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, shifted_iid_reg, iid_reg, 3);
-               MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, masked_iid_reg, iid_reg, 7);
-               MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
-               MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
-               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
-       } else {
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
-       }
+       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
 }
 
 /* 
@@ -4493,6 +4484,8 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        cheader = mono_method_get_header (cmethod);
 
        if (cheader == NULL || mono_loader_get_last_error ()) {
+               if (cheader)
+                       mono_metadata_free_mh (cheader);
                mono_loader_clear_error ();
                return 0;
        }
@@ -4623,6 +4616,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                        EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
                        *sp++ = ins;
                }
+               mono_metadata_free_mh (cheader);
                return costs + 1;
        } else {
                if (cfg->verbose_level > 2)
@@ -4633,6 +4627,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                /* This gets rid of the newly added bblocks */
                cfg->cbb = prev_cbb;
        }
+       mono_metadata_free_mh (cheader);
        return 0;
 }
 
@@ -5011,8 +5006,9 @@ set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsign
 {
        char *method_fname = mono_method_full_name (method, TRUE);
        char *method_code;
+       MonoMethodHeader *header = mono_method_get_header (method);
 
-       if (mono_method_get_header (method)->code_size == 0)
+       if (header->code_size == 0)
                method_code = g_strdup ("method body is empty.");
        else
                method_code = mono_disasm_code_one (NULL, method, ip, NULL);
@@ -5020,6 +5016,7 @@ set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsign
        cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
        g_free (method_fname);
        g_free (method_code);
+       mono_metadata_free_mh (header);
 }
 
 static void
@@ -5126,7 +5123,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        MonoError error;
        MonoInst *ins, **sp, **stack_start;
        MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
-       MonoSimpleBasicBlock *bb = NULL;
+       MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
        MonoMethod *cmethod, *method_definition;
        MonoInst **arg_array;
        MonoMethodHeader *header;
@@ -5532,7 +5529,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
        skip_dead_blocks = !dont_verify;
        if (skip_dead_blocks) {
-               bb = mono_basic_block_split (method, &error);
+               original_bb = bb = mono_basic_block_split (method, &error);
                if (!mono_error_ok (&error)) {
                        mono_error_cleanup (&error);
                        UNVERIFIED;
@@ -6084,7 +6081,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        array_rank = cmethod->klass->rank;
                                        fsig = mono_method_signature (cmethod);
                                } else {
-                                       if (mono_method_signature (cmethod)->pinvoke) {
+                                       fsig = mono_method_signature (cmethod);
+
+                                       if (!fsig)
+                                               goto load_error;
+
+                                       if (fsig->pinvoke) {
                                                MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
                                                        check_for_pending_exc, FALSE);
                                                fsig = mono_method_signature (wrapper);
@@ -8770,59 +8772,37 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
                        } else {
-                               gboolean use_slow_path = TRUE;
                                if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
                                        ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
-                                       (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context))) {
-
-                                       if ((cmethod->klass == mono_defaults.monotype_class->parent) && (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
-                                               MonoClass *tclass = mono_class_from_mono_type (handle);
+                                       (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
+                                       (cmethod->klass == mono_defaults.monotype_class->parent) &&
+                                       (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
+                                       MonoClass *tclass = mono_class_from_mono_type (handle);
 
-                                               mono_class_init (tclass);
-                                               if (context_used) {
-                                                       ins = emit_get_rgctx_klass (cfg, context_used,
-                                                               tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
-                                               } else if (cfg->compile_aot) {
-                                                       if (method->wrapper_type) {
-                                                               if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
-                                                                       /* Special case for static synchronized wrappers */
-                                                                       EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
-                                                               } else {
-                                                                       /* FIXME: n is not a normal token */
-                                                                       cfg->disable_aot = TRUE;
-                                                                       EMIT_NEW_PCONST (cfg, ins, NULL);
-                                                               }
+                                       mono_class_init (tclass);
+                                       if (context_used) {
+                                               ins = emit_get_rgctx_klass (cfg, context_used,
+                                                       tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
+                                       } else if (cfg->compile_aot) {
+                                               if (method->wrapper_type) {
+                                                       if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
+                                                               /* Special case for static synchronized wrappers */
+                                                               EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
                                                        } else {
-                                                               EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
+                                                               /* FIXME: n is not a normal token */
+                                                               cfg->disable_aot = TRUE;
+                                                               EMIT_NEW_PCONST (cfg, ins, NULL);
                                                        }
                                                } else {
-                                                       EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
-                                               }
-                                               ins->type = STACK_OBJ;
-                                               ins->klass = cmethod->klass;
-                                               ip += 5;
-                                               use_slow_path = FALSE;
-                                       } else if (cmethod->klass->image == mono_defaults.corlib &&
-                                                               !strcmp ("Mono", cmethod->klass->name_space) &&
-                                                               !strcmp ("Runtime", cmethod->klass->name) &&
-                                                               !strcmp ("NewObject", cmethod->name)) {
-
-                                               /*FIXME relax those restrictions if it's worth the trouble*/
-                                               if (!context_used && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED)) {
-                                                       MonoClass *klass = mono_class_from_mono_type (handle);
-                                                       gpointer vtable = mono_class_vtable (cfg->domain, klass);
-                                                       MonoInst *iargs [1];
-
-                                                       EMIT_NEW_PCONST (cfg, iargs [0], vtable);
-                                                       ins = mono_emit_jit_icall (cfg, mono_object_new_specific, iargs);
-
-                                                       ip += 5;
-                                                       use_slow_path = FALSE;
+                                                       EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
                                                }
+                                       } else {
+                                               EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
                                        }
-                               }
-
-                               if (use_slow_path) {
+                                       ins->type = STACK_OBJ;
+                                       ins->klass = cmethod->klass;
+                                       ip += 5;
+                               } else {
                                        MonoInst *addr, *vtvar;
 
                                        vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
@@ -8948,11 +8928,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
                                GList *tmp;
+                               MonoExceptionClause *clause;
+
                                for (tmp = handlers; tmp; tmp = tmp->next) {
-                                       tblock = tmp->data;
+                                       clause = tmp->data;
+                                       tblock = cfg->cil_offset_to_bb [clause->handler_offset];
+                                       g_assert (tblock);
                                        link_bblock (cfg, bblock, tblock);
                                        MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
                                        ins->inst_target_bb = tblock;
+                                       ins->inst_eh_block = clause;
                                        MONO_ADD_INS (bblock, ins);
                                        bblock->has_call_handler = 1;
                                        if (COMPILE_LLVM (cfg)) {
@@ -9853,39 +9838,38 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
                cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
                g_free (mname);
+               mono_metadata_free_mh (header);
+               mono_basic_block_free (original_bb);
                return -1;
        }
 
        if ((cfg->verbose_level > 2) && (cfg->method == method)) 
                mono_print_code (cfg, "AFTER METHOD-TO-IR");
 
+       mono_metadata_free_mh (header);
+       mono_basic_block_free (original_bb);
        return inline_costs;
  
  exception_exit:
        g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
-       g_slist_free (class_inits);
-       mono_basic_block_free (bb);
-       dont_inline = g_list_remove (dont_inline, method);
-       return -1;
+       goto cleanup;
 
  inline_failure:
-       g_slist_free (class_inits);
-       mono_basic_block_free (bb);
-       dont_inline = g_list_remove (dont_inline, method);
-       return -1;
+       goto cleanup;
 
  load_error:
-       g_slist_free (class_inits);
-       mono_basic_block_free (bb);
-       dont_inline = g_list_remove (dont_inline, method);
        cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
-       return -1;
+       goto cleanup;
 
  unverified:
+       set_exception_type_from_invalid_il (cfg, method, ip);
+       goto cleanup;
+
+ cleanup:
        g_slist_free (class_inits);
-       mono_basic_block_free (bb);
+       mono_basic_block_free (original_bb);
        dont_inline = g_list_remove (dont_inline, method);
-       set_exception_type_from_invalid_il (cfg, method, ip);
+       mono_metadata_free_mh (header);
        return -1;
 }