OSDN Git Service

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