OSDN Git Service

[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, 93, 1994 Free Software Foundation, Inc.
4
5 This file is part of GNU CC.
6
7 GNU CC 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 2, or (at your option)
10 any later version.
11
12 GNU CC 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 GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 #include "config.h"
22 #include "tree.h"
23 #include "ch-tree.h"
24 #include "rtl.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 extern int  expand_exit_needed;
54 extern tree build_chill_exception_decl PROTO((char *));
55 extern void chill_handle_case_default  PROTO((void));
56 extern void emit_jump                  PROTO((rtx));
57 extern void expand_decl                PROTO((tree));
58 extern void fatal                      PROTO((char *, ...));
59 extern void make_decl_rtl              PROTO((tree, char *, int));
60 extern void rest_of_decl_compilation   PROTO((tree, char *, int, int));
61
62 static tree link_handler_decl;
63 static tree handler_link_pointer_type;
64 static tree unlink_handler_decl;
65 static int exceptions_initialized = 0;
66 static void emit_setup_handler PROTO((void));
67 static void initialize_exceptions PROTO((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 assocated 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       if (old == NULL)
365         fatal ("internal error: on stack out of sync");
366       current_handler = old->next;
367
368       if (used)
369         { /* Push unto global_handler_list. */
370           old->next = global_handler_list;
371           global_handler_list = old;
372         }
373       else
374         {
375           /* Push onto free_handlers free list. */
376           old->next = free_handlers;
377           free_handlers = old;
378         }
379     }
380   else if (used)
381     {
382       current_handler = current_handler->next;
383     }
384 }
385
386 /* Emit code before an action that has an ON-handler. */
387
388 static void
389 emit_setup_handler ()
390 {
391   tree handler_decl, handler_addr, t;
392
393   /* Field references. */
394   tree jbuf_ref, handlers_ref,prev_ref;
395   if (!exceptions_initialized)
396     {
397       /* We temporarily reset the maximum_field_alignment to zero so the
398          compiler's exception data structures can be compatible with the
399          run-time system, even when we're compiling with -fpack. */
400       extern int maximum_field_alignment;
401       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   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 = current_handler->on_alt_list;
516       while (TREE_INT_CST_LOW (TREE_PURPOSE (tmp)) != alternative)
517         tmp = TREE_CHAIN (tmp);
518       if (expand_exit_needed)
519         expand_exit_something (), expand_exit_needed = 0;
520       chill_handle_case_label (TREE_PURPOSE (tmp),
521                                current_handler->setjmp_expr);
522     }
523 }
524
525 void
526 chill_start_default_handler ()
527 {
528   current_handler->else_handler = ++current_handler->prev_on_alternative;
529   if (!ignoring)
530     {
531       chill_handle_case_default ();
532     }
533 }
534
535 void
536 chill_check_no_handlers ()
537 {
538   if (current_handler != NULL)
539     fatal ("internal error: on stack not empty when done");
540 }
541
542 static void
543 initialize_exceptions ()
544 {
545   tree jmp_buf_type = build_array_type (integer_type_node,
546                                         build_index_type (build_int_2 (_JBLEN_2-1, 0)));
547   tree setjmp_fndecl, link_ftype;
548   tree parmtypes
549     = tree_cons (NULL_TREE, build_pointer_type (jmp_buf_type), void_list_node);
550
551   setjmp_fndecl = builtin_function ("setjmp",
552                                     build_function_type (integer_type_node,
553                                                          parmtypes),
554                                     NOT_BUILT_IN,
555                                     SETJMP_LIBRARY_NAME);
556   BISJ = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (setjmp_fndecl)),
557                  setjmp_fndecl);
558  
559   char_pointer_type_for_handler
560     = build_pointer_type (build_type_variant (char_type_node, 1, 0));
561   handler_element_type =
562     build_chill_struct_type (chainon
563                              (build_decl (FIELD_DECL,
564                                           get_identifier("__exceptid"),
565                                           char_pointer_type_for_handler),
566                               build_decl (FIELD_DECL,
567                                           get_identifier("__handlerno"),
568                                           integer_type_node)));
569
570   jbuf_ident = get_identifier("__jbuf");
571   prev_ident = get_identifier("__prev");
572   handlers_ident = get_identifier("__handlers");
573
574   handler_link_type =
575     build_chill_struct_type
576       (chainon
577        (build_decl (FIELD_DECL, prev_ident, ptr_type_node),
578         chainon
579         (build_decl (FIELD_DECL, handlers_ident,
580                      build_pointer_type (handler_element_type)),
581          build_decl (FIELD_DECL, jbuf_ident, jmp_buf_type))));
582
583   handler_link_pointer_type = build_pointer_type (handler_link_type);
584
585   if (inline_exception_stack_ops)
586     {
587       exception_stack_decl =
588         build_lang_decl (VAR_DECL,
589                          get_identifier("__exceptionStack"),
590                          handler_link_pointer_type);
591       TREE_STATIC (exception_stack_decl) = 1;
592       TREE_PUBLIC (exception_stack_decl) = 1;
593       DECL_EXTERNAL (exception_stack_decl) = 1;
594       push_obstacks_nochange ();
595       pushdecl(exception_stack_decl);
596       make_decl_rtl (exception_stack_decl, NULL_PTR, 1);
597       finish_decl (exception_stack_decl);
598     }
599
600   link_ftype = build_function_type (void_type_node,
601                                     tree_cons (NULL_TREE,
602                                                handler_link_pointer_type,
603                                                void_list_node));
604   link_handler_decl = builtin_function ("__ch_link_handler", link_ftype,
605                                         NOT_BUILT_IN, NULL_PTR);
606   unlink_handler_decl = builtin_function ("__ch_unlink_handler", link_ftype,
607                                           NOT_BUILT_IN, NULL_PTR);
608
609   exceptions_initialized = 1;
610 }
611
612 /* Do the cleanup(s) needed for a GOTO label.
613    We only need to do the last of the cleanups. */
614
615 void
616 expand_goto_except_cleanup (label_level)
617      int label_level;
618 {
619   tree list = cleanup_chain;
620   tree last = NULL_TREE;
621   for ( ; list != NULL_TREE; list = TREE_CHAIN (list))
622     {
623       if (TREE_INT_CST_LOW (TREE_PURPOSE (list)) > label_level)
624         last = list;
625       else
626         break;
627     }
628   if (last)
629     expand_expr_stmt (TREE_VALUE (last));
630 }
631
632 /* Returns true if there is a valid handler for EXCEPT_NAME
633    in the current static scope.
634    0 ... no handler found
635    1 ... local handler available
636    2 ... function may propagate this exception
637 */
638
639 int
640 is_handled (except_name)
641      tree except_name;
642 {
643   tree t;
644   struct handler_state *h = current_handler;
645
646   /* if we are are currently compiling this handler
647      we have to start at the next level */
648   if (h && h->compiling)
649     h = h->next;
650   while (h != NULL)
651     {
652       if (h->function != current_function_decl)
653         break;
654       if (h->else_handler > 0)
655         return 1;
656       for (t = h->on_alt_list; t != NULL_TREE; t = TREE_CHAIN (t))
657         {
658           if (value_member (except_name, TREE_VALUE (t)))
659             return 1;
660         }
661       h = h->next;
662     }
663
664   t = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl));
665
666   if (value_member (except_name, t))
667     return 2;
668   return 0;
669 }
670
671 /* function generates code to reraise exceptions
672    for PROC's propagating exceptions. */
673
674 void
675 chill_reraise_exceptions (exceptions)
676      tree exceptions;
677 {
678   tree wrk;
679
680   if (exceptions == NULL_TREE)
681     return; /* just in case */
682
683   if (pass == 1)
684     {
685       for (wrk = exceptions; wrk != NULL_TREE; wrk = TREE_CHAIN (wrk))
686         chill_handle_on_labels (build_tree_list (NULL_TREE, TREE_VALUE (wrk)));
687     }
688   else /* pass == 2 */
689     {
690       chill_start_on ();
691       expand_exit_needed = 0;
692
693       for (wrk = exceptions; wrk != NULL_TREE; wrk = TREE_CHAIN (wrk))
694         {
695           chill_handle_on_labels (TREE_VALUE (wrk));
696           /* do a CAUSE exception */
697           expand_expr_stmt (build_cause_exception (TREE_VALUE (wrk), 0));
698           expand_exit_needed = 1;
699         }
700       chill_finish_on ();
701     }
702   pop_handler (1);
703 }