X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fjava%2Fexcept.c;h=048a92fc80220a6278f72b4e90774ad2fba19ca4;hb=72a6b07c4c8afddb3a5b5db4b1334a65dd713abf;hp=b77842e8a662a5a6722a5e320439fa1232918b1a;hpb=4ee9c6840ad3fc92a9034343278a1e476ad6872a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/java/except.c b/gcc/java/except.c index b77842e8a66..048a92fc802 100644 --- a/gcc/java/except.c +++ b/gcc/java/except.c @@ -1,5 +1,5 @@ /* Handle exceptions for GNU compiler for the Java(TM) language. - Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004 + Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. @@ -40,10 +40,8 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "toplev.h" static void expand_start_java_handler (struct eh_range *); -static void expand_end_java_handler (struct eh_range *); static struct eh_range *find_handler_in_range (int, struct eh_range *, struct eh_range *); -static void link_handler (struct eh_range *, struct eh_range *); static void check_start_handlers (struct eh_range *, int); static void free_eh_ranges (struct eh_range *range); @@ -51,8 +49,6 @@ struct eh_range *current_method_handlers; struct eh_range *current_try_block = NULL; -struct eh_range *eh_range_freelist = NULL; - /* These variables are used to speed up find_handler. */ static int cache_range_start, cache_range_end; @@ -63,12 +59,60 @@ static struct eh_range *cache_next_child; struct eh_range whole_range; +/* Check the invariants of the structure we're using to contain + exception regions. Either returns true or fails an assertion + check. */ + +bool +sanity_check_exception_range (struct eh_range *range) +{ + struct eh_range *ptr = range->first_child; + for (; ptr; ptr = ptr->next_sibling) + { + gcc_assert (ptr->outer == range + && ptr->end_pc > ptr->start_pc); + if (ptr->next_sibling) + gcc_assert (ptr->next_sibling->start_pc >= ptr->end_pc); + gcc_assert (ptr->start_pc >= ptr->outer->start_pc + && ptr->end_pc <= ptr->outer->end_pc); + (void) sanity_check_exception_range (ptr); + } + return true; +} + #if defined(DEBUG_JAVA_BINDING_LEVELS) -extern int binding_depth; extern int is_class_level; extern int current_pc; -extern void indent (); +extern int binding_depth; +extern void indent (void); +static void +print_ranges (struct eh_range *range) +{ + if (! range) + return; + + struct eh_range *child = range->first_child; + + indent (); + fprintf (stderr, "handler pc %d --> %d ", range->start_pc, range->end_pc); + + tree handler = range->handlers; + for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler)) + { + tree type = TREE_PURPOSE (handler); + if (type == NULL) + type = throwable_type_node; + fprintf (stderr, " type=%s ", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + } + fprintf (stderr, "\n"); + int saved = binding_depth; + binding_depth++; + print_ranges (child); + binding_depth = saved; + + print_ranges (range->next_sibling); +} #endif /* Search for the most specific eh_range containing PC. @@ -118,108 +162,6 @@ find_handler (int pc) return find_handler_in_range (pc, h, cache_next_child); } -/* Recursive helper routine for check_nested_ranges. */ - -static void -link_handler (struct eh_range *range, struct eh_range *outer) -{ - struct eh_range **ptr; - - if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc) - { - outer->handlers = chainon (outer->handlers, range->handlers); - return; - } - - /* If the new range completely encloses the `outer' range, then insert it - between the outer range and its parent. */ - if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc) - { - range->outer = outer->outer; - range->next_sibling = NULL; - range->first_child = outer; - { - struct eh_range **pr = &(outer->outer->first_child); - while (*pr != outer) - pr = &(*pr)->next_sibling; - *pr = range; - } - outer->outer = range; - return; - } - - /* Handle overlapping ranges by splitting the new range. */ - if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc) - { - struct eh_range *h = xmalloc (sizeof (struct eh_range)); - if (range->start_pc < outer->start_pc) - { - h->start_pc = range->start_pc; - h->end_pc = outer->start_pc; - range->start_pc = outer->start_pc; - } - else - { - h->start_pc = outer->end_pc; - h->end_pc = range->end_pc; - range->end_pc = outer->end_pc; - } - h->first_child = NULL; - h->outer = NULL; - h->handlers = build_tree_list (TREE_PURPOSE (range->handlers), - TREE_VALUE (range->handlers)); - h->next_sibling = NULL; - h->expanded = 0; - h->stmt = NULL; - /* Restart both from the top to avoid having to make this - function smart about reentrancy. */ - link_handler (h, &whole_range); - link_handler (range, &whole_range); - return; - } - - ptr = &outer->first_child; - for (;; ptr = &(*ptr)->next_sibling) - { - if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc) - { - range->next_sibling = *ptr; - range->first_child = NULL; - range->outer = outer; - *ptr = range; - return; - } - else if (range->start_pc < (*ptr)->end_pc) - { - link_handler (range, *ptr); - return; - } - /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */ - } -} - -/* The first pass of exception range processing (calling add_handler) - constructs a linked list of exception ranges. We turn this into - the data structure expected by the rest of the code, and also - ensure that exception ranges are properly nested. */ - -void -handle_nested_ranges (void) -{ - struct eh_range *ptr, *next; - - ptr = whole_range.first_child; - whole_range.first_child = NULL; - for (; ptr; ptr = next) - { - next = ptr->next_sibling; - ptr->next_sibling = NULL; - link_handler (ptr, &whole_range); - } -} - -/* Free RANGE as well as its children and siblings. */ - static void free_eh_ranges (struct eh_range *range) { @@ -247,55 +189,166 @@ method_init_exceptions (void) cache_range_start = 0xFFFFFF; } -/* Add an exception range. If we already have an exception range - which has the same handler and label, and the new range overlaps - that one, then we simply extend the existing range. Some bytecode - obfuscators generate seemingly nonoverlapping exception ranges - which, when coalesced, do in fact nest correctly. - - This constructs an ordinary linked list which check_nested_ranges() - later turns into the data structure we actually want. +/* Split an exception range into two at PC. The sub-ranges that + belong to the range are split and distributed between the two new + ranges. */ + +static void +split_range (struct eh_range *range, int pc) +{ + struct eh_range *ptr; + struct eh_range **first_child, **second_child; + struct eh_range *h; + + /* First, split all the sub-ranges. */ + for (ptr = range->first_child; ptr; ptr = ptr->next_sibling) + { + if (pc > ptr->start_pc + && pc < ptr->end_pc) + { + split_range (ptr, pc); + } + } + + /* Create a new range. */ + h = xmalloc (sizeof (struct eh_range)); + + h->start_pc = pc; + h->end_pc = range->end_pc; + h->next_sibling = range->next_sibling; + range->next_sibling = h; + range->end_pc = pc; + h->handlers = build_tree_list (TREE_PURPOSE (range->handlers), + TREE_VALUE (range->handlers)); + h->next_sibling = NULL; + h->expanded = 0; + h->stmt = NULL; + h->outer = range->outer; + h->first_child = NULL; + + ptr = range->first_child; + first_child = &range->first_child; + second_child = &h->first_child; + + /* Distribute the sub-ranges between the two new ranges. */ + for (ptr = range->first_child; ptr; ptr = ptr->next_sibling) + { + if (ptr->start_pc < pc) + { + *first_child = ptr; + ptr->outer = range; + first_child = &ptr->next_sibling; + } + else + { + *second_child = ptr; + ptr->outer = h; + second_child = &ptr->next_sibling; + } + } + *first_child = NULL; + *second_child = NULL; +} + + +/* Add an exception range. + + There are some missed optimization opportunities here. For + example, some bytecode obfuscators generate seemingly + nonoverlapping exception ranges which, when coalesced, do in fact + nest correctly. We could merge these, but we'd have to fix up all + the enclosed regions first and perhaps create a new range anyway if + it overlapped existing ranges. - We expect the input to come in order of increasing START_PC. This - function doesn't attempt to detect the case where two previously - added disjoint ranges could be coalesced by a new range; that is - what the sorting counteracts. */ + Also, we don't attempt to detect the case where two previously + added disjoint ranges could be coalesced by a new range. */ -void +void add_handler (int start_pc, int end_pc, tree handler, tree type) { - struct eh_range *ptr, *prev = NULL, *h; + struct eh_range *ptr, *h; + struct eh_range **first_child, **prev; + /* First, split all the existing ranges that we need to enclose. */ for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling) { - if (start_pc >= ptr->start_pc - && start_pc <= ptr->end_pc - && TREE_PURPOSE (ptr->handlers) == type - && TREE_VALUE (ptr->handlers) == handler) + if (start_pc > ptr->start_pc + && start_pc < ptr->end_pc) { - /* Already found an overlapping range, so coalesce. */ - ptr->end_pc = MAX (ptr->end_pc, end_pc); - return; + split_range (ptr, start_pc); } - prev = ptr; + + if (end_pc > ptr->start_pc + && end_pc < ptr->end_pc) + { + split_range (ptr, end_pc); + } + + if (ptr->start_pc >= end_pc) + break; } + /* Create the new range. */ h = xmalloc (sizeof (struct eh_range)); + first_child = &h->first_child; + h->start_pc = start_pc; h->end_pc = end_pc; h->first_child = NULL; - h->outer = NULL; + h->outer = NULL_EH_RANGE; h->handlers = build_tree_list (type, handler); h->next_sibling = NULL; h->expanded = 0; h->stmt = NULL; - if (prev == NULL) - whole_range.first_child = h; - else - prev->next_sibling = h; -} + /* Find every range at the top level that will be a sub-range of the + range we're inserting and make it so. */ + { + struct eh_range **prev = &whole_range.first_child; + for (ptr = *prev; ptr;) + { + struct eh_range *next = ptr->next_sibling; + + if (ptr->start_pc >= end_pc) + break; + + if (ptr->start_pc < start_pc) + { + prev = &ptr->next_sibling; + } + else if (ptr->start_pc >= start_pc + && ptr->start_pc < end_pc) + { + *prev = next; + *first_child = ptr; + first_child = &ptr->next_sibling; + ptr->outer = h; + ptr->next_sibling = NULL; + } + + ptr = next; + } + } + /* Find the right place to insert the new range. */ + prev = &whole_range.first_child; + for (ptr = *prev; ptr; prev = &ptr->next_sibling, ptr = ptr->next_sibling) + { + gcc_assert (ptr->outer == NULL_EH_RANGE); + if (ptr->start_pc >= start_pc) + break; + } + + /* And insert it there. */ + *prev = h; + if (ptr) + { + h->next_sibling = ptr; + h->outer = ptr->outer; + } +} + + /* if there are any handlers for this range, issue start of region */ static void expand_start_java_handler (struct eh_range *range) @@ -305,13 +358,8 @@ expand_start_java_handler (struct eh_range *range) fprintf (stderr, "expand start handler pc %d --> %d\n", current_pc, range->end_pc); #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */ - { - tree new = build (TRY_CATCH_EXPR, void_type_node, NULL, NULL); - TREE_SIDE_EFFECTS (new) = 1; - java_add_stmt (build_java_empty_stmt ()); - range->stmt = java_add_stmt (new); - } - + pushlevel (0); + register_exception_range (range, range->start_pc, range->end_pc); range->expanded = 1; } @@ -392,7 +440,7 @@ expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED) tree decl; STRIP_NOPS (addr); decl = TREE_OPERAND (addr, 0); - rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0); + rest_of_decl_compilation (decl, global_bindings_p (), 0); return true; } @@ -418,9 +466,9 @@ build_exception_object_ref (tree type) /* Java only passes object via pointer and doesn't require adjusting. The java object is immediately before the generic exception header. */ - obj = build (EXC_PTR_EXPR, build_pointer_type (type)); - obj = build (MINUS_EXPR, TREE_TYPE (obj), obj, - TYPE_SIZE_UNIT (TREE_TYPE (obj))); + obj = build0 (EXC_PTR_EXPR, build_pointer_type (type)); + obj = build2 (MINUS_EXPR, TREE_TYPE (obj), obj, + TYPE_SIZE_UNIT (TREE_TYPE (obj))); obj = build1 (INDIRECT_REF, type, obj); return obj; @@ -428,13 +476,11 @@ build_exception_object_ref (tree type) /* If there are any handlers for this range, isssue end of range, and then all handler blocks */ -static void +void expand_end_java_handler (struct eh_range *range) { tree handler = range->handlers; - tree compound = NULL; - force_poplevels (range->start_pc); for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler)) { /* For bytecode we treat exceptions a little unusually. A @@ -444,55 +490,18 @@ expand_end_java_handler (struct eh_range *range) extra (and difficult) work to get this to look like a gcc-style finally clause. */ tree type = TREE_PURPOSE (handler); - if (type == NULL) type = throwable_type_node; - type = prepare_eh_table_type (type); - if (compound) - { - /* If we already have a COMPOUND there is more than one - catch handler for this try block. Wrap the - TRY_CATCH_EXPR in operand 1 of COMPOUND with another - TRY_CATCH_EXPR. */ - tree inner_try_expr = TREE_OPERAND (compound, 1); - tree catch_expr - = build (CATCH_EXPR, void_type_node, type, - build (GOTO_EXPR, void_type_node, TREE_VALUE (handler))); - tree try_expr - = build (TRY_CATCH_EXPR, void_type_node, - inner_try_expr, catch_expr); - TREE_OPERAND (compound, 1) = try_expr; - } - else - { - tree *stmts = get_stmts (); - tree outer; - tree try_expr; - compound = range->stmt; - outer = TREE_OPERAND (compound, 0); - try_expr = TREE_OPERAND (compound, 1); - /* On the left of COMPOUND is the expresion to be evaluated - before the try handler is entered; on the right is a - TRY_FINALLY_EXPR with no operands as yet. In the current - statement list is an expression that we're going to move - inside the try handler. We'll create a new COMPOUND_EXPR - with the outer context on the left and the TRY_FINALLY_EXPR - on the right, then nullify both operands of COMPOUND, which - becomes the final expression in OUTER. This new compound - expression replaces the current statement list. */ - TREE_OPERAND (try_expr, 0) = *stmts; - TREE_OPERAND (try_expr, 1) - = build (CATCH_EXPR, void_type_node, type, - build (GOTO_EXPR, void_type_node, TREE_VALUE (handler))); - TREE_SIDE_EFFECTS (try_expr) = 1; - TREE_OPERAND (compound, 0) = build_java_empty_stmt (); - TREE_OPERAND (compound, 1) = build_java_empty_stmt (); - compound - = build (COMPOUND_EXPR, TREE_TYPE (try_expr), outer, try_expr); - *stmts = compound; - } + { + tree catch_expr = build2 (CATCH_EXPR, void_type_node, type, + build1 (GOTO_EXPR, void_type_node, + TREE_VALUE (handler))); + tree try_catch_expr = build2 (TRY_CATCH_EXPR, void_type_node, + *get_stmts (), catch_expr); + *get_stmts () = try_catch_expr; + } } #if defined(DEBUG_JAVA_BINDING_LEVELS) indent (); @@ -536,19 +545,3 @@ maybe_start_try (int start_pc, int end_pc) check_start_handlers (range, start_pc); } -/* Emit any end-of-try-range ending at end_pc and starting before - start_pc. */ - -void -maybe_end_try (int start_pc, int end_pc) -{ - if (! doing_eh (1)) - return; - - while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc - && current_range->start_pc >= start_pc) - { - expand_end_java_handler (current_range); - current_range = current_range->outer; - } -}