163} 164 165 166 167 168/* from: my-cp-except.c */ 169 170/* VI: ":set ts=4" */ 171#if 0 172#include <stdio.h> */ 173#include "config.h" 174#include "tree.h" 175#include "rtl.h" 176#include "cp-tree.h" 177#endif 178#include "decl.h" 179#if 0 180#include "flags.h" 181#endif 182#include "insn-flags.h" 183#include "obstack.h" 184#if 0 185#include "expr.h" 186#endif 187 188/* ====================================================================== 189 Briefly the algorithm works like this: 190 191 When a constructor or start of a try block is encountered, 192 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a 193 new entry in the unwind protection stack and returns a label to 194 output to start the protection for that block. 195 196 When a destructor or end try block is encountered, pop_eh_entry 197 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it 198 created when push_eh_entry () was called. The ehEntry structure 199 contains three things at this point. The start protect label, 200 the end protect label, and the exception handler label. The end 201 protect label should be output before the call to the destructor 202 (if any). If it was a destructor, then its parse tree is stored 203 in the finalization variable in the ehEntry structure. Otherwise 204 the finalization variable is set to NULL to reflect the fact that 205 is the the end of a try block. Next, this modified ehEntry node 206 is enqueued in the finalizations queue by calling 207 enqueue_eh_entry (&queue,entry). 208 209 +---------------------------------------------------------------+ 210 |XXX: Will need modification to deal with partially | 211 | constructed arrays of objects | 212 | | 213 | Basically, this consists of keeping track of how many | 214 | of the objects have been constructed already (this | 215 | should be in a register though, so that shouldn't be a | 216 | problem. | 217 +---------------------------------------------------------------+ 218 219 When a catch block is encountered, there is a lot of work to be 220 done. 221 222 Since we don't want to generate the catch block inline with the 223 regular flow of the function, we need to have some way of doing 224 so. Luckily, we can use sequences to defer the catch sections. 225 When the start of a catch block is encountered, we start the 226 sequence. After the catch block is generated, we end the 227 sequence. 228 229 Next we must insure that when the catch block is executed, all 230 finalizations for the matching try block have been completed. If 231 any of those finalizations throw an exception, we must call 232 terminate according to the ARM (section r.15.6.1). What this 233 means is that we need to dequeue and emit finalizations for each 234 entry in the ehQueue until we get to an entry with a NULL 235 finalization field. For any of the finalization entries, if it 236 is not a call to terminate (), we must protect it by giving it 237 another start label, end label, and exception handler label, 238 setting its finalization tree to be a call to terminate (), and 239 enqueue'ing this new ehEntry to be output at an outer level. 240 Finally, after all that is done, we can get around to outputting 241 the catch block which basically wraps all the "catch (...) {...}" 242 statements in a big if/then/else construct that matches the 243 correct block to call. 244 245 ===================================================================== */ 246 247extern rtx emit_insn PROTO((rtx)); 248extern rtx gen_nop PROTO(()); 249 250/* local globals for function calls 251 ====================================================================== */ 252 253/* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and 254 "set_unexpected ()" after default_conversion. (lib-except.c) */ 255static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw; 256 257/* used to cache __find_first_exception_table_match () 258 for throw (lib-except.c) */ 259static tree FirstExceptionMatch; 260 261/* used to cache a call to __unwind_function () (lib-except.c) */ 262static tree Unwind; 263 264/* holds a ready to emit call to "terminate ()". */ 265static tree TerminateFunctionCall; 266 267/* ====================================================================== */ 268 269 270 271/* data structures for my various quick and dirty stacks and queues 272 Eventually, most of this should go away, because I think it can be 273 integrated with stuff already built into the compiler. */ 274 275/* =================================================================== */ 276 277struct labelNode { 278 rtx label; 279 struct labelNode *chain; 280}; 281 282 283/* this is the most important structure here. Basically this is how I store 284 an exception table entry internally. */ 285struct ehEntry { 286 rtx start_label; 287 rtx end_label; 288 rtx exception_handler_label; 289 290 tree finalization; 291 tree context; 292}; 293 294struct ehNode { 295 struct ehEntry *entry; 296 struct ehNode *chain; 297}; 298 299struct ehStack { 300 struct ehNode *top; 301}; 302 303struct ehQueue { 304 struct ehNode *head; 305 struct ehNode *tail; 306}; 307/* ========================================================================= */ 308 309 310 311/* local globals - these local globals are for storing data necessary for 312 generating the exception table and code in the correct order. 313 314 ========================================================================= */ 315 316/* Holds the pc for doing "throw" */ 317tree saved_pc; 318/* Holds the type of the thing being thrown. */ 319tree saved_throw_type; 320/* Holds the value being thrown. */ 321tree saved_throw_value; 322 323int throw_used; 324 325static rtx catch_clauses; 326static first_catch_label; 327 328static struct ehStack ehstack; 329static struct ehQueue ehqueue; 330static struct ehQueue eh_table_output_queue; 331static struct labelNode *false_label_stack = NULL; 332static struct labelNode *caught_return_label_stack = NULL; 333/* ========================================================================= */ 334 335/* function prototypes */ 336static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack)); 337static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry)); 338static rtx push_eh_entry PROTO((struct ehStack *stack)); 339static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue)); 340static void new_eh_queue PROTO((struct ehQueue *queue)); 341static void new_eh_stack PROTO((struct ehStack *stack)); 342static void push_label_entry PROTO((struct labelNode **labelstack, rtx label)); 343static rtx pop_label_entry PROTO((struct labelNode **labelstack)); 344static rtx top_label_entry PROTO((struct labelNode **labelstack)); 345static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry)); 346 347 348 349/* All my cheesy stack/queue/misc data structure handling routines 350 351 ========================================================================= */ 352 353static void 354push_label_entry (labelstack, label) 355 struct labelNode **labelstack; 356 rtx label; 357{ 358 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode)); 359 360 newnode->label = label; 361 newnode->chain = *labelstack; 362 *labelstack = newnode; 363} 364 365static rtx 366pop_label_entry (labelstack) 367 struct labelNode **labelstack; 368{ 369 rtx label; 370 struct labelNode *tempnode; 371 372 if (! *labelstack) return NULL_RTX; 373 374 tempnode = *labelstack; 375 label = tempnode->label; 376 *labelstack = (*labelstack)->chain; 377 free (tempnode); 378 379 return label; 380} 381 382static rtx 383top_label_entry (labelstack) 384 struct labelNode **labelstack; 385{ 386 if (! *labelstack) return NULL_RTX; 387 388 return (*labelstack)->label; 389} 390 391/* Push to permanent obstack for rtl generation. 392 One level only! */ 393static struct obstack *saved_rtl_obstack; 394void 395push_rtl_perm () 396{ 397 extern struct obstack permanent_obstack; 398 extern struct obstack *rtl_obstack; 399 400 saved_rtl_obstack = rtl_obstack; 401 rtl_obstack = &permanent_obstack; 402} 403 404/* Pop back to normal rtl handling. */ 405static void 406pop_rtl_from_perm () 407{ 408 extern struct obstack permanent_obstack; 409 extern struct obstack *rtl_obstack; 410 411 rtl_obstack = saved_rtl_obstack; 412} 413 414static rtx 415push_eh_entry (stack) 416 struct ehStack *stack; 417{ 418 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode)); 419 struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry)); 420 421 if (stack == NULL) { 422 free (node); 423 free (entry); 424 return NULL_RTX; 425 } 426 427 /* These are saved for the exception table. */ 428 push_rtl_perm (); 429 entry->start_label = gen_label_rtx (); 430 entry->end_label = gen_label_rtx (); 431 entry->exception_handler_label = gen_label_rtx (); 432 pop_rtl_from_perm (); 433 434 LABEL_PRESERVE_P (entry->start_label) = 1; 435 LABEL_PRESERVE_P (entry->end_label) = 1; 436 LABEL_PRESERVE_P (entry->exception_handler_label) = 1; 437 438 entry->finalization = NULL_TREE; 439 entry->context = current_function_decl; 440 441 node->entry = entry; 442 node->chain = stack->top; 443 stack->top = node; 444 445 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry)); 446 447 return entry->start_label; 448} 449 450static struct ehEntry * 451pop_eh_entry (stack) 452 struct ehStack *stack; 453{ 454 struct ehNode *tempnode; 455 struct ehEntry *tempentry; 456 457 if (stack && (tempnode = stack->top)) { 458 tempentry = tempnode->entry; 459 stack->top = stack->top->chain; 460 free (tempnode); 461 462 return tempentry; 463 } 464 465 return NULL; 466} 467 468static struct ehEntry * 469copy_eh_entry (entry) 470 struct ehEntry *entry; 471{ 472 struct ehEntry *newentry; 473 474 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry)); 475 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry)); 476 477 return newentry; 478} 479 480static void 481enqueue_eh_entry (queue, entry) 482 struct ehQueue *queue; 483 struct ehEntry *entry; 484{ 485 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode)); 486 487 node->entry = entry; 488 node->chain = NULL; 489 490 if (queue->head == NULL) 491 { 492 queue->head = node; 493 } 494 else 495 { 496 queue->tail->chain = node; 497 } 498 queue->tail = node; 499} 500 501static struct ehEntry * 502dequeue_eh_entry (queue) 503 struct ehQueue *queue; 504{ 505 struct ehNode *tempnode; 506 struct ehEntry *tempentry; 507 508 if (queue->head == NULL) 509 return NULL; 510 511 tempnode = queue->head; 512 queue->head = queue->head->chain; 513 514 tempentry = tempnode->entry; 515 free (tempnode); 516 517 return tempentry; 518} 519 520static void 521new_eh_queue (queue) 522 struct ehQueue *queue; 523{ 524 queue->head = queue->tail = NULL; 525} 526 527static void 528new_eh_stack (stack) 529 struct ehStack *stack; 530{ 531 stack->top = NULL; 532} 533 534/* cheesyness to save some typing. returns the return value rtx */ 535rtx 536do_function_call (func, params, return_type) 537 tree func, params, return_type; 538{ 539 tree func_call; 540 func_call = build_function_call (func, params); 541 expand_call (func_call, NULL_RTX, 0); 542 if (return_type != NULL_TREE) 543 return hard_function_value (return_type, func_call); 544 return NULL_RTX; 545} 546 547static void 548expand_internal_throw (pc) 549 rtx pc; 550{ 551 tree params; 552 553 emit_move_insn (DECL_RTL (saved_pc), pc); 554#ifdef JUMP_TO_THROW 555 emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw")); 556#else 557 do_function_call (Throw, NULL_TREE, NULL_TREE); 558#endif 559 throw_used = 1; 560} 561 562/* ========================================================================= */ 563 564void 565lang_interim_eh (finalization) 566 tree finalization; 567{ 568 if (finalization) 569 end_protect (finalization); 570 else 571 start_protect (); 572} 573 574extern tree auto_function PROTO((tree, tree, enum built_in_function)); 575 576/* sets up all the global eh stuff that needs to be initialized at the 577 start of compilation. 578 579 This includes: 580 - Setting up all the function call trees 581 - Initializing the ehqueue 582 - Initializing the eh_table_output_queue 583 - Initializing the ehstack 584*/ 585 586void 587init_exception_processing () 588{ 589 extern tree define_function (); 590 tree unexpected_fndecl, terminate_fndecl; 591 tree set_unexpected_fndecl, set_terminate_fndecl; 592 tree catch_match_fndecl; 593 tree find_first_exception_match_fndecl; 594 tree unwind_fndecl; 595 tree declspecs; 596 tree d; 597 598 /* void (*)() */ 599 tree PFV = build_pointer_type (build_function_type 600 (void_type_node, void_list_node)); 601 602 /* arg list for the build_function_type call for set_terminate () and 603 set_unexpected () */ 604 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node); 605 606 /* void (*pfvtype (void (*) ()))() */ 607 tree pfvtype = build_function_type (PFV, pfvlist); 608 609 /* void vtype () */ 610 tree vtype = build_function_type (void_type_node, void_list_node); 611 612 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"), 613 pfvtype, NOT_BUILT_IN); 614 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"), 615 pfvtype, NOT_BUILT_IN); 616 unexpected_fndecl = auto_function (get_identifier ("unexpected"), 617 vtype, NOT_BUILT_IN); 618 terminate_fndecl = auto_function (get_identifier ("terminate"), 619 vtype, NOT_BUILT_IN); 620 621 interim_eh_hook = lang_interim_eh; 622 623 push_lang_context (lang_name_c); 624 625 catch_match_fndecl = 626 define_function (flag_rtti 627 ? "__throw_type_match_rtti" 628 : "__throw_type_match", 629 build_function_type (ptr_type_node, 630 tree_cons (NULL_TREE, ptr_type_node, 631 tree_cons (NULL_TREE, ptr_type_node, 632 tree_cons (NULL_TREE, ptr_type_node, 633 void_list_node)))), 634 NOT_BUILT_IN, 635 pushdecl, 636 0); 637 find_first_exception_match_fndecl = 638 define_function ("__find_first_exception_table_match", 639 build_function_type (ptr_type_node, 640 tree_cons (NULL_TREE, ptr_type_node, 641 void_list_node)), 642 NOT_BUILT_IN, 643 pushdecl, 644 0); 645 unwind_fndecl = 646 define_function ("__unwind_function", 647 build_function_type (void_type_node, 648 tree_cons (NULL_TREE, ptr_type_node, 649 void_list_node)), 650 NOT_BUILT_IN, 651 pushdecl, 652 0); 653 throw_fndecl = 654 define_function ("__throw", 655 build_function_type (void_type_node, void_list_node), 656 NOT_BUILT_IN, 657 pushdecl, 658 0); 659 DECL_EXTERNAL (throw_fndecl) = 0; 660 TREE_PUBLIC (throw_fndecl) = 0; 661 662 Unexpected = default_conversion (unexpected_fndecl); 663 Terminate = default_conversion (terminate_fndecl); 664 SetTerminate = default_conversion (set_terminate_fndecl); 665 SetUnexpected = default_conversion (set_unexpected_fndecl); 666 CatchMatch = default_conversion (catch_match_fndecl); 667 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl); 668 Unwind = default_conversion (unwind_fndecl); 669 Throw = default_conversion (throw_fndecl); 670 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl); 671 672 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE); 673 674 pop_lang_context (); 675 676 new_eh_queue (&ehqueue); 677 new_eh_queue (&eh_table_output_queue); 678 new_eh_stack (&ehstack); 679 680 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); 681 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc")); 682 d = start_decl (d, declspecs, 0, NULL_TREE); 683 DECL_COMMON (d) = 1; 684 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); 685 saved_pc = lookup_name (get_identifier ("__eh_pc"), 0); 686 687 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); 688 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type")); 689 d = start_decl (d, declspecs, 0, NULL_TREE); 690 DECL_COMMON (d) = 1; 691 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); 692 saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0); 693 694 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); 695 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value")); 696 d = start_decl (d, declspecs, 0, NULL_TREE); 697 DECL_COMMON (d) = 1; 698 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); 699 saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0); 700} 701 702/* call this to begin a block of unwind protection (ie: when an object is 703 constructed) */ 704void 705start_protect () 706{ 707 if (! doing_eh (0)) 708 return; 709 710 emit_label (push_eh_entry (&ehstack)); 711} 712 713/* call this to end a block of unwind protection. the finalization tree is 714 the finalization which needs to be run in order to cleanly unwind through 715 this level of protection. (ie: call this when a scope is exited)*/ 716void 717end_protect (finalization) 718 tree finalization; 719{ 720 struct ehEntry *entry; 721 722 if (! doing_eh (0)) 723 return; 724 725 entry = pop_eh_entry (&ehstack); 726 727 emit_label (entry->end_label); 728 /* Put in something that takes up space, as otherwise the end 729 address for the EH region could have the exact same address as 730 the outer region, causing us to miss the fact that resuming 731 exception handling with this PC value would be inside the outer 732 region. */ 733 emit_insn (gen_nop ()); 734 735 entry->finalization = finalization; 736 737 enqueue_eh_entry (&ehqueue, entry); 738} 739 740/* call this on start of a try block. */ 741void 742expand_start_try_stmts () 743{ 744 if (! doing_eh (1)) 745 return; 746 747 start_protect (); 748} 749 750void 751expand_end_try_stmts () 752{ 753 end_protect (integer_zero_node); 754} 755 756 757/* call this to start processing of all the catch blocks. */ 758void 759expand_start_all_catch () 760{ 761 struct ehEntry *entry; 762 rtx label; 763 764 if (! doing_eh (1)) 765 return; 766 767 emit_line_note (input_filename, lineno); 768 label = gen_label_rtx (); 769 770 /* The label for the exception handling block we will save. This is 771 Lresume, in the documention. */ 772 emit_label (label); 773 774 /* Put in something that takes up space, as otherwise the end 775 address for the EH region could have the exact same address as 776 the outer region, causing us to miss the fact that resuming 777 exception handling with this PC value would be inside the outer 778 region. */ 779 emit_insn (gen_nop ()); 780 781 push_label_entry (&caught_return_label_stack, label); 782 783 /* Start a new sequence for all the catch blocks. We will add this 784 to the gloabl sequence catch_clauses, when we have completed all 785 the handlers in this handler-seq. */ 786 start_sequence (); 787 788 while (1) 789 { 790 entry = dequeue_eh_entry (&ehqueue); 791 emit_label (entry->exception_handler_label); 792 793 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); 794 795 /* When we get down to the matching entry, stop. */ 796 if (entry->finalization == integer_zero_node) 797 break; 798 799 /* The below can be optimized away, and we could just fall into the 800 next EH handler, if we are certain they are nested. */ 801 /* Code to throw out to outer context, if we fall off end of the 802 handler. */ 803 expand_internal_throw (gen_rtx (LABEL_REF, 804 Pmode, 805 entry->end_label)); 806 free (entry); 807 } 808} 809 810/* call this to end processing of all the catch blocks. */ 811void 812expand_end_all_catch () 813{ 814 rtx new_catch_clause; 815 816 if (! doing_eh (1)) 817 return; 818 819 /* Code to throw out to outer context, if we fall off end of catch 820 handlers. This is rethrow (Lresume, same id, same obj); in the 821 documentation. */ 822 expand_internal_throw (gen_rtx (LABEL_REF, 823 Pmode, 824 top_label_entry (&caught_return_label_stack))); 825 826 /* Now we have the complete catch sequence. */ 827 new_catch_clause = get_insns (); 828 end_sequence (); 829 830 /* this level of catch blocks is done, so set up the successful catch jump 831 label for the next layer of catch blocks. */ 832 pop_label_entry (&caught_return_label_stack); 833 834 /* Add the new sequence of catchs to the main one for this 835 function. */ 836 push_to_sequence (catch_clauses); 837 emit_insns (new_catch_clause); 838 catch_clauses = get_insns (); 839 end_sequence (); 840 841 /* Here we fall through into the continuation code. */ 842} 843 844/* Build a type value for use at runtime for a type that is matched 845 against by the exception handling system. */ 846static tree 847build_eh_type_type (type) 848 tree type; 849{ 850 char *typestring; 851 tree exp; 852 853 if (type == error_mark_node) 854 return error_mark_node; 855 856 /* peel back references, so they match. */ 857 if (TREE_CODE (type) == REFERENCE_TYPE) 858 type = TREE_TYPE (type); 859 860 /* Peel off cv qualifiers. */ 861 type = TYPE_MAIN_VARIANT (type); 862 863 if (flag_rtti) 864 { 865 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type)); 866 } 867 868 typestring = build_overload_name (type, 1, 1); 869 exp = combine_strings (build_string (strlen (typestring)+1, typestring)); 870 return build1 (ADDR_EXPR, ptr_type_node, exp); 871} 872 873/* Build a type value for use at runtime for a exp that is thrown or 874 matched against by the exception handling system. */ 875static tree 876build_eh_type (exp) 877 tree exp; 878{ 879 if (flag_rtti) 880 { 881 exp = build_typeid (exp); 882 return build1 (ADDR_EXPR, ptr_type_node, exp); 883 } 884 return build_eh_type_type (TREE_TYPE (exp)); 885} 886 887/* call this to start a catch block. Typename is the typename, and identifier 888 is the variable to place the object in or NULL if the variable doesn't 889 matter. If typename is NULL, that means its a "catch (...)" or catch 890 everything. In that case we don't need to do any type checking. 891 (ie: it ends up as the "else" clause rather than an "else if" clause) */ 892void 893expand_start_catch_block (declspecs, declarator) 894 tree declspecs, declarator; 895{ 896 rtx false_label_rtx; 897 rtx protect_label_rtx; 898 tree decl = NULL_TREE; 899 tree init; 900 901 if (! doing_eh (1)) 902 return; 903 904 /* Create a binding level for the parm. */ 905 expand_start_bindings (0); 906 907 false_label_rtx = gen_label_rtx (); 908 /* This is saved for the exception table. */ 909 push_rtl_perm (); 910 protect_label_rtx = gen_label_rtx (); 911 pop_rtl_from_perm (); 912 push_label_entry (&false_label_stack, false_label_rtx); 913 push_label_entry (&false_label_stack, protect_label_rtx); 914 915 if (declspecs) 916 { 917 tree exp; 918 rtx call_rtx, return_value_rtx; 919 tree init_type; 920 921 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, 922 NULL_TREE, NULL_TREE); 923 924 if (decl == NULL_TREE) 925 { 926 error ("invalid catch parameter"); 927 return; 928 } 929 930 /* Figure out the type that the initializer is. */ 931 init_type = TREE_TYPE (decl); 932 if (TREE_CODE (init_type) != REFERENCE_TYPE 933 && TREE_CODE (init_type) != POINTER_TYPE) 934 init_type = build_reference_type (init_type); 935 936 exp = saved_throw_value; 937 exp = tree_cons (NULL_TREE, 938 build_eh_type_type (TREE_TYPE (decl)), 939 tree_cons (NULL_TREE, 940 saved_throw_type, 941 tree_cons (NULL_TREE, exp, NULL_TREE))); 942 exp = build_function_call (CatchMatch, exp); 943 call_rtx = expand_call (exp, NULL_RTX, 0); 944 assemble_external (TREE_OPERAND (CatchMatch, 0)); 945 946 return_value_rtx = hard_function_value (ptr_type_node, exp); 947 948 /* did the throw type match function return TRUE? */ 949 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX, 950 GET_MODE (return_value_rtx), 0, 0); 951 952 /* if it returned FALSE, jump over the catch block, else fall into it */ 953 emit_jump_insn (gen_beq (false_label_rtx)); 954 955 init = convert_from_reference (save_expr (make_tree (init_type, call_rtx))); 956 957 /* Do we need the below two lines? */ 958 /* Let `cp_finish_decl' know that this initializer is ok. */ 959 DECL_INITIAL (decl) = init; 960 decl = pushdecl (decl); 961 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); 962 } 963 else 964 { 965 /* Fall into the catch all section. */ 966 } 967 968 /* This is the starting of something to protect. */ 969 emit_label (protect_label_rtx); 970 971 emit_line_note (input_filename, lineno); 972} 973 974 975/* this is called from expand_exception_blocks and 976 expand_end_catch_block to expand the toplevel finalizations for a 977 function. We return the first label emitted, if any, otherwise 978 return NULL_RTX. */ 979static rtx 980expand_leftover_cleanups () 981{ 982 struct ehEntry *entry; 983 rtx first_label = NULL_RTX; 984 985 while ((entry = dequeue_eh_entry (&ehqueue)) != 0) 986 { 987 if (! first_label) 988 first_label = entry->exception_handler_label; 989 emit_label (entry->exception_handler_label); 990 991 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); 992 993 /* The below can be optimized away, and we could just fall into the 994 next EH handler, if we are certain they are nested. */ 995 /* Code to throw out to outer context, if we fall off end of the 996 handler. */ 997 expand_internal_throw (gen_rtx (LABEL_REF, 998 Pmode, 999 entry->end_label)); 1000 1001 /* leftover try block, opps. */ 1002 if (entry->finalization == integer_zero_node) 1003 abort (); 1004 1005 free (entry); 1006 } 1007 1008 return first_label; 1009} 1010 1011/* Call this to end a catch block. Its responsible for emitting the 1012 code to handle jumping back to the correct place, and for emitting 1013 the label to jump to if this catch block didn't match. */ 1014void expand_end_catch_block () 1015{ 1016 rtx start_protect_label_rtx; 1017 rtx end_protect_label_rtx; 1018 tree decls; 1019 struct ehEntry entry; 1020 1021 if (! doing_eh (1)) 1022 return; 1023 1024 /* fall to outside the try statement when done executing handler and 1025 we fall off end of handler. This is jump Lresume in the 1026 documentation. */ 1027 emit_jump (top_label_entry (&caught_return_label_stack)); 1028 1029 /* We end the rethrow protection region as soon as we hit a label. */ 1030 end_protect_label_rtx = expand_leftover_cleanups (); 1031 1032 /* Code to throw out to outer context, if we get a throw from within 1033 our catch handler. */ 1034 /* These are saved for the exception table. */ 1035 push_rtl_perm (); 1036 entry.exception_handler_label = gen_label_rtx (); 1037 pop_rtl_from_perm (); 1038 /* This label is Lhandler in the documentation. */ 1039 emit_label (entry.exception_handler_label); 1040 expand_internal_throw (gen_rtx (LABEL_REF, 1041 Pmode, 1042 top_label_entry (&caught_return_label_stack))); 1043 1044 /* No associated finalization. */ 1045 entry.finalization = NULL_TREE; 1046 entry.context = current_function_decl; 1047 1048 if (end_protect_label_rtx == NULL_RTX) 1049 end_protect_label_rtx = entry.exception_handler_label; 1050 1051 /* Because we are emitted out of line, we have to protect this. */ 1052 /* label for the start of the protection region. */ 1053 start_protect_label_rtx = pop_label_entry (&false_label_stack); 1054 1055 /* Cleanup the EH parameter. */ 1056 decls = getdecls (); 1057 expand_end_bindings (decls, decls != NULL_TREE, 0); 1058 1059 /* label we emit to jump to if this catch block didn't match. */ 1060 /* This the closing } in the `if (eq) {' of the documentation. */ 1061 emit_label (pop_label_entry (&false_label_stack)); 1062 1063 /* Because we are reordered out of line, we have to protect this. */ 1064 entry.start_label = start_protect_label_rtx; 1065 entry.end_label = end_protect_label_rtx; 1066 1067 LABEL_PRESERVE_P (entry.start_label) = 1; 1068 LABEL_PRESERVE_P (entry.end_label) = 1; 1069 LABEL_PRESERVE_P (entry.exception_handler_label) = 1; 1070 1071 /* These set up a call to throw the caught exception into the outer 1072 context. */ 1073 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry)); 1074} 1075 1076/* unwind the stack. */ 1077static void 1078do_unwind (inner_throw_label) 1079 rtx inner_throw_label; 1080{ 1081#if defined(SPARC_STACK_ALIGN) /* was sparc */ 1082 tree fcall; 1083 tree params; 1084 rtx return_val_rtx; 1085 rtx temp; 1086 1087 /* call to __builtin_return_address () */ 1088 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); 1089 fcall = build_function_call (BuiltinReturnAddress, params); 1090 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0); 1091 /* In the return, the new pc is pc+8, as the value coming in is 1092 really the address of the call insn, not the next insn. */ 1093 temp = gen_reg_rtx (Pmode); 1094 emit_move_insn (temp, inner_throw_label); 1095 emit_move_insn (return_val_rtx, plus_constant (temp, -8)); 1096 easy_expand_asm ("ret"); 1097 easy_expand_asm ("restore"); 1098 emit_barrier (); 1099#endif 1100#if defined(ARM_FRAME_RTX) /* was __arm */ 1101 if (flag_omit_frame_pointer) 1102 sorry ("this implementation of exception handling requires a frame pointer"); 1103 1104 emit_move_insn (stack_pointer_rtx, 1105 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8))); 1106 emit_move_insn (hard_frame_pointer_rtx, 1107 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12))); 1108#endif 1109#if defined(TARGET_88000) /* was m88k */ 1110 rtx temp_frame = frame_pointer_rtx; 1111 1112 temp_frame = memory_address (Pmode, temp_frame); 1113 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame)); 1114 1115 /* hopefully this will successfully pop the frame! */ 1116 emit_move_insn (frame_pointer_rtx, temp_frame); 1117 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); 1118 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx); 1119 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, 1120 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0)))); 1121 1122#if 0 1123 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, 1124 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); 1125 1126 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx); 1127 1128 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, 1129 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); 1130#endif 1131#endif 1132#if !defined(TARGET_88000) && !defined(ARM_FRAME_RTX) && !defined(SPARC_STACK_ALIGN) 1133 tree fcall; 1134 tree params; 1135 rtx return_val_rtx; 1136 1137 /* call to __builtin_return_address () */ 1138 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); 1139 fcall = build_function_call (BuiltinReturnAddress, params); 1140 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0); 1141#if 0 1142 /* I would like to do this here, but doesn't seem to work. */ 1143 emit_move_insn (return_val_rtx, inner_throw_label); 1144 /* So, for now, just pass throw label to stack unwinder. */ 1145#endif 1146 params = tree_cons (NULL_TREE, make_tree (ptr_type_node, 1147 inner_throw_label), NULL_TREE); 1148 1149 do_function_call (Unwind, params, NULL_TREE); 1150 assemble_external (TREE_OPERAND (Unwind, 0)); 1151 emit_barrier (); 1152#endif 1153} 1154 1155 1156/* is called from expand_exception_blocks () to generate the code in a function 1157 to "throw" if anything in the function needs to perform a throw. 1158 1159 expands "throw" as the following pseudo code: 1160 1161 throw: 1162 eh = find_first_exception_match (saved_pc); 1163 if (!eh) goto gotta_rethrow_it; 1164 goto eh; 1165 1166 gotta_rethrow_it: 1167 saved_pc = __builtin_return_address (0); 1168 pop_to_previous_level (); 1169 goto throw; 1170 1171 */ 1172void 1173expand_builtin_throw () 1174{ 1175 tree fcall; 1176 tree params; 1177 rtx return_val_rtx; 1178 rtx gotta_rethrow_it; 1179 rtx gotta_call_terminate; 1180 rtx unwind_and_throw; 1181 rtx goto_unwind_and_throw; 1182 rtx top_of_loop; 1183 rtx unwind_first; 1184 tree t; 1185 1186 if (! doing_eh (0)) 1187 return; 1188 1189 if (! throw_used) 1190 return; 1191 1192 params = void_list_node; 1193 t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE); 1194 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"), 1195 void_list_node), 1196 t, NULL_TREE, NULL_TREE, 0); 1197 store_parm_decls (); 1198 pushlevel (0); 1199 clear_last_expr (); 1200 push_momentary (); 1201 expand_start_bindings (0); 1202 1203 gotta_rethrow_it = gen_label_rtx (); 1204 gotta_call_terminate = gen_label_rtx (); 1205 unwind_and_throw = gen_label_rtx (); 1206 goto_unwind_and_throw = gen_label_rtx (); 1207 top_of_loop = gen_label_rtx (); 1208 unwind_first = gen_label_rtx (); 1209 1210 emit_jump (unwind_first); 1211 1212 emit_label (top_of_loop); 1213 1214 /* search for an exception handler for the saved_pc */ 1215 return_val_rtx = do_function_call (FirstExceptionMatch, 1216 tree_cons (NULL_TREE, saved_pc, NULL_TREE), 1217 ptr_type_node); 1218 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0)); 1219 1220 /* did we find one? */ 1221 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, 1222 GET_MODE (return_val_rtx), 0, 0); 1223 1224 /* if not, jump to gotta_rethrow_it */ 1225 emit_jump_insn (gen_beq (gotta_rethrow_it)); 1226 1227 /* we found it, so jump to it */ 1228 emit_indirect_jump (return_val_rtx); 1229 1230 /* code to deal with unwinding and looking for it again */ 1231 emit_label (gotta_rethrow_it); 1232 1233 /* call to __builtin_return_address () */ 1234#if defined(ARM_FRAME_RTX) /* was __arm */ 1235/* This replaces a 'call' to __builtin_return_address */ 1236 return_val_rtx = gen_reg_rtx (Pmode); 1237 emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4))); 1238#else 1239 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); 1240 fcall = build_function_call (BuiltinReturnAddress, params); 1241 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0); 1242#endif 1243 1244 /* did __builtin_return_address () return a valid address? */ 1245 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, 1246 GET_MODE (return_val_rtx), 0, 0); 1247 1248 emit_jump_insn (gen_beq (gotta_call_terminate)); 1249 1250#if defined(ARM_FRAME_RTX) /* was __arm */ 1251 /* On the ARM, '__builtin_return_address', must have 4 1252 subtracted from it. */ 1253 emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-4))); 1254 1255 /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit 1256 mode, the condition codes must be masked out of the return value, or else 1257 they will confuse BuiltinReturnAddress. This does not apply to ARM6 and 1258 later processors when running in 32 bit mode. */ 1259 if (!TARGET_6) 1260 emit_insn (gen_rtx (SET, Pmode, return_val_rtx, gen_rtx (AND, Pmode, return_val_rtx, GEN_INT (0x03fffffc)))); 1261#else 1262#if !defined(SPARC_STACK_ALIGN) /* was sparc */ 1263 /* On the SPARC, __builtin_return_address is already -8, no need to 1264 subtract any more from it. */ 1265 return_val_rtx = plus_constant (return_val_rtx, -1); 1266#endif 1267#endif 1268 1269 /* yes it did */ 1270 t = build_modify_expr (saved_pc, NOP_EXPR, make_tree (ptr_type_node, return_val_rtx)); 1271 expand_expr (t, const0_rtx, VOIDmode, 0); 1272 1273 do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop)); 1274 emit_jump (top_of_loop); 1275 1276 /* no it didn't --> therefore we need to call terminate */ 1277 emit_label (gotta_call_terminate); 1278 do_function_call (Terminate, NULL_TREE, NULL_TREE); 1279 assemble_external (TREE_OPERAND (Terminate, 0)); 1280 1281 { 1282 rtx ret_val, return_val_rtx; 1283 emit_label (unwind_first); 1284 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, 1285 0, hard_frame_pointer_rtx); 1286 1287 /* Set it up so that we continue inside, at the top of the loop. */ 1288 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop)); 1289#ifdef NORMAL_RETURN_ADDR_OFFSET 1290 return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET); 1291 if (return_val_rtx != ret_val) 1292 emit_move_insn (ret_val, return_val_rtx); 1293#endif 1294 1295 /* Fall into epilogue to unwind prologue. */ 1296 } 1297 1298 expand_end_bindings (getdecls(), 1, 0); 1299 poplevel (1, 0, 0); 1300 pop_momentary (); 1301 1302 finish_function (lineno, 0, 0); 1303} 1304 1305 1306void 1307expand_start_eh_spec () 1308{ 1309 start_protect (); 1310} 1311 1312void 1313expand_end_eh_spec (raises) 1314 tree raises; 1315{ 1316 tree expr, second_try; 1317 rtx check = gen_label_rtx (); 1318 rtx cont; 1319 rtx ret = gen_reg_rtx (Pmode); 1320 rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node)); 1321 rtx end = gen_label_rtx (); 1322 1323 expr = make_node (RTL_EXPR); 1324 TREE_TYPE (expr) = void_type_node; 1325 RTL_EXPR_RTL (expr) = const0_rtx; 1326 TREE_SIDE_EFFECTS (expr) = 1; 1327 start_sequence_for_rtl_expr (expr); 1328 cont = gen_label_rtx (); 1329 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont)); 1330 emit_jump (check); 1331 emit_label (cont); 1332 jumpif (make_tree (integer_type_node, flag), end); 1333 do_function_call (Terminate, NULL_TREE, NULL_TREE); 1334 assemble_external (TREE_OPERAND (Terminate, 0)); 1335 emit_barrier (); 1336 RTL_EXPR_SEQUENCE (expr) = get_insns (); 1337 end_sequence (); 1338 1339 second_try = expr; 1340 1341 expr = make_node (RTL_EXPR); 1342 TREE_TYPE (expr) = void_type_node; 1343 RTL_EXPR_RTL (expr) = const0_rtx; 1344 TREE_SIDE_EFFECTS (expr) = 1; 1345 start_sequence_for_rtl_expr (expr); 1346 1347 cont = gen_label_rtx (); 1348 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont)); 1349 emit_jump (check); 1350 emit_label (cont); 1351 jumpif (make_tree (integer_type_node, flag), end); 1352 start_protect (); 1353 do_function_call (Unexpected, NULL_TREE, NULL_TREE); 1354 assemble_external (TREE_OPERAND (Unexpected, 0)); 1355 emit_barrier (); 1356 end_protect (second_try); 1357 1358 emit_label (check); 1359 emit_move_insn (flag, const1_rtx); 1360 cont = gen_label_rtx (); 1361 while (raises) 1362 { 1363 tree exp; 1364 tree match_type = TREE_VALUE (raises); 1365 1366 if (match_type) 1367 { 1368 /* check TREE_VALUE (raises) here */ 1369 exp = saved_throw_value; 1370 exp = tree_cons (NULL_TREE, 1371 build_eh_type_type (match_type), 1372 tree_cons (NULL_TREE, 1373 saved_throw_type, 1374 tree_cons (NULL_TREE, exp, NULL_TREE))); 1375 exp = build_function_call (CatchMatch, exp); 1376 assemble_external (TREE_OPERAND (CatchMatch, 0)); 1377 1378 jumpif (exp, cont); 1379 } 1380 1381 raises = TREE_CHAIN (raises); 1382 } 1383 emit_move_insn (flag, const0_rtx); 1384 emit_label (cont); 1385 emit_indirect_jump (ret); 1386 emit_label (end); 1387 1388 RTL_EXPR_SEQUENCE (expr) = get_insns (); 1389 end_sequence (); 1390 1391 end_protect (expr); 1392} 1393 1394/* This is called to expand all the toplevel exception handling 1395 finalization for a function. It should only be called once per 1396 function. */ 1397void 1398expand_exception_blocks () 1399{ 1400 static rtx funcend; 1401 rtx insns; 1402 1403 start_sequence (); 1404 1405 funcend = gen_label_rtx (); 1406 emit_jump (funcend); 1407 /* expand_null_return (); */ 1408 1409 start_sequence (); 1410 1411 /* Add all the catch clauses here. */ 1412 emit_insns (catch_clauses); 1413 catch_clauses = NULL_RTX; 1414 1415 expand_leftover_cleanups (); 1416 1417 insns = get_insns (); 1418 end_sequence (); 1419 1420 /* Do this after we expand leftover cleanups, so that the end_protect 1421 that expand_end_eh_spec does will match the right start_protect, 1422 and make sure it comes out before the terminate protected region. */ 1423 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) 1424 { 1425 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))); 1426 push_to_sequence (insns); 1427 1428 /* Now expand any new ones. */ 1429 expand_leftover_cleanups (); 1430 1431 insns = get_insns (); 1432 end_sequence (); 1433 } 1434 1435 if (insns) 1436 { 1437 struct ehEntry entry; 1438 1439 /* These are saved for the exception table. */ 1440 push_rtl_perm (); 1441 entry.start_label = gen_label_rtx (); 1442 entry.end_label = gen_label_rtx (); 1443 entry.exception_handler_label = gen_label_rtx (); 1444 entry.finalization = TerminateFunctionCall; 1445 entry.context = current_function_decl; 1446 assemble_external (TREE_OPERAND (Terminate, 0)); 1447 pop_rtl_from_perm (); 1448 1449 LABEL_PRESERVE_P (entry.start_label) = 1; 1450 LABEL_PRESERVE_P (entry.end_label) = 1; 1451 LABEL_PRESERVE_P (entry.exception_handler_label) = 1; 1452 1453 emit_label (entry.start_label); 1454 emit_insns (insns); 1455 1456 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry)); 1457 1458 emit_label (entry.exception_handler_label); 1459 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0); 1460 emit_label (entry.end_label); 1461 emit_barrier (); 1462 } 1463 1464 { 1465 /* Mark the end of the stack unwinder. */ 1466 rtx unwind_insns; 1467 start_sequence (); 1468 end_eh_unwinder (funcend); 1469 expand_leftover_cleanups (); 1470 unwind_insns = get_insns (); 1471 end_sequence (); 1472 if (unwind_insns) 1473 { 1474 insns = unwind_insns; 1475 emit_insns (insns); 1476 } 1477 } 1478 1479 emit_label (funcend); 1480 1481 /* Only if we had previous insns do we want to emit the jump around 1482 them. If there weren't any, then insns will remain NULL_RTX. */ 1483 if (insns) 1484 insns = get_insns (); 1485 end_sequence (); 1486 1487 emit_insns (insns); 1488} 1489 1490 1491/* call this to expand a throw statement. This follows the following 1492 algorithm: 1493 1494 1. Allocate space to save the current PC onto the stack. 1495 2. Generate and emit a label and save its address into the 1496 newly allocated stack space since we can't save the pc directly. 1497 3. If this is the first call to throw in this function: 1498 generate a label for the throw block 1499 4. jump to the throw block label. */ 1500void 1501expand_throw (exp) 1502 tree exp; 1503{ 1504 rtx label; 1505 1506 if (! doing_eh (1)) 1507 return; 1508 1509 /* This is the label that represents where in the code we were, when 1510 we got an exception. This needs to be updated when we rethrow an 1511 exception, so that the matching routine knows to search out. */ 1512 label = gen_label_rtx (); 1513 emit_label (label); 1514 1515 if (exp) 1516 { 1517 tree throw_type; 1518 tree e; 1519 1520 /* throw expression */ 1521 /* First, decay it. */ 1522 exp = decay_conversion (exp); 1523 1524 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE) 1525 { 1526 throw_type = build_eh_type (exp); 1527 exp = build_reinterpret_cast (ptr_type_node, exp); 1528 } 1529 else 1530 { 1531 /* Make a copy of the thrown object. WP 15.1.5 */ 1532 exp = build_new (NULL_TREE, TREE_TYPE (exp), 1533 build_tree_list (NULL_TREE, exp), 1534 0); 1535 1536 if (exp == error_mark_node) 1537 error (" in thrown expression"); 1538 1539 throw_type = build_eh_type (build_indirect_ref (exp, NULL_PTR)); 1540 } 1541 1542 e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type); 1543 expand_expr (e, const0_rtx, VOIDmode, 0); 1544 e = build_modify_expr (saved_throw_value, NOP_EXPR, exp); 1545 e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e); 1546 expand_expr (e, const0_rtx, VOIDmode, 0); 1547 } 1548 else 1549 { 1550 /* rethrow current exception */ 1551 /* This part is easy, as we don't have to do anything else. */ 1552 } 1553 1554 expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label)); 1555} 1556 1557void 1558end_protect_partials () { 1559 while (protect_list) 1560 { 1561 end_protect (TREE_VALUE (protect_list)); 1562 protect_list = TREE_CHAIN (protect_list); 1563 } 1564} 1565 1566int 1567might_have_exceptions_p () 1568{ 1569 if (eh_table_output_queue.head) 1570 return 1; 1571 return 0; 1572} 1573 1574/* Output the exception table. 1575 Return the number of handlers. */ 1576void 1577emit_exception_table () 1578{ 1579 int count = 0; 1580 extern FILE *asm_out_file; 1581 struct ehEntry *entry; 1582 tree eh_node_decl; 1583 1584 if (! doing_eh (0)) 1585 return; 1586 1587 exception_section (); 1588 1589 /* Beginning marker for table. */ 1590 assemble_align (GET_MODE_ALIGNMENT (Pmode)); 1591 assemble_label ("__EXCEPTION_TABLE__"); 1592 output_exception_table_entry (asm_out_file, 1593 const0_rtx, const0_rtx, const0_rtx); 1594 1595 while (entry = dequeue_eh_entry (&eh_table_output_queue)) 1596 { 1597 tree context = entry->context; 1598 1599 if (context && ! TREE_ASM_WRITTEN (context)) 1600 continue; 1601 1602 count++; 1603 output_exception_table_entry (asm_out_file, 1604 entry->start_label, entry->end_label, 1605 entry->exception_handler_label); 1606 } 1607 1608 /* Ending marker for table. */ 1609 assemble_label ("__EXCEPTION_END__"); 1610 output_exception_table_entry (asm_out_file, 1611 constm1_rtx, constm1_rtx, constm1_rtx); 1612} 1613 1614void 1615register_exception_table () 1616{ 1617 rtx addr = gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"); 1618 1619#ifdef MARK_LOCAL_ADDRESS 1620 MARK_LOCAL_ADDRESS(addr); 1621#endif 1622 1623 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0, 1624 VOIDmode, 1, 1625 addr, 1626 Pmode); 1627} 1628 1629/* Build a throw expression. */ 1630tree 1631build_throw (e) 1632 tree e; 1633{ 1634 if (e != error_mark_node) 1635 { 1636 e = build1 (THROW_EXPR, void_type_node, e); 1637 TREE_SIDE_EFFECTS (e) = 1; 1638 TREE_USED (e) = 1; 1639 } 1640 return e; 1641} 1642 1643start_eh_unwinder () 1644{ 1645 start_protect (); 1646} 1647 1648end_eh_unwinder (end) 1649 rtx end; 1650{ 1651 tree expr; 1652 rtx return_val_rtx, ret_val, label; 1653 1654 if (! doing_eh (0)) 1655 return; 1656 1657 expr = make_node (RTL_EXPR); 1658 TREE_TYPE (expr) = void_type_node; 1659 RTL_EXPR_RTL (expr) = const0_rtx; 1660 TREE_SIDE_EFFECTS (expr) = 1; 1661 start_sequence_for_rtl_expr (expr); 1662 1663 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, 1664 0, hard_frame_pointer_rtx); 1665 return_val_rtx = copy_to_reg (ret_val); 1666#ifdef NORMAL_RETURN_ADDR_OFFSET 1667 return_val_rtx = plus_constant (return_val_rtx, NORMAL_RETURN_ADDR_OFFSET-1); 1668#else 1669 return_val_rtx = plus_constant (return_val_rtx, -1); 1670#endif 1671 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx); 1672 1673#ifdef JUMP_TO_THROW 1674 emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw")); 1675#else 1676 label = gen_label_rtx (); 1677 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label)); 1678#endif 1679 1680#ifdef NORMAL_RETURN_ADDR_OFFSET 1681 return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET); 1682 if (return_val_rtx != ret_val) 1683 emit_move_insn (ret_val, return_val_rtx); 1684#endif 1685 1686 emit_jump (end); 1687 1688#ifndef JUMP_TO_THROW 1689 emit_label (label); 1690 do_function_call (Throw, NULL_TREE, NULL_TREE); 1691#endif 1692 1693 RTL_EXPR_SEQUENCE (expr) = get_insns (); 1694 end_sequence (); 1695 end_protect (expr); 1696}
| 167} 168 169 170 171 172/* from: my-cp-except.c */ 173 174/* VI: ":set ts=4" */ 175#if 0 176#include <stdio.h> */ 177#include "config.h" 178#include "tree.h" 179#include "rtl.h" 180#include "cp-tree.h" 181#endif 182#include "decl.h" 183#if 0 184#include "flags.h" 185#endif 186#include "insn-flags.h" 187#include "obstack.h" 188#if 0 189#include "expr.h" 190#endif 191 192/* ====================================================================== 193 Briefly the algorithm works like this: 194 195 When a constructor or start of a try block is encountered, 196 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a 197 new entry in the unwind protection stack and returns a label to 198 output to start the protection for that block. 199 200 When a destructor or end try block is encountered, pop_eh_entry 201 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it 202 created when push_eh_entry () was called. The ehEntry structure 203 contains three things at this point. The start protect label, 204 the end protect label, and the exception handler label. The end 205 protect label should be output before the call to the destructor 206 (if any). If it was a destructor, then its parse tree is stored 207 in the finalization variable in the ehEntry structure. Otherwise 208 the finalization variable is set to NULL to reflect the fact that 209 is the the end of a try block. Next, this modified ehEntry node 210 is enqueued in the finalizations queue by calling 211 enqueue_eh_entry (&queue,entry). 212 213 +---------------------------------------------------------------+ 214 |XXX: Will need modification to deal with partially | 215 | constructed arrays of objects | 216 | | 217 | Basically, this consists of keeping track of how many | 218 | of the objects have been constructed already (this | 219 | should be in a register though, so that shouldn't be a | 220 | problem. | 221 +---------------------------------------------------------------+ 222 223 When a catch block is encountered, there is a lot of work to be 224 done. 225 226 Since we don't want to generate the catch block inline with the 227 regular flow of the function, we need to have some way of doing 228 so. Luckily, we can use sequences to defer the catch sections. 229 When the start of a catch block is encountered, we start the 230 sequence. After the catch block is generated, we end the 231 sequence. 232 233 Next we must insure that when the catch block is executed, all 234 finalizations for the matching try block have been completed. If 235 any of those finalizations throw an exception, we must call 236 terminate according to the ARM (section r.15.6.1). What this 237 means is that we need to dequeue and emit finalizations for each 238 entry in the ehQueue until we get to an entry with a NULL 239 finalization field. For any of the finalization entries, if it 240 is not a call to terminate (), we must protect it by giving it 241 another start label, end label, and exception handler label, 242 setting its finalization tree to be a call to terminate (), and 243 enqueue'ing this new ehEntry to be output at an outer level. 244 Finally, after all that is done, we can get around to outputting 245 the catch block which basically wraps all the "catch (...) {...}" 246 statements in a big if/then/else construct that matches the 247 correct block to call. 248 249 ===================================================================== */ 250 251extern rtx emit_insn PROTO((rtx)); 252extern rtx gen_nop PROTO(()); 253 254/* local globals for function calls 255 ====================================================================== */ 256 257/* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and 258 "set_unexpected ()" after default_conversion. (lib-except.c) */ 259static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw; 260 261/* used to cache __find_first_exception_table_match () 262 for throw (lib-except.c) */ 263static tree FirstExceptionMatch; 264 265/* used to cache a call to __unwind_function () (lib-except.c) */ 266static tree Unwind; 267 268/* holds a ready to emit call to "terminate ()". */ 269static tree TerminateFunctionCall; 270 271/* ====================================================================== */ 272 273 274 275/* data structures for my various quick and dirty stacks and queues 276 Eventually, most of this should go away, because I think it can be 277 integrated with stuff already built into the compiler. */ 278 279/* =================================================================== */ 280 281struct labelNode { 282 rtx label; 283 struct labelNode *chain; 284}; 285 286 287/* this is the most important structure here. Basically this is how I store 288 an exception table entry internally. */ 289struct ehEntry { 290 rtx start_label; 291 rtx end_label; 292 rtx exception_handler_label; 293 294 tree finalization; 295 tree context; 296}; 297 298struct ehNode { 299 struct ehEntry *entry; 300 struct ehNode *chain; 301}; 302 303struct ehStack { 304 struct ehNode *top; 305}; 306 307struct ehQueue { 308 struct ehNode *head; 309 struct ehNode *tail; 310}; 311/* ========================================================================= */ 312 313 314 315/* local globals - these local globals are for storing data necessary for 316 generating the exception table and code in the correct order. 317 318 ========================================================================= */ 319 320/* Holds the pc for doing "throw" */ 321tree saved_pc; 322/* Holds the type of the thing being thrown. */ 323tree saved_throw_type; 324/* Holds the value being thrown. */ 325tree saved_throw_value; 326 327int throw_used; 328 329static rtx catch_clauses; 330static first_catch_label; 331 332static struct ehStack ehstack; 333static struct ehQueue ehqueue; 334static struct ehQueue eh_table_output_queue; 335static struct labelNode *false_label_stack = NULL; 336static struct labelNode *caught_return_label_stack = NULL; 337/* ========================================================================= */ 338 339/* function prototypes */ 340static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack)); 341static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry)); 342static rtx push_eh_entry PROTO((struct ehStack *stack)); 343static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue)); 344static void new_eh_queue PROTO((struct ehQueue *queue)); 345static void new_eh_stack PROTO((struct ehStack *stack)); 346static void push_label_entry PROTO((struct labelNode **labelstack, rtx label)); 347static rtx pop_label_entry PROTO((struct labelNode **labelstack)); 348static rtx top_label_entry PROTO((struct labelNode **labelstack)); 349static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry)); 350 351 352 353/* All my cheesy stack/queue/misc data structure handling routines 354 355 ========================================================================= */ 356 357static void 358push_label_entry (labelstack, label) 359 struct labelNode **labelstack; 360 rtx label; 361{ 362 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode)); 363 364 newnode->label = label; 365 newnode->chain = *labelstack; 366 *labelstack = newnode; 367} 368 369static rtx 370pop_label_entry (labelstack) 371 struct labelNode **labelstack; 372{ 373 rtx label; 374 struct labelNode *tempnode; 375 376 if (! *labelstack) return NULL_RTX; 377 378 tempnode = *labelstack; 379 label = tempnode->label; 380 *labelstack = (*labelstack)->chain; 381 free (tempnode); 382 383 return label; 384} 385 386static rtx 387top_label_entry (labelstack) 388 struct labelNode **labelstack; 389{ 390 if (! *labelstack) return NULL_RTX; 391 392 return (*labelstack)->label; 393} 394 395/* Push to permanent obstack for rtl generation. 396 One level only! */ 397static struct obstack *saved_rtl_obstack; 398void 399push_rtl_perm () 400{ 401 extern struct obstack permanent_obstack; 402 extern struct obstack *rtl_obstack; 403 404 saved_rtl_obstack = rtl_obstack; 405 rtl_obstack = &permanent_obstack; 406} 407 408/* Pop back to normal rtl handling. */ 409static void 410pop_rtl_from_perm () 411{ 412 extern struct obstack permanent_obstack; 413 extern struct obstack *rtl_obstack; 414 415 rtl_obstack = saved_rtl_obstack; 416} 417 418static rtx 419push_eh_entry (stack) 420 struct ehStack *stack; 421{ 422 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode)); 423 struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry)); 424 425 if (stack == NULL) { 426 free (node); 427 free (entry); 428 return NULL_RTX; 429 } 430 431 /* These are saved for the exception table. */ 432 push_rtl_perm (); 433 entry->start_label = gen_label_rtx (); 434 entry->end_label = gen_label_rtx (); 435 entry->exception_handler_label = gen_label_rtx (); 436 pop_rtl_from_perm (); 437 438 LABEL_PRESERVE_P (entry->start_label) = 1; 439 LABEL_PRESERVE_P (entry->end_label) = 1; 440 LABEL_PRESERVE_P (entry->exception_handler_label) = 1; 441 442 entry->finalization = NULL_TREE; 443 entry->context = current_function_decl; 444 445 node->entry = entry; 446 node->chain = stack->top; 447 stack->top = node; 448 449 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry)); 450 451 return entry->start_label; 452} 453 454static struct ehEntry * 455pop_eh_entry (stack) 456 struct ehStack *stack; 457{ 458 struct ehNode *tempnode; 459 struct ehEntry *tempentry; 460 461 if (stack && (tempnode = stack->top)) { 462 tempentry = tempnode->entry; 463 stack->top = stack->top->chain; 464 free (tempnode); 465 466 return tempentry; 467 } 468 469 return NULL; 470} 471 472static struct ehEntry * 473copy_eh_entry (entry) 474 struct ehEntry *entry; 475{ 476 struct ehEntry *newentry; 477 478 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry)); 479 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry)); 480 481 return newentry; 482} 483 484static void 485enqueue_eh_entry (queue, entry) 486 struct ehQueue *queue; 487 struct ehEntry *entry; 488{ 489 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode)); 490 491 node->entry = entry; 492 node->chain = NULL; 493 494 if (queue->head == NULL) 495 { 496 queue->head = node; 497 } 498 else 499 { 500 queue->tail->chain = node; 501 } 502 queue->tail = node; 503} 504 505static struct ehEntry * 506dequeue_eh_entry (queue) 507 struct ehQueue *queue; 508{ 509 struct ehNode *tempnode; 510 struct ehEntry *tempentry; 511 512 if (queue->head == NULL) 513 return NULL; 514 515 tempnode = queue->head; 516 queue->head = queue->head->chain; 517 518 tempentry = tempnode->entry; 519 free (tempnode); 520 521 return tempentry; 522} 523 524static void 525new_eh_queue (queue) 526 struct ehQueue *queue; 527{ 528 queue->head = queue->tail = NULL; 529} 530 531static void 532new_eh_stack (stack) 533 struct ehStack *stack; 534{ 535 stack->top = NULL; 536} 537 538/* cheesyness to save some typing. returns the return value rtx */ 539rtx 540do_function_call (func, params, return_type) 541 tree func, params, return_type; 542{ 543 tree func_call; 544 func_call = build_function_call (func, params); 545 expand_call (func_call, NULL_RTX, 0); 546 if (return_type != NULL_TREE) 547 return hard_function_value (return_type, func_call); 548 return NULL_RTX; 549} 550 551static void 552expand_internal_throw (pc) 553 rtx pc; 554{ 555 tree params; 556 557 emit_move_insn (DECL_RTL (saved_pc), pc); 558#ifdef JUMP_TO_THROW 559 emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw")); 560#else 561 do_function_call (Throw, NULL_TREE, NULL_TREE); 562#endif 563 throw_used = 1; 564} 565 566/* ========================================================================= */ 567 568void 569lang_interim_eh (finalization) 570 tree finalization; 571{ 572 if (finalization) 573 end_protect (finalization); 574 else 575 start_protect (); 576} 577 578extern tree auto_function PROTO((tree, tree, enum built_in_function)); 579 580/* sets up all the global eh stuff that needs to be initialized at the 581 start of compilation. 582 583 This includes: 584 - Setting up all the function call trees 585 - Initializing the ehqueue 586 - Initializing the eh_table_output_queue 587 - Initializing the ehstack 588*/ 589 590void 591init_exception_processing () 592{ 593 extern tree define_function (); 594 tree unexpected_fndecl, terminate_fndecl; 595 tree set_unexpected_fndecl, set_terminate_fndecl; 596 tree catch_match_fndecl; 597 tree find_first_exception_match_fndecl; 598 tree unwind_fndecl; 599 tree declspecs; 600 tree d; 601 602 /* void (*)() */ 603 tree PFV = build_pointer_type (build_function_type 604 (void_type_node, void_list_node)); 605 606 /* arg list for the build_function_type call for set_terminate () and 607 set_unexpected () */ 608 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node); 609 610 /* void (*pfvtype (void (*) ()))() */ 611 tree pfvtype = build_function_type (PFV, pfvlist); 612 613 /* void vtype () */ 614 tree vtype = build_function_type (void_type_node, void_list_node); 615 616 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"), 617 pfvtype, NOT_BUILT_IN); 618 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"), 619 pfvtype, NOT_BUILT_IN); 620 unexpected_fndecl = auto_function (get_identifier ("unexpected"), 621 vtype, NOT_BUILT_IN); 622 terminate_fndecl = auto_function (get_identifier ("terminate"), 623 vtype, NOT_BUILT_IN); 624 625 interim_eh_hook = lang_interim_eh; 626 627 push_lang_context (lang_name_c); 628 629 catch_match_fndecl = 630 define_function (flag_rtti 631 ? "__throw_type_match_rtti" 632 : "__throw_type_match", 633 build_function_type (ptr_type_node, 634 tree_cons (NULL_TREE, ptr_type_node, 635 tree_cons (NULL_TREE, ptr_type_node, 636 tree_cons (NULL_TREE, ptr_type_node, 637 void_list_node)))), 638 NOT_BUILT_IN, 639 pushdecl, 640 0); 641 find_first_exception_match_fndecl = 642 define_function ("__find_first_exception_table_match", 643 build_function_type (ptr_type_node, 644 tree_cons (NULL_TREE, ptr_type_node, 645 void_list_node)), 646 NOT_BUILT_IN, 647 pushdecl, 648 0); 649 unwind_fndecl = 650 define_function ("__unwind_function", 651 build_function_type (void_type_node, 652 tree_cons (NULL_TREE, ptr_type_node, 653 void_list_node)), 654 NOT_BUILT_IN, 655 pushdecl, 656 0); 657 throw_fndecl = 658 define_function ("__throw", 659 build_function_type (void_type_node, void_list_node), 660 NOT_BUILT_IN, 661 pushdecl, 662 0); 663 DECL_EXTERNAL (throw_fndecl) = 0; 664 TREE_PUBLIC (throw_fndecl) = 0; 665 666 Unexpected = default_conversion (unexpected_fndecl); 667 Terminate = default_conversion (terminate_fndecl); 668 SetTerminate = default_conversion (set_terminate_fndecl); 669 SetUnexpected = default_conversion (set_unexpected_fndecl); 670 CatchMatch = default_conversion (catch_match_fndecl); 671 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl); 672 Unwind = default_conversion (unwind_fndecl); 673 Throw = default_conversion (throw_fndecl); 674 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl); 675 676 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE); 677 678 pop_lang_context (); 679 680 new_eh_queue (&ehqueue); 681 new_eh_queue (&eh_table_output_queue); 682 new_eh_stack (&ehstack); 683 684 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); 685 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc")); 686 d = start_decl (d, declspecs, 0, NULL_TREE); 687 DECL_COMMON (d) = 1; 688 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); 689 saved_pc = lookup_name (get_identifier ("__eh_pc"), 0); 690 691 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); 692 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type")); 693 d = start_decl (d, declspecs, 0, NULL_TREE); 694 DECL_COMMON (d) = 1; 695 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); 696 saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0); 697 698 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); 699 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value")); 700 d = start_decl (d, declspecs, 0, NULL_TREE); 701 DECL_COMMON (d) = 1; 702 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); 703 saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0); 704} 705 706/* call this to begin a block of unwind protection (ie: when an object is 707 constructed) */ 708void 709start_protect () 710{ 711 if (! doing_eh (0)) 712 return; 713 714 emit_label (push_eh_entry (&ehstack)); 715} 716 717/* call this to end a block of unwind protection. the finalization tree is 718 the finalization which needs to be run in order to cleanly unwind through 719 this level of protection. (ie: call this when a scope is exited)*/ 720void 721end_protect (finalization) 722 tree finalization; 723{ 724 struct ehEntry *entry; 725 726 if (! doing_eh (0)) 727 return; 728 729 entry = pop_eh_entry (&ehstack); 730 731 emit_label (entry->end_label); 732 /* Put in something that takes up space, as otherwise the end 733 address for the EH region could have the exact same address as 734 the outer region, causing us to miss the fact that resuming 735 exception handling with this PC value would be inside the outer 736 region. */ 737 emit_insn (gen_nop ()); 738 739 entry->finalization = finalization; 740 741 enqueue_eh_entry (&ehqueue, entry); 742} 743 744/* call this on start of a try block. */ 745void 746expand_start_try_stmts () 747{ 748 if (! doing_eh (1)) 749 return; 750 751 start_protect (); 752} 753 754void 755expand_end_try_stmts () 756{ 757 end_protect (integer_zero_node); 758} 759 760 761/* call this to start processing of all the catch blocks. */ 762void 763expand_start_all_catch () 764{ 765 struct ehEntry *entry; 766 rtx label; 767 768 if (! doing_eh (1)) 769 return; 770 771 emit_line_note (input_filename, lineno); 772 label = gen_label_rtx (); 773 774 /* The label for the exception handling block we will save. This is 775 Lresume, in the documention. */ 776 emit_label (label); 777 778 /* Put in something that takes up space, as otherwise the end 779 address for the EH region could have the exact same address as 780 the outer region, causing us to miss the fact that resuming 781 exception handling with this PC value would be inside the outer 782 region. */ 783 emit_insn (gen_nop ()); 784 785 push_label_entry (&caught_return_label_stack, label); 786 787 /* Start a new sequence for all the catch blocks. We will add this 788 to the gloabl sequence catch_clauses, when we have completed all 789 the handlers in this handler-seq. */ 790 start_sequence (); 791 792 while (1) 793 { 794 entry = dequeue_eh_entry (&ehqueue); 795 emit_label (entry->exception_handler_label); 796 797 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); 798 799 /* When we get down to the matching entry, stop. */ 800 if (entry->finalization == integer_zero_node) 801 break; 802 803 /* The below can be optimized away, and we could just fall into the 804 next EH handler, if we are certain they are nested. */ 805 /* Code to throw out to outer context, if we fall off end of the 806 handler. */ 807 expand_internal_throw (gen_rtx (LABEL_REF, 808 Pmode, 809 entry->end_label)); 810 free (entry); 811 } 812} 813 814/* call this to end processing of all the catch blocks. */ 815void 816expand_end_all_catch () 817{ 818 rtx new_catch_clause; 819 820 if (! doing_eh (1)) 821 return; 822 823 /* Code to throw out to outer context, if we fall off end of catch 824 handlers. This is rethrow (Lresume, same id, same obj); in the 825 documentation. */ 826 expand_internal_throw (gen_rtx (LABEL_REF, 827 Pmode, 828 top_label_entry (&caught_return_label_stack))); 829 830 /* Now we have the complete catch sequence. */ 831 new_catch_clause = get_insns (); 832 end_sequence (); 833 834 /* this level of catch blocks is done, so set up the successful catch jump 835 label for the next layer of catch blocks. */ 836 pop_label_entry (&caught_return_label_stack); 837 838 /* Add the new sequence of catchs to the main one for this 839 function. */ 840 push_to_sequence (catch_clauses); 841 emit_insns (new_catch_clause); 842 catch_clauses = get_insns (); 843 end_sequence (); 844 845 /* Here we fall through into the continuation code. */ 846} 847 848/* Build a type value for use at runtime for a type that is matched 849 against by the exception handling system. */ 850static tree 851build_eh_type_type (type) 852 tree type; 853{ 854 char *typestring; 855 tree exp; 856 857 if (type == error_mark_node) 858 return error_mark_node; 859 860 /* peel back references, so they match. */ 861 if (TREE_CODE (type) == REFERENCE_TYPE) 862 type = TREE_TYPE (type); 863 864 /* Peel off cv qualifiers. */ 865 type = TYPE_MAIN_VARIANT (type); 866 867 if (flag_rtti) 868 { 869 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type)); 870 } 871 872 typestring = build_overload_name (type, 1, 1); 873 exp = combine_strings (build_string (strlen (typestring)+1, typestring)); 874 return build1 (ADDR_EXPR, ptr_type_node, exp); 875} 876 877/* Build a type value for use at runtime for a exp that is thrown or 878 matched against by the exception handling system. */ 879static tree 880build_eh_type (exp) 881 tree exp; 882{ 883 if (flag_rtti) 884 { 885 exp = build_typeid (exp); 886 return build1 (ADDR_EXPR, ptr_type_node, exp); 887 } 888 return build_eh_type_type (TREE_TYPE (exp)); 889} 890 891/* call this to start a catch block. Typename is the typename, and identifier 892 is the variable to place the object in or NULL if the variable doesn't 893 matter. If typename is NULL, that means its a "catch (...)" or catch 894 everything. In that case we don't need to do any type checking. 895 (ie: it ends up as the "else" clause rather than an "else if" clause) */ 896void 897expand_start_catch_block (declspecs, declarator) 898 tree declspecs, declarator; 899{ 900 rtx false_label_rtx; 901 rtx protect_label_rtx; 902 tree decl = NULL_TREE; 903 tree init; 904 905 if (! doing_eh (1)) 906 return; 907 908 /* Create a binding level for the parm. */ 909 expand_start_bindings (0); 910 911 false_label_rtx = gen_label_rtx (); 912 /* This is saved for the exception table. */ 913 push_rtl_perm (); 914 protect_label_rtx = gen_label_rtx (); 915 pop_rtl_from_perm (); 916 push_label_entry (&false_label_stack, false_label_rtx); 917 push_label_entry (&false_label_stack, protect_label_rtx); 918 919 if (declspecs) 920 { 921 tree exp; 922 rtx call_rtx, return_value_rtx; 923 tree init_type; 924 925 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, 926 NULL_TREE, NULL_TREE); 927 928 if (decl == NULL_TREE) 929 { 930 error ("invalid catch parameter"); 931 return; 932 } 933 934 /* Figure out the type that the initializer is. */ 935 init_type = TREE_TYPE (decl); 936 if (TREE_CODE (init_type) != REFERENCE_TYPE 937 && TREE_CODE (init_type) != POINTER_TYPE) 938 init_type = build_reference_type (init_type); 939 940 exp = saved_throw_value; 941 exp = tree_cons (NULL_TREE, 942 build_eh_type_type (TREE_TYPE (decl)), 943 tree_cons (NULL_TREE, 944 saved_throw_type, 945 tree_cons (NULL_TREE, exp, NULL_TREE))); 946 exp = build_function_call (CatchMatch, exp); 947 call_rtx = expand_call (exp, NULL_RTX, 0); 948 assemble_external (TREE_OPERAND (CatchMatch, 0)); 949 950 return_value_rtx = hard_function_value (ptr_type_node, exp); 951 952 /* did the throw type match function return TRUE? */ 953 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX, 954 GET_MODE (return_value_rtx), 0, 0); 955 956 /* if it returned FALSE, jump over the catch block, else fall into it */ 957 emit_jump_insn (gen_beq (false_label_rtx)); 958 959 init = convert_from_reference (save_expr (make_tree (init_type, call_rtx))); 960 961 /* Do we need the below two lines? */ 962 /* Let `cp_finish_decl' know that this initializer is ok. */ 963 DECL_INITIAL (decl) = init; 964 decl = pushdecl (decl); 965 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); 966 } 967 else 968 { 969 /* Fall into the catch all section. */ 970 } 971 972 /* This is the starting of something to protect. */ 973 emit_label (protect_label_rtx); 974 975 emit_line_note (input_filename, lineno); 976} 977 978 979/* this is called from expand_exception_blocks and 980 expand_end_catch_block to expand the toplevel finalizations for a 981 function. We return the first label emitted, if any, otherwise 982 return NULL_RTX. */ 983static rtx 984expand_leftover_cleanups () 985{ 986 struct ehEntry *entry; 987 rtx first_label = NULL_RTX; 988 989 while ((entry = dequeue_eh_entry (&ehqueue)) != 0) 990 { 991 if (! first_label) 992 first_label = entry->exception_handler_label; 993 emit_label (entry->exception_handler_label); 994 995 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); 996 997 /* The below can be optimized away, and we could just fall into the 998 next EH handler, if we are certain they are nested. */ 999 /* Code to throw out to outer context, if we fall off end of the 1000 handler. */ 1001 expand_internal_throw (gen_rtx (LABEL_REF, 1002 Pmode, 1003 entry->end_label)); 1004 1005 /* leftover try block, opps. */ 1006 if (entry->finalization == integer_zero_node) 1007 abort (); 1008 1009 free (entry); 1010 } 1011 1012 return first_label; 1013} 1014 1015/* Call this to end a catch block. Its responsible for emitting the 1016 code to handle jumping back to the correct place, and for emitting 1017 the label to jump to if this catch block didn't match. */ 1018void expand_end_catch_block () 1019{ 1020 rtx start_protect_label_rtx; 1021 rtx end_protect_label_rtx; 1022 tree decls; 1023 struct ehEntry entry; 1024 1025 if (! doing_eh (1)) 1026 return; 1027 1028 /* fall to outside the try statement when done executing handler and 1029 we fall off end of handler. This is jump Lresume in the 1030 documentation. */ 1031 emit_jump (top_label_entry (&caught_return_label_stack)); 1032 1033 /* We end the rethrow protection region as soon as we hit a label. */ 1034 end_protect_label_rtx = expand_leftover_cleanups (); 1035 1036 /* Code to throw out to outer context, if we get a throw from within 1037 our catch handler. */ 1038 /* These are saved for the exception table. */ 1039 push_rtl_perm (); 1040 entry.exception_handler_label = gen_label_rtx (); 1041 pop_rtl_from_perm (); 1042 /* This label is Lhandler in the documentation. */ 1043 emit_label (entry.exception_handler_label); 1044 expand_internal_throw (gen_rtx (LABEL_REF, 1045 Pmode, 1046 top_label_entry (&caught_return_label_stack))); 1047 1048 /* No associated finalization. */ 1049 entry.finalization = NULL_TREE; 1050 entry.context = current_function_decl; 1051 1052 if (end_protect_label_rtx == NULL_RTX) 1053 end_protect_label_rtx = entry.exception_handler_label; 1054 1055 /* Because we are emitted out of line, we have to protect this. */ 1056 /* label for the start of the protection region. */ 1057 start_protect_label_rtx = pop_label_entry (&false_label_stack); 1058 1059 /* Cleanup the EH parameter. */ 1060 decls = getdecls (); 1061 expand_end_bindings (decls, decls != NULL_TREE, 0); 1062 1063 /* label we emit to jump to if this catch block didn't match. */ 1064 /* This the closing } in the `if (eq) {' of the documentation. */ 1065 emit_label (pop_label_entry (&false_label_stack)); 1066 1067 /* Because we are reordered out of line, we have to protect this. */ 1068 entry.start_label = start_protect_label_rtx; 1069 entry.end_label = end_protect_label_rtx; 1070 1071 LABEL_PRESERVE_P (entry.start_label) = 1; 1072 LABEL_PRESERVE_P (entry.end_label) = 1; 1073 LABEL_PRESERVE_P (entry.exception_handler_label) = 1; 1074 1075 /* These set up a call to throw the caught exception into the outer 1076 context. */ 1077 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry)); 1078} 1079 1080/* unwind the stack. */ 1081static void 1082do_unwind (inner_throw_label) 1083 rtx inner_throw_label; 1084{ 1085#if defined(SPARC_STACK_ALIGN) /* was sparc */ 1086 tree fcall; 1087 tree params; 1088 rtx return_val_rtx; 1089 rtx temp; 1090 1091 /* call to __builtin_return_address () */ 1092 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); 1093 fcall = build_function_call (BuiltinReturnAddress, params); 1094 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0); 1095 /* In the return, the new pc is pc+8, as the value coming in is 1096 really the address of the call insn, not the next insn. */ 1097 temp = gen_reg_rtx (Pmode); 1098 emit_move_insn (temp, inner_throw_label); 1099 emit_move_insn (return_val_rtx, plus_constant (temp, -8)); 1100 easy_expand_asm ("ret"); 1101 easy_expand_asm ("restore"); 1102 emit_barrier (); 1103#endif 1104#if defined(ARM_FRAME_RTX) /* was __arm */ 1105 if (flag_omit_frame_pointer) 1106 sorry ("this implementation of exception handling requires a frame pointer"); 1107 1108 emit_move_insn (stack_pointer_rtx, 1109 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8))); 1110 emit_move_insn (hard_frame_pointer_rtx, 1111 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12))); 1112#endif 1113#if defined(TARGET_88000) /* was m88k */ 1114 rtx temp_frame = frame_pointer_rtx; 1115 1116 temp_frame = memory_address (Pmode, temp_frame); 1117 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame)); 1118 1119 /* hopefully this will successfully pop the frame! */ 1120 emit_move_insn (frame_pointer_rtx, temp_frame); 1121 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); 1122 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx); 1123 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, 1124 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0)))); 1125 1126#if 0 1127 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, 1128 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); 1129 1130 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx); 1131 1132 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, 1133 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); 1134#endif 1135#endif 1136#if !defined(TARGET_88000) && !defined(ARM_FRAME_RTX) && !defined(SPARC_STACK_ALIGN) 1137 tree fcall; 1138 tree params; 1139 rtx return_val_rtx; 1140 1141 /* call to __builtin_return_address () */ 1142 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); 1143 fcall = build_function_call (BuiltinReturnAddress, params); 1144 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0); 1145#if 0 1146 /* I would like to do this here, but doesn't seem to work. */ 1147 emit_move_insn (return_val_rtx, inner_throw_label); 1148 /* So, for now, just pass throw label to stack unwinder. */ 1149#endif 1150 params = tree_cons (NULL_TREE, make_tree (ptr_type_node, 1151 inner_throw_label), NULL_TREE); 1152 1153 do_function_call (Unwind, params, NULL_TREE); 1154 assemble_external (TREE_OPERAND (Unwind, 0)); 1155 emit_barrier (); 1156#endif 1157} 1158 1159 1160/* is called from expand_exception_blocks () to generate the code in a function 1161 to "throw" if anything in the function needs to perform a throw. 1162 1163 expands "throw" as the following pseudo code: 1164 1165 throw: 1166 eh = find_first_exception_match (saved_pc); 1167 if (!eh) goto gotta_rethrow_it; 1168 goto eh; 1169 1170 gotta_rethrow_it: 1171 saved_pc = __builtin_return_address (0); 1172 pop_to_previous_level (); 1173 goto throw; 1174 1175 */ 1176void 1177expand_builtin_throw () 1178{ 1179 tree fcall; 1180 tree params; 1181 rtx return_val_rtx; 1182 rtx gotta_rethrow_it; 1183 rtx gotta_call_terminate; 1184 rtx unwind_and_throw; 1185 rtx goto_unwind_and_throw; 1186 rtx top_of_loop; 1187 rtx unwind_first; 1188 tree t; 1189 1190 if (! doing_eh (0)) 1191 return; 1192 1193 if (! throw_used) 1194 return; 1195 1196 params = void_list_node; 1197 t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE); 1198 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"), 1199 void_list_node), 1200 t, NULL_TREE, NULL_TREE, 0); 1201 store_parm_decls (); 1202 pushlevel (0); 1203 clear_last_expr (); 1204 push_momentary (); 1205 expand_start_bindings (0); 1206 1207 gotta_rethrow_it = gen_label_rtx (); 1208 gotta_call_terminate = gen_label_rtx (); 1209 unwind_and_throw = gen_label_rtx (); 1210 goto_unwind_and_throw = gen_label_rtx (); 1211 top_of_loop = gen_label_rtx (); 1212 unwind_first = gen_label_rtx (); 1213 1214 emit_jump (unwind_first); 1215 1216 emit_label (top_of_loop); 1217 1218 /* search for an exception handler for the saved_pc */ 1219 return_val_rtx = do_function_call (FirstExceptionMatch, 1220 tree_cons (NULL_TREE, saved_pc, NULL_TREE), 1221 ptr_type_node); 1222 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0)); 1223 1224 /* did we find one? */ 1225 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, 1226 GET_MODE (return_val_rtx), 0, 0); 1227 1228 /* if not, jump to gotta_rethrow_it */ 1229 emit_jump_insn (gen_beq (gotta_rethrow_it)); 1230 1231 /* we found it, so jump to it */ 1232 emit_indirect_jump (return_val_rtx); 1233 1234 /* code to deal with unwinding and looking for it again */ 1235 emit_label (gotta_rethrow_it); 1236 1237 /* call to __builtin_return_address () */ 1238#if defined(ARM_FRAME_RTX) /* was __arm */ 1239/* This replaces a 'call' to __builtin_return_address */ 1240 return_val_rtx = gen_reg_rtx (Pmode); 1241 emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4))); 1242#else 1243 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); 1244 fcall = build_function_call (BuiltinReturnAddress, params); 1245 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0); 1246#endif 1247 1248 /* did __builtin_return_address () return a valid address? */ 1249 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, 1250 GET_MODE (return_val_rtx), 0, 0); 1251 1252 emit_jump_insn (gen_beq (gotta_call_terminate)); 1253 1254#if defined(ARM_FRAME_RTX) /* was __arm */ 1255 /* On the ARM, '__builtin_return_address', must have 4 1256 subtracted from it. */ 1257 emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-4))); 1258 1259 /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit 1260 mode, the condition codes must be masked out of the return value, or else 1261 they will confuse BuiltinReturnAddress. This does not apply to ARM6 and 1262 later processors when running in 32 bit mode. */ 1263 if (!TARGET_6) 1264 emit_insn (gen_rtx (SET, Pmode, return_val_rtx, gen_rtx (AND, Pmode, return_val_rtx, GEN_INT (0x03fffffc)))); 1265#else 1266#if !defined(SPARC_STACK_ALIGN) /* was sparc */ 1267 /* On the SPARC, __builtin_return_address is already -8, no need to 1268 subtract any more from it. */ 1269 return_val_rtx = plus_constant (return_val_rtx, -1); 1270#endif 1271#endif 1272 1273 /* yes it did */ 1274 t = build_modify_expr (saved_pc, NOP_EXPR, make_tree (ptr_type_node, return_val_rtx)); 1275 expand_expr (t, const0_rtx, VOIDmode, 0); 1276 1277 do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop)); 1278 emit_jump (top_of_loop); 1279 1280 /* no it didn't --> therefore we need to call terminate */ 1281 emit_label (gotta_call_terminate); 1282 do_function_call (Terminate, NULL_TREE, NULL_TREE); 1283 assemble_external (TREE_OPERAND (Terminate, 0)); 1284 1285 { 1286 rtx ret_val, return_val_rtx; 1287 emit_label (unwind_first); 1288 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, 1289 0, hard_frame_pointer_rtx); 1290 1291 /* Set it up so that we continue inside, at the top of the loop. */ 1292 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop)); 1293#ifdef NORMAL_RETURN_ADDR_OFFSET 1294 return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET); 1295 if (return_val_rtx != ret_val) 1296 emit_move_insn (ret_val, return_val_rtx); 1297#endif 1298 1299 /* Fall into epilogue to unwind prologue. */ 1300 } 1301 1302 expand_end_bindings (getdecls(), 1, 0); 1303 poplevel (1, 0, 0); 1304 pop_momentary (); 1305 1306 finish_function (lineno, 0, 0); 1307} 1308 1309 1310void 1311expand_start_eh_spec () 1312{ 1313 start_protect (); 1314} 1315 1316void 1317expand_end_eh_spec (raises) 1318 tree raises; 1319{ 1320 tree expr, second_try; 1321 rtx check = gen_label_rtx (); 1322 rtx cont; 1323 rtx ret = gen_reg_rtx (Pmode); 1324 rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node)); 1325 rtx end = gen_label_rtx (); 1326 1327 expr = make_node (RTL_EXPR); 1328 TREE_TYPE (expr) = void_type_node; 1329 RTL_EXPR_RTL (expr) = const0_rtx; 1330 TREE_SIDE_EFFECTS (expr) = 1; 1331 start_sequence_for_rtl_expr (expr); 1332 cont = gen_label_rtx (); 1333 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont)); 1334 emit_jump (check); 1335 emit_label (cont); 1336 jumpif (make_tree (integer_type_node, flag), end); 1337 do_function_call (Terminate, NULL_TREE, NULL_TREE); 1338 assemble_external (TREE_OPERAND (Terminate, 0)); 1339 emit_barrier (); 1340 RTL_EXPR_SEQUENCE (expr) = get_insns (); 1341 end_sequence (); 1342 1343 second_try = expr; 1344 1345 expr = make_node (RTL_EXPR); 1346 TREE_TYPE (expr) = void_type_node; 1347 RTL_EXPR_RTL (expr) = const0_rtx; 1348 TREE_SIDE_EFFECTS (expr) = 1; 1349 start_sequence_for_rtl_expr (expr); 1350 1351 cont = gen_label_rtx (); 1352 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont)); 1353 emit_jump (check); 1354 emit_label (cont); 1355 jumpif (make_tree (integer_type_node, flag), end); 1356 start_protect (); 1357 do_function_call (Unexpected, NULL_TREE, NULL_TREE); 1358 assemble_external (TREE_OPERAND (Unexpected, 0)); 1359 emit_barrier (); 1360 end_protect (second_try); 1361 1362 emit_label (check); 1363 emit_move_insn (flag, const1_rtx); 1364 cont = gen_label_rtx (); 1365 while (raises) 1366 { 1367 tree exp; 1368 tree match_type = TREE_VALUE (raises); 1369 1370 if (match_type) 1371 { 1372 /* check TREE_VALUE (raises) here */ 1373 exp = saved_throw_value; 1374 exp = tree_cons (NULL_TREE, 1375 build_eh_type_type (match_type), 1376 tree_cons (NULL_TREE, 1377 saved_throw_type, 1378 tree_cons (NULL_TREE, exp, NULL_TREE))); 1379 exp = build_function_call (CatchMatch, exp); 1380 assemble_external (TREE_OPERAND (CatchMatch, 0)); 1381 1382 jumpif (exp, cont); 1383 } 1384 1385 raises = TREE_CHAIN (raises); 1386 } 1387 emit_move_insn (flag, const0_rtx); 1388 emit_label (cont); 1389 emit_indirect_jump (ret); 1390 emit_label (end); 1391 1392 RTL_EXPR_SEQUENCE (expr) = get_insns (); 1393 end_sequence (); 1394 1395 end_protect (expr); 1396} 1397 1398/* This is called to expand all the toplevel exception handling 1399 finalization for a function. It should only be called once per 1400 function. */ 1401void 1402expand_exception_blocks () 1403{ 1404 static rtx funcend; 1405 rtx insns; 1406 1407 start_sequence (); 1408 1409 funcend = gen_label_rtx (); 1410 emit_jump (funcend); 1411 /* expand_null_return (); */ 1412 1413 start_sequence (); 1414 1415 /* Add all the catch clauses here. */ 1416 emit_insns (catch_clauses); 1417 catch_clauses = NULL_RTX; 1418 1419 expand_leftover_cleanups (); 1420 1421 insns = get_insns (); 1422 end_sequence (); 1423 1424 /* Do this after we expand leftover cleanups, so that the end_protect 1425 that expand_end_eh_spec does will match the right start_protect, 1426 and make sure it comes out before the terminate protected region. */ 1427 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) 1428 { 1429 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))); 1430 push_to_sequence (insns); 1431 1432 /* Now expand any new ones. */ 1433 expand_leftover_cleanups (); 1434 1435 insns = get_insns (); 1436 end_sequence (); 1437 } 1438 1439 if (insns) 1440 { 1441 struct ehEntry entry; 1442 1443 /* These are saved for the exception table. */ 1444 push_rtl_perm (); 1445 entry.start_label = gen_label_rtx (); 1446 entry.end_label = gen_label_rtx (); 1447 entry.exception_handler_label = gen_label_rtx (); 1448 entry.finalization = TerminateFunctionCall; 1449 entry.context = current_function_decl; 1450 assemble_external (TREE_OPERAND (Terminate, 0)); 1451 pop_rtl_from_perm (); 1452 1453 LABEL_PRESERVE_P (entry.start_label) = 1; 1454 LABEL_PRESERVE_P (entry.end_label) = 1; 1455 LABEL_PRESERVE_P (entry.exception_handler_label) = 1; 1456 1457 emit_label (entry.start_label); 1458 emit_insns (insns); 1459 1460 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry)); 1461 1462 emit_label (entry.exception_handler_label); 1463 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0); 1464 emit_label (entry.end_label); 1465 emit_barrier (); 1466 } 1467 1468 { 1469 /* Mark the end of the stack unwinder. */ 1470 rtx unwind_insns; 1471 start_sequence (); 1472 end_eh_unwinder (funcend); 1473 expand_leftover_cleanups (); 1474 unwind_insns = get_insns (); 1475 end_sequence (); 1476 if (unwind_insns) 1477 { 1478 insns = unwind_insns; 1479 emit_insns (insns); 1480 } 1481 } 1482 1483 emit_label (funcend); 1484 1485 /* Only if we had previous insns do we want to emit the jump around 1486 them. If there weren't any, then insns will remain NULL_RTX. */ 1487 if (insns) 1488 insns = get_insns (); 1489 end_sequence (); 1490 1491 emit_insns (insns); 1492} 1493 1494 1495/* call this to expand a throw statement. This follows the following 1496 algorithm: 1497 1498 1. Allocate space to save the current PC onto the stack. 1499 2. Generate and emit a label and save its address into the 1500 newly allocated stack space since we can't save the pc directly. 1501 3. If this is the first call to throw in this function: 1502 generate a label for the throw block 1503 4. jump to the throw block label. */ 1504void 1505expand_throw (exp) 1506 tree exp; 1507{ 1508 rtx label; 1509 1510 if (! doing_eh (1)) 1511 return; 1512 1513 /* This is the label that represents where in the code we were, when 1514 we got an exception. This needs to be updated when we rethrow an 1515 exception, so that the matching routine knows to search out. */ 1516 label = gen_label_rtx (); 1517 emit_label (label); 1518 1519 if (exp) 1520 { 1521 tree throw_type; 1522 tree e; 1523 1524 /* throw expression */ 1525 /* First, decay it. */ 1526 exp = decay_conversion (exp); 1527 1528 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE) 1529 { 1530 throw_type = build_eh_type (exp); 1531 exp = build_reinterpret_cast (ptr_type_node, exp); 1532 } 1533 else 1534 { 1535 /* Make a copy of the thrown object. WP 15.1.5 */ 1536 exp = build_new (NULL_TREE, TREE_TYPE (exp), 1537 build_tree_list (NULL_TREE, exp), 1538 0); 1539 1540 if (exp == error_mark_node) 1541 error (" in thrown expression"); 1542 1543 throw_type = build_eh_type (build_indirect_ref (exp, NULL_PTR)); 1544 } 1545 1546 e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type); 1547 expand_expr (e, const0_rtx, VOIDmode, 0); 1548 e = build_modify_expr (saved_throw_value, NOP_EXPR, exp); 1549 e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e); 1550 expand_expr (e, const0_rtx, VOIDmode, 0); 1551 } 1552 else 1553 { 1554 /* rethrow current exception */ 1555 /* This part is easy, as we don't have to do anything else. */ 1556 } 1557 1558 expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label)); 1559} 1560 1561void 1562end_protect_partials () { 1563 while (protect_list) 1564 { 1565 end_protect (TREE_VALUE (protect_list)); 1566 protect_list = TREE_CHAIN (protect_list); 1567 } 1568} 1569 1570int 1571might_have_exceptions_p () 1572{ 1573 if (eh_table_output_queue.head) 1574 return 1; 1575 return 0; 1576} 1577 1578/* Output the exception table. 1579 Return the number of handlers. */ 1580void 1581emit_exception_table () 1582{ 1583 int count = 0; 1584 extern FILE *asm_out_file; 1585 struct ehEntry *entry; 1586 tree eh_node_decl; 1587 1588 if (! doing_eh (0)) 1589 return; 1590 1591 exception_section (); 1592 1593 /* Beginning marker for table. */ 1594 assemble_align (GET_MODE_ALIGNMENT (Pmode)); 1595 assemble_label ("__EXCEPTION_TABLE__"); 1596 output_exception_table_entry (asm_out_file, 1597 const0_rtx, const0_rtx, const0_rtx); 1598 1599 while (entry = dequeue_eh_entry (&eh_table_output_queue)) 1600 { 1601 tree context = entry->context; 1602 1603 if (context && ! TREE_ASM_WRITTEN (context)) 1604 continue; 1605 1606 count++; 1607 output_exception_table_entry (asm_out_file, 1608 entry->start_label, entry->end_label, 1609 entry->exception_handler_label); 1610 } 1611 1612 /* Ending marker for table. */ 1613 assemble_label ("__EXCEPTION_END__"); 1614 output_exception_table_entry (asm_out_file, 1615 constm1_rtx, constm1_rtx, constm1_rtx); 1616} 1617 1618void 1619register_exception_table () 1620{ 1621 rtx addr = gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"); 1622 1623#ifdef MARK_LOCAL_ADDRESS 1624 MARK_LOCAL_ADDRESS(addr); 1625#endif 1626 1627 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0, 1628 VOIDmode, 1, 1629 addr, 1630 Pmode); 1631} 1632 1633/* Build a throw expression. */ 1634tree 1635build_throw (e) 1636 tree e; 1637{ 1638 if (e != error_mark_node) 1639 { 1640 e = build1 (THROW_EXPR, void_type_node, e); 1641 TREE_SIDE_EFFECTS (e) = 1; 1642 TREE_USED (e) = 1; 1643 } 1644 return e; 1645} 1646 1647start_eh_unwinder () 1648{ 1649 start_protect (); 1650} 1651 1652end_eh_unwinder (end) 1653 rtx end; 1654{ 1655 tree expr; 1656 rtx return_val_rtx, ret_val, label; 1657 1658 if (! doing_eh (0)) 1659 return; 1660 1661 expr = make_node (RTL_EXPR); 1662 TREE_TYPE (expr) = void_type_node; 1663 RTL_EXPR_RTL (expr) = const0_rtx; 1664 TREE_SIDE_EFFECTS (expr) = 1; 1665 start_sequence_for_rtl_expr (expr); 1666 1667 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, 1668 0, hard_frame_pointer_rtx); 1669 return_val_rtx = copy_to_reg (ret_val); 1670#ifdef NORMAL_RETURN_ADDR_OFFSET 1671 return_val_rtx = plus_constant (return_val_rtx, NORMAL_RETURN_ADDR_OFFSET-1); 1672#else 1673 return_val_rtx = plus_constant (return_val_rtx, -1); 1674#endif 1675 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx); 1676 1677#ifdef JUMP_TO_THROW 1678 emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw")); 1679#else 1680 label = gen_label_rtx (); 1681 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label)); 1682#endif 1683 1684#ifdef NORMAL_RETURN_ADDR_OFFSET 1685 return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET); 1686 if (return_val_rtx != ret_val) 1687 emit_move_insn (ret_val, return_val_rtx); 1688#endif 1689 1690 emit_jump (end); 1691 1692#ifndef JUMP_TO_THROW 1693 emit_label (label); 1694 do_function_call (Throw, NULL_TREE, NULL_TREE); 1695#endif 1696 1697 RTL_EXPR_SEQUENCE (expr) = get_insns (); 1698 end_sequence (); 1699 end_protect (expr); 1700}
|