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 *));
43 extern struct obstack permanent_obstack;
45 struct eh_range *current_method_handlers;
47 struct eh_range *current_try_block = NULL;
49 struct eh_range *eh_range_freelist = NULL;
51 /* These variables are used to speed up find_handler. */
53 static int cache_range_start, cache_range_end;
54 static struct eh_range *cache_range;
55 static struct eh_range *cache_next_child;
57 /* A dummy range that represents the entire method. */
59 struct eh_range whole_range;
61 /* Search for the most specific eh_range containing PC.
62 Assume PC is within RANGE.
63 CHILD is a list of children of RANGE such that any
64 previous children have end_pc values that are too low. */
66 static struct eh_range *
67 find_handler_in_range (pc, range, child)
69 struct eh_range *range;
70 register struct eh_range *child;
72 for (; child != NULL; child = child->next_sibling)
74 if (pc < child->start_pc)
76 if (pc < child->end_pc)
77 return find_handler_in_range (pc, child, child->first_child);
80 cache_range_start = pc;
81 cache_next_child = child;
82 cache_range_end = child == NULL ? range->end_pc : child->start_pc;
86 /* Find the inner-most handler that contains PC. */
93 if (pc >= cache_range_start)
96 if (pc < cache_range_end)
98 while (pc >= h->end_pc)
100 cache_next_child = h->next_sibling;
107 cache_next_child = h->first_child;
109 return find_handler_in_range (pc, h, cache_next_child);
112 /* Recursive helper routine for check_nested_ranges. */
115 link_handler (range, outer)
116 struct eh_range *range, *outer;
118 struct eh_range **ptr;
120 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
122 outer->handlers = chainon (outer->handlers, range->handlers);
126 /* If the new range completely encloses the `outer' range, then insert it
127 between the outer range and its parent. */
128 if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
130 range->outer = outer->outer;
131 range->next_sibling = NULL;
132 range->first_child = outer;
134 struct eh_range **pr = &(outer->outer->first_child);
136 pr = &(*pr)->next_sibling;
139 outer->outer = range;
143 /* Handle overlapping ranges by splitting the new range. */
144 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
147 = (struct eh_range *) oballoc (sizeof (struct eh_range));
148 if (range->start_pc < outer->start_pc)
150 h->start_pc = range->start_pc;
151 h->end_pc = outer->start_pc;
152 range->start_pc = outer->start_pc;
156 h->start_pc = outer->end_pc;
157 h->end_pc = range->end_pc;
158 range->end_pc = outer->end_pc;
160 h->first_child = NULL;
162 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
163 TREE_VALUE (range->handlers));
164 h->next_sibling = NULL;
165 /* Restart both from the top to avoid having to make this
166 function smart about reentrancy. */
167 link_handler (h, &whole_range);
168 link_handler (range, &whole_range);
172 ptr = &outer->first_child;
173 for (;; ptr = &(*ptr)->next_sibling)
175 if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
177 range->next_sibling = *ptr;
178 range->first_child = NULL;
179 range->outer = outer;
183 else if (range->start_pc < (*ptr)->end_pc)
185 link_handler (range, *ptr);
188 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
192 /* The first pass of exception range processing (calling add_handler)
193 constructs a linked list of exception ranges. We turn this into
194 the data structure expected by the rest of the code, and also
195 ensure that exception ranges are properly nested. */
198 handle_nested_ranges ()
200 struct eh_range *ptr, *next;
202 ptr = whole_range.first_child;
203 whole_range.first_child = NULL;
204 for (; ptr; ptr = next)
206 next = ptr->next_sibling;
207 ptr->next_sibling = NULL;
208 link_handler (ptr, &whole_range);
213 /* Called to re-initialize the exception machinery for a new method. */
216 method_init_exceptions ()
218 whole_range.start_pc = 0;
219 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
220 whole_range.outer = NULL;
221 whole_range.first_child = NULL;
222 whole_range.next_sibling = NULL;
223 cache_range_start = 0xFFFFFF;
224 java_set_exception_lang_code ();
228 java_set_exception_lang_code ()
230 set_exception_lang_code (EH_LANG_Java);
231 set_exception_version_code (1);
234 /* Add an exception range. If we already have an exception range
235 which has the same handler and label, and the new range overlaps
236 that one, then we simply extend the existing range. Some bytecode
237 obfuscators generate seemingly nonoverlapping exception ranges
238 which, when coalesced, do in fact nest correctly.
240 This constructs an ordinary linked list which check_nested_ranges()
241 later turns into the data structure we actually want.
243 We expect the input to come in order of increasing START_PC. This
244 function doesn't attempt to detect the case where two previously
245 added disjoint ranges could be coalesced by a new range; that is
246 what the sorting counteracts. */
249 add_handler (start_pc, end_pc, handler, type)
250 int start_pc, end_pc;
254 struct eh_range *ptr, *prev = NULL, *h;
256 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
258 if (start_pc >= ptr->start_pc
259 && start_pc <= ptr->end_pc
260 && TREE_PURPOSE (ptr->handlers) == type
261 && TREE_VALUE (ptr->handlers) == handler)
263 /* Already found an overlapping range, so coalesce. */
264 ptr->end_pc = MAX (ptr->end_pc, end_pc);
270 h = (struct eh_range *) oballoc (sizeof (struct eh_range));
271 h->start_pc = start_pc;
273 h->first_child = NULL;
275 h->handlers = build_tree_list (type, handler);
276 h->next_sibling = NULL;
279 whole_range.first_child = h;
281 prev->next_sibling = h;
285 /* if there are any handlers for this range, issue start of region */
287 expand_start_java_handler (range)
288 struct eh_range *range ATTRIBUTE_UNUSED;
290 expand_eh_region_start ();
294 prepare_eh_table_type (type)
299 /* The "type" (metch_info) in a (Java) exception table is one:
300 * a) NULL - meaning match any type in a try-finally.
301 * b) a pointer to a (ccmpiled) class (low-order bit 0).
302 * c) a pointer to the Utf8Const name of the class, plus one
303 * (which yields a value with low-order bit 1). */
305 push_obstacks (&permanent_obstack, &permanent_obstack);
306 if (type == NULL_TREE)
307 exp = null_pointer_node;
308 else if (is_compiled_class (type))
309 exp = build_class_ref (type);
312 (PLUS_EXPR, ptr_type_node,
313 build_utf8_ref (build_internal_class_name (type)),
319 /* if there are any handlers for this range, isssue end of range,
320 and then all handler blocks */
322 expand_end_java_handler (range)
323 struct eh_range *range;
325 tree handler = range->handlers;
326 expand_start_all_catch ();
327 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
329 start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler)));
330 /* Push the thrown object on the top of the stack */
331 expand_goto (TREE_VALUE (handler));
333 expand_end_all_catch ();
336 /* Recursive helper routine for maybe_start_handlers. */
339 check_start_handlers (range, pc)
340 struct eh_range *range;
343 if (range != NULL_EH_RANGE && range->start_pc == pc)
345 check_start_handlers (range->outer, pc);
346 expand_start_java_handler (range);
350 struct eh_range *current_range;
352 /* Emit any start-of-try-range start at PC. */
361 current_range = find_handler (pc);
362 check_start_handlers (current_range, pc);
365 /* Emit any end-of-try-range end at PC. */
374 while (current_range != NULL_EH_RANGE && current_range->end_pc <= pc)
376 expand_end_java_handler (current_range);
377 current_range = current_range->outer;
381 /* Emit the handler labels and their code */
388 rtx funcend = gen_label_rtx ();
391 emit_insns (catch_clauses);
392 expand_leftover_cleanups ();
394 emit_label (funcend);
398 /* Resume executing at the statement immediately after the end of an
402 expand_resume_after_catch ()
404 expand_goto (top_label_entry (&caught_return_label_stack));