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)
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. */
28 #include "coretypes.h"
33 #include "java-tree.h"
35 #include "java-opcodes.h"
39 #include "java-except.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
*,
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 ();
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
)
86 if (pc
< child
->end_pc
)
87 return find_handler_in_range (pc
, child
, child
->first_child
);
90 cache_range_start
= pc
;
91 cache_next_child
= child
;
92 cache_range_end
= child
== NULL
? range
->end_pc
: child
->start_pc
;
96 /* Find the inner-most handler that contains PC. */
102 if (pc
>= cache_range_start
)
105 if (pc
< cache_range_end
)
107 while (pc
>= h
->end_pc
)
109 cache_next_child
= h
->next_sibling
;
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. */
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
);
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
);
144 pr
= &(*pr
)->next_sibling
;
147 outer
->outer
= range
;
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
;
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
;
169 h
->handlers
= build_tree_list (TREE_PURPOSE (range
->handlers
),
170 TREE_VALUE (range
->handlers
));
171 h
->next_sibling
= 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
);
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
;
192 else if (range
->start_pc
< (*ptr
)->end_pc
)
194 link_handler (range
, *ptr
);
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. */
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. */
224 free_eh_ranges (struct eh_range
*range
)
228 struct eh_range
*next
= range
->next_sibling
;
229 free_eh_ranges (range
->first_child
);
230 if (range
!= &whole_range
)
236 /* Called to re-initialize the exception machinery for a new method. */
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. */
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
);
283 h
= xmalloc (sizeof (struct eh_range
));
284 h
->start_pc
= start_pc
;
286 h
->first_child
= NULL
;
288 h
->handlers
= build_tree_list (type
, handler
);
289 h
->next_sibling
= NULL
;
294 whole_range
.first_child
= h
;
296 prev
->next_sibling
= h
;
299 /* if there are any handlers for this range, issue start of region */
301 expand_start_java_handler (struct eh_range
*range
)
303 #if defined(DEBUG_JAVA_BINDING_LEVELS)
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);
319 prepare_eh_table_type (tree type
)
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
)
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
);
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);
358 exp
= build1 (ADDR_EXPR
, build_pointer_type (TREE_TYPE (decl
)), decl
);
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);
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
);
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
);
394 decl
= TREE_OPERAND (addr
, 0);
395 rest_of_decl_compilation (decl
, (char*) 0, global_bindings_p (), 0);
399 /* For every class in the TYPE_TO_RUNTIME_MAP, expand the
400 corresponding object that is used by the runtime type matcher. */
403 java_expand_catch_classes (tree this_class
)
405 if (TYPE_TO_RUNTIME_MAP (this_class
))
407 (TYPE_TO_RUNTIME_MAP (this_class
),
408 expand_catch_class
, NULL
);
411 /* Build a reference to the jthrowable object being carried in the
415 build_exception_object_ref (tree type
)
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
);
429 /* If there are any handlers for this range, isssue end of range,
430 and then all handler blocks */
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
);
449 type
= throwable_type_node
;
451 type
= prepare_eh_table_type (type
);
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
459 tree inner_try_expr
= TREE_OPERAND (compound
, 1);
461 = build (CATCH_EXPR
, void_type_node
, type
,
462 build (GOTO_EXPR
, void_type_node
, TREE_VALUE (handler
)));
464 = build (TRY_CATCH_EXPR
, void_type_node
,
465 inner_try_expr
, catch_expr
);
466 TREE_OPERAND (compound
, 1) = try_expr
;
470 tree
*stmts
= get_stmts ();
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 ();
493 = build (COMPOUND_EXPR
, TREE_TYPE (try_expr
), outer
, try_expr
);
497 #if defined(DEBUG_JAVA_BINDING_LEVELS)
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. */
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
524 maybe_start_try (int start_pc
, int end_pc
)
526 struct eh_range
*range
;
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
543 maybe_end_try (int start_pc
, int end_pc
)
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
;