OSDN Git Service

2000-01-25 Andrew Haley <aph@cygnus.com>
[pf3gnuchains/gcc-fork.git] / gcc / java / except.c
1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2    Copyright (C) 1997, 98-99, 2000 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 "eh-common.h"
38 #include "toplev.h"
39
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 *,
43                                                       struct eh_range *));
44 static void link_handler PARAMS ((struct eh_range *, struct eh_range *));
45
46 extern struct obstack permanent_obstack;
47
48 struct eh_range *current_method_handlers;
49
50 struct eh_range *current_try_block = NULL;
51
52 struct eh_range *eh_range_freelist = NULL;
53
54 /* These variables are used to speed up find_handler. */
55
56 static int cache_range_start, cache_range_end;
57 static struct eh_range *cache_range;
58 static struct eh_range *cache_next_child;
59
60 /* A dummy range that represents the entire method. */
61
62 struct eh_range whole_range;
63
64 #if defined(DEBUG_JAVA_BINDING_LEVELS)
65 int binding_depth;
66 int is_class_level;
67 int current_pc;
68 extern void indent ();
69
70 #endif
71
72 /* Search for the most specific eh_range containing PC.
73    Assume PC is within RANGE.
74    CHILD is a list of children of RANGE such that any
75    previous children have end_pc values that are too low. */
76
77 static struct eh_range *
78 find_handler_in_range (pc, range, child)
79      int pc;
80      struct eh_range *range;
81      register struct eh_range *child;
82 {
83   for (; child != NULL;  child = child->next_sibling)
84     {
85       if (pc < child->start_pc)
86         break;
87       if (pc < child->end_pc)
88         return find_handler_in_range (pc, child, child->first_child);
89     }
90   cache_range = range;
91   cache_range_start = pc;
92   cache_next_child = child;
93   cache_range_end = child == NULL ? range->end_pc : child->start_pc;
94   return range;
95 }
96
97 /* Find the inner-most handler that contains PC. */
98
99 struct eh_range *
100 find_handler (pc)
101      int pc;
102 {
103   struct eh_range *h;
104   if (pc >= cache_range_start)
105     {
106       h = cache_range;
107       if (pc < cache_range_end)
108         return h;
109       while (pc >= h->end_pc)
110         {
111           cache_next_child = h->next_sibling;
112           h = h->outer;
113         }
114     }
115   else
116     {
117       h = &whole_range;
118       cache_next_child = h->first_child;
119     }
120   return find_handler_in_range (pc, h, cache_next_child);
121 }
122
123 /* Recursive helper routine for check_nested_ranges. */
124
125 static void
126 link_handler (range, outer)
127      struct eh_range *range, *outer;
128 {
129   struct eh_range **ptr;
130
131   if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
132     {
133       outer->handlers = chainon (outer->handlers, range->handlers);
134       return;
135     }
136
137   /* If the new range completely encloses the `outer' range, then insert it
138      between the outer range and its parent.  */
139   if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
140     {
141       range->outer = outer->outer;
142       range->next_sibling = NULL;
143       range->first_child = outer;
144       {
145         struct eh_range **pr = &(outer->outer->first_child);
146         while (*pr != outer)
147           pr = &(*pr)->next_sibling;
148         *pr = range;
149       }
150       outer->outer = range;
151       return;
152     }
153
154   /* Handle overlapping ranges by splitting the new range.  */
155   if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
156     {
157       struct eh_range *h
158         = (struct eh_range *) oballoc (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       /* 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;
181     }
182
183   ptr = &outer->first_child;
184   for (;; ptr = &(*ptr)->next_sibling)
185     {
186       if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
187         {
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;
198         }
199       /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
200     }
201 }
202
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
208 void
209 handle_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
223
224 /* Called to re-initialize the exception machinery for a new method. */
225
226 void
227 method_init_exceptions ()
228 {
229   whole_range.start_pc = 0;
230   whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
231   whole_range.outer = NULL;
232   whole_range.first_child = NULL;
233   whole_range.next_sibling = NULL;
234   cache_range_start = 0xFFFFFF;
235   java_set_exception_lang_code ();
236 }
237
238 void
239 java_set_exception_lang_code ()
240 {
241   set_exception_lang_code (EH_LANG_Java);
242   set_exception_version_code (1);
243 }
244
245 /* Add an exception range.  If we already have an exception range
246    which has the same handler and label, and the new range overlaps
247    that one, then we simply extend the existing range.  Some bytecode
248    obfuscators generate seemingly nonoverlapping exception ranges
249    which, when coalesced, do in fact nest correctly.
250    
251    This constructs an ordinary linked list which check_nested_ranges()
252    later turns into the data structure we actually want.
253    
254    We expect the input to come in order of increasing START_PC.  This
255    function doesn't attempt to detect the case where two previously
256    added disjoint ranges could be coalesced by a new range; that is
257    what the sorting counteracts.  */
258
259 void
260 add_handler (start_pc, end_pc, handler, type)
261      int start_pc, end_pc;
262      tree handler;
263      tree type;
264 {
265   struct eh_range *ptr, *prev = NULL, *h;
266
267   for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
268     {
269       if (start_pc >= ptr->start_pc
270           && start_pc <= ptr->end_pc
271           && TREE_PURPOSE (ptr->handlers) == type
272           && TREE_VALUE (ptr->handlers) == handler)
273         {
274           /* Already found an overlapping range, so coalesce.  */
275           ptr->end_pc = MAX (ptr->end_pc, end_pc);
276           return;
277         }
278       prev = ptr;
279     }
280
281   h = (struct eh_range *) oballoc (sizeof (struct eh_range));
282   h->start_pc = start_pc;
283   h->end_pc = end_pc;
284   h->first_child = NULL;
285   h->outer = NULL;
286   h->handlers = build_tree_list (type, handler);
287   h->next_sibling = NULL;
288   h->expanded = 0;
289
290   if (prev == NULL)
291     whole_range.first_child = h;
292   else
293     prev->next_sibling = h;
294 }
295
296
297 /* if there are any handlers for this range, issue start of region */
298 static void
299 expand_start_java_handler (range)
300   struct eh_range *range;
301 {
302 #if defined(DEBUG_JAVA_BINDING_LEVELS)
303   indent ();
304   fprintf (stderr, "expand start handler pc %d --> %d\n",
305            current_pc, range->end_pc);
306 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
307   range->expanded = 1;
308   push_obstacks (&permanent_obstack, &permanent_obstack);
309   expand_eh_region_start ();
310   pop_obstacks ();
311 }
312
313 tree
314 prepare_eh_table_type (type)
315     tree type;
316 {
317   tree exp;
318
319   /* The "type" (metch_info) in a (Java) exception table is one:
320    * a) NULL - meaning match any type in a try-finally.
321    * b) a pointer to a (ccmpiled) class (low-order bit 0).
322    * c) a pointer to the Utf8Const name of the class, plus one
323    * (which yields a value with low-order bit 1). */
324
325   push_obstacks (&permanent_obstack, &permanent_obstack);
326   if (type == NULL_TREE)
327     exp = null_pointer_node;
328   else if (is_compiled_class (type))
329     exp = build_class_ref (type);
330   else
331     exp = fold (build 
332                 (PLUS_EXPR, ptr_type_node,
333                  build_utf8_ref (build_internal_class_name (type)),
334                  size_one_node));
335   pop_obstacks ();
336   return exp;
337 }
338
339 /* if there are any handlers for this range, isssue end of range,
340    and then all handler blocks */
341 static void
342 expand_end_java_handler (range)
343      struct eh_range *range;
344 {  
345   tree handler = range->handlers;
346   force_poplevels (range->start_pc);
347   push_obstacks (&permanent_obstack, &permanent_obstack);
348   expand_start_all_catch ();
349   pop_obstacks ();
350   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
351     {
352       start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler)));
353       /* Push the thrown object on the top of the stack */
354       expand_goto (TREE_VALUE (handler));
355       expand_resume_after_catch ();
356       end_catch_handler ();
357     }
358   expand_end_all_catch ();
359 #if defined(DEBUG_JAVA_BINDING_LEVELS)
360   indent ();
361   fprintf (stderr, "expand end handler pc %d <-- %d\n",
362            current_pc, range->start_pc);
363 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
364 }
365
366 /* Recursive helper routine for maybe_start_handlers. */
367
368 static void
369 check_start_handlers (range, pc)
370      struct eh_range *range;
371      int pc;
372 {
373   if (range != NULL_EH_RANGE && range->start_pc == pc)
374     {
375       check_start_handlers (range->outer, pc);
376       if (!range->expanded)
377         expand_start_java_handler (range);
378     }
379 }
380
381
382 static struct eh_range *current_range;
383
384 /* Emit any start-of-try-range starting at start_pc and ending after
385    end_pc. */
386
387 void
388 maybe_start_try (start_pc, end_pc)
389      int start_pc;
390      int end_pc;
391 {
392   struct eh_range *range;
393   if (! doing_eh (1))
394     return;
395
396   range = find_handler (start_pc);
397   while (range != NULL_EH_RANGE && range->start_pc == start_pc
398          && range->end_pc < end_pc)
399     range = range->outer;
400          
401   current_range = range;
402   check_start_handlers (range, start_pc, end_pc);
403 }
404
405 /* Emit any end-of-try-range ending at end_pc and starting before
406    start_pc. */
407
408 void
409 maybe_end_try (start_pc, end_pc)
410      int start_pc;
411      int end_pc;
412 {
413   if (! doing_eh (1))
414     return;
415
416   while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
417          && current_range->start_pc >= start_pc)
418     {
419       expand_end_java_handler (current_range);
420       current_range = current_range->outer;
421     }
422 }
423
424 /* Emit the handler labels and their code */
425
426 void
427 emit_handlers ()
428 {
429   if (catch_clauses)
430     {
431       rtx funcend = gen_label_rtx ();
432       emit_jump (funcend);
433
434       emit_insns (catch_clauses);
435       catch_clauses = NULL_RTX;
436       expand_leftover_cleanups ();
437
438       emit_label (funcend);
439     }
440 }
441
442 /* Resume executing at the statement immediately after the end of an
443    exception region. */
444
445 void
446 expand_resume_after_catch ()
447 {
448   expand_goto (top_label_entry (&caught_return_label_stack));
449 }