]>
Commit | Line | Data |
---|---|---|
e04a16fb | 1 | /* Handle exceptions for GNU compiler for the Java(TM) language. |
3852e8af | 2 | Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc. |
e04a16fb AG |
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 | ||
e04a16fb | 25 | #include "config.h" |
1f43f4b4 | 26 | #include "system.h" |
e04a16fb AG |
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" | |
b384405b | 34 | #include "function.h" |
e04a16fb AG |
35 | #include "except.h" |
36 | #include "java-except.h" | |
37 | #include "eh-common.h" | |
1f43f4b4 | 38 | #include "toplev.h" |
e04a16fb | 39 | |
df32d2ce KG |
40 | static void expand_start_java_handler PARAMS ((struct eh_range *)); |
41 | static void expand_end_java_handler PARAMS ((struct eh_range *)); | |
42 | static struct eh_range *find_handler_in_range PARAMS ((int, struct eh_range *, | |
c8e7d2e6 | 43 | struct eh_range *)); |
df32d2ce | 44 | static void link_handler PARAMS ((struct eh_range *, struct eh_range *)); |
ae0a06c5 | 45 | static void check_start_handlers PARAMS ((struct eh_range *, int)); |
1f8f4a0b | 46 | static void free_eh_ranges PARAMS ((struct eh_range *range)); |
4bcde32e | 47 | |
e04a16fb AG |
48 | extern struct obstack permanent_obstack; |
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 | ||
e8b22dd1 AH |
66 | #if defined(DEBUG_JAVA_BINDING_LEVELS) |
67 | int binding_depth; | |
68 | int is_class_level; | |
69 | int current_pc; | |
70 | extern void indent (); | |
71 | ||
72 | #endif | |
73 | ||
e04a16fb AG |
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; | |
44d7502b | 89 | if (pc < child->end_pc) |
e04a16fb AG |
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 | ||
5a9e5c6f | 125 | /* Recursive helper routine for check_nested_ranges. */ |
e04a16fb | 126 | |
5a9e5c6f TT |
127 | static void |
128 | link_handler (range, outer) | |
129 | struct eh_range *range, *outer; | |
e04a16fb AG |
130 | { |
131 | struct eh_range **ptr; | |
5a9e5c6f TT |
132 | |
133 | if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc) | |
134 | { | |
99fd3aa5 | 135 | outer->handlers = chainon (outer->handlers, range->handlers); |
5a9e5c6f TT |
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; | |
44d7502b AH |
146 | { |
147 | struct eh_range **pr = &(outer->outer->first_child); | |
148 | while (*pr != outer) | |
149 | pr = &(*pr)->next_sibling; | |
150 | *pr = range; | |
151 | } | |
5a9e5c6f TT |
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) | |
e04a16fb | 158 | { |
5a9e5c6f | 159 | struct eh_range *h |
1f8f4a0b | 160 | = (struct eh_range *) xmalloc (sizeof (struct eh_range)); |
5a9e5c6f TT |
161 | if (range->start_pc < outer->start_pc) |
162 | { | |
163 | h->start_pc = range->start_pc; | |
164 | h->end_pc = outer->start_pc; | |
165 | range->start_pc = outer->start_pc; | |
166 | } | |
167 | else | |
168 | { | |
169 | h->start_pc = outer->end_pc; | |
170 | h->end_pc = range->end_pc; | |
171 | range->end_pc = outer->end_pc; | |
172 | } | |
173 | h->first_child = NULL; | |
174 | h->outer = NULL; | |
175 | h->handlers = build_tree_list (TREE_PURPOSE (range->handlers), | |
176 | TREE_VALUE (range->handlers)); | |
177 | h->next_sibling = NULL; | |
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; | |
e04a16fb | 183 | } |
5a9e5c6f | 184 | |
e04a16fb AG |
185 | ptr = &outer->first_child; |
186 | for (;; ptr = &(*ptr)->next_sibling) | |
187 | { | |
5a9e5c6f | 188 | if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc) |
e04a16fb | 189 | { |
5a9e5c6f TT |
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; | |
e04a16fb | 200 | } |
e04a16fb AG |
201 | /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */ |
202 | } | |
203 | } | |
204 | ||
5a9e5c6f TT |
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 | ||
1f8f4a0b MM |
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); | |
1a2ebe6d APB |
235 | if (range != &whole_range) |
236 | free (range); | |
1f8f4a0b MM |
237 | range = next; |
238 | } | |
239 | } | |
5a9e5c6f | 240 | |
e04a16fb AG |
241 | /* Called to re-initialize the exception machinery for a new method. */ |
242 | ||
243 | void | |
244 | method_init_exceptions () | |
245 | { | |
1f8f4a0b | 246 | free_eh_ranges (&whole_range); |
e04a16fb AG |
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; | |
e4de5a10 PB |
253 | java_set_exception_lang_code (); |
254 | } | |
255 | ||
256 | void | |
257 | java_set_exception_lang_code () | |
258 | { | |
e04a16fb AG |
259 | set_exception_lang_code (EH_LANG_Java); |
260 | set_exception_version_code (1); | |
261 | } | |
262 | ||
5a9e5c6f TT |
263 | /* Add an exception range. If we already have an exception range |
264 | which has the same handler and label, and the new range overlaps | |
265 | that one, then we simply extend the existing range. Some bytecode | |
266 | obfuscators generate seemingly nonoverlapping exception ranges | |
267 | which, when coalesced, do in fact nest correctly. | |
268 | ||
269 | This constructs an ordinary linked list which check_nested_ranges() | |
270 | later turns into the data structure we actually want. | |
271 | ||
272 | We expect the input to come in order of increasing START_PC. This | |
273 | function doesn't attempt to detect the case where two previously | |
274 | added disjoint ranges could be coalesced by a new range; that is | |
275 | what the sorting counteracts. */ | |
276 | ||
277 | void | |
e04a16fb AG |
278 | add_handler (start_pc, end_pc, handler, type) |
279 | int start_pc, end_pc; | |
280 | tree handler; | |
281 | tree type; | |
282 | { | |
5a9e5c6f TT |
283 | struct eh_range *ptr, *prev = NULL, *h; |
284 | ||
285 | for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling) | |
286 | { | |
287 | if (start_pc >= ptr->start_pc | |
288 | && start_pc <= ptr->end_pc | |
289 | && TREE_PURPOSE (ptr->handlers) == type | |
290 | && TREE_VALUE (ptr->handlers) == handler) | |
291 | { | |
292 | /* Already found an overlapping range, so coalesce. */ | |
293 | ptr->end_pc = MAX (ptr->end_pc, end_pc); | |
294 | return; | |
295 | } | |
296 | prev = ptr; | |
297 | } | |
298 | ||
1f8f4a0b | 299 | h = (struct eh_range *) xmalloc (sizeof (struct eh_range)); |
5a9e5c6f TT |
300 | h->start_pc = start_pc; |
301 | h->end_pc = end_pc; | |
302 | h->first_child = NULL; | |
303 | h->outer = NULL; | |
304 | h->handlers = build_tree_list (type, handler); | |
305 | h->next_sibling = NULL; | |
e8b22dd1 | 306 | h->expanded = 0; |
5a9e5c6f TT |
307 | |
308 | if (prev == NULL) | |
309 | whole_range.first_child = h; | |
310 | else | |
311 | prev->next_sibling = h; | |
e04a16fb AG |
312 | } |
313 | ||
314 | ||
315 | /* if there are any handlers for this range, issue start of region */ | |
4bcde32e | 316 | static void |
e04a16fb | 317 | expand_start_java_handler (range) |
e8b22dd1 | 318 | struct eh_range *range; |
e04a16fb | 319 | { |
e8b22dd1 AH |
320 | #if defined(DEBUG_JAVA_BINDING_LEVELS) |
321 | indent (); | |
322 | fprintf (stderr, "expand start handler pc %d --> %d\n", | |
323 | current_pc, range->end_pc); | |
324 | #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */ | |
325 | range->expanded = 1; | |
e04a16fb AG |
326 | expand_eh_region_start (); |
327 | } | |
328 | ||
e4de5a10 PB |
329 | tree |
330 | prepare_eh_table_type (type) | |
331 | tree type; | |
332 | { | |
333 | tree exp; | |
334 | ||
335 | /* The "type" (metch_info) in a (Java) exception table is one: | |
336 | * a) NULL - meaning match any type in a try-finally. | |
337 | * b) a pointer to a (ccmpiled) class (low-order bit 0). | |
338 | * c) a pointer to the Utf8Const name of the class, plus one | |
339 | * (which yields a value with low-order bit 1). */ | |
340 | ||
e4de5a10 | 341 | if (type == NULL_TREE) |
9a7ab4b3 | 342 | exp = CATCH_ALL_TYPE; |
e4de5a10 PB |
343 | else if (is_compiled_class (type)) |
344 | exp = build_class_ref (type); | |
345 | else | |
346 | exp = fold (build | |
347 | (PLUS_EXPR, ptr_type_node, | |
348 | build_utf8_ref (build_internal_class_name (type)), | |
349 | size_one_node)); | |
e4de5a10 PB |
350 | return exp; |
351 | } | |
352 | ||
e04a16fb AG |
353 | /* if there are any handlers for this range, isssue end of range, |
354 | and then all handler blocks */ | |
4bcde32e | 355 | static void |
e04a16fb AG |
356 | expand_end_java_handler (range) |
357 | struct eh_range *range; | |
e8b22dd1 | 358 | { |
e04a16fb | 359 | tree handler = range->handlers; |
e8b22dd1 | 360 | force_poplevels (range->start_pc); |
e04a16fb AG |
361 | expand_start_all_catch (); |
362 | for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler)) | |
363 | { | |
e4de5a10 PB |
364 | start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler))); |
365 | /* Push the thrown object on the top of the stack */ | |
e04a16fb | 366 | expand_goto (TREE_VALUE (handler)); |
0974e9fe APB |
367 | expand_resume_after_catch (); |
368 | end_catch_handler (); | |
e04a16fb AG |
369 | } |
370 | expand_end_all_catch (); | |
e8b22dd1 AH |
371 | #if defined(DEBUG_JAVA_BINDING_LEVELS) |
372 | indent (); | |
373 | fprintf (stderr, "expand end handler pc %d <-- %d\n", | |
374 | current_pc, range->start_pc); | |
375 | #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */ | |
e04a16fb AG |
376 | } |
377 | ||
378 | /* Recursive helper routine for maybe_start_handlers. */ | |
379 | ||
380 | static void | |
381 | check_start_handlers (range, pc) | |
382 | struct eh_range *range; | |
383 | int pc; | |
384 | { | |
385 | if (range != NULL_EH_RANGE && range->start_pc == pc) | |
386 | { | |
387 | check_start_handlers (range->outer, pc); | |
e8b22dd1 AH |
388 | if (!range->expanded) |
389 | expand_start_java_handler (range); | |
e04a16fb AG |
390 | } |
391 | } | |
392 | ||
e04a16fb | 393 | |
e8b22dd1 AH |
394 | static struct eh_range *current_range; |
395 | ||
396 | /* Emit any start-of-try-range starting at start_pc and ending after | |
397 | end_pc. */ | |
e04a16fb AG |
398 | |
399 | void | |
e8b22dd1 AH |
400 | maybe_start_try (start_pc, end_pc) |
401 | int start_pc; | |
402 | int end_pc; | |
e04a16fb | 403 | { |
e8b22dd1 | 404 | struct eh_range *range; |
e04a16fb AG |
405 | if (! doing_eh (1)) |
406 | return; | |
407 | ||
e8b22dd1 AH |
408 | range = find_handler (start_pc); |
409 | while (range != NULL_EH_RANGE && range->start_pc == start_pc | |
410 | && range->end_pc < end_pc) | |
411 | range = range->outer; | |
412 | ||
413 | current_range = range; | |
ef86eabb | 414 | check_start_handlers (range, start_pc); |
e04a16fb AG |
415 | } |
416 | ||
e8b22dd1 AH |
417 | /* Emit any end-of-try-range ending at end_pc and starting before |
418 | start_pc. */ | |
e04a16fb AG |
419 | |
420 | void | |
e8b22dd1 AH |
421 | maybe_end_try (start_pc, end_pc) |
422 | int start_pc; | |
423 | int end_pc; | |
e04a16fb AG |
424 | { |
425 | if (! doing_eh (1)) | |
426 | return; | |
427 | ||
e8b22dd1 AH |
428 | while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc |
429 | && current_range->start_pc >= start_pc) | |
e04a16fb AG |
430 | { |
431 | expand_end_java_handler (current_range); | |
432 | current_range = current_range->outer; | |
433 | } | |
434 | } | |
435 | ||
436 | /* Emit the handler labels and their code */ | |
437 | ||
438 | void | |
439 | emit_handlers () | |
440 | { | |
441 | if (catch_clauses) | |
442 | { | |
443 | rtx funcend = gen_label_rtx (); | |
444 | emit_jump (funcend); | |
445 | ||
446 | emit_insns (catch_clauses); | |
c14f7160 | 447 | catch_clauses = catch_clauses_last = NULL_RTX; |
e04a16fb AG |
448 | expand_leftover_cleanups (); |
449 | ||
450 | emit_label (funcend); | |
451 | } | |
452 | } | |
1b18747f AH |
453 | |
454 | /* Resume executing at the statement immediately after the end of an | |
455 | exception region. */ | |
456 | ||
457 | void | |
458 | expand_resume_after_catch () | |
459 | { | |
460 | expand_goto (top_label_entry (&caught_return_label_stack)); | |
461 | } |