]>
Commit | Line | Data |
---|---|---|
377029eb | 1 | /* Handle exceptions for GNU compiler for the Java(TM) language. |
757f6c6c | 2 | Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004 |
7d82ed5e | 3 | Free Software Foundation, Inc. |
377029eb | 4 | |
7d82ed5e | 5 | This file is part of GCC. |
377029eb | 6 | |
7d82ed5e | 7 | GCC is free software; you can redistribute it and/or modify |
377029eb | 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 | ||
7d82ed5e | 12 | GCC is distributed in the hope that it will be useful, |
377029eb | 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 | |
7d82ed5e | 18 | along with GCC; see the file COPYING. If not, write to |
377029eb | 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 | ||
377029eb | 26 | #include "config.h" |
014e6e0c | 27 | #include "system.h" |
805e22b2 | 28 | #include "coretypes.h" |
29 | #include "tm.h" | |
377029eb | 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" | |
304c5bf1 | 37 | #include "function.h" |
377029eb | 38 | #include "except.h" |
39 | #include "java-except.h" | |
014e6e0c | 40 | #include "toplev.h" |
377029eb | 41 | |
6852521a | 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); | |
003019ba | 49 | |
377029eb | 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 | ||
c1b6623d | 66 | #if defined(DEBUG_JAVA_BINDING_LEVELS) |
678d3f71 | 67 | extern int binding_depth; |
68 | extern int is_class_level; | |
69 | extern int current_pc; | |
c1b6623d | 70 | extern void indent (); |
71 | ||
72 | #endif | |
73 | ||
377029eb | 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 * | |
2883a3ed | 80 | find_handler_in_range (int pc, struct eh_range *range, struct eh_range *child) |
377029eb | 81 | { |
82 | for (; child != NULL; child = child->next_sibling) | |
83 | { | |
84 | if (pc < child->start_pc) | |
85 | break; | |
e986fd23 | 86 | if (pc < child->end_pc) |
377029eb | 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 * | |
2883a3ed | 99 | find_handler (int pc) |
377029eb | 100 | { |
101 | struct eh_range *h; | |
102 | if (pc >= cache_range_start) | |
103 | { | |
104 | h = cache_range; | |
105 | if (pc < cache_range_end) | |
106 | return h; | |
107 | while (pc >= h->end_pc) | |
108 | { | |
109 | cache_next_child = h->next_sibling; | |
110 | h = h->outer; | |
111 | } | |
112 | } | |
113 | else | |
114 | { | |
115 | h = &whole_range; | |
116 | cache_next_child = h->first_child; | |
117 | } | |
118 | return find_handler_in_range (pc, h, cache_next_child); | |
119 | } | |
120 | ||
addd693c | 121 | /* Recursive helper routine for check_nested_ranges. */ |
377029eb | 122 | |
addd693c | 123 | static void |
2883a3ed | 124 | link_handler (struct eh_range *range, struct eh_range *outer) |
377029eb | 125 | { |
126 | struct eh_range **ptr; | |
addd693c | 127 | |
128 | if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc) | |
129 | { | |
9a984332 | 130 | outer->handlers = chainon (outer->handlers, range->handlers); |
addd693c | 131 | return; |
132 | } | |
133 | ||
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) | |
137 | { | |
138 | range->outer = outer->outer; | |
139 | range->next_sibling = NULL; | |
140 | range->first_child = outer; | |
e986fd23 | 141 | { |
142 | struct eh_range **pr = &(outer->outer->first_child); | |
143 | while (*pr != outer) | |
144 | pr = &(*pr)->next_sibling; | |
145 | *pr = range; | |
146 | } | |
addd693c | 147 | outer->outer = range; |
148 | return; | |
149 | } | |
150 | ||
151 | /* Handle overlapping ranges by splitting the new range. */ | |
152 | if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc) | |
377029eb | 153 | { |
0cc50a21 | 154 | struct eh_range *h = xmalloc (sizeof (struct eh_range)); |
addd693c | 155 | if (range->start_pc < outer->start_pc) |
156 | { | |
157 | h->start_pc = range->start_pc; | |
158 | h->end_pc = outer->start_pc; | |
159 | range->start_pc = outer->start_pc; | |
160 | } | |
161 | else | |
162 | { | |
163 | h->start_pc = outer->end_pc; | |
164 | h->end_pc = range->end_pc; | |
165 | range->end_pc = outer->end_pc; | |
166 | } | |
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; | |
678d3f71 | 172 | h->expanded = 0; |
4ee9c684 | 173 | h->stmt = NULL; |
addd693c | 174 | /* Restart both from the top to avoid having to make this |
175 | function smart about reentrancy. */ | |
176 | link_handler (h, &whole_range); | |
177 | link_handler (range, &whole_range); | |
178 | return; | |
377029eb | 179 | } |
addd693c | 180 | |
377029eb | 181 | ptr = &outer->first_child; |
182 | for (;; ptr = &(*ptr)->next_sibling) | |
183 | { | |
addd693c | 184 | if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc) |
377029eb | 185 | { |
addd693c | 186 | range->next_sibling = *ptr; |
187 | range->first_child = NULL; | |
188 | range->outer = outer; | |
189 | *ptr = range; | |
190 | return; | |
191 | } | |
192 | else if (range->start_pc < (*ptr)->end_pc) | |
193 | { | |
194 | link_handler (range, *ptr); | |
195 | return; | |
377029eb | 196 | } |
377029eb | 197 | /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */ |
198 | } | |
199 | } | |
200 | ||
addd693c | 201 | /* The first pass of exception range processing (calling add_handler) |
202 | constructs a linked list of exception ranges. We turn this into | |
203 | the data structure expected by the rest of the code, and also | |
204 | ensure that exception ranges are properly nested. */ | |
205 | ||
206 | void | |
2883a3ed | 207 | handle_nested_ranges (void) |
addd693c | 208 | { |
209 | struct eh_range *ptr, *next; | |
210 | ||
211 | ptr = whole_range.first_child; | |
212 | whole_range.first_child = NULL; | |
213 | for (; ptr; ptr = next) | |
214 | { | |
215 | next = ptr->next_sibling; | |
216 | ptr->next_sibling = NULL; | |
217 | link_handler (ptr, &whole_range); | |
218 | } | |
219 | } | |
220 | ||
d7c47c0e | 221 | /* Free RANGE as well as its children and siblings. */ |
222 | ||
223 | static void | |
2883a3ed | 224 | free_eh_ranges (struct eh_range *range) |
d7c47c0e | 225 | { |
226 | while (range) | |
227 | { | |
228 | struct eh_range *next = range->next_sibling; | |
229 | free_eh_ranges (range->first_child); | |
0e41c837 | 230 | if (range != &whole_range) |
231 | free (range); | |
d7c47c0e | 232 | range = next; |
233 | } | |
234 | } | |
addd693c | 235 | |
377029eb | 236 | /* Called to re-initialize the exception machinery for a new method. */ |
237 | ||
238 | void | |
2883a3ed | 239 | method_init_exceptions (void) |
377029eb | 240 | { |
d7c47c0e | 241 | free_eh_ranges (&whole_range); |
377029eb | 242 | whole_range.start_pc = 0; |
243 | whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1; | |
244 | whole_range.outer = NULL; | |
245 | whole_range.first_child = NULL; | |
246 | whole_range.next_sibling = NULL; | |
247 | cache_range_start = 0xFFFFFF; | |
377029eb | 248 | } |
249 | ||
addd693c | 250 | /* Add an exception range. If we already have an exception range |
251 | which has the same handler and label, and the new range overlaps | |
252 | that one, then we simply extend the existing range. Some bytecode | |
253 | obfuscators generate seemingly nonoverlapping exception ranges | |
254 | which, when coalesced, do in fact nest correctly. | |
255 | ||
256 | This constructs an ordinary linked list which check_nested_ranges() | |
257 | later turns into the data structure we actually want. | |
258 | ||
259 | We expect the input to come in order of increasing START_PC. This | |
260 | function doesn't attempt to detect the case where two previously | |
261 | added disjoint ranges could be coalesced by a new range; that is | |
262 | what the sorting counteracts. */ | |
263 | ||
264 | void | |
2883a3ed | 265 | add_handler (int start_pc, int end_pc, tree handler, tree type) |
377029eb | 266 | { |
addd693c | 267 | struct eh_range *ptr, *prev = NULL, *h; |
268 | ||
269 | for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling) | |
270 | { | |
271 | if (start_pc >= ptr->start_pc | |
272 | && start_pc <= ptr->end_pc | |
273 | && TREE_PURPOSE (ptr->handlers) == type | |
274 | && TREE_VALUE (ptr->handlers) == handler) | |
275 | { | |
276 | /* Already found an overlapping range, so coalesce. */ | |
277 | ptr->end_pc = MAX (ptr->end_pc, end_pc); | |
278 | return; | |
279 | } | |
280 | prev = ptr; | |
281 | } | |
282 | ||
0cc50a21 | 283 | h = xmalloc (sizeof (struct eh_range)); |
addd693c | 284 | h->start_pc = start_pc; |
285 | h->end_pc = end_pc; | |
286 | h->first_child = NULL; | |
287 | h->outer = NULL; | |
288 | h->handlers = build_tree_list (type, handler); | |
289 | h->next_sibling = NULL; | |
c1b6623d | 290 | h->expanded = 0; |
4ee9c684 | 291 | h->stmt = NULL; |
addd693c | 292 | |
293 | if (prev == NULL) | |
294 | whole_range.first_child = h; | |
295 | else | |
296 | prev->next_sibling = h; | |
377029eb | 297 | } |
298 | ||
377029eb | 299 | /* if there are any handlers for this range, issue start of region */ |
003019ba | 300 | static void |
2883a3ed | 301 | expand_start_java_handler (struct eh_range *range) |
377029eb | 302 | { |
c1b6623d | 303 | #if defined(DEBUG_JAVA_BINDING_LEVELS) |
304 | indent (); | |
305 | fprintf (stderr, "expand start handler pc %d --> %d\n", | |
306 | current_pc, range->end_pc); | |
307 | #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */ | |
4ee9c684 | 308 | { |
309 | tree new = build (TRY_CATCH_EXPR, void_type_node, NULL, NULL); | |
310 | TREE_SIDE_EFFECTS (new) = 1; | |
311 | java_add_stmt (build_java_empty_stmt ()); | |
312 | range->stmt = java_add_stmt (new); | |
313 | } | |
314 | ||
c1b6623d | 315 | range->expanded = 1; |
377029eb | 316 | } |
317 | ||
f1f55166 | 318 | tree |
2883a3ed | 319 | prepare_eh_table_type (tree type) |
f1f55166 | 320 | { |
321 | tree exp; | |
757f6c6c | 322 | tree *slot; |
927abe86 | 323 | const char *name; |
324 | char *buf; | |
325 | tree decl; | |
326 | tree utf8_ref; | |
f1f55166 | 327 | |
e164eae7 | 328 | /* The "type" (match_info) in a (Java) exception table is a pointer to: |
f1f55166 | 329 | * a) NULL - meaning match any type in a try-finally. |
e164eae7 | 330 | * b) a pointer to a pointer to a class. |
331 | * c) a pointer to a pointer to a utf8_ref. The pointer is | |
332 | * rewritten to point to the appropriate class. */ | |
f1f55166 | 333 | |
f1f55166 | 334 | if (type == NULL_TREE) |
757f6c6c | 335 | return NULL_TREE; |
336 | ||
337 | if (TYPE_TO_RUNTIME_MAP (output_class) == NULL) | |
338 | TYPE_TO_RUNTIME_MAP (output_class) = java_treetreehash_create (10, 1); | |
339 | ||
340 | slot = java_treetreehash_new (TYPE_TO_RUNTIME_MAP (output_class), type); | |
341 | if (*slot != NULL) | |
342 | return TREE_VALUE (*slot); | |
343 | ||
344 | if (is_compiled_class (type) && !flag_indirect_dispatch) | |
e164eae7 | 345 | { |
927abe86 | 346 | name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); |
347 | buf = alloca (strlen (name) + 5); | |
348 | sprintf (buf, "%s_ref", name); | |
e164eae7 | 349 | decl = build_decl (VAR_DECL, get_identifier (buf), ptr_type_node); |
350 | TREE_STATIC (decl) = 1; | |
351 | DECL_ARTIFICIAL (decl) = 1; | |
352 | DECL_IGNORED_P (decl) = 1; | |
353 | TREE_READONLY (decl) = 1; | |
354 | TREE_THIS_VOLATILE (decl) = 0; | |
355 | DECL_INITIAL (decl) = build_class_ref (type); | |
356 | layout_decl (decl, 0); | |
357 | pushdecl (decl); | |
4ee9c684 | 358 | exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl); |
e164eae7 | 359 | } |
f1f55166 | 360 | else |
30e23acf | 361 | { |
927abe86 | 362 | utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type))); |
363 | name = IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0))); | |
364 | buf = alloca (strlen (name) + 5); | |
365 | sprintf (buf, "%s_ref", name); | |
e164eae7 | 366 | decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_ptr_type); |
30e23acf | 367 | TREE_STATIC (decl) = 1; |
368 | DECL_ARTIFICIAL (decl) = 1; | |
369 | DECL_IGNORED_P (decl) = 1; | |
370 | TREE_READONLY (decl) = 1; | |
371 | TREE_THIS_VOLATILE (decl) = 0; | |
30e23acf | 372 | layout_decl (decl, 0); |
373 | pushdecl (decl); | |
e164eae7 | 374 | exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl); |
757f6c6c | 375 | TYPE_CATCH_CLASSES (output_class) = |
376 | tree_cons (NULL, make_catch_class_record (exp, utf8_ref), | |
377 | TYPE_CATCH_CLASSES (output_class)); | |
30e23acf | 378 | } |
757f6c6c | 379 | |
4ee9c684 | 380 | exp = convert (ptr_type_node, exp); |
381 | ||
757f6c6c | 382 | *slot = tree_cons (type, exp, NULL_TREE); |
383 | ||
f1f55166 | 384 | return exp; |
385 | } | |
386 | ||
757f6c6c | 387 | static int |
388 | expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED) | |
389 | { | |
390 | struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry; | |
4ee9c684 | 391 | tree addr = TREE_VALUE ((tree)ite->value); |
392 | tree decl; | |
393 | STRIP_NOPS (addr); | |
394 | decl = TREE_OPERAND (addr, 0); | |
757f6c6c | 395 | rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0); |
396 | return true; | |
397 | } | |
398 | ||
399 | /* For every class in the TYPE_TO_RUNTIME_MAP, expand the | |
400 | corresponding object that is used by the runtime type matcher. */ | |
401 | ||
402 | void | |
403 | java_expand_catch_classes (tree this_class) | |
404 | { | |
405 | if (TYPE_TO_RUNTIME_MAP (this_class)) | |
406 | htab_traverse | |
407 | (TYPE_TO_RUNTIME_MAP (this_class), | |
408 | expand_catch_class, NULL); | |
409 | } | |
df4b504c | 410 | |
411 | /* Build a reference to the jthrowable object being carried in the | |
412 | exception header. */ | |
413 | ||
414 | tree | |
2883a3ed | 415 | build_exception_object_ref (tree type) |
df4b504c | 416 | { |
417 | tree obj; | |
418 | ||
419 | /* Java only passes object via pointer and doesn't require adjusting. | |
420 | The java object is immediately before the generic exception header. */ | |
421 | obj = build (EXC_PTR_EXPR, build_pointer_type (type)); | |
422 | obj = build (MINUS_EXPR, TREE_TYPE (obj), obj, | |
423 | TYPE_SIZE_UNIT (TREE_TYPE (obj))); | |
424 | obj = build1 (INDIRECT_REF, type, obj); | |
425 | ||
426 | return obj; | |
427 | } | |
428 | ||
429 | /* If there are any handlers for this range, isssue end of range, | |
377029eb | 430 | and then all handler blocks */ |
003019ba | 431 | static void |
2883a3ed | 432 | expand_end_java_handler (struct eh_range *range) |
c1b6623d | 433 | { |
377029eb | 434 | tree handler = range->handlers; |
4ee9c684 | 435 | tree compound = NULL; |
436 | ||
437 | force_poplevels (range->start_pc); | |
377029eb | 438 | for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler)) |
439 | { | |
d179df43 | 440 | /* For bytecode we treat exceptions a little unusually. A |
441 | `finally' clause looks like an ordinary exception handler for | |
442 | Throwable. The reason for this is that the bytecode has | |
443 | already expanded the finally logic, and we would have to do | |
444 | extra (and difficult) work to get this to look like a | |
445 | gcc-style finally clause. */ | |
446 | tree type = TREE_PURPOSE (handler); | |
4ee9c684 | 447 | |
d179df43 | 448 | if (type == NULL) |
449 | type = throwable_type_node; | |
450 | ||
4ee9c684 | 451 | type = prepare_eh_table_type (type); |
452 | ||
453 | if (compound) | |
454 | { | |
455 | /* If we already have a COMPOUND there is more than one | |
456 | catch handler for this try block. Wrap the | |
457 | TRY_CATCH_EXPR in operand 1 of COMPOUND with another | |
458 | TRY_CATCH_EXPR. */ | |
459 | tree inner_try_expr = TREE_OPERAND (compound, 1); | |
460 | tree catch_expr | |
461 | = build (CATCH_EXPR, void_type_node, type, | |
462 | build (GOTO_EXPR, void_type_node, TREE_VALUE (handler))); | |
463 | tree try_expr | |
464 | = build (TRY_CATCH_EXPR, void_type_node, | |
465 | inner_try_expr, catch_expr); | |
466 | TREE_OPERAND (compound, 1) = try_expr; | |
467 | } | |
468 | else | |
469 | { | |
470 | tree *stmts = get_stmts (); | |
471 | tree outer; | |
472 | tree try_expr; | |
473 | compound = range->stmt; | |
474 | outer = TREE_OPERAND (compound, 0); | |
475 | try_expr = TREE_OPERAND (compound, 1); | |
476 | /* On the left of COMPOUND is the expresion to be evaluated | |
477 | before the try handler is entered; on the right is a | |
478 | TRY_FINALLY_EXPR with no operands as yet. In the current | |
479 | statement list is an expression that we're going to move | |
480 | inside the try handler. We'll create a new COMPOUND_EXPR | |
481 | with the outer context on the left and the TRY_FINALLY_EXPR | |
482 | on the right, then nullify both operands of COMPOUND, which | |
483 | becomes the final expression in OUTER. This new compound | |
484 | expression replaces the current statement list. */ | |
485 | TREE_OPERAND (try_expr, 0) = *stmts; | |
486 | TREE_OPERAND (try_expr, 1) | |
487 | = build (CATCH_EXPR, void_type_node, type, | |
488 | build (GOTO_EXPR, void_type_node, TREE_VALUE (handler))); | |
489 | TREE_SIDE_EFFECTS (try_expr) = 1; | |
490 | TREE_OPERAND (compound, 0) = build_java_empty_stmt (); | |
491 | TREE_OPERAND (compound, 1) = build_java_empty_stmt (); | |
492 | compound | |
493 | = build (COMPOUND_EXPR, TREE_TYPE (try_expr), outer, try_expr); | |
494 | *stmts = compound; | |
495 | } | |
377029eb | 496 | } |
c1b6623d | 497 | #if defined(DEBUG_JAVA_BINDING_LEVELS) |
498 | indent (); | |
499 | fprintf (stderr, "expand end handler pc %d <-- %d\n", | |
500 | current_pc, range->start_pc); | |
501 | #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */ | |
377029eb | 502 | } |
503 | ||
504 | /* Recursive helper routine for maybe_start_handlers. */ | |
505 | ||
506 | static void | |
2883a3ed | 507 | check_start_handlers (struct eh_range *range, int pc) |
377029eb | 508 | { |
509 | if (range != NULL_EH_RANGE && range->start_pc == pc) | |
510 | { | |
511 | check_start_handlers (range->outer, pc); | |
c1b6623d | 512 | if (!range->expanded) |
513 | expand_start_java_handler (range); | |
377029eb | 514 | } |
515 | } | |
516 | ||
377029eb | 517 | |
c1b6623d | 518 | static struct eh_range *current_range; |
519 | ||
520 | /* Emit any start-of-try-range starting at start_pc and ending after | |
521 | end_pc. */ | |
377029eb | 522 | |
523 | void | |
2883a3ed | 524 | maybe_start_try (int start_pc, int end_pc) |
377029eb | 525 | { |
c1b6623d | 526 | struct eh_range *range; |
377029eb | 527 | if (! doing_eh (1)) |
528 | return; | |
529 | ||
c1b6623d | 530 | range = find_handler (start_pc); |
531 | while (range != NULL_EH_RANGE && range->start_pc == start_pc | |
532 | && range->end_pc < end_pc) | |
533 | range = range->outer; | |
534 | ||
535 | current_range = range; | |
083909e3 | 536 | check_start_handlers (range, start_pc); |
377029eb | 537 | } |
538 | ||
c1b6623d | 539 | /* Emit any end-of-try-range ending at end_pc and starting before |
540 | start_pc. */ | |
377029eb | 541 | |
542 | void | |
2883a3ed | 543 | maybe_end_try (int start_pc, int end_pc) |
377029eb | 544 | { |
545 | if (! doing_eh (1)) | |
546 | return; | |
547 | ||
c1b6623d | 548 | while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc |
549 | && current_range->start_pc >= start_pc) | |
377029eb | 550 | { |
551 | expand_end_java_handler (current_range); | |
552 | current_range = current_range->outer; | |
553 | } | |
554 | } |