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