OSDN Git Service

Workaround for Itanium A/B step errata
[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 static void free_eh_ranges PARAMS ((struct eh_range *range));
47
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
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
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;
89       if (pc < child->end_pc)
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
125 /* Recursive helper routine for check_nested_ranges. */
126
127 static void
128 link_handler (range, outer)
129      struct eh_range *range, *outer;
130 {
131   struct eh_range **ptr;
132
133   if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
134     {
135       outer->handlers = chainon (outer->handlers, range->handlers);
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;
146       {
147         struct eh_range **pr = &(outer->outer->first_child);
148         while (*pr != outer)
149           pr = &(*pr)->next_sibling;
150         *pr = range;
151       }
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)
158     {
159       struct eh_range *h
160         = (struct eh_range *) xmalloc (sizeof (struct eh_range));
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;
183     }
184
185   ptr = &outer->first_child;
186   for (;; ptr = &(*ptr)->next_sibling)
187     {
188       if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
189         {
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;
200         }
201       /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
202     }
203 }
204
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
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);
235       if (range != &whole_range)
236         free (range);
237       range = next;
238     }
239 }
240
241 /* Called to re-initialize the exception machinery for a new method. */
242
243 void
244 method_init_exceptions ()
245 {
246   free_eh_ranges (&whole_range);
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;
253   java_set_exception_lang_code ();
254 }
255
256 void
257 java_set_exception_lang_code ()
258 {
259   set_exception_lang_code (EH_LANG_Java);
260   set_exception_version_code (1);
261 }
262
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
278 add_handler (start_pc, end_pc, handler, type)
279      int start_pc, end_pc;
280      tree handler;
281      tree type;
282 {
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
299   h = (struct eh_range *) xmalloc (sizeof (struct eh_range));
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;
306   h->expanded = 0;
307
308   if (prev == NULL)
309     whole_range.first_child = h;
310   else
311     prev->next_sibling = h;
312 }
313
314
315 /* if there are any handlers for this range, issue start of region */
316 static void
317 expand_start_java_handler (range)
318   struct eh_range *range;
319 {
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;
326   expand_eh_region_start ();
327 }
328
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
341   if (type == NULL_TREE)
342     exp = CATCH_ALL_TYPE;
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));
350   return exp;
351 }
352
353 /* if there are any handlers for this range, isssue end of range,
354    and then all handler blocks */
355 static void
356 expand_end_java_handler (range)
357      struct eh_range *range;
358 {  
359   tree handler = range->handlers;
360   force_poplevels (range->start_pc);
361   expand_start_all_catch ();
362   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
363     {
364       start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler)));
365       /* Push the thrown object on the top of the stack */
366       expand_goto (TREE_VALUE (handler));
367       expand_resume_after_catch ();
368       end_catch_handler ();
369     }
370   expand_end_all_catch ();
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) */
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);
388       if (!range->expanded)
389         expand_start_java_handler (range);
390     }
391 }
392
393
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. */
398
399 void
400 maybe_start_try (start_pc, end_pc)
401      int start_pc;
402      int end_pc;
403 {
404   struct eh_range *range;
405   if (! doing_eh (1))
406     return;
407
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;
414   check_start_handlers (range, start_pc);
415 }
416
417 /* Emit any end-of-try-range ending at end_pc and starting before
418    start_pc. */
419
420 void
421 maybe_end_try (start_pc, end_pc)
422      int start_pc;
423      int end_pc;
424 {
425   if (! doing_eh (1))
426     return;
427
428   while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
429          && current_range->start_pc >= start_pc)
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);
447       catch_clauses = catch_clauses_last = NULL_RTX;
448       expand_leftover_cleanups ();
449
450       emit_label (funcend);
451     }
452 }
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 }