1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2 Copyright (C) 1997, 98-99, 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 *));
46 extern struct obstack permanent_obstack;
48 struct eh_range *current_method_handlers;
50 struct eh_range *current_try_block = NULL;
52 struct eh_range *eh_range_freelist = NULL;
54 /* These variables are used to speed up find_handler. */
56 static int cache_range_start, cache_range_end;
57 static struct eh_range *cache_range;
58 static struct eh_range *cache_next_child;
60 /* A dummy range that represents the entire method. */
62 struct eh_range whole_range;
64 #if defined(DEBUG_JAVA_BINDING_LEVELS)
68 extern void indent ();
72 /* Search for the most specific eh_range containing PC.
73 Assume PC is within RANGE.
74 CHILD is a list of children of RANGE such that any
75 previous children have end_pc values that are too low. */
77 static struct eh_range *
78 find_handler_in_range (pc, range, child)
80 struct eh_range *range;
81 register struct eh_range *child;
83 for (; child != NULL; child = child->next_sibling)
85 if (pc < child->start_pc)
87 if (pc < child->end_pc)
88 return find_handler_in_range (pc, child, child->first_child);
91 cache_range_start = pc;
92 cache_next_child = child;
93 cache_range_end = child == NULL ? range->end_pc : child->start_pc;
97 /* Find the inner-most handler that contains PC. */
104 if (pc >= cache_range_start)
107 if (pc < cache_range_end)
109 while (pc >= h->end_pc)
111 cache_next_child = h->next_sibling;
118 cache_next_child = h->first_child;
120 return find_handler_in_range (pc, h, cache_next_child);
123 /* Recursive helper routine for check_nested_ranges. */
126 link_handler (range, outer)
127 struct eh_range *range, *outer;
129 struct eh_range **ptr;
131 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
133 outer->handlers = chainon (outer->handlers, range->handlers);
137 /* If the new range completely encloses the `outer' range, then insert it
138 between the outer range and its parent. */
139 if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
141 range->outer = outer->outer;
142 range->next_sibling = NULL;
143 range->first_child = outer;
145 struct eh_range **pr = &(outer->outer->first_child);
147 pr = &(*pr)->next_sibling;
150 outer->outer = range;
154 /* Handle overlapping ranges by splitting the new range. */
155 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
158 = (struct eh_range *) oballoc (sizeof (struct eh_range));
159 if (range->start_pc < outer->start_pc)
161 h->start_pc = range->start_pc;
162 h->end_pc = outer->start_pc;
163 range->start_pc = outer->start_pc;
167 h->start_pc = outer->end_pc;
168 h->end_pc = range->end_pc;
169 range->end_pc = outer->end_pc;
171 h->first_child = NULL;
173 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
174 TREE_VALUE (range->handlers));
175 h->next_sibling = NULL;
176 /* Restart both from the top to avoid having to make this
177 function smart about reentrancy. */
178 link_handler (h, &whole_range);
179 link_handler (range, &whole_range);
183 ptr = &outer->first_child;
184 for (;; ptr = &(*ptr)->next_sibling)
186 if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
188 range->next_sibling = *ptr;
189 range->first_child = NULL;
190 range->outer = outer;
194 else if (range->start_pc < (*ptr)->end_pc)
196 link_handler (range, *ptr);
199 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
203 /* The first pass of exception range processing (calling add_handler)
204 constructs a linked list of exception ranges. We turn this into
205 the data structure expected by the rest of the code, and also
206 ensure that exception ranges are properly nested. */
209 handle_nested_ranges ()
211 struct eh_range *ptr, *next;
213 ptr = whole_range.first_child;
214 whole_range.first_child = NULL;
215 for (; ptr; ptr = next)
217 next = ptr->next_sibling;
218 ptr->next_sibling = NULL;
219 link_handler (ptr, &whole_range);
224 /* Called to re-initialize the exception machinery for a new method. */
227 method_init_exceptions ()
229 whole_range.start_pc = 0;
230 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
231 whole_range.outer = NULL;
232 whole_range.first_child = NULL;
233 whole_range.next_sibling = NULL;
234 cache_range_start = 0xFFFFFF;
235 java_set_exception_lang_code ();
239 java_set_exception_lang_code ()
241 set_exception_lang_code (EH_LANG_Java);
242 set_exception_version_code (1);
245 /* Add an exception range. If we already have an exception range
246 which has the same handler and label, and the new range overlaps
247 that one, then we simply extend the existing range. Some bytecode
248 obfuscators generate seemingly nonoverlapping exception ranges
249 which, when coalesced, do in fact nest correctly.
251 This constructs an ordinary linked list which check_nested_ranges()
252 later turns into the data structure we actually want.
254 We expect the input to come in order of increasing START_PC. This
255 function doesn't attempt to detect the case where two previously
256 added disjoint ranges could be coalesced by a new range; that is
257 what the sorting counteracts. */
260 add_handler (start_pc, end_pc, handler, type)
261 int start_pc, end_pc;
265 struct eh_range *ptr, *prev = NULL, *h;
267 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
269 if (start_pc >= ptr->start_pc
270 && start_pc <= ptr->end_pc
271 && TREE_PURPOSE (ptr->handlers) == type
272 && TREE_VALUE (ptr->handlers) == handler)
274 /* Already found an overlapping range, so coalesce. */
275 ptr->end_pc = MAX (ptr->end_pc, end_pc);
281 h = (struct eh_range *) oballoc (sizeof (struct eh_range));
282 h->start_pc = start_pc;
284 h->first_child = NULL;
286 h->handlers = build_tree_list (type, handler);
287 h->next_sibling = NULL;
291 whole_range.first_child = h;
293 prev->next_sibling = h;
297 /* if there are any handlers for this range, issue start of region */
299 expand_start_java_handler (range)
300 struct eh_range *range;
302 #if defined(DEBUG_JAVA_BINDING_LEVELS)
304 fprintf (stderr, "expand start handler pc %d --> %d\n",
305 current_pc, range->end_pc);
306 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
308 push_obstacks (&permanent_obstack, &permanent_obstack);
309 expand_eh_region_start ();
314 prepare_eh_table_type (type)
319 /* The "type" (metch_info) in a (Java) exception table is one:
320 * a) NULL - meaning match any type in a try-finally.
321 * b) a pointer to a (ccmpiled) class (low-order bit 0).
322 * c) a pointer to the Utf8Const name of the class, plus one
323 * (which yields a value with low-order bit 1). */
325 push_obstacks (&permanent_obstack, &permanent_obstack);
326 if (type == NULL_TREE)
327 exp = null_pointer_node;
328 else if (is_compiled_class (type))
329 exp = build_class_ref (type);
332 (PLUS_EXPR, ptr_type_node,
333 build_utf8_ref (build_internal_class_name (type)),
339 /* if there are any handlers for this range, isssue end of range,
340 and then all handler blocks */
342 expand_end_java_handler (range)
343 struct eh_range *range;
345 tree handler = range->handlers;
346 force_poplevels (range->start_pc);
347 push_obstacks (&permanent_obstack, &permanent_obstack);
348 expand_start_all_catch ();
350 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
352 start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler)));
353 /* Push the thrown object on the top of the stack */
354 expand_goto (TREE_VALUE (handler));
355 expand_resume_after_catch ();
356 end_catch_handler ();
358 expand_end_all_catch ();
359 #if defined(DEBUG_JAVA_BINDING_LEVELS)
361 fprintf (stderr, "expand end handler pc %d <-- %d\n",
362 current_pc, range->start_pc);
363 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
366 /* Recursive helper routine for maybe_start_handlers. */
369 check_start_handlers (range, pc)
370 struct eh_range *range;
373 if (range != NULL_EH_RANGE && range->start_pc == pc)
375 check_start_handlers (range->outer, pc);
376 if (!range->expanded)
377 expand_start_java_handler (range);
382 static struct eh_range *current_range;
384 /* Emit any start-of-try-range starting at start_pc and ending after
388 maybe_start_try (start_pc, end_pc)
392 struct eh_range *range;
396 range = find_handler (start_pc);
397 while (range != NULL_EH_RANGE && range->start_pc == start_pc
398 && range->end_pc < end_pc)
399 range = range->outer;
401 current_range = range;
402 check_start_handlers (range, start_pc, end_pc);
405 /* Emit any end-of-try-range ending at end_pc and starting before
409 maybe_end_try (start_pc, end_pc)
416 while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
417 && current_range->start_pc >= start_pc)
419 expand_end_java_handler (current_range);
420 current_range = current_range->outer;
424 /* Emit the handler labels and their code */
431 rtx funcend = gen_label_rtx ();
434 emit_insns (catch_clauses);
435 catch_clauses = NULL_RTX;
436 expand_leftover_cleanups ();
438 emit_label (funcend);
442 /* Resume executing at the statement immediately after the end of an
446 expand_resume_after_catch ()
448 expand_goto (top_label_entry (&caught_return_label_stack));