Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / gcc / java / except.c
blob6735b598311bdc8855489349aacfdece3dac7607
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 struct eh_range *find_handler_in_range (int, struct eh_range *,
44 struct eh_range *);
45 static void link_handler (struct eh_range *, struct eh_range *);
46 static void check_start_handlers (struct eh_range *, int);
47 static void free_eh_ranges (struct eh_range *range);
49 struct eh_range *current_method_handlers;
51 struct eh_range *current_try_block = NULL;
53 struct eh_range *eh_range_freelist = NULL;
55 /* These variables are used to speed up find_handler. */
57 static int cache_range_start, cache_range_end;
58 static struct eh_range *cache_range;
59 static struct eh_range *cache_next_child;
61 /* A dummy range that represents the entire method. */
63 struct eh_range whole_range;
65 #if defined(DEBUG_JAVA_BINDING_LEVELS)
66 extern int binding_depth;
67 extern int is_class_level;
68 extern int current_pc;
69 extern void indent ();
71 #endif
73 /* Search for the most specific eh_range containing PC.
74 Assume PC is within RANGE.
75 CHILD is a list of children of RANGE such that any
76 previous children have end_pc values that are too low. */
78 static struct eh_range *
79 find_handler_in_range (int pc, struct eh_range *range, struct eh_range *child)
81 for (; child != NULL; child = child->next_sibling)
83 if (pc < child->start_pc)
84 break;
85 if (pc < child->end_pc)
86 return find_handler_in_range (pc, child, child->first_child);
88 cache_range = range;
89 cache_range_start = pc;
90 cache_next_child = child;
91 cache_range_end = child == NULL ? range->end_pc : child->start_pc;
92 return range;
95 /* Find the inner-most handler that contains PC. */
97 struct eh_range *
98 find_handler (int pc)
100 struct eh_range *h;
101 if (pc >= cache_range_start)
103 h = cache_range;
104 if (pc < cache_range_end)
105 return h;
106 while (pc >= h->end_pc)
108 cache_next_child = h->next_sibling;
109 h = h->outer;
112 else
114 h = &whole_range;
115 cache_next_child = h->first_child;
117 return find_handler_in_range (pc, h, cache_next_child);
120 /* Recursive helper routine for check_nested_ranges. */
122 static void
123 link_handler (struct eh_range *range, struct eh_range *outer)
125 struct eh_range **ptr;
127 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
129 outer->handlers = chainon (outer->handlers, range->handlers);
130 return;
133 /* If the new range completely encloses the `outer' range, then insert it
134 between the outer range and its parent. */
135 if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
137 range->outer = outer->outer;
138 range->next_sibling = NULL;
139 range->first_child = outer;
141 struct eh_range *p = outer;
142 struct eh_range **pr = &(outer->outer->first_child);
143 while (*pr != outer)
144 pr = &(*pr)->next_sibling;
145 *pr = range;
147 while (p)
149 p->outer = range;
150 p = p->next_sibling;
153 return;
156 /* Handle overlapping ranges by splitting the new range. */
157 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
159 struct eh_range *h = xmalloc (sizeof (struct eh_range));
160 if (range->start_pc < outer->start_pc)
162 h->start_pc = range->start_pc;
163 h->end_pc = outer->start_pc;
164 range->start_pc = outer->start_pc;
166 else
168 h->start_pc = outer->end_pc;
169 h->end_pc = range->end_pc;
170 range->end_pc = outer->end_pc;
172 h->first_child = NULL;
173 h->outer = NULL;
174 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
175 TREE_VALUE (range->handlers));
176 h->next_sibling = NULL;
177 h->expanded = 0;
178 h->stmt = NULL;
179 /* Restart both from the top to avoid having to make this
180 function smart about reentrancy. */
181 link_handler (h, &whole_range);
182 link_handler (range, &whole_range);
183 return;
186 ptr = &outer->first_child;
187 for (;; ptr = &(*ptr)->next_sibling)
189 if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
191 range->next_sibling = *ptr;
192 range->first_child = NULL;
193 range->outer = outer;
194 *ptr = range;
195 return;
197 else if (range->start_pc < (*ptr)->end_pc)
199 link_handler (range, *ptr);
200 return;
202 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
206 /* The first pass of exception range processing (calling add_handler)
207 constructs a linked list of exception ranges. We turn this into
208 the data structure expected by the rest of the code, and also
209 ensure that exception ranges are properly nested. */
211 void
212 handle_nested_ranges (void)
214 struct eh_range *ptr, *next;
216 ptr = whole_range.first_child;
217 whole_range.first_child = NULL;
218 for (; ptr; ptr = next)
220 next = ptr->next_sibling;
221 ptr->next_sibling = NULL;
222 link_handler (ptr, &whole_range);
226 /* Free RANGE as well as its children and siblings. */
228 static void
229 free_eh_ranges (struct eh_range *range)
231 while (range)
233 struct eh_range *next = range->next_sibling;
234 free_eh_ranges (range->first_child);
235 if (range != &whole_range)
236 free (range);
237 range = next;
241 /* Called to re-initialize the exception machinery for a new method. */
243 void
244 method_init_exceptions (void)
246 free_eh_ranges (&whole_range);
247 whole_range.start_pc = 0;
248 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
249 whole_range.outer = NULL;
250 whole_range.first_child = NULL;
251 whole_range.next_sibling = NULL;
252 cache_range_start = 0xFFFFFF;
255 /* Add an exception range. If we already have an exception range
256 which has the same handler and label, and the new range overlaps
257 that one, then we simply extend the existing range. Some bytecode
258 obfuscators generate seemingly nonoverlapping exception ranges
259 which, when coalesced, do in fact nest correctly.
261 This constructs an ordinary linked list which check_nested_ranges()
262 later turns into the data structure we actually want.
264 We expect the input to come in order of increasing START_PC. This
265 function doesn't attempt to detect the case where two previously
266 added disjoint ranges could be coalesced by a new range; that is
267 what the sorting counteracts. */
269 void
270 add_handler (int start_pc, int end_pc, tree handler, tree type)
272 struct eh_range *ptr, *prev = NULL, *h;
274 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
276 if (start_pc >= ptr->start_pc
277 && start_pc <= ptr->end_pc
278 && TREE_PURPOSE (ptr->handlers) == type
279 && TREE_VALUE (ptr->handlers) == handler)
281 /* Already found an overlapping range, so coalesce. */
282 ptr->end_pc = MAX (ptr->end_pc, end_pc);
283 return;
285 prev = ptr;
288 h = xmalloc (sizeof (struct eh_range));
289 h->start_pc = start_pc;
290 h->end_pc = end_pc;
291 h->first_child = NULL;
292 h->outer = NULL;
293 h->handlers = build_tree_list (type, handler);
294 h->next_sibling = NULL;
295 h->expanded = 0;
296 h->stmt = NULL;
298 if (prev == NULL)
299 whole_range.first_child = h;
300 else
301 prev->next_sibling = h;
304 /* if there are any handlers for this range, issue start of region */
305 static void
306 expand_start_java_handler (struct eh_range *range)
308 #if defined(DEBUG_JAVA_BINDING_LEVELS)
309 indent ();
310 fprintf (stderr, "expand start handler pc %d --> %d\n",
311 current_pc, range->end_pc);
312 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
313 pushlevel (0);
314 register_exception_range (range, range->start_pc, range->end_pc);
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, 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 = build0 (EXC_PTR_EXPR, build_pointer_type (type));
422 obj = build2 (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 void
432 expand_end_java_handler (struct eh_range *range)
434 tree handler = range->handlers;
436 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
438 /* For bytecode we treat exceptions a little unusually. A
439 `finally' clause looks like an ordinary exception handler for
440 Throwable. The reason for this is that the bytecode has
441 already expanded the finally logic, and we would have to do
442 extra (and difficult) work to get this to look like a
443 gcc-style finally clause. */
444 tree type = TREE_PURPOSE (handler);
445 if (type == NULL)
446 type = throwable_type_node;
447 type = prepare_eh_table_type (type);
450 tree catch_expr = build2 (CATCH_EXPR, void_type_node, type,
451 build1 (GOTO_EXPR, void_type_node,
452 TREE_VALUE (handler)));
453 tree try_catch_expr = build2 (TRY_CATCH_EXPR, void_type_node,
454 *get_stmts (), catch_expr);
455 *get_stmts () = try_catch_expr;
458 #if defined(DEBUG_JAVA_BINDING_LEVELS)
459 indent ();
460 fprintf (stderr, "expand end handler pc %d <-- %d\n",
461 current_pc, range->start_pc);
462 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
465 /* Recursive helper routine for maybe_start_handlers. */
467 static void
468 check_start_handlers (struct eh_range *range, int pc)
470 if (range != NULL_EH_RANGE && range->start_pc == pc)
472 check_start_handlers (range->outer, pc);
473 if (!range->expanded)
474 expand_start_java_handler (range);
479 static struct eh_range *current_range;
481 /* Emit any start-of-try-range starting at start_pc and ending after
482 end_pc. */
484 void
485 maybe_start_try (int start_pc, int end_pc)
487 struct eh_range *range;
488 if (! doing_eh (1))
489 return;
491 range = find_handler (start_pc);
492 while (range != NULL_EH_RANGE && range->start_pc == start_pc
493 && range->end_pc < end_pc)
494 range = range->outer;
496 current_range = range;
497 check_start_handlers (range, start_pc);