OSDN Git Service

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