* dbxout.c (dbxout_source_line): Remove extra tab.
[gcc.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 }