1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2 Copyright (C) 1997, 1998, 1999, 2000 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 PARAMS ((struct eh_range *));
41 static void expand_end_java_handler PARAMS ((struct eh_range *));
42 static struct eh_range *find_handler_in_range PARAMS ((int, struct eh_range *,
44 static void link_handler PARAMS ((struct eh_range *, struct eh_range *));
45 static void check_start_handlers PARAMS ((struct eh_range *, int));
46 static void free_eh_ranges PARAMS ((struct eh_range *range));
48 extern struct obstack permanent_obstack;
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)
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)
160 = (struct eh_range *) xmalloc (sizeof (struct eh_range));
161 if (range->start_pc < outer->start_pc)
163 h->start_pc = range->start_pc;
164 h->end_pc = outer->start_pc;
165 range->start_pc = outer->start_pc;
169 h->start_pc = outer->end_pc;
170 h->end_pc = range->end_pc;
171 range->end_pc = outer->end_pc;
173 h->first_child = NULL;
175 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
176 TREE_VALUE (range->handlers));
177 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;
253 java_set_exception_lang_code ();
257 java_set_exception_lang_code ()
259 set_exception_lang_code (EH_LANG_Java);
260 set_exception_version_code (1);
263 /* Add an exception range. If we already have an exception range
264 which has the same handler and label, and the new range overlaps
265 that one, then we simply extend the existing range. Some bytecode
266 obfuscators generate seemingly nonoverlapping exception ranges
267 which, when coalesced, do in fact nest correctly.
269 This constructs an ordinary linked list which check_nested_ranges()
270 later turns into the data structure we actually want.
272 We expect the input to come in order of increasing START_PC. This
273 function doesn't attempt to detect the case where two previously
274 added disjoint ranges could be coalesced by a new range; that is
275 what the sorting counteracts. */
278 add_handler (start_pc, end_pc, handler, type)
279 int start_pc, end_pc;
283 struct eh_range *ptr, *prev = NULL, *h;
285 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
287 if (start_pc >= ptr->start_pc
288 && start_pc <= ptr->end_pc
289 && TREE_PURPOSE (ptr->handlers) == type
290 && TREE_VALUE (ptr->handlers) == handler)
292 /* Already found an overlapping range, so coalesce. */
293 ptr->end_pc = MAX (ptr->end_pc, end_pc);
299 h = (struct eh_range *) xmalloc (sizeof (struct eh_range));
300 h->start_pc = start_pc;
302 h->first_child = NULL;
304 h->handlers = build_tree_list (type, handler);
305 h->next_sibling = NULL;
309 whole_range.first_child = h;
311 prev->next_sibling = h;
315 /* if there are any handlers for this range, issue start of region */
317 expand_start_java_handler (range)
318 struct eh_range *range;
320 #if defined(DEBUG_JAVA_BINDING_LEVELS)
322 fprintf (stderr, "expand start handler pc %d --> %d\n",
323 current_pc, range->end_pc);
324 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
326 expand_eh_region_start ();
330 prepare_eh_table_type (type)
335 /* The "type" (metch_info) in a (Java) exception table is one:
336 * a) NULL - meaning match any type in a try-finally.
337 * b) a pointer to a (ccmpiled) class (low-order bit 0).
338 * c) a pointer to the Utf8Const name of the class, plus one
339 * (which yields a value with low-order bit 1). */
341 if (type == NULL_TREE)
342 exp = CATCH_ALL_TYPE;
343 else if (is_compiled_class (type))
344 exp = build_class_ref (type);
347 (PLUS_EXPR, ptr_type_node,
348 build_utf8_ref (build_internal_class_name (type)),
353 /* if there are any handlers for this range, isssue end of range,
354 and then all handler blocks */
356 expand_end_java_handler (range)
357 struct eh_range *range;
359 tree handler = range->handlers;
360 force_poplevels (range->start_pc);
361 expand_start_all_catch ();
362 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
364 start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler)));
365 /* Push the thrown object on the top of the stack */
366 expand_goto (TREE_VALUE (handler));
367 expand_resume_after_catch ();
368 end_catch_handler ();
370 expand_end_all_catch ();
371 #if defined(DEBUG_JAVA_BINDING_LEVELS)
373 fprintf (stderr, "expand end handler pc %d <-- %d\n",
374 current_pc, range->start_pc);
375 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
378 /* Recursive helper routine for maybe_start_handlers. */
381 check_start_handlers (range, pc)
382 struct eh_range *range;
385 if (range != NULL_EH_RANGE && range->start_pc == pc)
387 check_start_handlers (range->outer, pc);
388 if (!range->expanded)
389 expand_start_java_handler (range);
394 static struct eh_range *current_range;
396 /* Emit any start-of-try-range starting at start_pc and ending after
400 maybe_start_try (start_pc, end_pc)
404 struct eh_range *range;
408 range = find_handler (start_pc);
409 while (range != NULL_EH_RANGE && range->start_pc == start_pc
410 && range->end_pc < end_pc)
411 range = range->outer;
413 current_range = range;
414 check_start_handlers (range, start_pc);
417 /* Emit any end-of-try-range ending at end_pc and starting before
421 maybe_end_try (start_pc, end_pc)
428 while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
429 && current_range->start_pc >= start_pc)
431 expand_end_java_handler (current_range);
432 current_range = current_range->outer;
436 /* Emit the handler labels and their code */
443 rtx funcend = gen_label_rtx ();
446 emit_insns (catch_clauses);
447 catch_clauses = catch_clauses_last = NULL_RTX;
448 expand_leftover_cleanups ();
450 emit_label (funcend);
454 /* Resume executing at the statement immediately after the end of an
458 expand_resume_after_catch ()
460 expand_goto (top_label_entry (&caught_return_label_stack));