OSDN Git Service

* check-init.c (check_bool2_init, done_alternative): Add static
[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 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 "eh-common.h"
38 #include "toplev.h"
39
40 static void expand_start_java_handler PROTO ((struct eh_range *));
41 static void expand_end_java_handler PROTO ((struct eh_range *));
42 static struct eh_range *find_handler_in_range PROTO ((int, struct eh_range *,
43                                                       struct eh_range *));
44 static void link_handler PROTO ((struct eh_range *, struct eh_range *));
45 static void check_start_handlers PROTO ((struct eh_range *, int));
46
47 extern struct obstack permanent_obstack;
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 /* Search for the most specific eh_range containing PC.
66    Assume PC is within RANGE.
67    CHILD is a list of children of RANGE such that any
68    previous children have end_pc values that are too low. */
69
70 static struct eh_range *
71 find_handler_in_range (pc, range, child)
72      int pc;
73      struct eh_range *range;
74      register struct eh_range *child;
75 {
76   for (; child != NULL;  child = child->next_sibling)
77     {
78       if (pc < child->start_pc)
79         break;
80       if (pc < child->end_pc)
81         return find_handler_in_range (pc, child, child->first_child);
82     }
83   cache_range = range;
84   cache_range_start = pc;
85   cache_next_child = child;
86   cache_range_end = child == NULL ? range->end_pc : child->start_pc;
87   return range;
88 }
89
90 /* Find the inner-most handler that contains PC. */
91
92 struct eh_range *
93 find_handler (pc)
94      int pc;
95 {
96   struct eh_range *h;
97   if (pc >= cache_range_start)
98     {
99       h = cache_range;
100       if (pc < cache_range_end)
101         return h;
102       while (pc >= h->end_pc)
103         {
104           cache_next_child = h->next_sibling;
105           h = h->outer;
106         }
107     }
108   else
109     {
110       h = &whole_range;
111       cache_next_child = h->first_child;
112     }
113   return find_handler_in_range (pc, h, cache_next_child);
114 }
115
116 /* Recursive helper routine for check_nested_ranges. */
117
118 static void
119 link_handler (range, outer)
120      struct eh_range *range, *outer;
121 {
122   struct eh_range **ptr;
123
124   if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
125     {
126       outer->handlers = chainon (outer->handlers, range->handlers);
127       return;
128     }
129
130   /* If the new range completely encloses the `outer' range, then insert it
131      between the outer range and its parent.  */
132   if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
133     {
134       range->outer = outer->outer;
135       range->next_sibling = NULL;
136       range->first_child = outer;
137       {
138         struct eh_range **pr = &(outer->outer->first_child);
139         while (*pr != outer)
140           pr = &(*pr)->next_sibling;
141         *pr = range;
142       }
143       outer->outer = range;
144       return;
145     }
146
147   /* Handle overlapping ranges by splitting the new range.  */
148   if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
149     {
150       struct eh_range *h
151         = (struct eh_range *) oballoc (sizeof (struct eh_range));
152       if (range->start_pc < outer->start_pc)
153         {
154           h->start_pc = range->start_pc;
155           h->end_pc = outer->start_pc;
156           range->start_pc = outer->start_pc;
157         }
158       else
159         {
160           h->start_pc = outer->end_pc;
161           h->end_pc = range->end_pc;
162           range->end_pc = outer->end_pc;
163         }
164       h->first_child = NULL;
165       h->outer = NULL;
166       h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
167                                      TREE_VALUE (range->handlers));
168       h->next_sibling = NULL;
169       /* Restart both from the top to avoid having to make this
170          function smart about reentrancy.  */
171       link_handler (h, &whole_range);
172       link_handler (range, &whole_range);
173       return;
174     }
175
176   ptr = &outer->first_child;
177   for (;; ptr = &(*ptr)->next_sibling)
178     {
179       if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
180         {
181           range->next_sibling = *ptr;
182           range->first_child = NULL;
183           range->outer = outer;
184           *ptr = range;
185           return;
186         }
187       else if (range->start_pc < (*ptr)->end_pc)
188         {
189           link_handler (range, *ptr);
190           return;
191         }
192       /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
193     }
194 }
195
196 /* The first pass of exception range processing (calling add_handler)
197    constructs a linked list of exception ranges.  We turn this into
198    the data structure expected by the rest of the code, and also
199    ensure that exception ranges are properly nested.  */
200
201 void
202 handle_nested_ranges ()
203 {
204   struct eh_range *ptr, *next;
205
206   ptr = whole_range.first_child;
207   whole_range.first_child = NULL;
208   for (; ptr; ptr = next)
209     {
210       next = ptr->next_sibling;
211       ptr->next_sibling = NULL;
212       link_handler (ptr, &whole_range);
213     }
214 }
215
216
217 /* Called to re-initialize the exception machinery for a new method. */
218
219 void
220 method_init_exceptions ()
221 {
222   whole_range.start_pc = 0;
223   whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
224   whole_range.outer = NULL;
225   whole_range.first_child = NULL;
226   whole_range.next_sibling = NULL;
227   cache_range_start = 0xFFFFFF;
228   java_set_exception_lang_code ();
229 }
230
231 void
232 java_set_exception_lang_code ()
233 {
234   set_exception_lang_code (EH_LANG_Java);
235   set_exception_version_code (1);
236 }
237
238 /* Add an exception range.  If we already have an exception range
239    which has the same handler and label, and the new range overlaps
240    that one, then we simply extend the existing range.  Some bytecode
241    obfuscators generate seemingly nonoverlapping exception ranges
242    which, when coalesced, do in fact nest correctly.
243    
244    This constructs an ordinary linked list which check_nested_ranges()
245    later turns into the data structure we actually want.
246    
247    We expect the input to come in order of increasing START_PC.  This
248    function doesn't attempt to detect the case where two previously
249    added disjoint ranges could be coalesced by a new range; that is
250    what the sorting counteracts.  */
251
252 void
253 add_handler (start_pc, end_pc, handler, type)
254      int start_pc, end_pc;
255      tree handler;
256      tree type;
257 {
258   struct eh_range *ptr, *prev = NULL, *h;
259
260   for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
261     {
262       if (start_pc >= ptr->start_pc
263           && start_pc <= ptr->end_pc
264           && TREE_PURPOSE (ptr->handlers) == type
265           && TREE_VALUE (ptr->handlers) == handler)
266         {
267           /* Already found an overlapping range, so coalesce.  */
268           ptr->end_pc = MAX (ptr->end_pc, end_pc);
269           return;
270         }
271       prev = ptr;
272     }
273
274   h = (struct eh_range *) oballoc (sizeof (struct eh_range));
275   h->start_pc = start_pc;
276   h->end_pc = end_pc;
277   h->first_child = NULL;
278   h->outer = NULL;
279   h->handlers = build_tree_list (type, handler);
280   h->next_sibling = NULL;
281
282   if (prev == NULL)
283     whole_range.first_child = h;
284   else
285     prev->next_sibling = h;
286 }
287
288
289 /* if there are any handlers for this range, issue start of region */
290 static void
291 expand_start_java_handler (range)
292   struct eh_range *range ATTRIBUTE_UNUSED;
293 {
294   expand_eh_region_start ();
295 }
296
297 tree
298 prepare_eh_table_type (type)
299     tree type;
300 {
301   tree exp;
302
303   /* The "type" (metch_info) in a (Java) exception table is one:
304    * a) NULL - meaning match any type in a try-finally.
305    * b) a pointer to a (ccmpiled) class (low-order bit 0).
306    * c) a pointer to the Utf8Const name of the class, plus one
307    * (which yields a value with low-order bit 1). */
308
309   push_obstacks (&permanent_obstack, &permanent_obstack);
310   if (type == NULL_TREE)
311     exp = null_pointer_node;
312   else if (is_compiled_class (type))
313     exp = build_class_ref (type);
314   else
315     exp = fold (build 
316                 (PLUS_EXPR, ptr_type_node,
317                  build_utf8_ref (build_internal_class_name (type)),
318                  size_one_node));
319   pop_obstacks ();
320   return exp;
321 }
322
323 /* if there are any handlers for this range, isssue end of range,
324    and then all handler blocks */
325 static void
326 expand_end_java_handler (range)
327      struct eh_range *range;
328 {
329   tree handler = range->handlers;
330   expand_start_all_catch ();
331   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
332     {
333       start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler)));
334       /* Push the thrown object on the top of the stack */
335       expand_goto (TREE_VALUE (handler));
336     }
337   expand_end_all_catch ();
338 }
339
340 /* Recursive helper routine for maybe_start_handlers. */
341
342 static void
343 check_start_handlers (range, pc)
344      struct eh_range *range;
345      int pc;
346 {
347   if (range != NULL_EH_RANGE && range->start_pc == pc)
348     {
349       check_start_handlers (range->outer, pc);
350       expand_start_java_handler (range);
351     }
352 }
353
354 struct eh_range *current_range;
355
356 /* Emit any start-of-try-range start at PC. */
357
358 void
359 maybe_start_try (pc)
360      int pc;
361 {
362   if (! doing_eh (1))
363     return;
364
365   current_range = find_handler (pc);
366   check_start_handlers (current_range, pc);
367 }
368
369 /* Emit any end-of-try-range end at PC. */
370
371 void
372 maybe_end_try (pc)
373      int pc;
374 {
375   if (! doing_eh (1))
376     return;
377
378   while (current_range != NULL_EH_RANGE && current_range->end_pc <= pc)
379     {
380       expand_end_java_handler (current_range);
381       current_range = current_range->outer;
382     }
383 }
384
385 /* Emit the handler labels and their code */
386
387 void
388 emit_handlers ()
389 {
390   if (catch_clauses)
391     {
392       rtx funcend = gen_label_rtx ();
393       emit_jump (funcend);
394
395       emit_insns (catch_clauses);
396       expand_leftover_cleanups ();
397
398       emit_label (funcend);
399     }
400 }
401
402 /* Resume executing at the statement immediately after the end of an
403    exception region. */
404
405 void
406 expand_resume_after_catch ()
407 {
408   expand_goto (top_label_entry (&caught_return_label_stack));
409 }