Make-lang.in, [...]: Replace "GNU CC" with "GCC" in the copyright header.
[gcc.git] / gcc / java / except.c
1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2 Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003
3 Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
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.
11
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.
16
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.
21
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. */
25
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"
41
42 static void expand_start_java_handler PARAMS ((struct eh_range *));
43 static void expand_end_java_handler PARAMS ((struct eh_range *));
44 static struct eh_range *find_handler_in_range PARAMS ((int, struct eh_range *,
45 struct eh_range *));
46 static void link_handler PARAMS ((struct eh_range *, struct eh_range *));
47 static void check_start_handlers PARAMS ((struct eh_range *, int));
48 static void free_eh_ranges PARAMS ((struct eh_range *range));
49
50 struct eh_range *current_method_handlers;
51
52 struct eh_range *current_try_block = NULL;
53
54 struct eh_range *eh_range_freelist = NULL;
55
56 /* These variables are used to speed up find_handler. */
57
58 static int cache_range_start, cache_range_end;
59 static struct eh_range *cache_range;
60 static struct eh_range *cache_next_child;
61
62 /* A dummy range that represents the entire method. */
63
64 struct eh_range whole_range;
65
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 ();
71
72 #endif
73
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. */
78
79 static struct eh_range *
80 find_handler_in_range (pc, range, child)
81 int pc;
82 struct eh_range *range;
83 register struct eh_range *child;
84 {
85 for (; child != NULL; child = child->next_sibling)
86 {
87 if (pc < child->start_pc)
88 break;
89 if (pc < child->end_pc)
90 return find_handler_in_range (pc, child, child->first_child);
91 }
92 cache_range = range;
93 cache_range_start = pc;
94 cache_next_child = child;
95 cache_range_end = child == NULL ? range->end_pc : child->start_pc;
96 return range;
97 }
98
99 /* Find the inner-most handler that contains PC. */
100
101 struct eh_range *
102 find_handler (pc)
103 int pc;
104 {
105 struct eh_range *h;
106 if (pc >= cache_range_start)
107 {
108 h = cache_range;
109 if (pc < cache_range_end)
110 return h;
111 while (pc >= h->end_pc)
112 {
113 cache_next_child = h->next_sibling;
114 h = h->outer;
115 }
116 }
117 else
118 {
119 h = &whole_range;
120 cache_next_child = h->first_child;
121 }
122 return find_handler_in_range (pc, h, cache_next_child);
123 }
124
125 /* Recursive helper routine for check_nested_ranges. */
126
127 static void
128 link_handler (range, outer)
129 struct eh_range *range, *outer;
130 {
131 struct eh_range **ptr;
132
133 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
134 {
135 outer->handlers = chainon (outer->handlers, range->handlers);
136 return;
137 }
138
139 /* If the new range completely encloses the `outer' range, then insert it
140 between the outer range and its parent. */
141 if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
142 {
143 range->outer = outer->outer;
144 range->next_sibling = NULL;
145 range->first_child = outer;
146 {
147 struct eh_range **pr = &(outer->outer->first_child);
148 while (*pr != outer)
149 pr = &(*pr)->next_sibling;
150 *pr = range;
151 }
152 outer->outer = range;
153 return;
154 }
155
156 /* Handle overlapping ranges by splitting the new range. */
157 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
158 {
159 struct eh_range *h = xmalloc (sizeof (struct eh_range));
160 if (range->start_pc < outer->start_pc)
161 {
162 h->start_pc = range->start_pc;
163 h->end_pc = outer->start_pc;
164 range->start_pc = outer->start_pc;
165 }
166 else
167 {
168 h->start_pc = outer->end_pc;
169 h->end_pc = range->end_pc;
170 range->end_pc = outer->end_pc;
171 }
172 h->first_child = NULL;
173 h->outer = NULL;
174 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
175 TREE_VALUE (range->handlers));
176 h->next_sibling = NULL;
177 h->expanded = 0;
178 /* Restart both from the top to avoid having to make this
179 function smart about reentrancy. */
180 link_handler (h, &whole_range);
181 link_handler (range, &whole_range);
182 return;
183 }
184
185 ptr = &outer->first_child;
186 for (;; ptr = &(*ptr)->next_sibling)
187 {
188 if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
189 {
190 range->next_sibling = *ptr;
191 range->first_child = NULL;
192 range->outer = outer;
193 *ptr = range;
194 return;
195 }
196 else if (range->start_pc < (*ptr)->end_pc)
197 {
198 link_handler (range, *ptr);
199 return;
200 }
201 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
202 }
203 }
204
205 /* The first pass of exception range processing (calling add_handler)
206 constructs a linked list of exception ranges. We turn this into
207 the data structure expected by the rest of the code, and also
208 ensure that exception ranges are properly nested. */
209
210 void
211 handle_nested_ranges ()
212 {
213 struct eh_range *ptr, *next;
214
215 ptr = whole_range.first_child;
216 whole_range.first_child = NULL;
217 for (; ptr; ptr = next)
218 {
219 next = ptr->next_sibling;
220 ptr->next_sibling = NULL;
221 link_handler (ptr, &whole_range);
222 }
223 }
224
225 /* Free RANGE as well as its children and siblings. */
226
227 static void
228 free_eh_ranges (range)
229 struct eh_range *range;
230 {
231 while (range)
232 {
233 struct eh_range *next = range->next_sibling;
234 free_eh_ranges (range->first_child);
235 if (range != &whole_range)
236 free (range);
237 range = next;
238 }
239 }
240
241 /* Called to re-initialize the exception machinery for a new method. */
242
243 void
244 method_init_exceptions ()
245 {
246 free_eh_ranges (&whole_range);
247 whole_range.start_pc = 0;
248 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
249 whole_range.outer = NULL;
250 whole_range.first_child = NULL;
251 whole_range.next_sibling = NULL;
252 cache_range_start = 0xFFFFFF;
253 }
254
255 /* Add an exception range. If we already have an exception range
256 which has the same handler and label, and the new range overlaps
257 that one, then we simply extend the existing range. Some bytecode
258 obfuscators generate seemingly nonoverlapping exception ranges
259 which, when coalesced, do in fact nest correctly.
260
261 This constructs an ordinary linked list which check_nested_ranges()
262 later turns into the data structure we actually want.
263
264 We expect the input to come in order of increasing START_PC. This
265 function doesn't attempt to detect the case where two previously
266 added disjoint ranges could be coalesced by a new range; that is
267 what the sorting counteracts. */
268
269 void
270 add_handler (start_pc, end_pc, handler, type)
271 int start_pc, end_pc;
272 tree handler;
273 tree type;
274 {
275 struct eh_range *ptr, *prev = NULL, *h;
276
277 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
278 {
279 if (start_pc >= ptr->start_pc
280 && start_pc <= ptr->end_pc
281 && TREE_PURPOSE (ptr->handlers) == type
282 && TREE_VALUE (ptr->handlers) == handler)
283 {
284 /* Already found an overlapping range, so coalesce. */
285 ptr->end_pc = MAX (ptr->end_pc, end_pc);
286 return;
287 }
288 prev = ptr;
289 }
290
291 h = xmalloc (sizeof (struct eh_range));
292 h->start_pc = start_pc;
293 h->end_pc = end_pc;
294 h->first_child = NULL;
295 h->outer = NULL;
296 h->handlers = build_tree_list (type, handler);
297 h->next_sibling = NULL;
298 h->expanded = 0;
299
300 if (prev == NULL)
301 whole_range.first_child = h;
302 else
303 prev->next_sibling = h;
304 }
305
306
307 /* if there are any handlers for this range, issue start of region */
308 static void
309 expand_start_java_handler (range)
310 struct eh_range *range;
311 {
312 #if defined(DEBUG_JAVA_BINDING_LEVELS)
313 indent ();
314 fprintf (stderr, "expand start handler pc %d --> %d\n",
315 current_pc, range->end_pc);
316 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
317 range->expanded = 1;
318 expand_eh_region_start ();
319 }
320
321 tree
322 prepare_eh_table_type (type)
323 tree type;
324 {
325 tree exp;
326
327 /* The "type" (metch_info) in a (Java) exception table is one:
328 * a) NULL - meaning match any type in a try-finally.
329 * b) a pointer to a (ccmpiled) class (low-order bit 0).
330 * c) a pointer to the Utf8Const name of the class, plus one
331 * (which yields a value with low-order bit 1). */
332
333 if (type == NULL_TREE)
334 exp = NULL_TREE;
335 else if (is_compiled_class (type))
336 exp = build_class_ref (type);
337 else
338 exp = fold (build
339 (PLUS_EXPR, ptr_type_node,
340 build_utf8_ref (DECL_NAME (TYPE_NAME (type))),
341 size_one_node));
342 return exp;
343 }
344
345
346 /* Build a reference to the jthrowable object being carried in the
347 exception header. */
348
349 tree
350 build_exception_object_ref (type)
351 tree type;
352 {
353 tree obj;
354
355 /* Java only passes object via pointer and doesn't require adjusting.
356 The java object is immediately before the generic exception header. */
357 obj = build (EXC_PTR_EXPR, build_pointer_type (type));
358 obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
359 TYPE_SIZE_UNIT (TREE_TYPE (obj)));
360 obj = build1 (INDIRECT_REF, type, obj);
361
362 return obj;
363 }
364
365 /* If there are any handlers for this range, isssue end of range,
366 and then all handler blocks */
367 static void
368 expand_end_java_handler (range)
369 struct eh_range *range;
370 {
371 tree handler = range->handlers;
372 force_poplevels (range->start_pc);
373 expand_start_all_catch ();
374 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
375 {
376 /* For bytecode we treat exceptions a little unusually. A
377 `finally' clause looks like an ordinary exception handler for
378 Throwable. The reason for this is that the bytecode has
379 already expanded the finally logic, and we would have to do
380 extra (and difficult) work to get this to look like a
381 gcc-style finally clause. */
382 tree type = TREE_PURPOSE (handler);
383 if (type == NULL)
384 type = throwable_type_node;
385
386 expand_start_catch (type);
387 expand_goto (TREE_VALUE (handler));
388 expand_end_catch ();
389 }
390 expand_end_all_catch ();
391 #if defined(DEBUG_JAVA_BINDING_LEVELS)
392 indent ();
393 fprintf (stderr, "expand end handler pc %d <-- %d\n",
394 current_pc, range->start_pc);
395 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
396 }
397
398 /* Recursive helper routine for maybe_start_handlers. */
399
400 static void
401 check_start_handlers (range, pc)
402 struct eh_range *range;
403 int pc;
404 {
405 if (range != NULL_EH_RANGE && range->start_pc == pc)
406 {
407 check_start_handlers (range->outer, pc);
408 if (!range->expanded)
409 expand_start_java_handler (range);
410 }
411 }
412
413
414 static struct eh_range *current_range;
415
416 /* Emit any start-of-try-range starting at start_pc and ending after
417 end_pc. */
418
419 void
420 maybe_start_try (start_pc, end_pc)
421 int start_pc;
422 int end_pc;
423 {
424 struct eh_range *range;
425 if (! doing_eh (1))
426 return;
427
428 range = find_handler (start_pc);
429 while (range != NULL_EH_RANGE && range->start_pc == start_pc
430 && range->end_pc < end_pc)
431 range = range->outer;
432
433 current_range = range;
434 check_start_handlers (range, start_pc);
435 }
436
437 /* Emit any end-of-try-range ending at end_pc and starting before
438 start_pc. */
439
440 void
441 maybe_end_try (start_pc, end_pc)
442 int start_pc;
443 int end_pc;
444 {
445 if (! doing_eh (1))
446 return;
447
448 while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
449 && current_range->start_pc >= start_pc)
450 {
451 expand_end_java_handler (current_range);
452 current_range = current_range->outer;
453 }
454 }