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