1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2 Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003
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
PARAMS ((struct eh_range
*));
43 static void expand_end_java_handler
PARAMS ((struct eh_range
*));
44 static struct eh_range
*find_handler_in_range
PARAMS ((int, struct eh_range
*,
46 static void link_handler
PARAMS ((struct eh_range
*, struct eh_range
*));
47 static void check_start_handlers
PARAMS ((struct eh_range
*, int));
48 static void free_eh_ranges
PARAMS ((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 (pc
, range
, child
)
82 struct eh_range
*range
;
83 register struct eh_range
*child
;
85 for (; child
!= NULL
; child
= child
->next_sibling
)
87 if (pc
< child
->start_pc
)
89 if (pc
< child
->end_pc
)
90 return find_handler_in_range (pc
, child
, child
->first_child
);
93 cache_range_start
= pc
;
94 cache_next_child
= child
;
95 cache_range_end
= child
== NULL
? range
->end_pc
: child
->start_pc
;
99 /* Find the inner-most handler that contains PC. */
106 if (pc
>= cache_range_start
)
109 if (pc
< cache_range_end
)
111 while (pc
>= h
->end_pc
)
113 cache_next_child
= h
->next_sibling
;
120 cache_next_child
= h
->first_child
;
122 return find_handler_in_range (pc
, h
, cache_next_child
);
125 /* Recursive helper routine for check_nested_ranges. */
128 link_handler (range
, outer
)
129 struct eh_range
*range
, *outer
;
131 struct eh_range
**ptr
;
133 if (range
->start_pc
== outer
->start_pc
&& range
->end_pc
== outer
->end_pc
)
135 outer
->handlers
= chainon (outer
->handlers
, range
->handlers
);
139 /* If the new range completely encloses the `outer' range, then insert it
140 between the outer range and its parent. */
141 if (range
->start_pc
<= outer
->start_pc
&& range
->end_pc
>= outer
->end_pc
)
143 range
->outer
= outer
->outer
;
144 range
->next_sibling
= NULL
;
145 range
->first_child
= outer
;
147 struct eh_range
**pr
= &(outer
->outer
->first_child
);
149 pr
= &(*pr
)->next_sibling
;
152 outer
->outer
= range
;
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
;
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
;
174 h
->handlers
= build_tree_list (TREE_PURPOSE (range
->handlers
),
175 TREE_VALUE (range
->handlers
));
176 h
->next_sibling
= NULL
;
178 /* Restart both from the top to avoid having to make this
179 function smart about reentrancy. */
180 link_handler (h
, &whole_range
);
181 link_handler (range
, &whole_range
);
185 ptr
= &outer
->first_child
;
186 for (;; ptr
= &(*ptr
)->next_sibling
)
188 if (*ptr
== NULL
|| range
->end_pc
<= (*ptr
)->start_pc
)
190 range
->next_sibling
= *ptr
;
191 range
->first_child
= NULL
;
192 range
->outer
= outer
;
196 else if (range
->start_pc
< (*ptr
)->end_pc
)
198 link_handler (range
, *ptr
);
201 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
205 /* The first pass of exception range processing (calling add_handler)
206 constructs a linked list of exception ranges. We turn this into
207 the data structure expected by the rest of the code, and also
208 ensure that exception ranges are properly nested. */
211 handle_nested_ranges ()
213 struct eh_range
*ptr
, *next
;
215 ptr
= whole_range
.first_child
;
216 whole_range
.first_child
= NULL
;
217 for (; ptr
; ptr
= next
)
219 next
= ptr
->next_sibling
;
220 ptr
->next_sibling
= NULL
;
221 link_handler (ptr
, &whole_range
);
225 /* Free RANGE as well as its children and siblings. */
228 free_eh_ranges (range
)
229 struct eh_range
*range
;
233 struct eh_range
*next
= range
->next_sibling
;
234 free_eh_ranges (range
->first_child
);
235 if (range
!= &whole_range
)
241 /* Called to re-initialize the exception machinery for a new method. */
244 method_init_exceptions ()
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. */
270 add_handler (start_pc
, end_pc
, handler
, type
)
271 int start_pc
, end_pc
;
275 struct eh_range
*ptr
, *prev
= NULL
, *h
;
277 for (ptr
= whole_range
.first_child
; ptr
; ptr
= ptr
->next_sibling
)
279 if (start_pc
>= ptr
->start_pc
280 && start_pc
<= ptr
->end_pc
281 && TREE_PURPOSE (ptr
->handlers
) == type
282 && TREE_VALUE (ptr
->handlers
) == handler
)
284 /* Already found an overlapping range, so coalesce. */
285 ptr
->end_pc
= MAX (ptr
->end_pc
, end_pc
);
291 h
= xmalloc (sizeof (struct eh_range
));
292 h
->start_pc
= start_pc
;
294 h
->first_child
= NULL
;
296 h
->handlers
= build_tree_list (type
, handler
);
297 h
->next_sibling
= NULL
;
301 whole_range
.first_child
= h
;
303 prev
->next_sibling
= h
;
307 /* if there are any handlers for this range, issue start of region */
309 expand_start_java_handler (range
)
310 struct eh_range
*range
;
312 #if defined(DEBUG_JAVA_BINDING_LEVELS)
314 fprintf (stderr
, "expand start handler pc %d --> %d\n",
315 current_pc
, range
->end_pc
);
316 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
318 expand_eh_region_start ();
322 prepare_eh_table_type (type
)
327 /* The "type" (metch_info) in a (Java) exception table is one:
328 * a) NULL - meaning match any type in a try-finally.
329 * b) a pointer to a (ccmpiled) class (low-order bit 0).
330 * c) a pointer to the Utf8Const name of the class, plus one
331 * (which yields a value with low-order bit 1). */
333 if (type
== NULL_TREE
)
335 else if (is_compiled_class (type
))
336 exp
= build_class_ref (type
);
339 (PLUS_EXPR
, ptr_type_node
,
340 build_utf8_ref (DECL_NAME (TYPE_NAME (type
))),
346 /* Build a reference to the jthrowable object being carried in the
350 build_exception_object_ref (type
)
355 /* Java only passes object via pointer and doesn't require adjusting.
356 The java object is immediately before the generic exception header. */
357 obj
= build (EXC_PTR_EXPR
, build_pointer_type (type
));
358 obj
= build (MINUS_EXPR
, TREE_TYPE (obj
), obj
,
359 TYPE_SIZE_UNIT (TREE_TYPE (obj
)));
360 obj
= build1 (INDIRECT_REF
, type
, obj
);
365 /* If there are any handlers for this range, isssue end of range,
366 and then all handler blocks */
368 expand_end_java_handler (range
)
369 struct eh_range
*range
;
371 tree handler
= range
->handlers
;
372 force_poplevels (range
->start_pc
);
373 expand_start_all_catch ();
374 for ( ; handler
!= NULL_TREE
; handler
= TREE_CHAIN (handler
))
376 /* For bytecode we treat exceptions a little unusually. A
377 `finally' clause looks like an ordinary exception handler for
378 Throwable. The reason for this is that the bytecode has
379 already expanded the finally logic, and we would have to do
380 extra (and difficult) work to get this to look like a
381 gcc-style finally clause. */
382 tree type
= TREE_PURPOSE (handler
);
384 type
= throwable_type_node
;
386 expand_start_catch (type
);
387 expand_goto (TREE_VALUE (handler
));
390 expand_end_all_catch ();
391 #if defined(DEBUG_JAVA_BINDING_LEVELS)
393 fprintf (stderr
, "expand end handler pc %d <-- %d\n",
394 current_pc
, range
->start_pc
);
395 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
398 /* Recursive helper routine for maybe_start_handlers. */
401 check_start_handlers (range
, pc
)
402 struct eh_range
*range
;
405 if (range
!= NULL_EH_RANGE
&& range
->start_pc
== pc
)
407 check_start_handlers (range
->outer
, pc
);
408 if (!range
->expanded
)
409 expand_start_java_handler (range
);
414 static struct eh_range
*current_range
;
416 /* Emit any start-of-try-range starting at start_pc and ending after
420 maybe_start_try (start_pc
, end_pc
)
424 struct eh_range
*range
;
428 range
= find_handler (start_pc
);
429 while (range
!= NULL_EH_RANGE
&& range
->start_pc
== start_pc
430 && range
->end_pc
< end_pc
)
431 range
= range
->outer
;
433 current_range
= range
;
434 check_start_handlers (range
, start_pc
);
437 /* Emit any end-of-try-range ending at end_pc and starting before
441 maybe_end_try (start_pc
, end_pc
)
448 while (current_range
!= NULL_EH_RANGE
&& current_range
->end_pc
<= end_pc
449 && current_range
->start_pc
>= start_pc
)
451 expand_end_java_handler (current_range
);
452 current_range
= current_range
->outer
;