* toplev.c (rest_of_compilation): Reorganize way reg_scan is called
[official-gcc.git] / gcc / java / except.c
blob614587d33622f2ba7c6f04d7582cdb1896f0e33c
1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2 Copyright (C) 1997, 1998, 1999, 2000, 2002 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 "toplev.h"
39 static void expand_start_java_handler PARAMS ((struct eh_range *));
40 static void expand_end_java_handler PARAMS ((struct eh_range *));
41 static struct eh_range *find_handler_in_range PARAMS ((int, struct eh_range *,
42 struct eh_range *));
43 static void link_handler PARAMS ((struct eh_range *, struct eh_range *));
44 static void check_start_handlers PARAMS ((struct eh_range *, int));
45 static void free_eh_ranges PARAMS ((struct eh_range *range));
47 struct eh_range *current_method_handlers;
49 struct eh_range *current_try_block = NULL;
51 struct eh_range *eh_range_freelist = NULL;
53 /* These variables are used to speed up find_handler. */
55 static int cache_range_start, cache_range_end;
56 static struct eh_range *cache_range;
57 static struct eh_range *cache_next_child;
59 /* A dummy range that represents the entire method. */
61 struct eh_range whole_range;
63 #if defined(DEBUG_JAVA_BINDING_LEVELS)
64 extern int binding_depth;
65 extern int is_class_level;
66 extern int current_pc;
67 extern void indent ();
69 #endif
71 /* Search for the most specific eh_range containing PC.
72 Assume PC is within RANGE.
73 CHILD is a list of children of RANGE such that any
74 previous children have end_pc values that are too low. */
76 static struct eh_range *
77 find_handler_in_range (pc, range, child)
78 int pc;
79 struct eh_range *range;
80 register struct eh_range *child;
82 for (; child != NULL; child = child->next_sibling)
84 if (pc < child->start_pc)
85 break;
86 if (pc < child->end_pc)
87 return find_handler_in_range (pc, child, child->first_child);
89 cache_range = range;
90 cache_range_start = pc;
91 cache_next_child = child;
92 cache_range_end = child == NULL ? range->end_pc : child->start_pc;
93 return range;
96 /* Find the inner-most handler that contains PC. */
98 struct eh_range *
99 find_handler (pc)
100 int pc;
102 struct eh_range *h;
103 if (pc >= cache_range_start)
105 h = cache_range;
106 if (pc < cache_range_end)
107 return h;
108 while (pc >= h->end_pc)
110 cache_next_child = h->next_sibling;
111 h = h->outer;
114 else
116 h = &whole_range;
117 cache_next_child = h->first_child;
119 return find_handler_in_range (pc, h, cache_next_child);
122 /* Recursive helper routine for check_nested_ranges. */
124 static void
125 link_handler (range, outer)
126 struct eh_range *range, *outer;
128 struct eh_range **ptr;
130 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
132 outer->handlers = chainon (outer->handlers, range->handlers);
133 return;
136 /* If the new range completely encloses the `outer' range, then insert it
137 between the outer range and its parent. */
138 if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
140 range->outer = outer->outer;
141 range->next_sibling = NULL;
142 range->first_child = outer;
144 struct eh_range **pr = &(outer->outer->first_child);
145 while (*pr != outer)
146 pr = &(*pr)->next_sibling;
147 *pr = range;
149 outer->outer = range;
150 return;
153 /* Handle overlapping ranges by splitting the new range. */
154 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
156 struct eh_range *h
157 = (struct eh_range *) xmalloc (sizeof (struct eh_range));
158 if (range->start_pc < outer->start_pc)
160 h->start_pc = range->start_pc;
161 h->end_pc = outer->start_pc;
162 range->start_pc = outer->start_pc;
164 else
166 h->start_pc = outer->end_pc;
167 h->end_pc = range->end_pc;
168 range->end_pc = outer->end_pc;
170 h->first_child = NULL;
171 h->outer = NULL;
172 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
173 TREE_VALUE (range->handlers));
174 h->next_sibling = NULL;
175 h->expanded = 0;
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);
180 return;
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;
191 *ptr = range;
192 return;
194 else if (range->start_pc < (*ptr)->end_pc)
196 link_handler (range, *ptr);
197 return;
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. */
208 void
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);
223 /* Free RANGE as well as its children and siblings. */
225 static void
226 free_eh_ranges (range)
227 struct eh_range *range;
229 while (range)
231 struct eh_range *next = range->next_sibling;
232 free_eh_ranges (range->first_child);
233 if (range != &whole_range)
234 free (range);
235 range = next;
239 /* Called to re-initialize the exception machinery for a new method. */
241 void
242 method_init_exceptions ()
244 free_eh_ranges (&whole_range);
245 whole_range.start_pc = 0;
246 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
247 whole_range.outer = NULL;
248 whole_range.first_child = NULL;
249 whole_range.next_sibling = NULL;
250 cache_range_start = 0xFFFFFF;
253 /* Add an exception range. If we already have an exception range
254 which has the same handler and label, and the new range overlaps
255 that one, then we simply extend the existing range. Some bytecode
256 obfuscators generate seemingly nonoverlapping exception ranges
257 which, when coalesced, do in fact nest correctly.
259 This constructs an ordinary linked list which check_nested_ranges()
260 later turns into the data structure we actually want.
262 We expect the input to come in order of increasing START_PC. This
263 function doesn't attempt to detect the case where two previously
264 added disjoint ranges could be coalesced by a new range; that is
265 what the sorting counteracts. */
267 void
268 add_handler (start_pc, end_pc, handler, type)
269 int start_pc, end_pc;
270 tree handler;
271 tree type;
273 struct eh_range *ptr, *prev = NULL, *h;
275 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
277 if (start_pc >= ptr->start_pc
278 && start_pc <= ptr->end_pc
279 && TREE_PURPOSE (ptr->handlers) == type
280 && TREE_VALUE (ptr->handlers) == handler)
282 /* Already found an overlapping range, so coalesce. */
283 ptr->end_pc = MAX (ptr->end_pc, end_pc);
284 return;
286 prev = ptr;
289 h = (struct eh_range *) xmalloc (sizeof (struct eh_range));
290 h->start_pc = start_pc;
291 h->end_pc = end_pc;
292 h->first_child = NULL;
293 h->outer = NULL;
294 h->handlers = build_tree_list (type, handler);
295 h->next_sibling = NULL;
296 h->expanded = 0;
298 if (prev == NULL)
299 whole_range.first_child = h;
300 else
301 prev->next_sibling = h;
305 /* if there are any handlers for this range, issue start of region */
306 static void
307 expand_start_java_handler (range)
308 struct eh_range *range;
310 #if defined(DEBUG_JAVA_BINDING_LEVELS)
311 indent ();
312 fprintf (stderr, "expand start handler pc %d --> %d\n",
313 current_pc, range->end_pc);
314 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
315 range->expanded = 1;
316 expand_eh_region_start ();
319 tree
320 prepare_eh_table_type (type)
321 tree type;
323 tree exp;
325 /* The "type" (metch_info) in a (Java) exception table is one:
326 * a) NULL - meaning match any type in a try-finally.
327 * b) a pointer to a (ccmpiled) class (low-order bit 0).
328 * c) a pointer to the Utf8Const name of the class, plus one
329 * (which yields a value with low-order bit 1). */
331 if (type == NULL_TREE)
332 exp = NULL_TREE;
333 else if (is_compiled_class (type))
334 exp = build_class_ref (type);
335 else
336 exp = fold (build
337 (PLUS_EXPR, ptr_type_node,
338 build_utf8_ref (build_internal_class_name (type)),
339 size_one_node));
340 return exp;
344 /* Build a reference to the jthrowable object being carried in the
345 exception header. */
347 tree
348 build_exception_object_ref (type)
349 tree type;
351 tree obj;
353 /* Java only passes object via pointer and doesn't require adjusting.
354 The java object is immediately before the generic exception header. */
355 obj = build (EXC_PTR_EXPR, build_pointer_type (type));
356 obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
357 TYPE_SIZE_UNIT (TREE_TYPE (obj)));
358 obj = build1 (INDIRECT_REF, type, obj);
360 return obj;
363 /* If there are any handlers for this range, isssue end of range,
364 and then all handler blocks */
365 static void
366 expand_end_java_handler (range)
367 struct eh_range *range;
369 tree handler = range->handlers;
370 force_poplevels (range->start_pc);
371 expand_start_all_catch ();
372 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
374 /* For bytecode we treat exceptions a little unusually. A
375 `finally' clause looks like an ordinary exception handler for
376 Throwable. The reason for this is that the bytecode has
377 already expanded the finally logic, and we would have to do
378 extra (and difficult) work to get this to look like a
379 gcc-style finally clause. */
380 tree type = TREE_PURPOSE (handler);
381 if (type == NULL)
382 type = throwable_type_node;
384 expand_start_catch (type);
385 expand_goto (TREE_VALUE (handler));
386 expand_end_catch ();
388 expand_end_all_catch ();
389 #if defined(DEBUG_JAVA_BINDING_LEVELS)
390 indent ();
391 fprintf (stderr, "expand end handler pc %d <-- %d\n",
392 current_pc, range->start_pc);
393 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
396 /* Recursive helper routine for maybe_start_handlers. */
398 static void
399 check_start_handlers (range, pc)
400 struct eh_range *range;
401 int pc;
403 if (range != NULL_EH_RANGE && range->start_pc == pc)
405 check_start_handlers (range->outer, pc);
406 if (!range->expanded)
407 expand_start_java_handler (range);
412 static struct eh_range *current_range;
414 /* Emit any start-of-try-range starting at start_pc and ending after
415 end_pc. */
417 void
418 maybe_start_try (start_pc, end_pc)
419 int start_pc;
420 int end_pc;
422 struct eh_range *range;
423 if (! doing_eh (1))
424 return;
426 range = find_handler (start_pc);
427 while (range != NULL_EH_RANGE && range->start_pc == start_pc
428 && range->end_pc < end_pc)
429 range = range->outer;
431 current_range = range;
432 check_start_handlers (range, start_pc);
435 /* Emit any end-of-try-range ending at end_pc and starting before
436 start_pc. */
438 void
439 maybe_end_try (start_pc, end_pc)
440 int start_pc;
441 int end_pc;
443 if (! doing_eh (1))
444 return;
446 while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
447 && current_range->start_pc >= start_pc)
449 expand_end_java_handler (current_range);
450 current_range = current_range->outer;