OSDN Git Service

2004-12-03 Andrew Haley <aph@redhat.com>
[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, 2002, 2003, 2004
3    Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21
22 Java and all Java-based marks are trademarks or registered trademarks
23 of Sun Microsystems, Inc. in the United States and other countries.
24 The Free Software Foundation is independent of Sun Microsystems, Inc.  */
25
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "tree.h"
31 #include "real.h"
32 #include "rtl.h"
33 #include "java-tree.h"
34 #include "javaop.h"
35 #include "java-opcodes.h"
36 #include "jcf.h"
37 #include "function.h"
38 #include "except.h"
39 #include "java-except.h"
40 #include "toplev.h"
41
42 static void expand_start_java_handler (struct eh_range *);
43 static struct eh_range *find_handler_in_range (int, struct eh_range *,
44                                                struct eh_range *);
45 static void link_handler (struct eh_range *, struct eh_range *);
46 static void check_start_handlers (struct eh_range *, int);
47 static void free_eh_ranges (struct eh_range *range);
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 extern int binding_depth;
67 extern int is_class_level;
68 extern 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 (int pc, struct eh_range *range, struct eh_range *child)
80 {
81   for (; child != NULL;  child = child->next_sibling)
82     {
83       if (pc < child->start_pc)
84         break;
85       if (pc < child->end_pc)
86         return find_handler_in_range (pc, child, child->first_child);
87     }
88   cache_range = range;
89   cache_range_start = pc;
90   cache_next_child = child;
91   cache_range_end = child == NULL ? range->end_pc : child->start_pc;
92   return range;
93 }
94
95 /* Find the inner-most handler that contains PC. */
96
97 struct eh_range *
98 find_handler (int pc)
99 {
100   struct eh_range *h;
101   if (pc >= cache_range_start)
102     {
103       h = cache_range;
104       if (pc < cache_range_end)
105         return h;
106       while (pc >= h->end_pc)
107         {
108           cache_next_child = h->next_sibling;
109           h = h->outer;
110         }
111     }
112   else
113     {
114       h = &whole_range;
115       cache_next_child = h->first_child;
116     }
117   return find_handler_in_range (pc, h, cache_next_child);
118 }
119
120 /* Recursive helper routine for check_nested_ranges. */
121
122 static void
123 link_handler (struct eh_range *range, struct eh_range *outer)
124 {
125   struct eh_range **ptr;
126
127   if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
128     {
129       outer->handlers = chainon (outer->handlers, range->handlers);
130       return;
131     }
132
133   /* If the new range completely encloses the `outer' range, then insert it
134      between the outer range and its parent.  */
135   if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
136     {
137       range->outer = outer->outer;
138       range->next_sibling = NULL;
139       range->first_child = outer;
140       {
141         struct eh_range *p = outer;
142         struct eh_range **pr = &(outer->outer->first_child);
143         while (*pr != outer)
144           pr = &(*pr)->next_sibling;
145         *pr = range;
146
147         while (p)
148           {
149             p->outer = range;
150             p = p->next_sibling;
151           }
152       }
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 = 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       h->expanded = 0;
178       h->stmt = NULL;
179       /* Restart both from the top to avoid having to make this
180          function smart about reentrancy.  */
181       link_handler (h, &whole_range);
182       link_handler (range, &whole_range);
183       return;
184     }
185
186   ptr = &outer->first_child;
187   for (;; ptr = &(*ptr)->next_sibling)
188     {
189       if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
190         {
191           range->next_sibling = *ptr;
192           range->first_child = NULL;
193           range->outer = outer;
194           *ptr = range;
195           return;
196         }
197       else if (range->start_pc < (*ptr)->end_pc)
198         {
199           link_handler (range, *ptr);
200           return;
201         }
202       /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
203     }
204 }
205
206 /* The first pass of exception range processing (calling add_handler)
207    constructs a linked list of exception ranges.  We turn this into
208    the data structure expected by the rest of the code, and also
209    ensure that exception ranges are properly nested.  */
210
211 void
212 handle_nested_ranges (void)
213 {
214   struct eh_range *ptr, *next;
215
216   ptr = whole_range.first_child;
217   whole_range.first_child = NULL;
218   for (; ptr; ptr = next)
219     {
220       next = ptr->next_sibling;
221       ptr->next_sibling = NULL;
222       link_handler (ptr, &whole_range);
223     }
224 }
225
226 /* Free RANGE as well as its children and siblings.  */
227
228 static void
229 free_eh_ranges (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 (void)
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 }
254
255 /* Add an exception range.  If we already have an exception range
256    which has the same handler and label, and the new range overlaps
257    that one, then we simply extend the existing range.  Some bytecode
258    obfuscators generate seemingly nonoverlapping exception ranges
259    which, when coalesced, do in fact nest correctly.
260    
261    This constructs an ordinary linked list which check_nested_ranges()
262    later turns into the data structure we actually want.
263    
264    We expect the input to come in order of increasing START_PC.  This
265    function doesn't attempt to detect the case where two previously
266    added disjoint ranges could be coalesced by a new range; that is
267    what the sorting counteracts.  */
268
269 void
270 add_handler (int start_pc, int end_pc, tree handler, tree type)
271 {
272   struct eh_range *ptr, *prev = NULL, *h;
273
274   for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
275     {
276       if (start_pc >= ptr->start_pc
277           && start_pc <= ptr->end_pc
278           && TREE_PURPOSE (ptr->handlers) == type
279           && TREE_VALUE (ptr->handlers) == handler)
280         {
281           /* Already found an overlapping range, so coalesce.  */
282           ptr->end_pc = MAX (ptr->end_pc, end_pc);
283           return;
284         }
285       prev = ptr;
286     }
287
288   h = xmalloc (sizeof (struct eh_range));
289   h->start_pc = start_pc;
290   h->end_pc = end_pc;
291   h->first_child = NULL;
292   h->outer = NULL;
293   h->handlers = build_tree_list (type, handler);
294   h->next_sibling = NULL;
295   h->expanded = 0;
296   h->stmt = NULL;
297
298   if (prev == NULL)
299     whole_range.first_child = h;
300   else
301     prev->next_sibling = h;
302 }
303
304 /* if there are any handlers for this range, issue start of region */
305 static void
306 expand_start_java_handler (struct eh_range *range)
307 {
308 #if defined(DEBUG_JAVA_BINDING_LEVELS)
309   indent ();
310   fprintf (stderr, "expand start handler pc %d --> %d\n",
311            current_pc, range->end_pc);
312 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
313   pushlevel (0);
314   register_exception_range (range,  range->start_pc, range->end_pc);
315   range->expanded = 1;
316 }
317
318 tree
319 prepare_eh_table_type (tree type)
320 {
321   tree exp;
322   tree *slot;
323   const char *name;
324   char *buf;
325   tree decl;
326   tree utf8_ref;
327
328   /* The "type" (match_info) in a (Java) exception table is a pointer to:
329    * a) NULL - meaning match any type in a try-finally.
330    * b) a pointer to a pointer to a class.
331    * c) a pointer to a pointer to a utf8_ref.  The pointer is
332    * rewritten to point to the appropriate class.  */
333
334   if (type == NULL_TREE)
335     return NULL_TREE;
336
337   if (TYPE_TO_RUNTIME_MAP (output_class) == NULL)
338     TYPE_TO_RUNTIME_MAP (output_class) = java_treetreehash_create (10, 1);
339   
340   slot = java_treetreehash_new (TYPE_TO_RUNTIME_MAP (output_class), type);
341   if (*slot != NULL)
342     return TREE_VALUE (*slot);
343
344   if (is_compiled_class (type) && !flag_indirect_dispatch)
345     {
346       name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
347       buf = alloca (strlen (name) + 5);
348       sprintf (buf, "%s_ref", name);
349       decl = build_decl (VAR_DECL, get_identifier (buf), ptr_type_node);
350       TREE_STATIC (decl) = 1;
351       DECL_ARTIFICIAL (decl) = 1;
352       DECL_IGNORED_P (decl) = 1;
353       TREE_READONLY (decl) = 1;
354       TREE_THIS_VOLATILE (decl) = 0;
355       DECL_INITIAL (decl) = build_class_ref (type);
356       layout_decl (decl, 0);
357       pushdecl (decl);
358       exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl);
359     }
360   else
361     {
362       utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type)));
363       name = IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0)));
364       buf = alloca (strlen (name) + 5);
365       sprintf (buf, "%s_ref", name);
366       decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_ptr_type);
367       TREE_STATIC (decl) = 1;
368       DECL_ARTIFICIAL (decl) = 1;
369       DECL_IGNORED_P (decl) = 1;
370       TREE_READONLY (decl) = 1;
371       TREE_THIS_VOLATILE (decl) = 0;
372       layout_decl (decl, 0);
373       pushdecl (decl);
374       exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl);
375       TYPE_CATCH_CLASSES (output_class) = 
376         tree_cons (NULL, make_catch_class_record (exp, utf8_ref), 
377                    TYPE_CATCH_CLASSES (output_class));
378     }
379
380   exp = convert (ptr_type_node, exp);
381
382   *slot = tree_cons (type, exp, NULL_TREE);
383
384   return exp;
385 }
386
387 static int
388 expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED)
389 {
390   struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
391   tree addr = TREE_VALUE ((tree)ite->value);
392   tree decl;
393   STRIP_NOPS (addr);
394   decl = TREE_OPERAND (addr, 0);
395   rest_of_decl_compilation (decl, global_bindings_p (), 0);
396   return true;
397 }
398   
399 /* For every class in the TYPE_TO_RUNTIME_MAP, expand the
400    corresponding object that is used by the runtime type matcher.  */
401
402 void
403 java_expand_catch_classes (tree this_class)
404 {
405   if (TYPE_TO_RUNTIME_MAP (this_class))
406     htab_traverse 
407       (TYPE_TO_RUNTIME_MAP (this_class),
408        expand_catch_class, NULL);
409 }
410
411 /* Build a reference to the jthrowable object being carried in the
412    exception header.  */
413
414 tree
415 build_exception_object_ref (tree type)
416 {
417   tree obj;
418
419   /* Java only passes object via pointer and doesn't require adjusting.
420      The java object is immediately before the generic exception header.  */
421   obj = build0 (EXC_PTR_EXPR, build_pointer_type (type));
422   obj = build2 (MINUS_EXPR, TREE_TYPE (obj), obj,
423                 TYPE_SIZE_UNIT (TREE_TYPE (obj)));
424   obj = build1 (INDIRECT_REF, type, obj);
425
426   return obj;
427 }
428
429 /* If there are any handlers for this range, isssue end of range,
430    and then all handler blocks */
431 void
432 expand_end_java_handler (struct eh_range *range)
433 {  
434   tree handler = range->handlers;
435
436   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
437     {
438       /* For bytecode we treat exceptions a little unusually.  A
439          `finally' clause looks like an ordinary exception handler for
440          Throwable.  The reason for this is that the bytecode has
441          already expanded the finally logic, and we would have to do
442          extra (and difficult) work to get this to look like a
443          gcc-style finally clause.  */
444       tree type = TREE_PURPOSE (handler);
445       if (type == NULL)
446         type = throwable_type_node;
447       type = prepare_eh_table_type (type);
448
449       {
450         tree catch_expr = build2 (CATCH_EXPR, void_type_node, type,
451                                   build1 (GOTO_EXPR, void_type_node,
452                                           TREE_VALUE (handler)));
453         tree try_catch_expr = build2 (TRY_CATCH_EXPR, void_type_node,
454                                       *get_stmts (), catch_expr);       
455         *get_stmts () = try_catch_expr;
456       }
457     }
458 #if defined(DEBUG_JAVA_BINDING_LEVELS)
459   indent ();
460   fprintf (stderr, "expand end handler pc %d <-- %d\n",
461            current_pc, range->start_pc);
462 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
463 }
464
465 /* Recursive helper routine for maybe_start_handlers. */
466
467 static void
468 check_start_handlers (struct eh_range *range, int pc)
469 {
470   if (range != NULL_EH_RANGE && range->start_pc == pc)
471     {
472       check_start_handlers (range->outer, pc);
473       if (!range->expanded)
474         expand_start_java_handler (range);
475     }
476 }
477
478
479 static struct eh_range *current_range;
480
481 /* Emit any start-of-try-range starting at start_pc and ending after
482    end_pc. */
483
484 void
485 maybe_start_try (int start_pc, int end_pc)
486 {
487   struct eh_range *range;
488   if (! doing_eh (1))
489     return;
490
491   range = find_handler (start_pc);
492   while (range != NULL_EH_RANGE && range->start_pc == start_pc
493          && range->end_pc < end_pc)
494     range = range->outer;
495          
496   current_range = range;
497   check_start_handlers (range, start_pc);
498 }
499