* tree.c (walk_tree): Don't recurse into DECL_INITIAL or DECL_SIZE
[official-gcc.git] / gcc / java / except.c
blob3f88093feb1b3a461247246f3874446f6271e066
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)
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 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 *,
43 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)
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 expand_eh_region_start ();
297 tree
298 prepare_eh_table_type (type)
299 tree type;
301 tree exp;
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);
314 else
315 exp = fold (build
316 (PLUS_EXPR, ptr_type_node,
317 build_utf8_ref (build_internal_class_name (type)),
318 size_one_node));
319 pop_obstacks ();
320 return exp;
323 /* if there are any handlers for this range, isssue end of range,
324 and then all handler blocks */
325 static void
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. */
344 static void
345 check_start_handlers (range, pc)
346 struct eh_range *range;
347 int pc;
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. */
360 void
361 maybe_start_try (pc)
362 int pc;
364 if (! doing_eh (1))
365 return;
367 current_range = find_handler (pc);
368 check_start_handlers (current_range, pc);
371 /* Emit any end-of-try-range end at PC. */
373 void
374 maybe_end_try (pc)
375 int pc;
377 if (! doing_eh (1))
378 return;
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 */
389 void
390 emit_handlers ()
392 if (catch_clauses)
394 rtx funcend = gen_label_rtx ();
395 emit_jump (funcend);
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
406 exception region. */
408 void
409 expand_resume_after_catch ()
411 expand_goto (top_label_entry (&caught_return_label_stack));