OSDN Git Service

* expr.h (expand_expr): Make it a macro, not a function.
[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       /* Restart both from the top to avoid having to make this
174          function smart about reentrancy.  */
175       link_handler (h, &whole_range);
176       link_handler (range, &whole_range);
177       return;
178     }
179
180   ptr = &outer->first_child;
181   for (;; ptr = &(*ptr)->next_sibling)
182     {
183       if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
184         {
185           range->next_sibling = *ptr;
186           range->first_child = NULL;
187           range->outer = outer;
188           *ptr = range;
189           return;
190         }
191       else if (range->start_pc < (*ptr)->end_pc)
192         {
193           link_handler (range, *ptr);
194           return;
195         }
196       /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
197     }
198 }
199
200 /* The first pass of exception range processing (calling add_handler)
201    constructs a linked list of exception ranges.  We turn this into
202    the data structure expected by the rest of the code, and also
203    ensure that exception ranges are properly nested.  */
204
205 void
206 handle_nested_ranges (void)
207 {
208   struct eh_range *ptr, *next;
209
210   ptr = whole_range.first_child;
211   whole_range.first_child = NULL;
212   for (; ptr; ptr = next)
213     {
214       next = ptr->next_sibling;
215       ptr->next_sibling = NULL;
216       link_handler (ptr, &whole_range);
217     }
218 }
219
220 /* Free RANGE as well as its children and siblings.  */
221
222 static void
223 free_eh_ranges (struct eh_range *range)
224 {
225   while (range) 
226     {
227       struct eh_range *next = range->next_sibling;
228       free_eh_ranges (range->first_child);
229       if (range != &whole_range)
230         free (range);
231       range = next;
232     }
233 }
234
235 /* Called to re-initialize the exception machinery for a new method. */
236
237 void
238 method_init_exceptions (void)
239 {
240   free_eh_ranges (&whole_range);
241   whole_range.start_pc = 0;
242   whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
243   whole_range.outer = NULL;
244   whole_range.first_child = NULL;
245   whole_range.next_sibling = NULL;
246   cache_range_start = 0xFFFFFF;
247 }
248
249 /* Add an exception range.  If we already have an exception range
250    which has the same handler and label, and the new range overlaps
251    that one, then we simply extend the existing range.  Some bytecode
252    obfuscators generate seemingly nonoverlapping exception ranges
253    which, when coalesced, do in fact nest correctly.
254    
255    This constructs an ordinary linked list which check_nested_ranges()
256    later turns into the data structure we actually want.
257    
258    We expect the input to come in order of increasing START_PC.  This
259    function doesn't attempt to detect the case where two previously
260    added disjoint ranges could be coalesced by a new range; that is
261    what the sorting counteracts.  */
262
263 void
264 add_handler (int start_pc, int end_pc, tree handler, 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 = xmalloc (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 (struct eh_range *range)
301 {
302 #if defined(DEBUG_JAVA_BINDING_LEVELS)
303   indent ();
304   fprintf (stderr, "expand start handler pc %d --> %d\n",
305            current_pc, range->end_pc);
306 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
307   range->expanded = 1;
308   expand_eh_region_start ();
309 }
310
311 tree
312 prepare_eh_table_type (tree type)
313 {
314   tree exp;
315   tree *slot;
316   const char *name;
317   char *buf;
318   tree decl;
319   tree utf8_ref;
320
321   /* The "type" (match_info) in a (Java) exception table is a pointer to:
322    * a) NULL - meaning match any type in a try-finally.
323    * b) a pointer to a pointer to a class.
324    * c) a pointer to a pointer to a utf8_ref.  The pointer is
325    * rewritten to point to the appropriate class.  */
326
327   if (type == NULL_TREE)
328     return NULL_TREE;
329
330   if (TYPE_TO_RUNTIME_MAP (output_class) == NULL)
331     TYPE_TO_RUNTIME_MAP (output_class) = java_treetreehash_create (10, 1);
332   
333   slot = java_treetreehash_new (TYPE_TO_RUNTIME_MAP (output_class), type);
334   if (*slot != NULL)
335     return TREE_VALUE (*slot);
336
337   if (is_compiled_class (type) && !flag_indirect_dispatch)
338     {
339       name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
340       buf = alloca (strlen (name) + 5);
341       sprintf (buf, "%s_ref", name);
342       decl = build_decl (VAR_DECL, get_identifier (buf), ptr_type_node);
343       TREE_STATIC (decl) = 1;
344       DECL_ARTIFICIAL (decl) = 1;
345       DECL_IGNORED_P (decl) = 1;
346       TREE_READONLY (decl) = 1;
347       TREE_THIS_VOLATILE (decl) = 0;
348       DECL_INITIAL (decl) = build_class_ref (type);
349       layout_decl (decl, 0);
350       pushdecl (decl);
351       exp = build1 (ADDR_EXPR, ptr_type_node, decl);
352     }
353   else
354     {
355       utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type)));
356       name = IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0)));
357       buf = alloca (strlen (name) + 5);
358       sprintf (buf, "%s_ref", name);
359       decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_ptr_type);
360       TREE_STATIC (decl) = 1;
361       DECL_ARTIFICIAL (decl) = 1;
362       DECL_IGNORED_P (decl) = 1;
363       TREE_READONLY (decl) = 1;
364       TREE_THIS_VOLATILE (decl) = 0;
365       layout_decl (decl, 0);
366       pushdecl (decl);
367       exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl);
368       TYPE_CATCH_CLASSES (output_class) = 
369         tree_cons (NULL, make_catch_class_record (exp, utf8_ref), 
370                    TYPE_CATCH_CLASSES (output_class));
371     }
372
373   *slot = tree_cons (type, exp, NULL_TREE);
374
375   return exp;
376 }
377
378 static int
379 expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED)
380 {
381   struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
382   tree decl = TREE_OPERAND (TREE_VALUE ((tree)ite->value), 0);
383   rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
384   return true;
385 }
386   
387 /* For every class in the TYPE_TO_RUNTIME_MAP, expand the
388    corresponding object that is used by the runtime type matcher.  */
389
390 void
391 java_expand_catch_classes (tree this_class)
392 {
393   if (TYPE_TO_RUNTIME_MAP (this_class))
394     htab_traverse 
395       (TYPE_TO_RUNTIME_MAP (this_class),
396        expand_catch_class, NULL);
397 }
398
399 /* Build a reference to the jthrowable object being carried in the
400    exception header.  */
401
402 tree
403 build_exception_object_ref (tree type)
404 {
405   tree obj;
406
407   /* Java only passes object via pointer and doesn't require adjusting.
408      The java object is immediately before the generic exception header.  */
409   obj = build (EXC_PTR_EXPR, build_pointer_type (type));
410   obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
411                TYPE_SIZE_UNIT (TREE_TYPE (obj)));
412   obj = build1 (INDIRECT_REF, type, obj);
413
414   return obj;
415 }
416
417 /* If there are any handlers for this range, isssue end of range,
418    and then all handler blocks */
419 static void
420 expand_end_java_handler (struct eh_range *range)
421 {  
422   tree handler = range->handlers;
423   force_poplevels (range->start_pc);
424   expand_start_all_catch ();
425   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
426     {
427       /* For bytecode we treat exceptions a little unusually.  A
428          `finally' clause looks like an ordinary exception handler for
429          Throwable.  The reason for this is that the bytecode has
430          already expanded the finally logic, and we would have to do
431          extra (and difficult) work to get this to look like a
432          gcc-style finally clause.  */
433       tree type = TREE_PURPOSE (handler);
434       if (type == NULL)
435         type = throwable_type_node;
436
437       expand_start_catch (prepare_eh_table_type (type));
438       expand_goto (TREE_VALUE (handler));
439       expand_end_catch ();
440     }
441   expand_end_all_catch ();
442 #if defined(DEBUG_JAVA_BINDING_LEVELS)
443   indent ();
444   fprintf (stderr, "expand end handler pc %d <-- %d\n",
445            current_pc, range->start_pc);
446 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
447 }
448
449 /* Recursive helper routine for maybe_start_handlers. */
450
451 static void
452 check_start_handlers (struct eh_range *range, int pc)
453 {
454   if (range != NULL_EH_RANGE && range->start_pc == pc)
455     {
456       check_start_handlers (range->outer, pc);
457       if (!range->expanded)
458         expand_start_java_handler (range);
459     }
460 }
461
462
463 static struct eh_range *current_range;
464
465 /* Emit any start-of-try-range starting at start_pc and ending after
466    end_pc. */
467
468 void
469 maybe_start_try (int start_pc, int end_pc)
470 {
471   struct eh_range *range;
472   if (! doing_eh (1))
473     return;
474
475   range = find_handler (start_pc);
476   while (range != NULL_EH_RANGE && range->start_pc == start_pc
477          && range->end_pc < end_pc)
478     range = range->outer;
479          
480   current_range = range;
481   check_start_handlers (range, start_pc);
482 }
483
484 /* Emit any end-of-try-range ending at end_pc and starting before
485    start_pc. */
486
487 void
488 maybe_end_try (int start_pc, int end_pc)
489 {
490   if (! doing_eh (1))
491     return;
492
493   while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
494          && current_range->start_pc >= start_pc)
495     {
496       expand_end_java_handler (current_range);
497       current_range = current_range->outer;
498     }
499 }