OSDN Git Service

IA-64 ABI Exception Handling.
[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 "toplev.h"
38
39 static void expand_start_java_handler PARAMS ((struct eh_range *));
40 static void expand_end_java_handler PARAMS ((struct eh_range *));
41 static struct eh_range *find_handler_in_range PARAMS ((int, struct eh_range *,
42                                                       struct eh_range *));
43 static void link_handler PARAMS ((struct eh_range *, struct eh_range *));
44 static void check_start_handlers PARAMS ((struct eh_range *, int));
45 static void free_eh_ranges PARAMS ((struct eh_range *range));
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 *) xmalloc (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 /* Free RANGE as well as its children and siblings.  */
225
226 static void
227 free_eh_ranges (range)
228      struct eh_range *range;
229 {
230   while (range) 
231     {
232       struct eh_range *next = range->next_sibling;
233       free_eh_ranges (range->first_child);
234       if (range != &whole_range)
235         free (range);
236       range = next;
237     }
238 }
239
240 /* Called to re-initialize the exception machinery for a new method. */
241
242 void
243 method_init_exceptions ()
244 {
245   free_eh_ranges (&whole_range);
246   whole_range.start_pc = 0;
247   whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
248   whole_range.outer = NULL;
249   whole_range.first_child = NULL;
250   whole_range.next_sibling = NULL;
251   cache_range_start = 0xFFFFFF;
252 }
253
254 /* Add an exception range.  If we already have an exception range
255    which has the same handler and label, and the new range overlaps
256    that one, then we simply extend the existing range.  Some bytecode
257    obfuscators generate seemingly nonoverlapping exception ranges
258    which, when coalesced, do in fact nest correctly.
259    
260    This constructs an ordinary linked list which check_nested_ranges()
261    later turns into the data structure we actually want.
262    
263    We expect the input to come in order of increasing START_PC.  This
264    function doesn't attempt to detect the case where two previously
265    added disjoint ranges could be coalesced by a new range; that is
266    what the sorting counteracts.  */
267
268 void
269 add_handler (start_pc, end_pc, handler, type)
270      int start_pc, end_pc;
271      tree handler;
272      tree type;
273 {
274   struct eh_range *ptr, *prev = NULL, *h;
275
276   for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
277     {
278       if (start_pc >= ptr->start_pc
279           && start_pc <= ptr->end_pc
280           && TREE_PURPOSE (ptr->handlers) == type
281           && TREE_VALUE (ptr->handlers) == handler)
282         {
283           /* Already found an overlapping range, so coalesce.  */
284           ptr->end_pc = MAX (ptr->end_pc, end_pc);
285           return;
286         }
287       prev = ptr;
288     }
289
290   h = (struct eh_range *) xmalloc (sizeof (struct eh_range));
291   h->start_pc = start_pc;
292   h->end_pc = end_pc;
293   h->first_child = NULL;
294   h->outer = NULL;
295   h->handlers = build_tree_list (type, handler);
296   h->next_sibling = NULL;
297   h->expanded = 0;
298
299   if (prev == NULL)
300     whole_range.first_child = h;
301   else
302     prev->next_sibling = h;
303 }
304
305
306 /* if there are any handlers for this range, issue start of region */
307 static void
308 expand_start_java_handler (range)
309   struct eh_range *range;
310 {
311 #if defined(DEBUG_JAVA_BINDING_LEVELS)
312   indent ();
313   fprintf (stderr, "expand start handler pc %d --> %d\n",
314            current_pc, range->end_pc);
315 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
316   range->expanded = 1;
317   expand_eh_region_start ();
318 }
319
320 tree
321 prepare_eh_table_type (type)
322     tree type;
323 {
324   tree exp;
325
326   /* The "type" (metch_info) in a (Java) exception table is one:
327    * a) NULL - meaning match any type in a try-finally.
328    * b) a pointer to a (ccmpiled) class (low-order bit 0).
329    * c) a pointer to the Utf8Const name of the class, plus one
330    * (which yields a value with low-order bit 1). */
331
332   if (type == NULL_TREE)
333     exp = NULL_TREE;
334   else if (is_compiled_class (type))
335     exp = build_class_ref (type);
336   else
337     exp = fold (build 
338                 (PLUS_EXPR, ptr_type_node,
339                  build_utf8_ref (build_internal_class_name (type)),
340                  size_one_node));
341   return exp;
342 }
343
344
345 /* Build a reference to the jthrowable object being carried in the
346    exception header.  */
347
348 tree
349 build_exception_object_ref (type)
350      tree type;
351 {
352   tree obj;
353
354   /* Java only passes object via pointer and doesn't require adjusting.
355      The java object is immediately before the generic exception header.  */
356   obj = build (EXC_PTR_EXPR, build_pointer_type (type));
357   obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
358                TYPE_SIZE_UNIT (TREE_TYPE (obj)));
359   obj = build1 (INDIRECT_REF, type, obj);
360
361   return obj;
362 }
363
364 /* If there are any handlers for this range, isssue end of range,
365    and then all handler blocks */
366 static void
367 expand_end_java_handler (range)
368      struct eh_range *range;
369 {  
370   tree handler = range->handlers;
371   force_poplevels (range->start_pc);
372   expand_start_all_catch ();
373   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
374     {
375       expand_start_catch (TREE_PURPOSE (handler));
376       expand_goto (TREE_VALUE (handler));
377       expand_end_catch ();
378     }
379   expand_end_all_catch ();
380 #if defined(DEBUG_JAVA_BINDING_LEVELS)
381   indent ();
382   fprintf (stderr, "expand end handler pc %d <-- %d\n",
383            current_pc, range->start_pc);
384 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
385 }
386
387 /* Recursive helper routine for maybe_start_handlers. */
388
389 static void
390 check_start_handlers (range, pc)
391      struct eh_range *range;
392      int pc;
393 {
394   if (range != NULL_EH_RANGE && range->start_pc == pc)
395     {
396       check_start_handlers (range->outer, pc);
397       if (!range->expanded)
398         expand_start_java_handler (range);
399     }
400 }
401
402
403 static struct eh_range *current_range;
404
405 /* Emit any start-of-try-range starting at start_pc and ending after
406    end_pc. */
407
408 void
409 maybe_start_try (start_pc, end_pc)
410      int start_pc;
411      int end_pc;
412 {
413   struct eh_range *range;
414   if (! doing_eh (1))
415     return;
416
417   range = find_handler (start_pc);
418   while (range != NULL_EH_RANGE && range->start_pc == start_pc
419          && range->end_pc < end_pc)
420     range = range->outer;
421          
422   current_range = range;
423   check_start_handlers (range, start_pc);
424 }
425
426 /* Emit any end-of-try-range ending at end_pc and starting before
427    start_pc. */
428
429 void
430 maybe_end_try (start_pc, end_pc)
431      int start_pc;
432      int end_pc;
433 {
434   if (! doing_eh (1))
435     return;
436
437   while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
438          && current_range->start_pc >= start_pc)
439     {
440       expand_end_java_handler (current_range);
441       current_range = current_range->outer;
442     }
443 }