1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2 Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
4 This file is part of GNU CC.
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Java and all Java-based marks are trademarks or registered trademarks
22 of Sun Microsystems, Inc. in the United States and other countries.
23 The Free Software Foundation is independent of Sun Microsystems, Inc. */
30 #include "java-tree.h"
32 #include "java-opcodes.h"
36 #include "java-except.h"
37 #include "eh-common.h"
40 static void expand_start_java_handler
PROTO ((struct eh_range
*));
41 static void expand_end_java_handler
PROTO ((struct eh_range
*));
42 static struct eh_range
*find_handler_in_range
PROTO ((int, struct eh_range
*,
44 static void link_handler
PROTO ((struct eh_range
*, struct eh_range
*));
45 static void check_start_handlers
PROTO ((struct eh_range
*, int));
47 extern struct obstack permanent_obstack
;
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 /* Search for the most specific eh_range containing PC.
66 Assume PC is within RANGE.
67 CHILD is a list of children of RANGE such that any
68 previous children have end_pc values that are too low. */
70 static struct eh_range
*
71 find_handler_in_range (pc
, range
, child
)
73 struct eh_range
*range
;
74 register struct eh_range
*child
;
76 for (; child
!= NULL
; child
= child
->next_sibling
)
78 if (pc
< child
->start_pc
)
80 if (pc
< child
->end_pc
)
81 return find_handler_in_range (pc
, child
, child
->first_child
);
84 cache_range_start
= pc
;
85 cache_next_child
= child
;
86 cache_range_end
= child
== NULL
? range
->end_pc
: child
->start_pc
;
90 /* Find the inner-most handler that contains PC. */
97 if (pc
>= cache_range_start
)
100 if (pc
< cache_range_end
)
102 while (pc
>= h
->end_pc
)
104 cache_next_child
= h
->next_sibling
;
111 cache_next_child
= h
->first_child
;
113 return find_handler_in_range (pc
, h
, cache_next_child
);
116 /* Recursive helper routine for check_nested_ranges. */
119 link_handler (range
, outer
)
120 struct eh_range
*range
, *outer
;
122 struct eh_range
**ptr
;
124 if (range
->start_pc
== outer
->start_pc
&& range
->end_pc
== outer
->end_pc
)
126 outer
->handlers
= chainon (outer
->handlers
, range
->handlers
);
130 /* If the new range completely encloses the `outer' range, then insert it
131 between the outer range and its parent. */
132 if (range
->start_pc
<= outer
->start_pc
&& range
->end_pc
>= outer
->end_pc
)
134 range
->outer
= outer
->outer
;
135 range
->next_sibling
= NULL
;
136 range
->first_child
= outer
;
138 struct eh_range
**pr
= &(outer
->outer
->first_child
);
140 pr
= &(*pr
)->next_sibling
;
143 outer
->outer
= range
;
147 /* Handle overlapping ranges by splitting the new range. */
148 if (range
->start_pc
< outer
->start_pc
|| range
->end_pc
> outer
->end_pc
)
151 = (struct eh_range
*) oballoc (sizeof (struct eh_range
));
152 if (range
->start_pc
< outer
->start_pc
)
154 h
->start_pc
= range
->start_pc
;
155 h
->end_pc
= outer
->start_pc
;
156 range
->start_pc
= outer
->start_pc
;
160 h
->start_pc
= outer
->end_pc
;
161 h
->end_pc
= range
->end_pc
;
162 range
->end_pc
= outer
->end_pc
;
164 h
->first_child
= NULL
;
166 h
->handlers
= build_tree_list (TREE_PURPOSE (range
->handlers
),
167 TREE_VALUE (range
->handlers
));
168 h
->next_sibling
= NULL
;
169 /* Restart both from the top to avoid having to make this
170 function smart about reentrancy. */
171 link_handler (h
, &whole_range
);
172 link_handler (range
, &whole_range
);
176 ptr
= &outer
->first_child
;
177 for (;; ptr
= &(*ptr
)->next_sibling
)
179 if (*ptr
== NULL
|| range
->end_pc
<= (*ptr
)->start_pc
)
181 range
->next_sibling
= *ptr
;
182 range
->first_child
= NULL
;
183 range
->outer
= outer
;
187 else if (range
->start_pc
< (*ptr
)->end_pc
)
189 link_handler (range
, *ptr
);
192 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
196 /* The first pass of exception range processing (calling add_handler)
197 constructs a linked list of exception ranges. We turn this into
198 the data structure expected by the rest of the code, and also
199 ensure that exception ranges are properly nested. */
202 handle_nested_ranges ()
204 struct eh_range
*ptr
, *next
;
206 ptr
= whole_range
.first_child
;
207 whole_range
.first_child
= NULL
;
208 for (; ptr
; ptr
= next
)
210 next
= ptr
->next_sibling
;
211 ptr
->next_sibling
= NULL
;
212 link_handler (ptr
, &whole_range
);
217 /* Called to re-initialize the exception machinery for a new method. */
220 method_init_exceptions ()
222 whole_range
.start_pc
= 0;
223 whole_range
.end_pc
= DECL_CODE_LENGTH (current_function_decl
) + 1;
224 whole_range
.outer
= NULL
;
225 whole_range
.first_child
= NULL
;
226 whole_range
.next_sibling
= NULL
;
227 cache_range_start
= 0xFFFFFF;
228 java_set_exception_lang_code ();
232 java_set_exception_lang_code ()
234 set_exception_lang_code (EH_LANG_Java
);
235 set_exception_version_code (1);
238 /* Add an exception range. If we already have an exception range
239 which has the same handler and label, and the new range overlaps
240 that one, then we simply extend the existing range. Some bytecode
241 obfuscators generate seemingly nonoverlapping exception ranges
242 which, when coalesced, do in fact nest correctly.
244 This constructs an ordinary linked list which check_nested_ranges()
245 later turns into the data structure we actually want.
247 We expect the input to come in order of increasing START_PC. This
248 function doesn't attempt to detect the case where two previously
249 added disjoint ranges could be coalesced by a new range; that is
250 what the sorting counteracts. */
253 add_handler (start_pc
, end_pc
, handler
, type
)
254 int start_pc
, end_pc
;
258 struct eh_range
*ptr
, *prev
= NULL
, *h
;
260 for (ptr
= whole_range
.first_child
; ptr
; ptr
= ptr
->next_sibling
)
262 if (start_pc
>= ptr
->start_pc
263 && start_pc
<= ptr
->end_pc
264 && TREE_PURPOSE (ptr
->handlers
) == type
265 && TREE_VALUE (ptr
->handlers
) == handler
)
267 /* Already found an overlapping range, so coalesce. */
268 ptr
->end_pc
= MAX (ptr
->end_pc
, end_pc
);
274 h
= (struct eh_range
*) oballoc (sizeof (struct eh_range
));
275 h
->start_pc
= start_pc
;
277 h
->first_child
= NULL
;
279 h
->handlers
= build_tree_list (type
, handler
);
280 h
->next_sibling
= NULL
;
283 whole_range
.first_child
= h
;
285 prev
->next_sibling
= h
;
289 /* if there are any handlers for this range, issue start of region */
291 expand_start_java_handler (range
)
292 struct eh_range
*range ATTRIBUTE_UNUSED
;
294 expand_eh_region_start ();
298 prepare_eh_table_type (type
)
303 /* The "type" (metch_info) in a (Java) exception table is one:
304 * a) NULL - meaning match any type in a try-finally.
305 * b) a pointer to a (ccmpiled) class (low-order bit 0).
306 * c) a pointer to the Utf8Const name of the class, plus one
307 * (which yields a value with low-order bit 1). */
309 push_obstacks (&permanent_obstack
, &permanent_obstack
);
310 if (type
== NULL_TREE
)
311 exp
= null_pointer_node
;
312 else if (is_compiled_class (type
))
313 exp
= build_class_ref (type
);
316 (PLUS_EXPR
, ptr_type_node
,
317 build_utf8_ref (build_internal_class_name (type
)),
323 /* if there are any handlers for this range, isssue end of range,
324 and then all handler blocks */
326 expand_end_java_handler (range
)
327 struct eh_range
*range
;
329 tree handler
= range
->handlers
;
330 expand_start_all_catch ();
331 for ( ; handler
!= NULL_TREE
; handler
= TREE_CHAIN (handler
))
333 start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler
)));
334 /* Push the thrown object on the top of the stack */
335 expand_goto (TREE_VALUE (handler
));
336 expand_resume_after_catch ();
337 end_catch_handler ();
339 expand_end_all_catch ();
342 /* Recursive helper routine for maybe_start_handlers. */
345 check_start_handlers (range
, pc
)
346 struct eh_range
*range
;
349 if (range
!= NULL_EH_RANGE
&& range
->start_pc
== pc
)
351 check_start_handlers (range
->outer
, pc
);
352 expand_start_java_handler (range
);
356 struct eh_range
*current_range
;
358 /* Emit any start-of-try-range start at PC. */
367 current_range
= find_handler (pc
);
368 check_start_handlers (current_range
, pc
);
371 /* Emit any end-of-try-range end at PC. */
380 while (current_range
!= NULL_EH_RANGE
&& current_range
->end_pc
<= pc
)
382 expand_end_java_handler (current_range
);
383 current_range
= current_range
->outer
;
387 /* Emit the handler labels and their code */
394 rtx funcend
= gen_label_rtx ();
397 emit_insns (catch_clauses
);
398 catch_clauses
= NULL_RTX
;
399 expand_leftover_cleanups ();
401 emit_label (funcend
);
405 /* Resume executing at the statement immediately after the end of an
409 expand_resume_after_catch ()
411 expand_goto (top_label_entry (&caught_return_label_stack
));