ChangeLog:
[official-gcc.git] / gcc / java / except.c
blobb77842e8a662a5a6722a5e320439fa1232918b1a
1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2 Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004
3 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Java and all Java-based marks are trademarks or registered trademarks
23 of Sun Microsystems, Inc. in the United States and other countries.
24 The Free Software Foundation is independent of Sun Microsystems, Inc. */
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "tree.h"
31 #include "real.h"
32 #include "rtl.h"
33 #include "java-tree.h"
34 #include "javaop.h"
35 #include "java-opcodes.h"
36 #include "jcf.h"
37 #include "function.h"
38 #include "except.h"
39 #include "java-except.h"
40 #include "toplev.h"
42 static void expand_start_java_handler (struct eh_range *);
43 static void expand_end_java_handler (struct eh_range *);
44 static struct eh_range *find_handler_in_range (int, struct eh_range *,
45 struct eh_range *);
46 static void link_handler (struct eh_range *, struct eh_range *);
47 static void check_start_handlers (struct eh_range *, int);
48 static void free_eh_ranges (struct eh_range *range);
50 struct eh_range *current_method_handlers;
52 struct eh_range *current_try_block = NULL;
54 struct eh_range *eh_range_freelist = NULL;
56 /* These variables are used to speed up find_handler. */
58 static int cache_range_start, cache_range_end;
59 static struct eh_range *cache_range;
60 static struct eh_range *cache_next_child;
62 /* A dummy range that represents the entire method. */
64 struct eh_range whole_range;
66 #if defined(DEBUG_JAVA_BINDING_LEVELS)
67 extern int binding_depth;
68 extern int is_class_level;
69 extern int current_pc;
70 extern void indent ();
72 #endif
74 /* Search for the most specific eh_range containing PC.
75 Assume PC is within RANGE.
76 CHILD is a list of children of RANGE such that any
77 previous children have end_pc values that are too low. */
79 static struct eh_range *
80 find_handler_in_range (int pc, struct eh_range *range, struct eh_range *child)
82 for (; child != NULL; child = child->next_sibling)
84 if (pc < child->start_pc)
85 break;
86 if (pc < child->end_pc)
87 return find_handler_in_range (pc, child, child->first_child);
89 cache_range = range;
90 cache_range_start = pc;
91 cache_next_child = child;
92 cache_range_end = child == NULL ? range->end_pc : child->start_pc;
93 return range;
96 /* Find the inner-most handler that contains PC. */
98 struct eh_range *
99 find_handler (int pc)
101 struct eh_range *h;
102 if (pc >= cache_range_start)
104 h = cache_range;
105 if (pc < cache_range_end)
106 return h;
107 while (pc >= h->end_pc)
109 cache_next_child = h->next_sibling;
110 h = h->outer;
113 else
115 h = &whole_range;
116 cache_next_child = h->first_child;
118 return find_handler_in_range (pc, h, cache_next_child);
121 /* Recursive helper routine for check_nested_ranges. */
123 static void
124 link_handler (struct eh_range *range, struct eh_range *outer)
126 struct eh_range **ptr;
128 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
130 outer->handlers = chainon (outer->handlers, range->handlers);
131 return;
134 /* If the new range completely encloses the `outer' range, then insert it
135 between the outer range and its parent. */
136 if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
138 range->outer = outer->outer;
139 range->next_sibling = NULL;
140 range->first_child = outer;
142 struct eh_range **pr = &(outer->outer->first_child);
143 while (*pr != outer)
144 pr = &(*pr)->next_sibling;
145 *pr = range;
147 outer->outer = range;
148 return;
151 /* Handle overlapping ranges by splitting the new range. */
152 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
154 struct eh_range *h = xmalloc (sizeof (struct eh_range));
155 if (range->start_pc < outer->start_pc)
157 h->start_pc = range->start_pc;
158 h->end_pc = outer->start_pc;
159 range->start_pc = outer->start_pc;
161 else
163 h->start_pc = outer->end_pc;
164 h->end_pc = range->end_pc;
165 range->end_pc = outer->end_pc;
167 h->first_child = NULL;
168 h->outer = NULL;
169 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
170 TREE_VALUE (range->handlers));
171 h->next_sibling = NULL;
172 h->expanded = 0;
173 h->stmt = NULL;
174 /* Restart both from the top to avoid having to make this
175 function smart about reentrancy. */
176 link_handler (h, &whole_range);
177 link_handler (range, &whole_range);
178 return;
181 ptr = &outer->first_child;
182 for (;; ptr = &(*ptr)->next_sibling)
184 if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
186 range->next_sibling = *ptr;
187 range->first_child = NULL;
188 range->outer = outer;
189 *ptr = range;
190 return;
192 else if (range->start_pc < (*ptr)->end_pc)
194 link_handler (range, *ptr);
195 return;
197 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
201 /* The first pass of exception range processing (calling add_handler)
202 constructs a linked list of exception ranges. We turn this into
203 the data structure expected by the rest of the code, and also
204 ensure that exception ranges are properly nested. */
206 void
207 handle_nested_ranges (void)
209 struct eh_range *ptr, *next;
211 ptr = whole_range.first_child;
212 whole_range.first_child = NULL;
213 for (; ptr; ptr = next)
215 next = ptr->next_sibling;
216 ptr->next_sibling = NULL;
217 link_handler (ptr, &whole_range);
221 /* Free RANGE as well as its children and siblings. */
223 static void
224 free_eh_ranges (struct eh_range *range)
226 while (range)
228 struct eh_range *next = range->next_sibling;
229 free_eh_ranges (range->first_child);
230 if (range != &whole_range)
231 free (range);
232 range = next;
236 /* Called to re-initialize the exception machinery for a new method. */
238 void
239 method_init_exceptions (void)
241 free_eh_ranges (&whole_range);
242 whole_range.start_pc = 0;
243 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
244 whole_range.outer = NULL;
245 whole_range.first_child = NULL;
246 whole_range.next_sibling = NULL;
247 cache_range_start = 0xFFFFFF;
250 /* Add an exception range. If we already have an exception range
251 which has the same handler and label, and the new range overlaps
252 that one, then we simply extend the existing range. Some bytecode
253 obfuscators generate seemingly nonoverlapping exception ranges
254 which, when coalesced, do in fact nest correctly.
256 This constructs an ordinary linked list which check_nested_ranges()
257 later turns into the data structure we actually want.
259 We expect the input to come in order of increasing START_PC. This
260 function doesn't attempt to detect the case where two previously
261 added disjoint ranges could be coalesced by a new range; that is
262 what the sorting counteracts. */
264 void
265 add_handler (int start_pc, int end_pc, tree handler, tree type)
267 struct eh_range *ptr, *prev = NULL, *h;
269 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
271 if (start_pc >= ptr->start_pc
272 && start_pc <= ptr->end_pc
273 && TREE_PURPOSE (ptr->handlers) == type
274 && TREE_VALUE (ptr->handlers) == handler)
276 /* Already found an overlapping range, so coalesce. */
277 ptr->end_pc = MAX (ptr->end_pc, end_pc);
278 return;
280 prev = ptr;
283 h = xmalloc (sizeof (struct eh_range));
284 h->start_pc = start_pc;
285 h->end_pc = end_pc;
286 h->first_child = NULL;
287 h->outer = NULL;
288 h->handlers = build_tree_list (type, handler);
289 h->next_sibling = NULL;
290 h->expanded = 0;
291 h->stmt = NULL;
293 if (prev == NULL)
294 whole_range.first_child = h;
295 else
296 prev->next_sibling = h;
299 /* if there are any handlers for this range, issue start of region */
300 static void
301 expand_start_java_handler (struct eh_range *range)
303 #if defined(DEBUG_JAVA_BINDING_LEVELS)
304 indent ();
305 fprintf (stderr, "expand start handler pc %d --> %d\n",
306 current_pc, range->end_pc);
307 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
309 tree new = build (TRY_CATCH_EXPR, void_type_node, NULL, NULL);
310 TREE_SIDE_EFFECTS (new) = 1;
311 java_add_stmt (build_java_empty_stmt ());
312 range->stmt = java_add_stmt (new);
315 range->expanded = 1;
318 tree
319 prepare_eh_table_type (tree type)
321 tree exp;
322 tree *slot;
323 const char *name;
324 char *buf;
325 tree decl;
326 tree utf8_ref;
328 /* The "type" (match_info) in a (Java) exception table is a pointer to:
329 * a) NULL - meaning match any type in a try-finally.
330 * b) a pointer to a pointer to a class.
331 * c) a pointer to a pointer to a utf8_ref. The pointer is
332 * rewritten to point to the appropriate class. */
334 if (type == NULL_TREE)
335 return NULL_TREE;
337 if (TYPE_TO_RUNTIME_MAP (output_class) == NULL)
338 TYPE_TO_RUNTIME_MAP (output_class) = java_treetreehash_create (10, 1);
340 slot = java_treetreehash_new (TYPE_TO_RUNTIME_MAP (output_class), type);
341 if (*slot != NULL)
342 return TREE_VALUE (*slot);
344 if (is_compiled_class (type) && !flag_indirect_dispatch)
346 name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
347 buf = alloca (strlen (name) + 5);
348 sprintf (buf, "%s_ref", name);
349 decl = build_decl (VAR_DECL, get_identifier (buf), ptr_type_node);
350 TREE_STATIC (decl) = 1;
351 DECL_ARTIFICIAL (decl) = 1;
352 DECL_IGNORED_P (decl) = 1;
353 TREE_READONLY (decl) = 1;
354 TREE_THIS_VOLATILE (decl) = 0;
355 DECL_INITIAL (decl) = build_class_ref (type);
356 layout_decl (decl, 0);
357 pushdecl (decl);
358 exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl);
360 else
362 utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type)));
363 name = IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0)));
364 buf = alloca (strlen (name) + 5);
365 sprintf (buf, "%s_ref", name);
366 decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_ptr_type);
367 TREE_STATIC (decl) = 1;
368 DECL_ARTIFICIAL (decl) = 1;
369 DECL_IGNORED_P (decl) = 1;
370 TREE_READONLY (decl) = 1;
371 TREE_THIS_VOLATILE (decl) = 0;
372 layout_decl (decl, 0);
373 pushdecl (decl);
374 exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl);
375 TYPE_CATCH_CLASSES (output_class) =
376 tree_cons (NULL, make_catch_class_record (exp, utf8_ref),
377 TYPE_CATCH_CLASSES (output_class));
380 exp = convert (ptr_type_node, exp);
382 *slot = tree_cons (type, exp, NULL_TREE);
384 return exp;
387 static int
388 expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED)
390 struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
391 tree addr = TREE_VALUE ((tree)ite->value);
392 tree decl;
393 STRIP_NOPS (addr);
394 decl = TREE_OPERAND (addr, 0);
395 rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
396 return true;
399 /* For every class in the TYPE_TO_RUNTIME_MAP, expand the
400 corresponding object that is used by the runtime type matcher. */
402 void
403 java_expand_catch_classes (tree this_class)
405 if (TYPE_TO_RUNTIME_MAP (this_class))
406 htab_traverse
407 (TYPE_TO_RUNTIME_MAP (this_class),
408 expand_catch_class, NULL);
411 /* Build a reference to the jthrowable object being carried in the
412 exception header. */
414 tree
415 build_exception_object_ref (tree type)
417 tree obj;
419 /* Java only passes object via pointer and doesn't require adjusting.
420 The java object is immediately before the generic exception header. */
421 obj = build (EXC_PTR_EXPR, build_pointer_type (type));
422 obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
423 TYPE_SIZE_UNIT (TREE_TYPE (obj)));
424 obj = build1 (INDIRECT_REF, type, obj);
426 return obj;
429 /* If there are any handlers for this range, isssue end of range,
430 and then all handler blocks */
431 static void
432 expand_end_java_handler (struct eh_range *range)
434 tree handler = range->handlers;
435 tree compound = NULL;
437 force_poplevels (range->start_pc);
438 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
440 /* For bytecode we treat exceptions a little unusually. A
441 `finally' clause looks like an ordinary exception handler for
442 Throwable. The reason for this is that the bytecode has
443 already expanded the finally logic, and we would have to do
444 extra (and difficult) work to get this to look like a
445 gcc-style finally clause. */
446 tree type = TREE_PURPOSE (handler);
448 if (type == NULL)
449 type = throwable_type_node;
451 type = prepare_eh_table_type (type);
453 if (compound)
455 /* If we already have a COMPOUND there is more than one
456 catch handler for this try block. Wrap the
457 TRY_CATCH_EXPR in operand 1 of COMPOUND with another
458 TRY_CATCH_EXPR. */
459 tree inner_try_expr = TREE_OPERAND (compound, 1);
460 tree catch_expr
461 = build (CATCH_EXPR, void_type_node, type,
462 build (GOTO_EXPR, void_type_node, TREE_VALUE (handler)));
463 tree try_expr
464 = build (TRY_CATCH_EXPR, void_type_node,
465 inner_try_expr, catch_expr);
466 TREE_OPERAND (compound, 1) = try_expr;
468 else
470 tree *stmts = get_stmts ();
471 tree outer;
472 tree try_expr;
473 compound = range->stmt;
474 outer = TREE_OPERAND (compound, 0);
475 try_expr = TREE_OPERAND (compound, 1);
476 /* On the left of COMPOUND is the expresion to be evaluated
477 before the try handler is entered; on the right is a
478 TRY_FINALLY_EXPR with no operands as yet. In the current
479 statement list is an expression that we're going to move
480 inside the try handler. We'll create a new COMPOUND_EXPR
481 with the outer context on the left and the TRY_FINALLY_EXPR
482 on the right, then nullify both operands of COMPOUND, which
483 becomes the final expression in OUTER. This new compound
484 expression replaces the current statement list. */
485 TREE_OPERAND (try_expr, 0) = *stmts;
486 TREE_OPERAND (try_expr, 1)
487 = build (CATCH_EXPR, void_type_node, type,
488 build (GOTO_EXPR, void_type_node, TREE_VALUE (handler)));
489 TREE_SIDE_EFFECTS (try_expr) = 1;
490 TREE_OPERAND (compound, 0) = build_java_empty_stmt ();
491 TREE_OPERAND (compound, 1) = build_java_empty_stmt ();
492 compound
493 = build (COMPOUND_EXPR, TREE_TYPE (try_expr), outer, try_expr);
494 *stmts = compound;
497 #if defined(DEBUG_JAVA_BINDING_LEVELS)
498 indent ();
499 fprintf (stderr, "expand end handler pc %d <-- %d\n",
500 current_pc, range->start_pc);
501 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
504 /* Recursive helper routine for maybe_start_handlers. */
506 static void
507 check_start_handlers (struct eh_range *range, int pc)
509 if (range != NULL_EH_RANGE && range->start_pc == pc)
511 check_start_handlers (range->outer, pc);
512 if (!range->expanded)
513 expand_start_java_handler (range);
518 static struct eh_range *current_range;
520 /* Emit any start-of-try-range starting at start_pc and ending after
521 end_pc. */
523 void
524 maybe_start_try (int start_pc, int end_pc)
526 struct eh_range *range;
527 if (! doing_eh (1))
528 return;
530 range = find_handler (start_pc);
531 while (range != NULL_EH_RANGE && range->start_pc == start_pc
532 && range->end_pc < end_pc)
533 range = range->outer;
535 current_range = range;
536 check_start_handlers (range, start_pc);
539 /* Emit any end-of-try-range ending at end_pc and starting before
540 start_pc. */
542 void
543 maybe_end_try (int start_pc, int end_pc)
545 if (! doing_eh (1))
546 return;
548 while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
549 && current_range->start_pc >= start_pc)
551 expand_end_java_handler (current_range);
552 current_range = current_range->outer;