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