]> gcc.gnu.org Git - gcc.git/blame - gcc/java/except.c
verify.c (verify_jvm_instructions): Allow exception handler inside code that is being...
[gcc.git] / gcc / java / except.c
CommitLineData
e04a16fb 1/* Handle exceptions for GNU compiler for the Java(TM) language.
073681c5 2 Copyright (C) 1997, 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
e04a16fb
AG
3
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU CC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU CC; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.
20
21Java and all Java-based marks are trademarks or registered trademarks
22of Sun Microsystems, Inc. in the United States and other countries.
23The 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"
1f43f4b4 37#include "toplev.h"
e04a16fb 38
df32d2ce
KG
39static void expand_start_java_handler PARAMS ((struct eh_range *));
40static void expand_end_java_handler PARAMS ((struct eh_range *));
41static struct eh_range *find_handler_in_range PARAMS ((int, struct eh_range *,
c8e7d2e6 42 struct eh_range *));
df32d2ce 43static void link_handler PARAMS ((struct eh_range *, struct eh_range *));
ae0a06c5 44static void check_start_handlers PARAMS ((struct eh_range *, int));
1f8f4a0b 45static void free_eh_ranges PARAMS ((struct eh_range *range));
4bcde32e 46
e04a16fb
AG
47struct eh_range *current_method_handlers;
48
49struct eh_range *current_try_block = NULL;
50
51struct eh_range *eh_range_freelist = NULL;
52
53/* These variables are used to speed up find_handler. */
54
55static int cache_range_start, cache_range_end;
56static struct eh_range *cache_range;
57static struct eh_range *cache_next_child;
58
59/* A dummy range that represents the entire method. */
60
61struct eh_range whole_range;
62
e8b22dd1 63#if defined(DEBUG_JAVA_BINDING_LEVELS)
b139fcfd
AH
64extern int binding_depth;
65extern int is_class_level;
66extern int current_pc;
e8b22dd1
AH
67extern void indent ();
68
69#endif
70
e04a16fb
AG
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
76static struct eh_range *
77find_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;
44d7502b 86 if (pc < child->end_pc)
e04a16fb
AG
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
98struct eh_range *
99find_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
5a9e5c6f 122/* Recursive helper routine for check_nested_ranges. */
e04a16fb 123
5a9e5c6f
TT
124static void
125link_handler (range, outer)
126 struct eh_range *range, *outer;
e04a16fb
AG
127{
128 struct eh_range **ptr;
5a9e5c6f
TT
129
130 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
131 {
99fd3aa5 132 outer->handlers = chainon (outer->handlers, range->handlers);
5a9e5c6f
TT
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;
44d7502b
AH
143 {
144 struct eh_range **pr = &(outer->outer->first_child);
145 while (*pr != outer)
146 pr = &(*pr)->next_sibling;
147 *pr = range;
148 }
5a9e5c6f
TT
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)
e04a16fb 155 {
5a9e5c6f 156 struct eh_range *h
1f8f4a0b 157 = (struct eh_range *) xmalloc (sizeof (struct eh_range));
5a9e5c6f
TT
158 if (range->start_pc < outer->start_pc)
159 {
160 h->start_pc = range->start_pc;
161 h->end_pc = outer->start_pc;
162 range->start_pc = outer->start_pc;
163 }
164 else
165 {
166 h->start_pc = outer->end_pc;
167 h->end_pc = range->end_pc;
168 range->end_pc = outer->end_pc;
169 }
170 h->first_child = NULL;
171 h->outer = NULL;
172 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
173 TREE_VALUE (range->handlers));
174 h->next_sibling = NULL;
b139fcfd 175 h->expanded = 0;
5a9e5c6f
TT
176 /* Restart both from the top to avoid having to make this
177 function smart about reentrancy. */
178 link_handler (h, &whole_range);
179 link_handler (range, &whole_range);
180 return;
e04a16fb 181 }
5a9e5c6f 182
e04a16fb
AG
183 ptr = &outer->first_child;
184 for (;; ptr = &(*ptr)->next_sibling)
185 {
5a9e5c6f 186 if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
e04a16fb 187 {
5a9e5c6f
TT
188 range->next_sibling = *ptr;
189 range->first_child = NULL;
190 range->outer = outer;
191 *ptr = range;
192 return;
193 }
194 else if (range->start_pc < (*ptr)->end_pc)
195 {
196 link_handler (range, *ptr);
197 return;
e04a16fb 198 }
e04a16fb
AG
199 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
200 }
201}
202
5a9e5c6f
TT
203/* The first pass of exception range processing (calling add_handler)
204 constructs a linked list of exception ranges. We turn this into
205 the data structure expected by the rest of the code, and also
206 ensure that exception ranges are properly nested. */
207
208void
209handle_nested_ranges ()
210{
211 struct eh_range *ptr, *next;
212
213 ptr = whole_range.first_child;
214 whole_range.first_child = NULL;
215 for (; ptr; ptr = next)
216 {
217 next = ptr->next_sibling;
218 ptr->next_sibling = NULL;
219 link_handler (ptr, &whole_range);
220 }
221}
222
1f8f4a0b
MM
223/* Free RANGE as well as its children and siblings. */
224
225static void
226free_eh_ranges (range)
227 struct eh_range *range;
228{
229 while (range)
230 {
231 struct eh_range *next = range->next_sibling;
232 free_eh_ranges (range->first_child);
1a2ebe6d
APB
233 if (range != &whole_range)
234 free (range);
1f8f4a0b
MM
235 range = next;
236 }
237}
5a9e5c6f 238
e04a16fb
AG
239/* Called to re-initialize the exception machinery for a new method. */
240
241void
242method_init_exceptions ()
243{
1f8f4a0b 244 free_eh_ranges (&whole_range);
e04a16fb
AG
245 whole_range.start_pc = 0;
246 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
247 whole_range.outer = NULL;
248 whole_range.first_child = NULL;
249 whole_range.next_sibling = NULL;
250 cache_range_start = 0xFFFFFF;
e04a16fb
AG
251}
252
5a9e5c6f
TT
253/* Add an exception range. If we already have an exception range
254 which has the same handler and label, and the new range overlaps
255 that one, then we simply extend the existing range. Some bytecode
256 obfuscators generate seemingly nonoverlapping exception ranges
257 which, when coalesced, do in fact nest correctly.
258
259 This constructs an ordinary linked list which check_nested_ranges()
260 later turns into the data structure we actually want.
261
262 We expect the input to come in order of increasing START_PC. This
263 function doesn't attempt to detect the case where two previously
264 added disjoint ranges could be coalesced by a new range; that is
265 what the sorting counteracts. */
266
267void
e04a16fb
AG
268add_handler (start_pc, end_pc, handler, type)
269 int start_pc, end_pc;
270 tree handler;
271 tree type;
272{
5a9e5c6f
TT
273 struct eh_range *ptr, *prev = NULL, *h;
274
275 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
276 {
277 if (start_pc >= ptr->start_pc
278 && start_pc <= ptr->end_pc
279 && TREE_PURPOSE (ptr->handlers) == type
280 && TREE_VALUE (ptr->handlers) == handler)
281 {
282 /* Already found an overlapping range, so coalesce. */
283 ptr->end_pc = MAX (ptr->end_pc, end_pc);
284 return;
285 }
286 prev = ptr;
287 }
288
1f8f4a0b 289 h = (struct eh_range *) xmalloc (sizeof (struct eh_range));
5a9e5c6f
TT
290 h->start_pc = start_pc;
291 h->end_pc = end_pc;
292 h->first_child = NULL;
293 h->outer = NULL;
294 h->handlers = build_tree_list (type, handler);
295 h->next_sibling = NULL;
e8b22dd1 296 h->expanded = 0;
5a9e5c6f
TT
297
298 if (prev == NULL)
299 whole_range.first_child = h;
300 else
301 prev->next_sibling = h;
e04a16fb
AG
302}
303
304
305/* if there are any handlers for this range, issue start of region */
4bcde32e 306static void
e04a16fb 307expand_start_java_handler (range)
e8b22dd1 308 struct eh_range *range;
e04a16fb 309{
e8b22dd1
AH
310#if defined(DEBUG_JAVA_BINDING_LEVELS)
311 indent ();
312 fprintf (stderr, "expand start handler pc %d --> %d\n",
313 current_pc, range->end_pc);
314#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
315 range->expanded = 1;
e04a16fb
AG
316 expand_eh_region_start ();
317}
318
e4de5a10
PB
319tree
320prepare_eh_table_type (type)
321 tree type;
322{
323 tree exp;
324
325 /* The "type" (metch_info) in a (Java) exception table is one:
326 * a) NULL - meaning match any type in a try-finally.
327 * b) a pointer to a (ccmpiled) class (low-order bit 0).
328 * c) a pointer to the Utf8Const name of the class, plus one
329 * (which yields a value with low-order bit 1). */
330
e4de5a10 331 if (type == NULL_TREE)
52a11cbf 332 exp = NULL_TREE;
e4de5a10
PB
333 else if (is_compiled_class (type))
334 exp = build_class_ref (type);
335 else
336 exp = fold (build
337 (PLUS_EXPR, ptr_type_node,
338 build_utf8_ref (build_internal_class_name (type)),
339 size_one_node));
e4de5a10
PB
340 return exp;
341}
342
52a11cbf
RH
343
344/* Build a reference to the jthrowable object being carried in the
345 exception header. */
346
347tree
348build_exception_object_ref (type)
349 tree type;
350{
351 tree obj;
352
353 /* Java only passes object via pointer and doesn't require adjusting.
354 The java object is immediately before the generic exception header. */
355 obj = build (EXC_PTR_EXPR, build_pointer_type (type));
356 obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
357 TYPE_SIZE_UNIT (TREE_TYPE (obj)));
358 obj = build1 (INDIRECT_REF, type, obj);
359
360 return obj;
361}
362
363/* If there are any handlers for this range, isssue end of range,
e04a16fb 364 and then all handler blocks */
4bcde32e 365static void
e04a16fb
AG
366expand_end_java_handler (range)
367 struct eh_range *range;
e8b22dd1 368{
e04a16fb 369 tree handler = range->handlers;
e8b22dd1 370 force_poplevels (range->start_pc);
e04a16fb
AG
371 expand_start_all_catch ();
372 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
373 {
073681c5
TT
374 /* For bytecode we treat exceptions a little unusually. A
375 `finally' clause looks like an ordinary exception handler for
376 Throwable. The reason for this is that the bytecode has
377 already expanded the finally logic, and we would have to do
378 extra (and difficult) work to get this to look like a
379 gcc-style finally clause. */
380 tree type = TREE_PURPOSE (handler);
381 if (type == NULL)
382 type = throwable_type_node;
383
384 expand_start_catch (type);
e04a16fb 385 expand_goto (TREE_VALUE (handler));
52a11cbf 386 expand_end_catch ();
e04a16fb
AG
387 }
388 expand_end_all_catch ();
e8b22dd1
AH
389#if defined(DEBUG_JAVA_BINDING_LEVELS)
390 indent ();
391 fprintf (stderr, "expand end handler pc %d <-- %d\n",
392 current_pc, range->start_pc);
393#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
e04a16fb
AG
394}
395
396/* Recursive helper routine for maybe_start_handlers. */
397
398static void
399check_start_handlers (range, pc)
400 struct eh_range *range;
401 int pc;
402{
403 if (range != NULL_EH_RANGE && range->start_pc == pc)
404 {
405 check_start_handlers (range->outer, pc);
e8b22dd1
AH
406 if (!range->expanded)
407 expand_start_java_handler (range);
e04a16fb
AG
408 }
409}
410
e04a16fb 411
e8b22dd1
AH
412static struct eh_range *current_range;
413
414/* Emit any start-of-try-range starting at start_pc and ending after
415 end_pc. */
e04a16fb
AG
416
417void
e8b22dd1
AH
418maybe_start_try (start_pc, end_pc)
419 int start_pc;
420 int end_pc;
e04a16fb 421{
e8b22dd1 422 struct eh_range *range;
e04a16fb
AG
423 if (! doing_eh (1))
424 return;
425
e8b22dd1
AH
426 range = find_handler (start_pc);
427 while (range != NULL_EH_RANGE && range->start_pc == start_pc
428 && range->end_pc < end_pc)
429 range = range->outer;
430
431 current_range = range;
ef86eabb 432 check_start_handlers (range, start_pc);
e04a16fb
AG
433}
434
e8b22dd1
AH
435/* Emit any end-of-try-range ending at end_pc and starting before
436 start_pc. */
e04a16fb
AG
437
438void
e8b22dd1
AH
439maybe_end_try (start_pc, end_pc)
440 int start_pc;
441 int end_pc;
e04a16fb
AG
442{
443 if (! doing_eh (1))
444 return;
445
e8b22dd1
AH
446 while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
447 && current_range->start_pc >= start_pc)
e04a16fb
AG
448 {
449 expand_end_java_handler (current_range);
450 current_range = current_range->outer;
451 }
452}
This page took 1.021795 seconds and 5 git commands to generate.