OSDN Git Service

b77842e8a662a5a6722a5e320439fa1232918b1a
[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 void expand_end_java_handler (struct eh_range *);
44 static struct eh_range *find_handler_in_range (int, struct eh_range *,
45                                                struct eh_range *);
46 static void link_handler (struct eh_range *, struct eh_range *);
47 static void check_start_handlers (struct eh_range *, int);
48 static void free_eh_ranges (struct eh_range *range);
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 extern int binding_depth;
68 extern int is_class_level;
69 extern 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 (int pc, struct eh_range *range, struct eh_range *child)
81 {
82   for (; child != NULL;  child = child->next_sibling)
83     {
84       if (pc < child->start_pc)
85         break;
86       if (pc < child->end_pc)
87         return find_handler_in_range (pc, child, child->first_child);
88     }
89   cache_range = range;
90   cache_range_start = pc;
91   cache_next_child = child;
92   cache_range_end = child == NULL ? range->end_pc : child->start_pc;
93   return range;
94 }
95
96 /* Find the inner-most handler that contains PC. */
97
98 struct eh_range *
99 find_handler (int pc)
100 {
101   struct eh_range *h;
102   if (pc >= cache_range_start)
103     {
104       h = cache_range;
105       if (pc < cache_range_end)
106         return h;
107       while (pc >= h->end_pc)
108         {
109           cache_next_child = h->next_sibling;
110           h = h->outer;
111         }
112     }
113   else
114     {
115       h = &whole_range;
116       cache_next_child = h->first_child;
117     }
118   return find_handler_in_range (pc, h, cache_next_child);
119 }
120
121 /* Recursive helper routine for check_nested_ranges. */
122
123 static void
124 link_handler (struct eh_range *range, struct eh_range *outer)
125 {
126   struct eh_range **ptr;
127
128   if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
129     {
130       outer->handlers = chainon (outer->handlers, range->handlers);
131       return;
132     }
133
134   /* If the new range completely encloses the `outer' range, then insert it
135      between the outer range and its parent.  */
136   if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
137     {
138       range->outer = outer->outer;
139       range->next_sibling = NULL;
140       range->first_child = outer;
141       {
142         struct eh_range **pr = &(outer->outer->first_child);
143         while (*pr != outer)
144           pr = &(*pr)->next_sibling;
145         *pr = range;
146       }
147       outer->outer = range;
148       return;
149     }
150
151   /* Handle overlapping ranges by splitting the new range.  */
152   if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
153     {
154       struct eh_range *h = xmalloc (sizeof (struct eh_range));
155       if (range->start_pc < outer->start_pc)
156         {
157           h->start_pc = range->start_pc;
158           h->end_pc = outer->start_pc;
159           range->start_pc = outer->start_pc;
160         }
161       else
162         {
163           h->start_pc = outer->end_pc;
164           h->end_pc = range->end_pc;
165           range->end_pc = outer->end_pc;
166         }
167       h->first_child = NULL;
168       h->outer = NULL;
169       h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
170                                      TREE_VALUE (range->handlers));
171       h->next_sibling = NULL;
172       h->expanded = 0;
173       h->stmt = NULL;
174       /* Restart both from the top to avoid having to make this
175          function smart about reentrancy.  */
176       link_handler (h, &whole_range);
177       link_handler (range, &whole_range);
178       return;
179     }
180
181   ptr = &outer->first_child;
182   for (;; ptr = &(*ptr)->next_sibling)
183     {
184       if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
185         {
186           range->next_sibling = *ptr;
187           range->first_child = NULL;
188           range->outer = outer;
189           *ptr = range;
190           return;
191         }
192       else if (range->start_pc < (*ptr)->end_pc)
193         {
194           link_handler (range, *ptr);
195           return;
196         }
197       /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
198     }
199 }
200
201 /* The first pass of exception range processing (calling add_handler)
202    constructs a linked list of exception ranges.  We turn this into
203    the data structure expected by the rest of the code, and also
204    ensure that exception ranges are properly nested.  */
205
206 void
207 handle_nested_ranges (void)
208 {
209   struct eh_range *ptr, *next;
210
211   ptr = whole_range.first_child;
212   whole_range.first_child = NULL;
213   for (; ptr; ptr = next)
214     {
215       next = ptr->next_sibling;
216       ptr->next_sibling = NULL;
217       link_handler (ptr, &whole_range);
218     }
219 }
220
221 /* Free RANGE as well as its children and siblings.  */
222
223 static void
224 free_eh_ranges (struct eh_range *range)
225 {
226   while (range) 
227     {
228       struct eh_range *next = range->next_sibling;
229       free_eh_ranges (range->first_child);
230       if (range != &whole_range)
231         free (range);
232       range = next;
233     }
234 }
235
236 /* Called to re-initialize the exception machinery for a new method. */
237
238 void
239 method_init_exceptions (void)
240 {
241   free_eh_ranges (&whole_range);
242   whole_range.start_pc = 0;
243   whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
244   whole_range.outer = NULL;
245   whole_range.first_child = NULL;
246   whole_range.next_sibling = NULL;
247   cache_range_start = 0xFFFFFF;
248 }
249
250 /* Add an exception range.  If we already have an exception range
251    which has the same handler and label, and the new range overlaps
252    that one, then we simply extend the existing range.  Some bytecode
253    obfuscators generate seemingly nonoverlapping exception ranges
254    which, when coalesced, do in fact nest correctly.
255    
256    This constructs an ordinary linked list which check_nested_ranges()
257    later turns into the data structure we actually want.
258    
259    We expect the input to come in order of increasing START_PC.  This
260    function doesn't attempt to detect the case where two previously
261    added disjoint ranges could be coalesced by a new range; that is
262    what the sorting counteracts.  */
263
264 void
265 add_handler (int start_pc, int end_pc, tree handler, tree type)
266 {
267   struct eh_range *ptr, *prev = NULL, *h;
268
269   for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
270     {
271       if (start_pc >= ptr->start_pc
272           && start_pc <= ptr->end_pc
273           && TREE_PURPOSE (ptr->handlers) == type
274           && TREE_VALUE (ptr->handlers) == handler)
275         {
276           /* Already found an overlapping range, so coalesce.  */
277           ptr->end_pc = MAX (ptr->end_pc, end_pc);
278           return;
279         }
280       prev = ptr;
281     }
282
283   h = xmalloc (sizeof (struct eh_range));
284   h->start_pc = start_pc;
285   h->end_pc = end_pc;
286   h->first_child = NULL;
287   h->outer = NULL;
288   h->handlers = build_tree_list (type, handler);
289   h->next_sibling = NULL;
290   h->expanded = 0;
291   h->stmt = NULL;
292
293   if (prev == NULL)
294     whole_range.first_child = h;
295   else
296     prev->next_sibling = h;
297 }
298
299 /* if there are any handlers for this range, issue start of region */
300 static void
301 expand_start_java_handler (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   {
309     tree new = build (TRY_CATCH_EXPR, void_type_node, NULL, NULL);
310     TREE_SIDE_EFFECTS (new) = 1;
311     java_add_stmt (build_java_empty_stmt ());
312     range->stmt = java_add_stmt (new);
313   }
314                      
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, (char*) 0, 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 = build (EXC_PTR_EXPR, build_pointer_type (type));
422   obj = build (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 static void
432 expand_end_java_handler (struct eh_range *range)
433 {  
434   tree handler = range->handlers;
435   tree compound = NULL;
436
437   force_poplevels (range->start_pc);  
438   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
439     {
440       /* For bytecode we treat exceptions a little unusually.  A
441          `finally' clause looks like an ordinary exception handler for
442          Throwable.  The reason for this is that the bytecode has
443          already expanded the finally logic, and we would have to do
444          extra (and difficult) work to get this to look like a
445          gcc-style finally clause.  */
446       tree type = TREE_PURPOSE (handler);
447
448       if (type == NULL)
449         type = throwable_type_node;
450
451       type = prepare_eh_table_type (type);
452
453       if (compound)
454         {
455           /* If we already have a COMPOUND there is more than one
456              catch handler for this try block.  Wrap the
457              TRY_CATCH_EXPR in operand 1 of COMPOUND with another
458              TRY_CATCH_EXPR.  */
459           tree inner_try_expr = TREE_OPERAND (compound, 1);
460           tree catch_expr 
461             = build (CATCH_EXPR, void_type_node, type,
462                      build (GOTO_EXPR, void_type_node, TREE_VALUE (handler)));
463           tree try_expr
464             = build (TRY_CATCH_EXPR, void_type_node,
465                      inner_try_expr, catch_expr);
466           TREE_OPERAND (compound, 1) = try_expr;
467         }
468       else
469         {
470           tree *stmts = get_stmts ();
471           tree outer;
472           tree try_expr;
473           compound = range->stmt;
474           outer = TREE_OPERAND (compound, 0);
475           try_expr = TREE_OPERAND (compound, 1);
476           /* On the left of COMPOUND is the expresion to be evaluated
477              before the try handler is entered; on the right is a
478              TRY_FINALLY_EXPR with no operands as yet.  In the current
479              statement list is an expression that we're going to move
480              inside the try handler.  We'll create a new COMPOUND_EXPR
481              with the outer context on the left and the TRY_FINALLY_EXPR
482              on the right, then nullify both operands of COMPOUND, which
483              becomes the final expression in OUTER.  This new compound
484              expression replaces the current statement list.  */
485           TREE_OPERAND (try_expr, 0) = *stmts;
486           TREE_OPERAND (try_expr, 1)
487             = build (CATCH_EXPR, void_type_node, type,
488                      build (GOTO_EXPR, void_type_node, TREE_VALUE (handler)));
489           TREE_SIDE_EFFECTS (try_expr) = 1;
490           TREE_OPERAND (compound, 0) = build_java_empty_stmt ();
491           TREE_OPERAND (compound, 1) = build_java_empty_stmt ();
492           compound 
493             = build (COMPOUND_EXPR, TREE_TYPE (try_expr), outer, try_expr);
494           *stmts = compound;
495         }
496     }
497 #if defined(DEBUG_JAVA_BINDING_LEVELS)
498   indent ();
499   fprintf (stderr, "expand end handler pc %d <-- %d\n",
500            current_pc, range->start_pc);
501 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
502 }
503
504 /* Recursive helper routine for maybe_start_handlers. */
505
506 static void
507 check_start_handlers (struct eh_range *range, int pc)
508 {
509   if (range != NULL_EH_RANGE && range->start_pc == pc)
510     {
511       check_start_handlers (range->outer, pc);
512       if (!range->expanded)
513         expand_start_java_handler (range);
514     }
515 }
516
517
518 static struct eh_range *current_range;
519
520 /* Emit any start-of-try-range starting at start_pc and ending after
521    end_pc. */
522
523 void
524 maybe_start_try (int start_pc, int end_pc)
525 {
526   struct eh_range *range;
527   if (! doing_eh (1))
528     return;
529
530   range = find_handler (start_pc);
531   while (range != NULL_EH_RANGE && range->start_pc == start_pc
532          && range->end_pc < end_pc)
533     range = range->outer;
534          
535   current_range = range;
536   check_start_handlers (range, start_pc);
537 }
538
539 /* Emit any end-of-try-range ending at end_pc and starting before
540    start_pc. */
541
542 void
543 maybe_end_try (int start_pc, int end_pc)
544 {
545   if (! doing_eh (1))
546     return;
547
548   while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
549          && current_range->start_pc >= start_pc)
550     {
551       expand_end_java_handler (current_range);
552       current_range = current_range->outer;
553     }
554 }