]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/java/except.c
Merge tree-ssa-20020619-branch into mainline.
[thirdparty/gcc.git] / gcc / java / except.c
CommitLineData
377029eb 1/* Handle exceptions for GNU compiler for the Java(TM) language.
757f6c6c 2 Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004
7d82ed5e 3 Free Software Foundation, Inc.
377029eb 4
7d82ed5e 5This file is part of GCC.
377029eb 6
7d82ed5e 7GCC is free software; you can redistribute it and/or modify
377029eb 8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
7d82ed5e 12GCC is distributed in the hope that it will be useful,
377029eb 13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
7d82ed5e 18along with GCC; see the file COPYING. If not, write to
377029eb 19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA.
21
22Java and all Java-based marks are trademarks or registered trademarks
23of Sun Microsystems, Inc. in the United States and other countries.
24The Free Software Foundation is independent of Sun Microsystems, Inc. */
25
377029eb 26#include "config.h"
014e6e0c 27#include "system.h"
805e22b2 28#include "coretypes.h"
29#include "tm.h"
377029eb 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"
304c5bf1 37#include "function.h"
377029eb 38#include "except.h"
39#include "java-except.h"
014e6e0c 40#include "toplev.h"
377029eb 41
6852521a 42static void expand_start_java_handler (struct eh_range *);
43static void expand_end_java_handler (struct eh_range *);
44static struct eh_range *find_handler_in_range (int, struct eh_range *,
45 struct eh_range *);
46static void link_handler (struct eh_range *, struct eh_range *);
47static void check_start_handlers (struct eh_range *, int);
48static void free_eh_ranges (struct eh_range *range);
003019ba 49
377029eb 50struct eh_range *current_method_handlers;
51
52struct eh_range *current_try_block = NULL;
53
54struct eh_range *eh_range_freelist = NULL;
55
56/* These variables are used to speed up find_handler. */
57
58static int cache_range_start, cache_range_end;
59static struct eh_range *cache_range;
60static struct eh_range *cache_next_child;
61
62/* A dummy range that represents the entire method. */
63
64struct eh_range whole_range;
65
c1b6623d 66#if defined(DEBUG_JAVA_BINDING_LEVELS)
678d3f71 67extern int binding_depth;
68extern int is_class_level;
69extern int current_pc;
c1b6623d 70extern void indent ();
71
72#endif
73
377029eb 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. */
78
79static struct eh_range *
2883a3ed 80find_handler_in_range (int pc, struct eh_range *range, struct eh_range *child)
377029eb 81{
82 for (; child != NULL; child = child->next_sibling)
83 {
84 if (pc < child->start_pc)
85 break;
e986fd23 86 if (pc < child->end_pc)
377029eb 87 return find_handler_in_range (pc, child, child->first_child);
88 }
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;
94}
95
96/* Find the inner-most handler that contains PC. */
97
98struct eh_range *
2883a3ed 99find_handler (int pc)
377029eb 100{
101 struct eh_range *h;
102 if (pc >= cache_range_start)
103 {
104 h = cache_range;
105 if (pc < cache_range_end)
106 return h;
107 while (pc >= h->end_pc)
108 {
109 cache_next_child = h->next_sibling;
110 h = h->outer;
111 }
112 }
113 else
114 {
115 h = &whole_range;
116 cache_next_child = h->first_child;
117 }
118 return find_handler_in_range (pc, h, cache_next_child);
119}
120
addd693c 121/* Recursive helper routine for check_nested_ranges. */
377029eb 122
addd693c 123static void
2883a3ed 124link_handler (struct eh_range *range, struct eh_range *outer)
377029eb 125{
126 struct eh_range **ptr;
addd693c 127
128 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
129 {
9a984332 130 outer->handlers = chainon (outer->handlers, range->handlers);
addd693c 131 return;
132 }
133
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)
137 {
138 range->outer = outer->outer;
139 range->next_sibling = NULL;
140 range->first_child = outer;
e986fd23 141 {
142 struct eh_range **pr = &(outer->outer->first_child);
143 while (*pr != outer)
144 pr = &(*pr)->next_sibling;
145 *pr = range;
146 }
addd693c 147 outer->outer = range;
148 return;
149 }
150
151 /* Handle overlapping ranges by splitting the new range. */
152 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
377029eb 153 {
0cc50a21 154 struct eh_range *h = xmalloc (sizeof (struct eh_range));
addd693c 155 if (range->start_pc < outer->start_pc)
156 {
157 h->start_pc = range->start_pc;
158 h->end_pc = outer->start_pc;
159 range->start_pc = outer->start_pc;
160 }
161 else
162 {
163 h->start_pc = outer->end_pc;
164 h->end_pc = range->end_pc;
165 range->end_pc = outer->end_pc;
166 }
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;
678d3f71 172 h->expanded = 0;
4ee9c684 173 h->stmt = NULL;
addd693c 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;
377029eb 179 }
addd693c 180
377029eb 181 ptr = &outer->first_child;
182 for (;; ptr = &(*ptr)->next_sibling)
183 {
addd693c 184 if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
377029eb 185 {
addd693c 186 range->next_sibling = *ptr;
187 range->first_child = NULL;
188 range->outer = outer;
189 *ptr = range;
190 return;
191 }
192 else if (range->start_pc < (*ptr)->end_pc)
193 {
194 link_handler (range, *ptr);
195 return;
377029eb 196 }
377029eb 197 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
198 }
199}
200
addd693c 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. */
205
206void
2883a3ed 207handle_nested_ranges (void)
addd693c 208{
209 struct eh_range *ptr, *next;
210
211 ptr = whole_range.first_child;
212 whole_range.first_child = NULL;
213 for (; ptr; ptr = next)
214 {
215 next = ptr->next_sibling;
216 ptr->next_sibling = NULL;
217 link_handler (ptr, &whole_range);
218 }
219}
220
d7c47c0e 221/* Free RANGE as well as its children and siblings. */
222
223static void
2883a3ed 224free_eh_ranges (struct eh_range *range)
d7c47c0e 225{
226 while (range)
227 {
228 struct eh_range *next = range->next_sibling;
229 free_eh_ranges (range->first_child);
0e41c837 230 if (range != &whole_range)
231 free (range);
d7c47c0e 232 range = next;
233 }
234}
addd693c 235
377029eb 236/* Called to re-initialize the exception machinery for a new method. */
237
238void
2883a3ed 239method_init_exceptions (void)
377029eb 240{
d7c47c0e 241 free_eh_ranges (&whole_range);
377029eb 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;
377029eb 248}
249
addd693c 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.
255
256 This constructs an ordinary linked list which check_nested_ranges()
257 later turns into the data structure we actually want.
258
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. */
263
264void
2883a3ed 265add_handler (int start_pc, int end_pc, tree handler, tree type)
377029eb 266{
addd693c 267 struct eh_range *ptr, *prev = NULL, *h;
268
269 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
270 {
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)
275 {
276 /* Already found an overlapping range, so coalesce. */
277 ptr->end_pc = MAX (ptr->end_pc, end_pc);
278 return;
279 }
280 prev = ptr;
281 }
282
0cc50a21 283 h = xmalloc (sizeof (struct eh_range));
addd693c 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;
c1b6623d 290 h->expanded = 0;
4ee9c684 291 h->stmt = NULL;
addd693c 292
293 if (prev == NULL)
294 whole_range.first_child = h;
295 else
296 prev->next_sibling = h;
377029eb 297}
298
377029eb 299/* if there are any handlers for this range, issue start of region */
003019ba 300static void
2883a3ed 301expand_start_java_handler (struct eh_range *range)
377029eb 302{
c1b6623d 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) */
4ee9c684 308 {
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);
313 }
314
c1b6623d 315 range->expanded = 1;
377029eb 316}
317
f1f55166 318tree
2883a3ed 319prepare_eh_table_type (tree type)
f1f55166 320{
321 tree exp;
757f6c6c 322 tree *slot;
927abe86 323 const char *name;
324 char *buf;
325 tree decl;
326 tree utf8_ref;
f1f55166 327
e164eae7 328 /* The "type" (match_info) in a (Java) exception table is a pointer to:
f1f55166 329 * a) NULL - meaning match any type in a try-finally.
e164eae7 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. */
f1f55166 333
f1f55166 334 if (type == NULL_TREE)
757f6c6c 335 return NULL_TREE;
336
337 if (TYPE_TO_RUNTIME_MAP (output_class) == NULL)
338 TYPE_TO_RUNTIME_MAP (output_class) = java_treetreehash_create (10, 1);
339
340 slot = java_treetreehash_new (TYPE_TO_RUNTIME_MAP (output_class), type);
341 if (*slot != NULL)
342 return TREE_VALUE (*slot);
343
344 if (is_compiled_class (type) && !flag_indirect_dispatch)
e164eae7 345 {
927abe86 346 name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
347 buf = alloca (strlen (name) + 5);
348 sprintf (buf, "%s_ref", name);
e164eae7 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);
4ee9c684 358 exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl);
e164eae7 359 }
f1f55166 360 else
30e23acf 361 {
927abe86 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);
e164eae7 366 decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_ptr_type);
30e23acf 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;
30e23acf 372 layout_decl (decl, 0);
373 pushdecl (decl);
e164eae7 374 exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl);
757f6c6c 375 TYPE_CATCH_CLASSES (output_class) =
376 tree_cons (NULL, make_catch_class_record (exp, utf8_ref),
377 TYPE_CATCH_CLASSES (output_class));
30e23acf 378 }
757f6c6c 379
4ee9c684 380 exp = convert (ptr_type_node, exp);
381
757f6c6c 382 *slot = tree_cons (type, exp, NULL_TREE);
383
f1f55166 384 return exp;
385}
386
757f6c6c 387static int
388expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED)
389{
390 struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
4ee9c684 391 tree addr = TREE_VALUE ((tree)ite->value);
392 tree decl;
393 STRIP_NOPS (addr);
394 decl = TREE_OPERAND (addr, 0);
757f6c6c 395 rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
396 return true;
397}
398
399/* For every class in the TYPE_TO_RUNTIME_MAP, expand the
400 corresponding object that is used by the runtime type matcher. */
401
402void
403java_expand_catch_classes (tree this_class)
404{
405 if (TYPE_TO_RUNTIME_MAP (this_class))
406 htab_traverse
407 (TYPE_TO_RUNTIME_MAP (this_class),
408 expand_catch_class, NULL);
409}
df4b504c 410
411/* Build a reference to the jthrowable object being carried in the
412 exception header. */
413
414tree
2883a3ed 415build_exception_object_ref (tree type)
df4b504c 416{
417 tree obj;
418
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);
425
426 return obj;
427}
428
429/* If there are any handlers for this range, isssue end of range,
377029eb 430 and then all handler blocks */
003019ba 431static void
2883a3ed 432expand_end_java_handler (struct eh_range *range)
c1b6623d 433{
377029eb 434 tree handler = range->handlers;
4ee9c684 435 tree compound = NULL;
436
437 force_poplevels (range->start_pc);
377029eb 438 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
439 {
d179df43 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);
4ee9c684 447
d179df43 448 if (type == NULL)
449 type = throwable_type_node;
450
4ee9c684 451 type = prepare_eh_table_type (type);
452
453 if (compound)
454 {
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;
467 }
468 else
469 {
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;
495 }
377029eb 496 }
c1b6623d 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) */
377029eb 502}
503
504/* Recursive helper routine for maybe_start_handlers. */
505
506static void
2883a3ed 507check_start_handlers (struct eh_range *range, int pc)
377029eb 508{
509 if (range != NULL_EH_RANGE && range->start_pc == pc)
510 {
511 check_start_handlers (range->outer, pc);
c1b6623d 512 if (!range->expanded)
513 expand_start_java_handler (range);
377029eb 514 }
515}
516
377029eb 517
c1b6623d 518static struct eh_range *current_range;
519
520/* Emit any start-of-try-range starting at start_pc and ending after
521 end_pc. */
377029eb 522
523void
2883a3ed 524maybe_start_try (int start_pc, int end_pc)
377029eb 525{
c1b6623d 526 struct eh_range *range;
377029eb 527 if (! doing_eh (1))
528 return;
529
c1b6623d 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;
534
535 current_range = range;
083909e3 536 check_start_handlers (range, start_pc);
377029eb 537}
538
c1b6623d 539/* Emit any end-of-try-range ending at end_pc and starting before
540 start_pc. */
377029eb 541
542void
2883a3ed 543maybe_end_try (int start_pc, int end_pc)
377029eb 544{
545 if (! doing_eh (1))
546 return;
547
c1b6623d 548 while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
549 && current_range->start_pc >= start_pc)
377029eb 550 {
551 expand_end_java_handler (current_range);
552 current_range = current_range->outer;
553 }
554}