OSDN Git Service

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