* splay-tree.h (splay_tree_max): New function.
[official-gcc.git] / gcc / ch / except.c
blobb32dba60636bf5f6a22daf485ff52a7ce6ca1fb2
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.
6 This file is part of GNU CC.
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.
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.
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. */
23 #include "config.h"
24 #include "system.h"
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
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
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
53 #include "tree.h"
54 #include "ch-tree.h"
55 #include "rtl.h"
56 #include "toplev.h"
58 extern int expand_exit_needed;
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;
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;
75 struct handler_state
77 struct handler_state *next;
79 /* Starts at 0, then incremented for every <on-alternative>. */
80 int prev_on_alternative;
82 /* If > 0: handler number for ELSE handler. */
83 int else_handler;
85 int action_number;
87 char do_pushlevel;
89 tree on_alt_list;
90 tree setjmp_expr;
92 /* A decl for the static handler array (used to map exception name to int).*/
93 tree handler_array_decl;
95 rtx end_label;
97 /* Used to pass a tree from emit_setup_handler to chill_start_on. */
98 tree handler_ref;
100 tree unlink_cleanup;
102 tree function;
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;
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;
113 int action_nesting_level = 0;
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;
122 /* This is a stack of handlers, one for each nested ON-handler. */
123 static struct handler_state *current_handler = NULL;
125 static struct handler_state *free_handlers = NULL; /* freelist */
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;
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. */
138 static tree cleanup_chain = NULL_TREE;
140 #if 0
141 /* Merge the current sequence onto the tail of the previous one. */
143 void
144 pop_sequence ()
146 rtx sequence_first = get_insns ();
148 end_sequence ();
149 emit_insns (sequence_first);
152 #endif
154 /* Things we need to do at the beginning of pass 2. */
156 void
157 except_init_pass_2 ()
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. */
163 register struct handler_state *old_list = global_handler_list;
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)
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;
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;
188 /* Don't forget to reset action_number. */
189 action_number = 0;
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. */
197 void
198 push_handler ()
200 register struct handler_state *hstate;
202 action_number++;
203 action_nesting_level++;
205 if (pass == 1)
207 if (free_handlers)
209 hstate = free_handlers;
210 free_handlers = hstate->next;
212 else
214 hstate =
215 (struct handler_state*) permalloc (sizeof (struct handler_state));
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;
225 ACTION_NUMBER (hstate) = action_number;
226 return;
229 if (ACTION_NUMBER (global_handler_list) != action_number)
230 return;
232 /* OK. This action actually has an ON-handler.
233 Pop it from global_handler_list, and use it. */
235 hstate = global_handler_list;
236 global_handler_list = hstate->next;
238 /* Since this is pass 2, let's generate prologue code for that. */
240 hstate->next = current_handler;
241 current_handler = hstate;
243 hstate->prev_on_alternative = 0;
244 hstate->function = current_function_decl;
246 emit_setup_handler ();
249 static tree
250 start_handler_array ()
252 tree handler_array_type, decl;
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);
261 /* TREE_TYPE (decl) = handler_array_type;*/
262 TREE_READONLY (decl) = 1;
263 TREE_STATIC (decl) = 1;
264 DECL_INITIAL (decl) = error_mark_node;
266 pushdecl (decl);
267 make_decl_rtl (decl, NULL_PTR, 0);
268 current_handler->handler_array_decl = decl;
269 return decl;
272 static void
273 finish_handler_array ()
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;
281 /* Build the table mapping exceptions to handler(-number)s.
282 This is done in reverse order. */
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))))));
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))
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++;
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));
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);
349 finish_decl (current_handler->handler_array_decl,
350 build_nt (CONSTRUCTOR, NULL_TREE, handler_array_init),
351 NULL_TREE);
352 #endif
356 void
357 pop_handler (used)
358 int used;
360 action_nesting_level--;
361 if (pass == 1)
363 struct handler_state *old = current_handler;
365 if (old == NULL)
366 abort ();
367 current_handler = old->next;
369 if (used)
370 { /* Push unto global_handler_list. */
371 old->next = global_handler_list;
372 global_handler_list = old;
374 else
376 /* Push onto free_handlers free list. */
377 old->next = free_handlers;
378 free_handlers = old;
381 else if (used)
383 current_handler = current_handler->next;
387 /* Emit code before an action that has an ON-handler. */
389 static void
390 emit_setup_handler ()
392 tree handler_decl, handler_addr, t;
394 /* Field references. */
395 tree jbuf_ref, handlers_ref,prev_ref;
396 if (!exceptions_initialized)
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;
410 push_momentary ();
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);
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);
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)
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;
436 else
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;
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));
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);
463 /* Emit code for setjmp. */
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");
470 chill_handle_case_label (integer_zero_node, current_handler->setjmp_expr);
473 /* Start emitting code for: <actions> ON <handlers> END.
474 Assume we've parsed <actions>, and the setup needed for it. */
476 void
477 chill_start_on ()
479 expand_expr_stmt (current_handler->unlink_cleanup);
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);
487 void
488 chill_finish_on ()
490 expand_end_case (current_handler->setjmp_expr);
492 finish_handler_array ();
494 emit_label (current_handler->end_label);
496 pop_momentary ();
498 cleanup_chain = TREE_CHAIN (cleanup_chain);
501 void
502 chill_handle_on_labels (labels)
503 tree labels;
505 unsigned int alternative = ++current_handler->prev_on_alternative;
506 if (pass == 1)
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);
512 else
514 /* Find handler_number saved in pass 1. */
515 tree tmp;
517 for (tmp = current_handler->on_alt_list;
518 compare_tree_int (TREE_PURPOSE (tmp), alternative) != 0;
519 tmp = TREE_CHAIN (tmp))
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);
529 void
530 chill_start_default_handler ()
532 current_handler->else_handler = ++current_handler->prev_on_alternative;
533 if (!ignoring)
535 chill_handle_case_default ();
539 void
540 chill_check_no_handlers ()
542 if (current_handler != NULL)
543 abort ();
546 static void
547 initialize_exceptions ()
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);
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);
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)));
574 jbuf_ident = get_identifier("__jbuf");
575 prev_ident = get_identifier("__prev");
576 handlers_ident = get_identifier("__handlers");
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))));
587 handler_link_pointer_type = build_pointer_type (handler_link_type);
589 if (inline_exception_stack_ops)
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);
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);
613 exceptions_initialized = 1;
616 /* Do the cleanup(s) needed for a GOTO label.
617 We only need to do the last of the cleanups. */
619 void
620 expand_goto_except_cleanup (label_level)
621 int label_level;
623 tree list = cleanup_chain;
624 tree last = NULL_TREE;
625 for ( ; list != NULL_TREE; list = TREE_CHAIN (list))
627 if (compare_tree_int (TREE_PURPOSE (list), label_level) > 0)
628 last = list;
629 else
630 break;
632 if (last)
633 expand_expr_stmt (TREE_VALUE (last));
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
644 is_handled (except_name)
645 tree except_name;
647 tree t;
648 struct handler_state *h = current_handler;
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)
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))
662 if (value_member (except_name, TREE_VALUE (t)))
663 return 1;
665 h = h->next;
668 t = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl));
670 if (value_member (except_name, t))
671 return 2;
672 return 0;
675 /* function generates code to reraise exceptions
676 for PROC's propagating exceptions. */
678 void
679 chill_reraise_exceptions (exceptions)
680 tree exceptions;
682 tree wrk;
684 if (exceptions == NULL_TREE)
685 return; /* just in case */
687 if (pass == 1)
689 for (wrk = exceptions; wrk != NULL_TREE; wrk = TREE_CHAIN (wrk))
690 chill_handle_on_labels (build_tree_list (NULL_TREE, TREE_VALUE (wrk)));
692 else /* pass == 2 */
694 chill_start_on ();
695 expand_exit_needed = 0;
697 for (wrk = exceptions; wrk != NULL_TREE; wrk = TREE_CHAIN (wrk))
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;
704 chill_finish_on ();
706 pop_handler (1);