OSDN Git Service

* config/alpha/vms.h (INCLUDE_DEFAULTS): Add /gnu/lib/gcc-lib/include.
[pf3gnuchains/gcc-fork.git] / gcc / ch / except.c
1 /* Exception support for GNU CHILL.
2    WARNING:  Only works for native (needs setjmp.h)!  FIXME!
3    Copyright (C) 1992, 1993, 1994, 1998, 1999, 2000, 2001
4    Free Software Foundation, Inc.
5
6 This file is part of GNU CC.
7
8 GNU CC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GNU CC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU CC; see the file COPYING.  If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25
26 /* On Suns this can get you to the right definition if you
27    set the right value for TARGET.  */
28 #include <setjmp.h>
29 #ifdef sequent
30 /* Can you believe they forgot this?  */
31 #ifndef _JBLEN
32 #define _JBLEN 11
33 #endif
34 #endif
35
36 #ifndef _JBLEN
37 #define _JBLEN (sizeof(jmp_buf)/sizeof(int))
38 #define _JBLEN_2 _JBLEN+20
39 #else
40 /* if we use i.e. posix threads, this buffer must be longer */
41 #define _JBLEN_2 _JBLEN+20
42 #endif
43
44 /* On Linux setjmp is __setjmp FIXME: what is for CROSS */
45 #ifndef SETJMP_LIBRARY_NAME
46 #ifdef __linux__
47 #define SETJMP_LIBRARY_NAME "__setjmp"
48 #else
49 #define SETJMP_LIBRARY_NAME "setjmp"
50 #endif
51 #endif
52
53 #include "tree.h"
54 #include "ch-tree.h"
55 #include "rtl.h"
56 #include "toplev.h"
57
58 extern int  expand_exit_needed;
59
60 static tree link_handler_decl;
61 static tree handler_link_pointer_type;
62 static tree unlink_handler_decl;
63 static int exceptions_initialized = 0;
64 static void emit_setup_handler PARAMS ((void));
65 static void initialize_exceptions PARAMS ((void));
66 static tree start_handler_array PARAMS ((void));
67 static void finish_handler_array PARAMS ((void));
68 static tree char_pointer_type_for_handler;
69
70 /* If this is 1, operations to push and pop on the __exceptionStack
71    are inline.  The default is is to use a function call, to
72    allow for a per-thread exception stack. */
73 static int inline_exception_stack_ops = 0;
74
75 struct handler_state
76 {
77   struct handler_state *next;
78
79   /* Starts at 0, then incremented for every <on-alternative>. */
80   int prev_on_alternative;
81
82   /* If > 0: handler number for ELSE handler. */
83   int else_handler;
84
85   int action_number;
86
87   char do_pushlevel;
88
89   tree on_alt_list;
90   tree setjmp_expr;
91
92   /* A decl for the static handler array (used to map exception name to int).*/
93   tree handler_array_decl;
94
95   rtx end_label;
96
97   /* Used to pass a tree from emit_setup_handler to chill_start_on. */
98   tree handler_ref;
99
100   tree unlink_cleanup;
101
102   tree function;
103
104   /* flag to indicate that we are currently compiling this handler.
105      is_handled will need this to determine an unhandled exception */
106   int compiling;
107 };
108
109 /* This is incremented by one each time we start an action which
110    might have an ON-handler.  It is reset between passes. */
111 static int action_number = 0;
112
113 int action_nesting_level = 0;
114
115 /* The global_handler_list is constructed in pass 1.  It is not sorted.
116    It contains one element for each action that actually had an ON-handler.
117    An element's ACTION_NUMBER matches the action_number
118    of that action.  The global_handler_list is eaten up during pass 2. */
119 #define ACTION_NUMBER(HANDLER) ((HANDLER)->action_number)
120 struct handler_state *global_handler_list = NULL;
121
122 /* This is a stack of handlers, one for each nested ON-handler. */
123 static struct handler_state *current_handler = NULL;
124
125 static struct handler_state *free_handlers = NULL; /* freelist */
126
127 static tree handler_element_type;
128 static tree handler_link_type;
129 static tree BISJ;
130 static tree jbuf_ident, prev_ident, handlers_ident;
131 static tree exception_stack_decl = 0;
132
133 /* Chain of cleanups associated with exception handlers.
134    The TREE_PURPOSE is an INTEGER_CST whose value is the
135    DECL_ACTION_NESTING_LEVEL (when the handled actions was entered).
136    The TREE_VALUE is an expression to expand when we exit that action. */
137
138 static tree cleanup_chain = NULL_TREE;
139 \f
140 #if 0
141 /* Merge the current sequence onto the tail of the previous one. */
142
143 void
144 pop_sequence ()
145 {
146   rtx sequence_first = get_insns ();
147
148   end_sequence ();
149   emit_insns (sequence_first);
150   
151 }
152 #endif
153
154 /* Things we need to do at the beginning of pass 2. */
155
156 void
157 except_init_pass_2 ()
158 {
159   /* First sort the global_handler_list on ACTION_NUMBER.
160      This will already be in close to reverse order (the exception being
161      nested ON-handlers), so insertion sort should essentially linear. */
162
163   register struct handler_state *old_list = global_handler_list;
164
165   /* First add a dummy final element. */
166   if (free_handlers)
167     global_handler_list = free_handlers;
168   else
169     global_handler_list
170       = (struct handler_state*) permalloc (sizeof (struct handler_state));
171   /* Make the final dummy "larger" than any other element. */
172   ACTION_NUMBER (global_handler_list) = action_number + 1;
173   /* Now move all the elements in old_list over to global_handler_list. */
174   while (old_list != NULL)
175     {
176       register struct handler_state **ptr = &global_handler_list;
177       /* Unlink from old_list. */
178       register struct handler_state *current = old_list;
179       old_list = old_list->next;
180
181       while (ACTION_NUMBER (current) > ACTION_NUMBER (*ptr))
182         ptr = &(*ptr)->next;
183       /* Link into proper place in global_handler_list (new list). */
184       current->next = *ptr;
185       *ptr = current;
186     }
187      
188   /* Don't forget to reset action_number. */
189   action_number = 0;
190 }
191
192 /* This function is called at the beginning of an action that might be
193    followed by an ON-handler.  Chill syntax doesn't let us know if
194    we actually have an ON-handler until we see the ON, so we save
195    away during pass 1 that information for use during pass 2. */
196
197 void
198 push_handler ()
199 {
200   register struct handler_state *hstate;
201
202   action_number++;
203   action_nesting_level++;
204
205   if (pass == 1)
206     {
207       if (free_handlers)
208         {
209           hstate = free_handlers;
210           free_handlers = hstate->next;
211         }
212       else
213         {
214           hstate =
215             (struct handler_state*) permalloc (sizeof (struct handler_state));
216         }
217
218       hstate->next = current_handler;
219       current_handler = hstate;
220       hstate->prev_on_alternative = 0;
221       hstate->else_handler = 0;
222       hstate->on_alt_list = NULL_TREE;
223       hstate->compiling = 0;
224
225       ACTION_NUMBER (hstate) = action_number;
226       return;
227     }
228
229   if (ACTION_NUMBER (global_handler_list) != action_number)
230     return;
231
232   /* OK.  This action actually has an ON-handler.
233      Pop it from global_handler_list, and use it. */
234
235   hstate = global_handler_list;
236   global_handler_list = hstate->next;
237
238   /* Since this is pass 2, let's generate prologue code for that. */
239
240   hstate->next = current_handler;
241   current_handler = hstate;
242
243   hstate->prev_on_alternative = 0;
244   hstate->function = current_function_decl;
245
246   emit_setup_handler ();
247 }
248
249 static tree
250 start_handler_array ()
251 {
252   tree handler_array_type, decl;
253
254   push_obstacks_nochange ();
255   end_temporary_allocation ();
256   handler_array_type = build_array_type (handler_element_type, NULL_TREE);
257   decl = build_lang_decl (VAR_DECL,
258                           get_unique_identifier ("handler_table"),
259                           handler_array_type);
260
261 /*  TREE_TYPE (decl) = handler_array_type;*/
262   TREE_READONLY (decl) = 1;
263   TREE_STATIC (decl) = 1;
264   DECL_INITIAL (decl) = error_mark_node;
265   
266   pushdecl (decl);
267   make_decl_rtl (decl, NULL_PTR, 0);
268   current_handler->handler_array_decl = decl;
269   return decl;
270 }
271
272 static void
273 finish_handler_array ()
274 {
275   tree decl = current_handler->handler_array_decl;
276   tree t;
277   tree handler_array_init = NULL_TREE;
278   int handlers_count = 1;
279   int nelts;
280
281   /* Build the table mapping exceptions to handler(-number)s.
282      This is done in reverse order. */
283   
284   /* First push the end of the list.  This is either the ELSE
285      handler (current_handler->else_handler>0) or NULL handler to indicate
286      the end of the list (if current_handler->else-handler == 0).
287      The following works either way. */
288   handler_array_init = build_tree_list
289     (NULL_TREE, chill_expand_tuple
290      (handler_element_type,
291       build_nt (CONSTRUCTOR, NULL_TREE,
292                 tree_cons (NULL_TREE,
293                            null_pointer_node,
294                            build_tree_list (NULL_TREE,
295                                             build_int_2 (current_handler->else_handler,
296                                                              0))))));
297   
298   for (t = current_handler->on_alt_list; t != NULL_TREE; t = TREE_CHAIN (t))
299     { tree handler_number = TREE_PURPOSE(t);
300       tree elist = TREE_VALUE (t);
301       for ( ; elist != NULL_TREE; elist = TREE_CHAIN (elist))
302         {
303           tree ex_decl =
304             build_chill_exception_decl (IDENTIFIER_POINTER(TREE_VALUE(elist)));
305           tree ex_addr = build1 (ADDR_EXPR,
306                                  char_pointer_type_for_handler,
307                                  ex_decl);
308           tree el = build_nt (CONSTRUCTOR, NULL_TREE,
309                               tree_cons (NULL_TREE,
310                                          ex_addr,
311                                          build_tree_list (NULL_TREE,
312                                                           handler_number)));
313           mark_addressable (ex_decl);
314           TREE_CONSTANT (ex_addr) = 1;
315           handler_array_init =
316             tree_cons (NULL_TREE,
317                        chill_expand_tuple (handler_element_type, el),
318                        handler_array_init);
319           handlers_count++;
320         }
321     }
322
323 #if 1
324   nelts = list_length (handler_array_init);
325   TYPE_DOMAIN (TREE_TYPE (decl))
326     = build_index_type (build_int_2 (nelts - 1, - (nelts == 0)));
327   layout_type (TREE_TYPE (decl));
328   DECL_INITIAL (decl)
329     = convert (TREE_TYPE (decl),
330                build_nt (CONSTRUCTOR, NULL_TREE, handler_array_init));
331
332   /* Pop back to the obstack that is current for this binding level.
333      This is because MAXINDEX, rtl, etc. to be made below
334      must go in the permanent obstack.  But don't discard the
335      temporary data yet.  */
336   pop_obstacks ();
337   layout_decl (decl, 0);
338   /* To prevent make_decl_rtl (called indiectly by rest_of_decl_compilation)
339      throwing the existing RTL (which has already been used). */
340   PUT_MODE (DECL_RTL (decl), DECL_MODE (decl));
341   rest_of_decl_compilation (decl, (char*)0, 0, 0);
342   expand_decl_init (decl);
343 #else
344   /* To prevent make_decl_rtl (called indirectly by finish_decl)
345      altering the existing RTL. */
346   GET_MODE (DECL_RTL (current_handler->handler_array_decl)) =
347     DECL_MODE (current_handler->handler_array_decl);
348
349   finish_decl (current_handler->handler_array_decl,
350                build_nt (CONSTRUCTOR, NULL_TREE, handler_array_init),
351                NULL_TREE);
352 #endif
353 }
354
355
356 void
357 pop_handler (used)
358      int used;
359 {
360   action_nesting_level--;
361   if (pass == 1)
362     {
363       struct handler_state *old = current_handler;
364
365       if (old == NULL)
366         abort ();
367       current_handler = old->next;
368
369       if (used)
370         { /* Push unto global_handler_list. */
371           old->next = global_handler_list;
372           global_handler_list = old;
373         }
374       else
375         {
376           /* Push onto free_handlers free list. */
377           old->next = free_handlers;
378           free_handlers = old;
379         }
380     }
381   else if (used)
382     {
383       current_handler = current_handler->next;
384     }
385 }
386
387 /* Emit code before an action that has an ON-handler. */
388
389 static void
390 emit_setup_handler ()
391 {
392   tree handler_decl, handler_addr, t;
393
394   /* Field references. */
395   tree jbuf_ref, handlers_ref,prev_ref;
396   if (!exceptions_initialized)
397     {
398       /* We temporarily reset the maximum_field_alignment to zero so the
399          compiler's exception data structures can be compatible with the
400          run-time system, even when we're compiling with -fpack. */
401       unsigned int save_maximum_field_alignment = maximum_field_alignment;
402       maximum_field_alignment = 0;
403       push_obstacks_nochange ();
404       end_temporary_allocation ();
405       initialize_exceptions ();
406       pop_obstacks ();
407       maximum_field_alignment = save_maximum_field_alignment;
408     }
409
410   push_momentary ();
411
412   handler_decl = build_lang_decl (VAR_DECL,
413                                   get_unique_identifier ("handler"),
414                                   handler_link_type);
415   push_obstacks_nochange ();
416   pushdecl(handler_decl);
417   expand_decl (handler_decl);
418   finish_decl (handler_decl);
419
420   jbuf_ref = build_component_ref (handler_decl, jbuf_ident);
421   jbuf_ref = build_chill_arrow_expr (jbuf_ref, 1);
422   handlers_ref = build_component_ref (handler_decl, handlers_ident);
423   prev_ref = build_component_ref (handler_decl, prev_ident);
424
425   /* Emit code to link in handler in __exceptionStack chain. */
426   mark_addressable (handler_decl);
427   handler_addr = build1 (ADDR_EXPR, handler_link_pointer_type, handler_decl);
428   if (inline_exception_stack_ops)
429     {
430       expand_expr_stmt (build_chill_modify_expr (prev_ref,
431                                                  exception_stack_decl));
432       expand_expr_stmt (build_chill_modify_expr (exception_stack_decl,
433                                                  handler_addr));
434       current_handler->handler_ref = prev_ref;
435     }
436   else
437     {
438       expand_expr_stmt (build_chill_function_call (link_handler_decl,
439                                              build_tree_list (NULL_TREE,
440                                                               handler_addr)));
441       current_handler->handler_ref = handler_addr;
442     }
443
444   /* Expand:  handler->__handlers = { <<array mapping names to ints } */
445   t =  build1 (NOP_EXPR, build_pointer_type (handler_element_type),
446                build_chill_arrow_expr (start_handler_array (), 1));
447   expand_expr_stmt (build_chill_modify_expr (handlers_ref, t));
448
449   /* Emit code to unlink handler. */
450   if (inline_exception_stack_ops)
451     current_handler->unlink_cleanup
452       = build_chill_modify_expr (exception_stack_decl,
453                                  current_handler->handler_ref);
454   else
455     current_handler->unlink_cleanup
456       = build_chill_function_call (unlink_handler_decl,
457                                    build_tree_list(NULL_TREE,
458                                                current_handler->handler_ref));
459   cleanup_chain = tree_cons (build_int_2 (action_nesting_level, 0),
460                              current_handler->unlink_cleanup,
461                              cleanup_chain);
462
463   /* Emit code for setjmp. */
464   
465   current_handler->setjmp_expr =
466     build_chill_function_call (BISJ, build_tree_list (NULL_TREE, jbuf_ref));
467   expand_start_case (1, current_handler->setjmp_expr,
468                      integer_type_node, "on handler");
469
470   chill_handle_case_label (integer_zero_node, current_handler->setjmp_expr);
471 }
472
473 /* Start emitting code for: <actions> ON <handlers> END.
474    Assume we've parsed <actions>, and the setup needed for it. */
475
476 void
477 chill_start_on ()
478 {
479   expand_expr_stmt (current_handler->unlink_cleanup);
480
481   /* Emit code to jump past the handlers. */
482   current_handler->end_label = gen_label_rtx ();
483   current_handler->compiling = 1;
484   emit_jump (current_handler->end_label);
485 }
486
487 void
488 chill_finish_on ()
489 {
490   expand_end_case (current_handler->setjmp_expr);
491   
492   finish_handler_array ();
493
494   emit_label (current_handler->end_label);
495
496   pop_momentary ();
497
498   cleanup_chain = TREE_CHAIN (cleanup_chain);
499 }
500
501 void
502 chill_handle_on_labels (labels)
503      tree labels;
504 {
505   unsigned int alternative = ++current_handler->prev_on_alternative;
506   if (pass == 1)
507     {
508       tree handler_number = build_int_2 (alternative, 0);
509       current_handler->on_alt_list =
510         tree_cons (handler_number, labels, current_handler->on_alt_list);
511     }
512   else
513     {
514       /* Find handler_number saved in pass 1. */
515       tree tmp;
516
517       for (tmp = current_handler->on_alt_list;
518            compare_tree_int (TREE_PURPOSE (tmp), alternative) != 0;
519            tmp = TREE_CHAIN (tmp))
520         ;
521
522       if (expand_exit_needed)
523         expand_exit_something (), expand_exit_needed = 0;
524       chill_handle_case_label (TREE_PURPOSE (tmp),
525                                current_handler->setjmp_expr);
526     }
527 }
528
529 void
530 chill_start_default_handler ()
531 {
532   current_handler->else_handler = ++current_handler->prev_on_alternative;
533   if (!ignoring)
534     {
535       chill_handle_case_default ();
536     }
537 }
538
539 void
540 chill_check_no_handlers ()
541 {
542   if (current_handler != NULL)
543     abort ();
544 }
545
546 static void
547 initialize_exceptions ()
548 {
549   tree jmp_buf_type = build_array_type (integer_type_node,
550                                         build_index_type (build_int_2 (_JBLEN_2-1, 0)));
551   tree setjmp_fndecl, link_ftype;
552   tree parmtypes
553     = tree_cons (NULL_TREE, build_pointer_type (jmp_buf_type), void_list_node);
554
555   setjmp_fndecl = builtin_function ("setjmp",
556                                     build_function_type (integer_type_node,
557                                                          parmtypes),
558                                     0, NOT_BUILT_IN,
559                                     SETJMP_LIBRARY_NAME);
560   BISJ = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (setjmp_fndecl)),
561                  setjmp_fndecl);
562  
563   char_pointer_type_for_handler
564     = build_pointer_type (build_type_variant (char_type_node, 1, 0));
565   handler_element_type =
566     build_chill_struct_type (chainon
567                              (build_decl (FIELD_DECL,
568                                           get_identifier("__exceptid"),
569                                           char_pointer_type_for_handler),
570                               build_decl (FIELD_DECL,
571                                           get_identifier("__handlerno"),
572                                           integer_type_node)));
573
574   jbuf_ident = get_identifier("__jbuf");
575   prev_ident = get_identifier("__prev");
576   handlers_ident = get_identifier("__handlers");
577
578   handler_link_type =
579     build_chill_struct_type
580       (chainon
581        (build_decl (FIELD_DECL, prev_ident, ptr_type_node),
582         chainon
583         (build_decl (FIELD_DECL, handlers_ident,
584                      build_pointer_type (handler_element_type)),
585          build_decl (FIELD_DECL, jbuf_ident, jmp_buf_type))));
586
587   handler_link_pointer_type = build_pointer_type (handler_link_type);
588
589   if (inline_exception_stack_ops)
590     {
591       exception_stack_decl =
592         build_lang_decl (VAR_DECL,
593                          get_identifier("__exceptionStack"),
594                          handler_link_pointer_type);
595       TREE_STATIC (exception_stack_decl) = 1;
596       TREE_PUBLIC (exception_stack_decl) = 1;
597       DECL_EXTERNAL (exception_stack_decl) = 1;
598       push_obstacks_nochange ();
599       pushdecl(exception_stack_decl);
600       make_decl_rtl (exception_stack_decl, NULL_PTR, 1);
601       finish_decl (exception_stack_decl);
602     }
603
604   link_ftype = build_function_type (void_type_node,
605                                     tree_cons (NULL_TREE,
606                                                handler_link_pointer_type,
607                                                void_list_node));
608   link_handler_decl = builtin_function ("__ch_link_handler", link_ftype,
609                                         0, NOT_BUILT_IN, NULL_PTR);
610   unlink_handler_decl = builtin_function ("__ch_unlink_handler", link_ftype,
611                                           0, NOT_BUILT_IN, NULL_PTR);
612
613   exceptions_initialized = 1;
614 }
615
616 /* Do the cleanup(s) needed for a GOTO label.
617    We only need to do the last of the cleanups. */
618
619 void
620 expand_goto_except_cleanup (label_level)
621      int label_level;
622 {
623   tree list = cleanup_chain;
624   tree last = NULL_TREE;
625   for ( ; list != NULL_TREE; list = TREE_CHAIN (list))
626     {
627       if (compare_tree_int (TREE_PURPOSE (list), label_level) > 0)
628         last = list;
629       else
630         break;
631     }
632   if (last)
633     expand_expr_stmt (TREE_VALUE (last));
634 }
635
636 /* Returns true if there is a valid handler for EXCEPT_NAME
637    in the current static scope.
638    0 ... no handler found
639    1 ... local handler available
640    2 ... function may propagate this exception
641 */
642
643 int
644 is_handled (except_name)
645      tree except_name;
646 {
647   tree t;
648   struct handler_state *h = current_handler;
649
650   /* if we are are currently compiling this handler
651      we have to start at the next level */
652   if (h && h->compiling)
653     h = h->next;
654   while (h != NULL)
655     {
656       if (h->function != current_function_decl)
657         break;
658       if (h->else_handler > 0)
659         return 1;
660       for (t = h->on_alt_list; t != NULL_TREE; t = TREE_CHAIN (t))
661         {
662           if (value_member (except_name, TREE_VALUE (t)))
663             return 1;
664         }
665       h = h->next;
666     }
667
668   t = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl));
669
670   if (value_member (except_name, t))
671     return 2;
672   return 0;
673 }
674
675 /* function generates code to reraise exceptions
676    for PROC's propagating exceptions. */
677
678 void
679 chill_reraise_exceptions (exceptions)
680      tree exceptions;
681 {
682   tree wrk;
683
684   if (exceptions == NULL_TREE)
685     return; /* just in case */
686
687   if (pass == 1)
688     {
689       for (wrk = exceptions; wrk != NULL_TREE; wrk = TREE_CHAIN (wrk))
690         chill_handle_on_labels (build_tree_list (NULL_TREE, TREE_VALUE (wrk)));
691     }
692   else /* pass == 2 */
693     {
694       chill_start_on ();
695       expand_exit_needed = 0;
696
697       for (wrk = exceptions; wrk != NULL_TREE; wrk = TREE_CHAIN (wrk))
698         {
699           chill_handle_on_labels (TREE_VALUE (wrk));
700           /* do a CAUSE exception */
701           expand_expr_stmt (build_cause_exception (TREE_VALUE (wrk), 0));
702           expand_exit_needed = 1;
703         }
704       chill_finish_on ();
705     }
706   pop_handler (1);
707 }