oops - omitted from previous delta fixing UNIQUE_SECTION
[official-gcc.git] / gcc / java / except.c
blobf44f07270f8a1b822c6b65626b512f593673f60d
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)
9 any later version.
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. */
25 #include "config.h"
26 #include "system.h"
27 #include "tree.h"
28 #include "real.h"
29 #include "rtl.h"
30 #include "java-tree.h"
31 #include "javaop.h"
32 #include "java-opcodes.h"
33 #include "jcf.h"
34 #include "function.h"
35 #include "except.h"
36 #include "java-except.h"
37 #include "eh-common.h"
38 #include "toplev.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 *,
43 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));
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)
72 int pc;
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)
79 break;
80 if (pc < child->end_pc)
81 return find_handler_in_range (pc, child, child->first_child);
83 cache_range = range;
84 cache_range_start = pc;
85 cache_next_child = child;
86 cache_range_end = child == NULL ? range->end_pc : child->start_pc;
87 return range;
90 /* Find the inner-most handler that contains PC. */
92 struct eh_range *
93 find_handler (pc)
94 int pc;
96 struct eh_range *h;
97 if (pc >= cache_range_start)
99 h = cache_range;
100 if (pc < cache_range_end)
101 return h;
102 while (pc >= h->end_pc)
104 cache_next_child = h->next_sibling;
105 h = h->outer;
108 else
110 h = &whole_range;
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. */
118 static void
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);
127 return;
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);
139 while (*pr != outer)
140 pr = &(*pr)->next_sibling;
141 *pr = range;
143 outer->outer = range;
144 return;
147 /* Handle overlapping ranges by splitting the new range. */
148 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
150 struct eh_range *h
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;
158 else
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;
165 h->outer = 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);
173 return;
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;
184 *ptr = range;
185 return;
187 else if (range->start_pc < (*ptr)->end_pc)
189 link_handler (range, *ptr);
190 return;
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. */
201 void
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. */
219 void
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 ();
231 void
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. */
252 void
253 add_handler (start_pc, end_pc, handler, type)
254 int start_pc, end_pc;
255 tree handler;
256 tree type;
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);
269 return;
271 prev = ptr;
274 h = (struct eh_range *) oballoc (sizeof (struct eh_range));
275 h->start_pc = start_pc;
276 h->end_pc = end_pc;
277 h->first_child = NULL;
278 h->outer = NULL;
279 h->handlers = build_tree_list (type, handler);
280 h->next_sibling = NULL;
282 if (prev == NULL)
283 whole_range.first_child = h;
284 else
285 prev->next_sibling = h;
289 /* if there are any handlers for this range, issue start of region */
290 static void
291 expand_start_java_handler (range)
292 struct eh_range *range ATTRIBUTE_UNUSED;
294 push_obstacks (&permanent_obstack, &permanent_obstack);
295 expand_eh_region_start ();
296 pop_obstacks ();
299 tree
300 prepare_eh_table_type (type)
301 tree type;
303 tree exp;
305 /* The "type" (metch_info) in a (Java) exception table is one:
306 * a) NULL - meaning match any type in a try-finally.
307 * b) a pointer to a (ccmpiled) class (low-order bit 0).
308 * c) a pointer to the Utf8Const name of the class, plus one
309 * (which yields a value with low-order bit 1). */
311 push_obstacks (&permanent_obstack, &permanent_obstack);
312 if (type == NULL_TREE)
313 exp = null_pointer_node;
314 else if (is_compiled_class (type))
315 exp = build_class_ref (type);
316 else
317 exp = fold (build
318 (PLUS_EXPR, ptr_type_node,
319 build_utf8_ref (build_internal_class_name (type)),
320 size_one_node));
321 pop_obstacks ();
322 return exp;
325 /* if there are any handlers for this range, isssue end of range,
326 and then all handler blocks */
327 static void
328 expand_end_java_handler (range)
329 struct eh_range *range;
331 tree handler = range->handlers;
332 push_obstacks (&permanent_obstack, &permanent_obstack);
333 expand_start_all_catch ();
334 pop_obstacks ();
335 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
337 start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler)));
338 /* Push the thrown object on the top of the stack */
339 expand_goto (TREE_VALUE (handler));
340 expand_resume_after_catch ();
341 end_catch_handler ();
343 expand_end_all_catch ();
346 /* Recursive helper routine for maybe_start_handlers. */
348 static void
349 check_start_handlers (range, pc)
350 struct eh_range *range;
351 int pc;
353 if (range != NULL_EH_RANGE && range->start_pc == pc)
355 check_start_handlers (range->outer, pc);
356 expand_start_java_handler (range);
360 struct eh_range *current_range;
362 /* Emit any start-of-try-range start at PC. */
364 void
365 maybe_start_try (pc)
366 int pc;
368 if (! doing_eh (1))
369 return;
371 current_range = find_handler (pc);
372 check_start_handlers (current_range, pc);
375 /* Emit any end-of-try-range end at PC. */
377 void
378 maybe_end_try (pc)
379 int pc;
381 if (! doing_eh (1))
382 return;
384 while (current_range != NULL_EH_RANGE && current_range->end_pc <= pc)
386 expand_end_java_handler (current_range);
387 current_range = current_range->outer;
391 /* Emit the handler labels and their code */
393 void
394 emit_handlers ()
396 if (catch_clauses)
398 rtx funcend = gen_label_rtx ();
399 emit_jump (funcend);
401 emit_insns (catch_clauses);
402 catch_clauses = NULL_RTX;
403 expand_leftover_cleanups ();
405 emit_label (funcend);
409 /* Resume executing at the statement immediately after the end of an
410 exception region. */
412 void
413 expand_resume_after_catch ()
415 expand_goto (top_label_entry (&caught_return_label_stack));