* tree.h (SET_ARRAY_OR_VECTOR_CHECK): Rename to SET_OR_ARRAY_CHECK
[official-gcc.git] / gcc / java / except.c
blobc5c7dcf27f4bc3edb379a543b63f74652dddacb3
1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2 Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004
3 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Java and all Java-based marks are trademarks or registered trademarks
23 of Sun Microsystems, Inc. in the United States and other countries.
24 The Free Software Foundation is independent of Sun Microsystems, Inc. */
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "tree.h"
31 #include "real.h"
32 #include "rtl.h"
33 #include "java-tree.h"
34 #include "javaop.h"
35 #include "java-opcodes.h"
36 #include "jcf.h"
37 #include "function.h"
38 #include "except.h"
39 #include "java-except.h"
40 #include "toplev.h"
42 static void expand_start_java_handler (struct eh_range *);
43 static void expand_end_java_handler (struct eh_range *);
44 static struct eh_range *find_handler_in_range (int, struct eh_range *,
45 struct eh_range *);
46 static void link_handler (struct eh_range *, struct eh_range *);
47 static void check_start_handlers (struct eh_range *, int);
48 static void free_eh_ranges (struct eh_range *range);
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)
67 extern int binding_depth;
68 extern int is_class_level;
69 extern int current_pc;
70 extern void indent ();
72 #endif
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 (int pc, struct eh_range *range, 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 (int pc)
101 struct eh_range *h;
102 if (pc >= cache_range_start)
104 h = cache_range;
105 if (pc < cache_range_end)
106 return h;
107 while (pc >= h->end_pc)
109 cache_next_child = h->next_sibling;
110 h = h->outer;
113 else
115 h = &whole_range;
116 cache_next_child = h->first_child;
118 return find_handler_in_range (pc, h, cache_next_child);
121 /* Recursive helper routine for check_nested_ranges. */
123 static void
124 link_handler (struct eh_range *range, struct eh_range *outer)
126 struct eh_range **ptr;
128 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
130 outer->handlers = chainon (outer->handlers, range->handlers);
131 return;
134 /* If the new range completely encloses the `outer' range, then insert it
135 between the outer range and its parent. */
136 if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
138 range->outer = outer->outer;
139 range->next_sibling = NULL;
140 range->first_child = outer;
142 struct eh_range **pr = &(outer->outer->first_child);
143 while (*pr != outer)
144 pr = &(*pr)->next_sibling;
145 *pr = range;
147 outer->outer = range;
148 return;
151 /* Handle overlapping ranges by splitting the new range. */
152 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
154 struct eh_range *h = xmalloc (sizeof (struct eh_range));
155 if (range->start_pc < outer->start_pc)
157 h->start_pc = range->start_pc;
158 h->end_pc = outer->start_pc;
159 range->start_pc = outer->start_pc;
161 else
163 h->start_pc = outer->end_pc;
164 h->end_pc = range->end_pc;
165 range->end_pc = outer->end_pc;
167 h->first_child = NULL;
168 h->outer = NULL;
169 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
170 TREE_VALUE (range->handlers));
171 h->next_sibling = NULL;
172 h->expanded = 0;
173 /* Restart both from the top to avoid having to make this
174 function smart about reentrancy. */
175 link_handler (h, &whole_range);
176 link_handler (range, &whole_range);
177 return;
180 ptr = &outer->first_child;
181 for (;; ptr = &(*ptr)->next_sibling)
183 if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
185 range->next_sibling = *ptr;
186 range->first_child = NULL;
187 range->outer = outer;
188 *ptr = range;
189 return;
191 else if (range->start_pc < (*ptr)->end_pc)
193 link_handler (range, *ptr);
194 return;
196 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
200 /* The first pass of exception range processing (calling add_handler)
201 constructs a linked list of exception ranges. We turn this into
202 the data structure expected by the rest of the code, and also
203 ensure that exception ranges are properly nested. */
205 void
206 handle_nested_ranges (void)
208 struct eh_range *ptr, *next;
210 ptr = whole_range.first_child;
211 whole_range.first_child = NULL;
212 for (; ptr; ptr = next)
214 next = ptr->next_sibling;
215 ptr->next_sibling = NULL;
216 link_handler (ptr, &whole_range);
220 /* Free RANGE as well as its children and siblings. */
222 static void
223 free_eh_ranges (struct eh_range *range)
225 while (range)
227 struct eh_range *next = range->next_sibling;
228 free_eh_ranges (range->first_child);
229 if (range != &whole_range)
230 free (range);
231 range = next;
235 /* Called to re-initialize the exception machinery for a new method. */
237 void
238 method_init_exceptions (void)
240 free_eh_ranges (&whole_range);
241 whole_range.start_pc = 0;
242 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
243 whole_range.outer = NULL;
244 whole_range.first_child = NULL;
245 whole_range.next_sibling = NULL;
246 cache_range_start = 0xFFFFFF;
249 /* Add an exception range. If we already have an exception range
250 which has the same handler and label, and the new range overlaps
251 that one, then we simply extend the existing range. Some bytecode
252 obfuscators generate seemingly nonoverlapping exception ranges
253 which, when coalesced, do in fact nest correctly.
255 This constructs an ordinary linked list which check_nested_ranges()
256 later turns into the data structure we actually want.
258 We expect the input to come in order of increasing START_PC. This
259 function doesn't attempt to detect the case where two previously
260 added disjoint ranges could be coalesced by a new range; that is
261 what the sorting counteracts. */
263 void
264 add_handler (int start_pc, int end_pc, tree handler, tree type)
266 struct eh_range *ptr, *prev = NULL, *h;
268 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
270 if (start_pc >= ptr->start_pc
271 && start_pc <= ptr->end_pc
272 && TREE_PURPOSE (ptr->handlers) == type
273 && TREE_VALUE (ptr->handlers) == handler)
275 /* Already found an overlapping range, so coalesce. */
276 ptr->end_pc = MAX (ptr->end_pc, end_pc);
277 return;
279 prev = ptr;
282 h = xmalloc (sizeof (struct eh_range));
283 h->start_pc = start_pc;
284 h->end_pc = end_pc;
285 h->first_child = NULL;
286 h->outer = NULL;
287 h->handlers = build_tree_list (type, handler);
288 h->next_sibling = NULL;
289 h->expanded = 0;
291 if (prev == NULL)
292 whole_range.first_child = h;
293 else
294 prev->next_sibling = h;
298 /* if there are any handlers for this range, issue start of region */
299 static void
300 expand_start_java_handler (struct eh_range *range)
302 #if defined(DEBUG_JAVA_BINDING_LEVELS)
303 indent ();
304 fprintf (stderr, "expand start handler pc %d --> %d\n",
305 current_pc, range->end_pc);
306 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
307 range->expanded = 1;
308 expand_eh_region_start ();
311 tree
312 prepare_eh_table_type (tree type)
314 tree exp;
315 tree *slot;
316 const char *name;
317 char *buf;
318 tree decl;
319 tree utf8_ref;
321 /* The "type" (match_info) in a (Java) exception table is a pointer to:
322 * a) NULL - meaning match any type in a try-finally.
323 * b) a pointer to a pointer to a class.
324 * c) a pointer to a pointer to a utf8_ref. The pointer is
325 * rewritten to point to the appropriate class. */
327 if (type == NULL_TREE)
328 return NULL_TREE;
330 if (TYPE_TO_RUNTIME_MAP (output_class) == NULL)
331 TYPE_TO_RUNTIME_MAP (output_class) = java_treetreehash_create (10, 1);
333 slot = java_treetreehash_new (TYPE_TO_RUNTIME_MAP (output_class), type);
334 if (*slot != NULL)
335 return TREE_VALUE (*slot);
337 if (is_compiled_class (type) && !flag_indirect_dispatch)
339 name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
340 buf = alloca (strlen (name) + 5);
341 sprintf (buf, "%s_ref", name);
342 decl = build_decl (VAR_DECL, get_identifier (buf), ptr_type_node);
343 TREE_STATIC (decl) = 1;
344 DECL_ARTIFICIAL (decl) = 1;
345 DECL_IGNORED_P (decl) = 1;
346 TREE_READONLY (decl) = 1;
347 TREE_THIS_VOLATILE (decl) = 0;
348 DECL_INITIAL (decl) = build_class_ref (type);
349 layout_decl (decl, 0);
350 pushdecl (decl);
351 exp = build1 (ADDR_EXPR, ptr_type_node, decl);
353 else
355 utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type)));
356 name = IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0)));
357 buf = alloca (strlen (name) + 5);
358 sprintf (buf, "%s_ref", name);
359 decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_ptr_type);
360 TREE_STATIC (decl) = 1;
361 DECL_ARTIFICIAL (decl) = 1;
362 DECL_IGNORED_P (decl) = 1;
363 TREE_READONLY (decl) = 1;
364 TREE_THIS_VOLATILE (decl) = 0;
365 layout_decl (decl, 0);
366 pushdecl (decl);
367 exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl);
368 TYPE_CATCH_CLASSES (output_class) =
369 tree_cons (NULL, make_catch_class_record (exp, utf8_ref),
370 TYPE_CATCH_CLASSES (output_class));
373 *slot = tree_cons (type, exp, NULL_TREE);
375 return exp;
378 static int
379 expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED)
381 struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
382 tree decl = TREE_OPERAND (TREE_VALUE ((tree)ite->value), 0);
383 rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
384 return true;
387 /* For every class in the TYPE_TO_RUNTIME_MAP, expand the
388 corresponding object that is used by the runtime type matcher. */
390 void
391 java_expand_catch_classes (tree this_class)
393 if (TYPE_TO_RUNTIME_MAP (this_class))
394 htab_traverse
395 (TYPE_TO_RUNTIME_MAP (this_class),
396 expand_catch_class, NULL);
399 /* Build a reference to the jthrowable object being carried in the
400 exception header. */
402 tree
403 build_exception_object_ref (tree type)
405 tree obj;
407 /* Java only passes object via pointer and doesn't require adjusting.
408 The java object is immediately before the generic exception header. */
409 obj = build (EXC_PTR_EXPR, build_pointer_type (type));
410 obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
411 TYPE_SIZE_UNIT (TREE_TYPE (obj)));
412 obj = build1 (INDIRECT_REF, type, obj);
414 return obj;
417 /* If there are any handlers for this range, isssue end of range,
418 and then all handler blocks */
419 static void
420 expand_end_java_handler (struct eh_range *range)
422 tree handler = range->handlers;
423 force_poplevels (range->start_pc);
424 expand_start_all_catch ();
425 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
427 /* For bytecode we treat exceptions a little unusually. A
428 `finally' clause looks like an ordinary exception handler for
429 Throwable. The reason for this is that the bytecode has
430 already expanded the finally logic, and we would have to do
431 extra (and difficult) work to get this to look like a
432 gcc-style finally clause. */
433 tree type = TREE_PURPOSE (handler);
434 if (type == NULL)
435 type = throwable_type_node;
437 expand_start_catch (prepare_eh_table_type (type));
438 expand_goto (TREE_VALUE (handler));
439 expand_end_catch ();
441 expand_end_all_catch ();
442 #if defined(DEBUG_JAVA_BINDING_LEVELS)
443 indent ();
444 fprintf (stderr, "expand end handler pc %d <-- %d\n",
445 current_pc, range->start_pc);
446 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
449 /* Recursive helper routine for maybe_start_handlers. */
451 static void
452 check_start_handlers (struct eh_range *range, int pc)
454 if (range != NULL_EH_RANGE && range->start_pc == pc)
456 check_start_handlers (range->outer, pc);
457 if (!range->expanded)
458 expand_start_java_handler (range);
463 static struct eh_range *current_range;
465 /* Emit any start-of-try-range starting at start_pc and ending after
466 end_pc. */
468 void
469 maybe_start_try (int start_pc, int end_pc)
471 struct eh_range *range;
472 if (! doing_eh (1))
473 return;
475 range = find_handler (start_pc);
476 while (range != NULL_EH_RANGE && range->start_pc == start_pc
477 && range->end_pc < end_pc)
478 range = range->outer;
480 current_range = range;
481 check_start_handlers (range, start_pc);
484 /* Emit any end-of-try-range ending at end_pc and starting before
485 start_pc. */
487 void
488 maybe_end_try (int start_pc, int end_pc)
490 if (! doing_eh (1))
491 return;
493 while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
494 && current_range->start_pc >= start_pc)
496 expand_end_java_handler (current_range);
497 current_range = current_range->outer;