OSDN Git Service

PR 44103
[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, 2005,
3    2007, 2008, 2009 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 3, 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 COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.
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 "coretypes.h"
28 #include "tm.h"
29 #include "tree.h"
30 #include "real.h"
31 #include "rtl.h"
32 #include "java-tree.h"
33 #include "javaop.h"
34 #include "java-opcodes.h"
35 #include "jcf.h"
36 #include "function.h"
37 #include "except.h"
38 #include "java-except.h"
39 #include "toplev.h"
40 #include "tree-iterator.h"
41
42
43 static void expand_start_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 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 /* These variables are used to speed up find_handler. */
54
55 static int cache_range_start, cache_range_end;
56 static struct eh_range *cache_range;
57 static struct eh_range *cache_next_child;
58
59 /* A dummy range that represents the entire method. */
60
61 struct eh_range whole_range;
62
63 /* Check the invariants of the structure we're using to contain
64    exception regions.  Either returns true or fails an assertion
65    check.  */
66
67 bool
68 sanity_check_exception_range (struct eh_range *range)
69 {
70   struct eh_range *ptr = range->first_child;
71   for (; ptr; ptr = ptr->next_sibling)
72     {
73       gcc_assert (ptr->outer == range
74                   && ptr->end_pc > ptr->start_pc);
75       if (ptr->next_sibling)
76         gcc_assert (ptr->next_sibling->start_pc >= ptr->end_pc);
77       gcc_assert (ptr->start_pc >= ptr->outer->start_pc
78                   && ptr->end_pc <=  ptr->outer->end_pc);
79       (void) sanity_check_exception_range (ptr);
80     }
81   return true;
82 }
83
84 #if defined(DEBUG_JAVA_BINDING_LEVELS)
85 extern int is_class_level;
86 extern int current_pc;
87 extern int binding_depth;
88 extern void indent (void);
89 static void
90 print_ranges (struct eh_range *range)
91 {
92   if (! range)
93     return;
94
95   struct eh_range *child = range->first_child;
96   
97   indent ();
98   fprintf (stderr, "handler pc %d --> %d ", range->start_pc, range->end_pc);
99   
100   tree handler = range->handlers;
101   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
102     {
103       tree type = TREE_PURPOSE (handler);
104       if (type == NULL)
105         type = throwable_type_node;
106       fprintf (stderr, " type=%s ", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
107     }
108   fprintf (stderr, "\n");
109
110   int saved = binding_depth;
111   binding_depth++;
112   print_ranges (child);
113   binding_depth = saved;
114
115   print_ranges (range->next_sibling);
116 }
117 #endif
118
119 /* Search for the most specific eh_range containing PC.
120    Assume PC is within RANGE.
121    CHILD is a list of children of RANGE such that any
122    previous children have end_pc values that are too low. */
123
124 static struct eh_range *
125 find_handler_in_range (int pc, struct eh_range *range, struct eh_range *child)
126 {
127   for (; child != NULL;  child = child->next_sibling)
128     {
129       if (pc < child->start_pc)
130         break;
131       if (pc < child->end_pc)
132         return find_handler_in_range (pc, child, child->first_child);
133     }
134   cache_range = range;
135   cache_range_start = pc;
136   cache_next_child = child;
137   cache_range_end = child == NULL ? range->end_pc : child->start_pc;
138   return range;
139 }
140
141 /* Find the inner-most handler that contains PC. */
142
143 struct eh_range *
144 find_handler (int pc)
145 {
146   struct eh_range *h;
147   if (pc >= cache_range_start)
148     {
149       h = cache_range;
150       if (pc < cache_range_end)
151         return h;
152       while (pc >= h->end_pc)
153         {
154           cache_next_child = h->next_sibling;
155           h = h->outer;
156         }
157     }
158   else
159     {
160       h = &whole_range;
161       cache_next_child = h->first_child;
162     }
163   return find_handler_in_range (pc, h, cache_next_child);
164 }
165
166 static void
167 free_eh_ranges (struct eh_range *range)
168 {
169   while (range) 
170     {
171       struct eh_range *next = range->next_sibling;
172       free_eh_ranges (range->first_child);
173       if (range != &whole_range)
174         free (range);
175       range = next;
176     }
177 }
178
179 /* Called to re-initialize the exception machinery for a new method. */
180
181 void
182 method_init_exceptions (void)
183 {
184   free_eh_ranges (&whole_range);
185   whole_range.start_pc = 0;
186   whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
187   whole_range.outer = NULL;
188   whole_range.first_child = NULL;
189   whole_range.next_sibling = NULL;
190   cache_range_start = 0xFFFFFF;
191 }
192
193 /* Split an exception range into two at PC.  The sub-ranges that
194    belong to the range are split and distributed between the two new
195    ranges.  */
196
197 static void
198 split_range (struct eh_range *range, int pc)
199 {
200   struct eh_range *ptr;
201   struct eh_range **first_child, **second_child;
202   struct eh_range *h;
203
204   /* First, split all the sub-ranges.  */
205   for (ptr = range->first_child; ptr; ptr = ptr->next_sibling)
206     {
207       if (pc > ptr->start_pc
208           && pc < ptr->end_pc)
209         {
210           split_range (ptr, pc);
211         }
212     }
213
214   /* Create a new range.  */
215   h = XNEW (struct eh_range);
216
217   h->start_pc = pc;
218   h->end_pc = range->end_pc;
219   h->next_sibling = range->next_sibling;
220   range->next_sibling = h;
221   range->end_pc = pc;
222   h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
223                                  TREE_VALUE (range->handlers));
224   h->next_sibling = NULL;
225   h->expanded = 0;
226   h->stmt = NULL;
227   h->outer = range->outer;
228   h->first_child = NULL;
229
230   ptr = range->first_child;
231   first_child = &range->first_child;
232   second_child = &h->first_child;
233
234   /* Distribute the sub-ranges between the two new ranges.  */
235   for (ptr = range->first_child; ptr; ptr = ptr->next_sibling)
236     {
237       if (ptr->start_pc < pc)
238         {
239           *first_child = ptr;
240           ptr->outer = range;
241           first_child = &ptr->next_sibling;
242         }
243       else
244         {
245           *second_child = ptr;
246           ptr->outer = h;
247           second_child = &ptr->next_sibling;
248         }
249     }
250   *first_child = NULL;
251   *second_child = NULL;
252 }  
253
254
255 /* Add an exception range. 
256
257    There are some missed optimization opportunities here.  For
258    example, some bytecode obfuscators generate seemingly
259    nonoverlapping exception ranges which, when coalesced, do in fact
260    nest correctly.  We could merge these, but we'd have to fix up all
261    the enclosed regions first and perhaps create a new range anyway if
262    it overlapped existing ranges.
263    
264    Also, we don't attempt to detect the case where two previously
265    added disjoint ranges could be coalesced by a new range.  */
266
267 void 
268 add_handler (int start_pc, int end_pc, tree handler, tree type)
269 {
270   struct eh_range *ptr, *h;
271   struct eh_range **first_child, **prev;
272
273   /* First, split all the existing ranges that we need to enclose.  */
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         {
279           split_range (ptr, start_pc);
280         }
281
282       if (end_pc > ptr->start_pc
283           && end_pc < ptr->end_pc)
284         {
285           split_range (ptr, end_pc);
286         }
287
288       if (ptr->start_pc >= end_pc)
289         break;
290     }
291
292   /* Create the new range.  */
293   h = XNEW (struct eh_range);
294   first_child = &h->first_child;
295
296   h->start_pc = start_pc;
297   h->end_pc = end_pc;
298   h->first_child = NULL;
299   h->outer = NULL_EH_RANGE;
300   h->handlers = build_tree_list (type, handler);
301   h->next_sibling = NULL;
302   h->expanded = 0;
303   h->stmt = NULL;
304
305   /* Find every range at the top level that will be a sub-range of the
306      range we're inserting and make it so.  */
307   {
308     struct eh_range **prev = &whole_range.first_child;
309     for (ptr = *prev; ptr;)
310       {
311         struct eh_range *next = ptr->next_sibling;
312
313         if (ptr->start_pc >= end_pc)
314           break;
315
316         if (ptr->start_pc < start_pc)
317           {
318             prev = &ptr->next_sibling;
319           }
320         else if (ptr->start_pc >= start_pc
321                  && ptr->start_pc < end_pc)
322           {
323             *prev = next;
324             *first_child = ptr;
325             first_child = &ptr->next_sibling;
326             ptr->outer = h;
327             ptr->next_sibling = NULL;     
328           }
329
330         ptr = next;
331       }
332   }
333
334   /* Find the right place to insert the new range.  */
335   prev = &whole_range.first_child;
336   for (ptr = *prev; ptr; prev = &ptr->next_sibling, ptr = ptr->next_sibling)
337     {
338       gcc_assert (ptr->outer == NULL_EH_RANGE);
339       if (ptr->start_pc >= start_pc)
340         break;
341     }
342
343   /* And insert it there.  */
344   *prev = h;
345   if (ptr)
346     {
347       h->next_sibling = ptr;
348       h->outer = ptr->outer;
349     }
350 }
351       
352   
353 /* if there are any handlers for this range, issue start of region */
354 static void
355 expand_start_java_handler (struct eh_range *range)
356 {
357 #if defined(DEBUG_JAVA_BINDING_LEVELS)
358   indent ();
359   fprintf (stderr, "expand start handler pc %d --> %d\n",
360            current_pc, range->end_pc);
361 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
362   pushlevel (0);
363   register_exception_range (range,  range->start_pc, range->end_pc);
364   range->expanded = 1;
365 }
366
367 tree
368 prepare_eh_table_type (tree type)
369 {
370   tree exp;
371   tree *slot;
372   const char *name;
373   char *buf;
374   tree decl;
375   tree utf8_ref;
376
377   /* The "type" (match_info) in a (Java) exception table is a pointer to:
378    * a) NULL - meaning match any type in a try-finally.
379    * b) a pointer to a pointer to a class.
380    * c) a pointer to a pointer to a utf8_ref.  The pointer is
381    * rewritten to point to the appropriate class.  */
382
383   if (type == NULL_TREE)
384     return NULL_TREE;
385
386   if (TYPE_TO_RUNTIME_MAP (output_class) == NULL)
387     TYPE_TO_RUNTIME_MAP (output_class) = java_treetreehash_create (10, 1);
388   
389   slot = java_treetreehash_new (TYPE_TO_RUNTIME_MAP (output_class), type);
390   if (*slot != NULL)
391     return TREE_VALUE (*slot);
392
393   if (is_compiled_class (type) && !flag_indirect_dispatch)
394     {
395       name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
396       buf = (char *) alloca (strlen (name) + 5);
397       sprintf (buf, "%s_ref", name);
398       decl = build_decl (input_location,
399                          VAR_DECL, get_identifier (buf), ptr_type_node);
400       TREE_STATIC (decl) = 1;
401       DECL_ARTIFICIAL (decl) = 1;
402       DECL_IGNORED_P (decl) = 1;
403       TREE_READONLY (decl) = 1;
404       TREE_THIS_VOLATILE (decl) = 0;
405       DECL_INITIAL (decl) = build_class_ref (type);
406       layout_decl (decl, 0);
407       pushdecl (decl);
408       exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl);
409     }
410   else
411     {
412       utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type)));
413       name = IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0)));
414       buf = (char *) alloca (strlen (name) + 5);
415       sprintf (buf, "%s_ref", name);
416       decl = build_decl (input_location,
417                          VAR_DECL, get_identifier (buf), utf8const_ptr_type);
418       TREE_STATIC (decl) = 1;
419       DECL_ARTIFICIAL (decl) = 1;
420       DECL_IGNORED_P (decl) = 1;
421       TREE_READONLY (decl) = 1;
422       TREE_THIS_VOLATILE (decl) = 0;
423       layout_decl (decl, 0);
424       pushdecl (decl);
425       exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl);
426       TYPE_CATCH_CLASSES (output_class) = 
427         tree_cons (NULL, make_catch_class_record (exp, utf8_ref), 
428                    TYPE_CATCH_CLASSES (output_class));
429     }
430
431   exp = convert (ptr_type_node, exp);
432
433   *slot = tree_cons (type, exp, NULL_TREE);
434
435   return exp;
436 }
437
438 static int
439 expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED)
440 {
441   struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
442   tree addr = TREE_VALUE ((tree)ite->value);
443   tree decl;
444   STRIP_NOPS (addr);
445   decl = TREE_OPERAND (addr, 0);
446   rest_of_decl_compilation (decl, global_bindings_p (), 0);
447   return true;
448 }
449   
450 /* For every class in the TYPE_TO_RUNTIME_MAP, expand the
451    corresponding object that is used by the runtime type matcher.  */
452
453 void
454 java_expand_catch_classes (tree this_class)
455 {
456   if (TYPE_TO_RUNTIME_MAP (this_class))
457     htab_traverse 
458       (TYPE_TO_RUNTIME_MAP (this_class),
459        expand_catch_class, NULL);
460 }
461
462 /* Build and push the variable that will hold the exception object
463    within this function.  */
464
465 static tree
466 build_exception_object_var (void)
467 {
468   tree decl = DECL_FUNCTION_EXC_OBJ (current_function_decl);
469   if (decl == NULL)
470     {
471       decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
472                          VAR_DECL, get_identifier ("#exc_obj"), ptr_type_node);
473       DECL_IGNORED_P (decl) = 1;
474       DECL_ARTIFICIAL (decl) = 1;
475
476       DECL_FUNCTION_EXC_OBJ (current_function_decl) = decl;
477       pushdecl_function_level (decl);
478     }
479   return decl;
480 }
481
482 /* Build a reference to the jthrowable object being carried in the
483    exception header.  */
484
485 tree
486 build_exception_object_ref (tree type)
487 {
488   tree obj;
489
490   /* Java only passes object via pointer and doesn't require adjusting.
491      The java object is immediately before the generic exception header.  */
492   obj = build_exception_object_var ();
493   obj = fold_convert (build_pointer_type (type), obj);
494   obj = build2 (POINTER_PLUS_EXPR, TREE_TYPE (obj), obj,
495                 fold_build1 (NEGATE_EXPR, sizetype,
496                              TYPE_SIZE_UNIT (TREE_TYPE (obj))));
497   obj = build1 (INDIRECT_REF, type, obj);
498
499   return obj;
500 }
501
502 /* If there are any handlers for this range, issue end of range,
503    and then all handler blocks */
504 void
505 expand_end_java_handler (struct eh_range *range)
506 {  
507   tree handler = range->handlers;
508   if (handler)
509     {
510       tree exc_obj = build_exception_object_var ();
511       tree catches = make_node (STATEMENT_LIST);
512       tree_stmt_iterator catches_i = tsi_last (catches);
513       tree *body;
514
515       for (; handler; handler = TREE_CHAIN (handler))
516         {
517           tree type, eh_type, x;
518           tree stmts = make_node (STATEMENT_LIST);
519           tree_stmt_iterator stmts_i = tsi_last (stmts);
520
521           type = TREE_PURPOSE (handler);
522           if (type == NULL)
523             type = throwable_type_node;
524           eh_type = prepare_eh_table_type (type);
525
526           x = build_call_expr (built_in_decls[BUILT_IN_EH_POINTER],
527                                 1, integer_zero_node);
528           x = build2 (MODIFY_EXPR, void_type_node, exc_obj, x);
529           tsi_link_after (&stmts_i, x, TSI_CONTINUE_LINKING);
530
531           x = build1 (GOTO_EXPR, void_type_node, TREE_VALUE (handler));
532           tsi_link_after (&stmts_i, x, TSI_CONTINUE_LINKING);
533
534           x = build2 (CATCH_EXPR, void_type_node, eh_type, stmts);
535           tsi_link_after (&catches_i, x, TSI_CONTINUE_LINKING);
536
537           /* Throwable can match anything in Java, and therefore
538              any subsequent handlers are unreachable.  */
539           /* ??? If we're assured of no foreign language exceptions,
540              we'd be better off using NULL as the exception type
541              for the catch.  */
542           if (type == throwable_type_node)
543             break;
544         }
545
546       body = get_stmts ();
547       *body = build2 (TRY_CATCH_EXPR, void_type_node, *body, catches);
548     }
549
550 #if defined(DEBUG_JAVA_BINDING_LEVELS)
551   indent ();
552   fprintf (stderr, "expand end handler pc %d <-- %d\n",
553            current_pc, range->start_pc);
554 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
555 }
556
557 /* Recursive helper routine for maybe_start_handlers. */
558
559 static void
560 check_start_handlers (struct eh_range *range, int pc)
561 {
562   if (range != NULL_EH_RANGE && range->start_pc == pc)
563     {
564       check_start_handlers (range->outer, pc);
565       if (!range->expanded)
566         expand_start_java_handler (range);
567     }
568 }
569
570
571 static struct eh_range *current_range;
572
573 /* Emit any start-of-try-range starting at start_pc and ending after
574    end_pc. */
575
576 void
577 maybe_start_try (int start_pc, int end_pc)
578 {
579   struct eh_range *range;
580   if (! doing_eh (1))
581     return;
582
583   range = find_handler (start_pc);
584   while (range != NULL_EH_RANGE && range->start_pc == start_pc
585          && range->end_pc < end_pc)
586     range = range->outer;
587          
588   current_range = range;
589   check_start_handlers (range, start_pc);
590 }
591