New test.
[mono.git] / mono / mini / branch-opts.c
1 /*
2  * branch-opts.c: Branch optimizations support 
3  *
4  * Authors:
5  *   Patrik Torstensson (Patrik.Torstesson at gmail.com)
6  *
7  * (C) 2005 Ximian, Inc.  http://www.ximian.com
8  */
9  #include "mini.h"
10  
11  /*
12  * Used by the arch code to replace the exception handling
13  * with a direct branch. This is safe to do if the 
14  * exception object isn't used, no rethrow statement and
15  * no filter statement (verify).
16  *
17  */
18 MonoInst *
19 mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, const char * exname)
20 {
21         MonoMethod *method = cfg->method;
22         MonoMethodHeader *header = mono_method_get_header (method);
23         MonoExceptionClause *clause;
24         MonoClass *exclass;
25         int i;
26
27         if (!(cfg->opt & MONO_OPT_EXCEPTION))
28                 return NULL;
29
30         if (bb->region == -1 || !MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY))
31                 return NULL;
32
33         exclass = mono_class_from_name (mono_get_corlib (), "System", exname);
34         /* search for the handler */
35         for (i = 0; i < header->num_clauses; ++i) {
36                 clause = &header->clauses [i];
37                 if (MONO_OFFSET_IN_CLAUSE (clause, bb->real_offset)) {
38                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE && clause->data.catch_class && mono_class_is_assignable_from (clause->data.catch_class, exclass)) {
39                                 MonoBasicBlock *tbb;
40
41                                 /* get the basic block for the handler and 
42                                  * check if the exception object is used.
43                                  * Flag is set during method_to_ir due to 
44                                  * pop-op is optmized away in codegen (burg).
45                                  */
46                                 tbb = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
47                                 if (tbb && tbb->flags & BB_EXCEPTION_DEAD_OBJ && !(tbb->flags & BB_EXCEPTION_UNSAFE)) {
48                                         MonoBasicBlock *targetbb = tbb;
49                                         gboolean unsafe = FALSE;
50
51                                         /* Check if this catch clause is ok to optimize by
52                                          * looking for the BB_EXCEPTION_UNSAFE in every BB that
53                                          * belongs to the same region. 
54                                          *
55                                          * UNSAFE flag is set during method_to_ir (OP_RETHROW)
56                                          */
57                                         while (!unsafe && tbb->next_bb && tbb->region == tbb->next_bb->region) {
58                                                 if (tbb->next_bb->flags & BB_EXCEPTION_UNSAFE)  {
59                                                         unsafe = TRUE;
60                                                         break;
61                                                 }
62                                                 tbb = tbb->next_bb;
63                                         }
64
65                                         if (!unsafe) {
66                                                 MonoInst *jump;
67
68                                                 /* Create dummy inst to allow easier integration in
69                                                  * arch dependent code (opcode ignored)
70                                                  */
71                                                 MONO_INST_NEW (cfg, jump, CEE_BR);
72
73                                                 /* Allocate memory for our branch target */
74                                                 jump->inst_i1 = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
75                                                 jump->inst_true_bb = targetbb;
76
77                                                 if (cfg->verbose_level > 2) 
78                                                         g_print ("found exception to optimize - returning branch to BB%d (%s) (instead of throw) for method %s:%s\n", targetbb->block_num, clause->data.catch_class->name, cfg->method->klass->name, cfg->method->name);
79
80                                                 return jump;
81                                         } 
82
83                                         return NULL;
84                                 }
85                         } else {
86                                 /* Branching to an outer clause could skip inner clauses */
87                                 return NULL;
88                         }
89                 }
90         }
91
92         return NULL;
93 }
94