OSDN Git Service

ef773e4a6b32456c907e8e14fafa9bc4acd81838
[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 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 struct eh_range *current_method_handlers;
48
49 struct eh_range *current_try_block = NULL;
50
51 struct eh_range *eh_range_freelist = 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 #if defined(DEBUG_JAVA_BINDING_LEVELS)
64 int binding_depth;
65 int is_class_level;
66 int current_pc;
67 extern void indent ();
68
69 #endif
70
71 /* Search for the most specific eh_range containing PC.
72    Assume PC is within RANGE.
73    CHILD is a list of children of RANGE such that any
74    previous children have end_pc values that are too low. */
75
76 static struct eh_range *
77 find_handler_in_range (pc, range, child)
78      int pc;
79      struct eh_range *range;
80      register 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 (pc)
100      int pc;
101 {
102   struct eh_range *h;
103   if (pc >= cache_range_start)
104     {
105       h = cache_range;
106       if (pc < cache_range_end)
107         return h;
108       while (pc >= h->end_pc)
109         {
110           cache_next_child = h->next_sibling;
111           h = h->outer;
112         }
113     }
114   else
115     {
116       h = &whole_range;
117       cache_next_child = h->first_child;
118     }
119   return find_handler_in_range (pc, h, cache_next_child);
120 }
121
122 /* Recursive helper routine for check_nested_ranges. */
123
124 static void
125 link_handler (range, outer)
126      struct eh_range *range, *outer;
127 {
128   struct eh_range **ptr;
129
130   if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
131     {
132       outer->handlers = chainon (outer->handlers, range->handlers);
133       return;
134     }
135
136   /* If the new range completely encloses the `outer' range, then insert it
137      between the outer range and its parent.  */
138   if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
139     {
140       range->outer = outer->outer;
141       range->next_sibling = NULL;
142       range->first_child = outer;
143       {
144         struct eh_range **pr = &(outer->outer->first_child);
145         while (*pr != outer)
146           pr = &(*pr)->next_sibling;
147         *pr = range;
148       }
149       outer->outer = range;
150       return;
151     }
152
153   /* Handle overlapping ranges by splitting the new range.  */
154   if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
155     {
156       struct eh_range *h
157         = (struct eh_range *) xmalloc (sizeof (struct eh_range));
158       if (range->start_pc < outer->start_pc)
159         {
160           h->start_pc = range->start_pc;
161           h->end_pc = outer->start_pc;
162           range->start_pc = outer->start_pc;
163         }
164       else
165         {
166           h->start_pc = outer->end_pc;
167           h->end_pc = range->end_pc;
168           range->end_pc = outer->end_pc;
169         }
170       h->first_child = NULL;
171       h->outer = NULL;
172       h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
173                                      TREE_VALUE (range->handlers));
174       h->next_sibling = NULL;
175       /* Restart both from the top to avoid having to make this
176          function smart about reentrancy.  */
177       link_handler (h, &whole_range);
178       link_handler (range, &whole_range);
179       return;
180     }
181
182   ptr = &outer->first_child;
183   for (;; ptr = &(*ptr)->next_sibling)
184     {
185       if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
186         {
187           range->next_sibling = *ptr;
188           range->first_child = NULL;
189           range->outer = outer;
190           *ptr = range;
191           return;
192         }
193       else if (range->start_pc < (*ptr)->end_pc)
194         {
195           link_handler (range, *ptr);
196           return;
197         }
198       /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
199     }
200 }
201
202 /* The first pass of exception range processing (calling add_handler)
203    constructs a linked list of exception ranges.  We turn this into
204    the data structure expected by the rest of the code, and also
205    ensure that exception ranges are properly nested.  */
206
207 void
208 handle_nested_ranges ()
209 {
210   struct eh_range *ptr, *next;
211
212   ptr = whole_range.first_child;
213   whole_range.first_child = NULL;
214   for (; ptr; ptr = next)
215     {
216       next = ptr->next_sibling;
217       ptr->next_sibling = NULL;
218       link_handler (ptr, &whole_range);
219     }
220 }
221
222 /* Free RANGE as well as its children and siblings.  */
223
224 static void
225 free_eh_ranges (range)
226      struct eh_range *range;
227 {
228   while (range) 
229     {
230       struct eh_range *next = range->next_sibling;
231       free_eh_ranges (range->first_child);
232       if (range != &whole_range)
233         free (range);
234       range = next;
235     }
236 }
237
238 /* Called to re-initialize the exception machinery for a new method. */
239
240 void
241 method_init_exceptions ()
242 {
243   free_eh_ranges (&whole_range);
244   whole_range.start_pc = 0;
245   whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
246   whole_range.outer = NULL;
247   whole_range.first_child = NULL;
248   whole_range.next_sibling = NULL;
249   cache_range_start = 0xFFFFFF;
250 }
251
252 /* Add an exception range.  If we already have an exception range
253    which has the same handler and label, and the new range overlaps
254    that one, then we simply extend the existing range.  Some bytecode
255    obfuscators generate seemingly nonoverlapping exception ranges
256    which, when coalesced, do in fact nest correctly.
257    
258    This constructs an ordinary linked list which check_nested_ranges()
259    later turns into the data structure we actually want.
260    
261    We expect the input to come in order of increasing START_PC.  This
262    function doesn't attempt to detect the case where two previously
263    added disjoint ranges could be coalesced by a new range; that is
264    what the sorting counteracts.  */
265
266 void
267 add_handler (start_pc, end_pc, handler, type)
268      int start_pc, end_pc;
269      tree handler;
270      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 = (struct eh_range *) 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
297   if (prev == NULL)
298     whole_range.first_child = h;
299   else
300     prev->next_sibling = h;
301 }
302
303
304 /* if there are any handlers for this range, issue start of region */
305 static void
306 expand_start_java_handler (range)
307   struct eh_range *range;
308 {
309 #if defined(DEBUG_JAVA_BINDING_LEVELS)
310   indent ();
311   fprintf (stderr, "expand start handler pc %d --> %d\n",
312            current_pc, range->end_pc);
313 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
314   range->expanded = 1;
315   expand_eh_region_start ();
316 }
317
318 tree
319 prepare_eh_table_type (type)
320     tree type;
321 {
322   tree exp;
323
324   /* The "type" (metch_info) in a (Java) exception table is one:
325    * a) NULL - meaning match any type in a try-finally.
326    * b) a pointer to a (ccmpiled) class (low-order bit 0).
327    * c) a pointer to the Utf8Const name of the class, plus one
328    * (which yields a value with low-order bit 1). */
329
330   if (type == NULL_TREE)
331     exp = NULL_TREE;
332   else if (is_compiled_class (type))
333     exp = build_class_ref (type);
334   else
335     exp = fold (build 
336                 (PLUS_EXPR, ptr_type_node,
337                  build_utf8_ref (build_internal_class_name (type)),
338                  size_one_node));
339   return exp;
340 }
341
342
343 /* Build a reference to the jthrowable object being carried in the
344    exception header.  */
345
346 tree
347 build_exception_object_ref (type)
348      tree type;
349 {
350   tree obj;
351
352   /* Java only passes object via pointer and doesn't require adjusting.
353      The java object is immediately before the generic exception header.  */
354   obj = build (EXC_PTR_EXPR, build_pointer_type (type));
355   obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
356                TYPE_SIZE_UNIT (TREE_TYPE (obj)));
357   obj = build1 (INDIRECT_REF, type, obj);
358
359   return obj;
360 }
361
362 /* If there are any handlers for this range, isssue end of range,
363    and then all handler blocks */
364 static void
365 expand_end_java_handler (range)
366      struct eh_range *range;
367 {  
368   tree handler = range->handlers;
369   force_poplevels (range->start_pc);
370   expand_start_all_catch ();
371   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
372     {
373       /* For bytecode we treat exceptions a little unusually.  A
374          `finally' clause looks like an ordinary exception handler for
375          Throwable.  The reason for this is that the bytecode has
376          already expanded the finally logic, and we would have to do
377          extra (and difficult) work to get this to look like a
378          gcc-style finally clause.  */
379       tree type = TREE_PURPOSE (handler);
380       if (type == NULL)
381         type = throwable_type_node;
382
383       expand_start_catch (type);
384       expand_goto (TREE_VALUE (handler));
385       expand_end_catch ();
386     }
387   expand_end_all_catch ();
388 #if defined(DEBUG_JAVA_BINDING_LEVELS)
389   indent ();
390   fprintf (stderr, "expand end handler pc %d <-- %d\n",
391            current_pc, range->start_pc);
392 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
393 }
394
395 /* Recursive helper routine for maybe_start_handlers. */
396
397 static void
398 check_start_handlers (range, pc)
399      struct eh_range *range;
400      int pc;
401 {
402   if (range != NULL_EH_RANGE && range->start_pc == pc)
403     {
404       check_start_handlers (range->outer, pc);
405       if (!range->expanded)
406         expand_start_java_handler (range);
407     }
408 }
409
410
411 static struct eh_range *current_range;
412
413 /* Emit any start-of-try-range starting at start_pc and ending after
414    end_pc. */
415
416 void
417 maybe_start_try (start_pc, end_pc)
418      int start_pc;
419      int end_pc;
420 {
421   struct eh_range *range;
422   if (! doing_eh (1))
423     return;
424
425   range = find_handler (start_pc);
426   while (range != NULL_EH_RANGE && range->start_pc == start_pc
427          && range->end_pc < end_pc)
428     range = range->outer;
429          
430   current_range = range;
431   check_start_handlers (range, start_pc);
432 }
433
434 /* Emit any end-of-try-range ending at end_pc and starting before
435    start_pc. */
436
437 void
438 maybe_end_try (start_pc, end_pc)
439      int start_pc;
440      int end_pc;
441 {
442   if (! doing_eh (1))
443     return;
444
445   while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
446          && current_range->start_pc >= start_pc)
447     {
448       expand_end_java_handler (current_range);
449       current_range = current_range->outer;
450     }
451 }