|
|
1.1 root 1: /* Handle exceptional things in C++. 1.1.1.2 ! root 2: Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. 1.1 root 3: Contributed by Michael Tiemann <[email protected]> 4: Rewritten by Mike Stump <[email protected]>, based upon an 5: initial re-implementation courtesy Tad Hunt. 6: 7: This file is part of GNU CC. 8: 9: GNU CC is free software; you can redistribute it and/or modify 10: it under the terms of the GNU General Public License as published by 11: the Free Software Foundation; either version 2, or (at your option) 12: any later version. 13: 14: GNU CC is distributed in the hope that it will be useful, 15: but WITHOUT ANY WARRANTY; without even the implied warranty of 16: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17: GNU General Public License for more details. 18: 19: You should have received a copy of the GNU General Public License 20: along with GNU CC; see the file COPYING. If not, write to 1.1.1.2 ! root 21: the Free Software Foundation, 59 Temple Place - Suite 330, ! 22: Boston, MA 02111-1307, USA. */ 1.1 root 23: 24: 25: /* High-level class interface. */ 26: 27: #include "config.h" 28: #include "tree.h" 29: #include "rtl.h" 30: #include "cp-tree.h" 31: #include "flags.h" 32: #include "obstack.h" 33: #include "expr.h" 34: 1.1.1.2 ! root 35: tree protect_list; ! 36: 1.1 root 37: extern void (*interim_eh_hook) PROTO((tree)); 1.1.1.2 ! root 38: rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx)); 1.1 root 39: 40: /* holds the fndecl for __builtin_return_address () */ 41: tree builtin_return_address_fndecl; 1.1.1.2 ! root 42: tree throw_fndecl; 1.1 root 43: 44: static int 45: doing_eh (do_warn) 46: int do_warn; 47: { 48: if (! flag_handle_exceptions) 49: { 50: static int warned = 0; 51: if (! warned && do_warn) 52: { 53: error ("exception handling disabled, use -fhandle-exceptions to enable."); 54: warned = 1; 55: } 56: return 0; 57: } 58: return 1; 59: } 60: 61: 62: /* 63: NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer 1.1.1.2 ! root 64: to supporting exception handling as per ANSI C++ working draft. 1.1 root 65: It is a complete rewrite of all the EH stuff that was here before 66: Shortcomings: 1.1.1.2 ! root 67: 1. Throw specifications of functions still don't work. 1.1 root 68: Cool Things: 69: 1. Destructors are called properly :-) 70: 2. No overhead for the non-exception thrown case. 1.1.1.2 ! root 71: 3. Fixing shortcoming 1 is simple. 1.1 root 72: -Tad Hunt ([email protected]) 73: 74: */ 75: 76: /* A couple of backend routines from m88k.c */ 77: 78: /* used to cache a call to __builtin_return_address () */ 79: static tree BuiltinReturnAddress; 1.1.1.2 ! root 80: 1.1 root 81: 82: #include <stdio.h> 83: 84: /* XXX - Tad: for EH */ 85: /* output an exception table entry */ 86: 87: static void 88: output_exception_table_entry (file, start_label, end_label, eh_label) 89: FILE *file; 90: rtx start_label, end_label, eh_label; 91: { 92: char label[100]; 93: 1.1.1.2 ! root 94: assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1); ! 95: assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1); ! 96: assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1); 1.1 root 97: putc ('\n', file); /* blank line */ 98: } 99: 100: static void 101: easy_expand_asm (str) 102: char *str; 103: { 104: expand_asm (build_string (strlen (str)+1, str)); 105: } 106: 107: 108: #if 0 109: /* This is the startup, and finish stuff per exception table. */ 110: 111: /* XXX - Tad: exception handling section */ 112: #ifndef EXCEPT_SECTION_ASM_OP 113: #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits" 114: #endif 115: 116: #ifdef EXCEPT_SECTION_ASM_OP 117: typedef struct { 118: void *start_protect; 119: void *end_protect; 120: void *exception_handler; 121: } exception_table; 122: #endif /* EXCEPT_SECTION_ASM_OP */ 123: 124: #ifdef EXCEPT_SECTION_ASM_OP 125: 126: /* on machines which support it, the exception table lives in another section, 127: but it needs a label so we can reference it... This sets up that 128: label! */ 129: asm (EXCEPT_SECTION_ASM_OP); 130: exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 }; 131: asm (TEXT_SECTION_ASM_OP); 132: 133: #endif /* EXCEPT_SECTION_ASM_OP */ 134: 135: #ifdef EXCEPT_SECTION_ASM_OP 136: 137: /* we need to know where the end of the exception table is... so this 138: is how we do it! */ 139: 140: asm (EXCEPT_SECTION_ASM_OP); 141: exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 }; 142: asm (TEXT_SECTION_ASM_OP); 143: 144: #endif /* EXCEPT_SECTION_ASM_OP */ 145: 146: #endif 147: 148: void 149: exception_section () 150: { 151: #ifdef ASM_OUTPUT_SECTION_NAME 1.1.1.2 ! root 152: named_section (NULL_TREE, ".gcc_except_table"); 1.1 root 153: #else 1.1.1.2 ! root 154: if (flag_pic) ! 155: data_section (); ! 156: else ! 157: #if defined(TARGET_POWERPC) /* are we on a __rs6000? */ ! 158: data_section (); ! 159: #else ! 160: readonly_data_section (); ! 161: #endif 1.1 root 162: #endif 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 1.1.1.2 ! root 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: 1.1 root 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: 247: extern rtx emit_insn PROTO((rtx)); 248: extern rtx gen_nop PROTO(()); 249: 250: /* local globals for function calls 251: ====================================================================== */ 252: 253: /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and 1.1.1.2 ! root 254: "set_unexpected ()" after default_conversion. (lib-except.c) */ ! 255: static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw; 1.1 root 256: 257: /* used to cache __find_first_exception_table_match () 258: for throw (lib-except.c) */ 259: static tree FirstExceptionMatch; 260: 1.1.1.2 ! root 261: /* used to cache a call to __unwind_function () (lib-except.c) */ 1.1 root 262: static tree Unwind; 263: 1.1.1.2 ! root 264: /* holds a ready to emit call to "terminate ()". */ 1.1 root 265: static 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 1.1.1.2 ! root 273: integrated with stuff already built into the compiler. */ 1.1 root 274: 275: /* =================================================================== */ 276: 277: struct labelNode { 1.1.1.2 ! root 278: rtx label; ! 279: struct labelNode *chain; ! 280: }; 1.1 root 281: 282: 283: /* this is the most important structure here. Basically this is how I store 284: an exception table entry internally. */ 285: struct ehEntry { 1.1.1.2 ! root 286: rtx start_label; ! 287: rtx end_label; ! 288: rtx exception_handler_label; ! 289: ! 290: tree finalization; ! 291: tree context; ! 292: }; 1.1 root 293: 294: struct ehNode { 1.1.1.2 ! root 295: struct ehEntry *entry; ! 296: struct ehNode *chain; ! 297: }; 1.1 root 298: 299: struct ehStack { 1.1.1.2 ! root 300: struct ehNode *top; ! 301: }; 1.1 root 302: 303: struct ehQueue { 1.1.1.2 ! root 304: struct ehNode *head; ! 305: struct ehNode *tail; ! 306: }; 1.1 root 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" */ 1.1.1.2 ! root 317: tree saved_pc; 1.1 root 318: /* Holds the type of the thing being thrown. */ 1.1.1.2 ! root 319: tree saved_throw_type; 1.1 root 320: /* Holds the value being thrown. */ 1.1.1.2 ! root 321: tree saved_throw_value; ! 322: ! 323: int throw_used; 1.1 root 324: 1.1.1.2 ! root 325: static rtx catch_clauses; ! 326: static first_catch_label; 1.1 root 327: 328: static struct ehStack ehstack; 329: static struct ehQueue ehqueue; 330: static struct ehQueue eh_table_output_queue; 331: static struct labelNode *false_label_stack = NULL; 332: static struct labelNode *caught_return_label_stack = NULL; 333: /* ========================================================================= */ 334: 335: /* function prototypes */ 336: static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack)); 337: static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry)); 338: static rtx push_eh_entry PROTO((struct ehStack *stack)); 339: static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue)); 340: static void new_eh_queue PROTO((struct ehQueue *queue)); 341: static void new_eh_stack PROTO((struct ehStack *stack)); 342: static void push_label_entry PROTO((struct labelNode **labelstack, rtx label)); 343: static rtx pop_label_entry PROTO((struct labelNode **labelstack)); 344: static rtx top_label_entry PROTO((struct labelNode **labelstack)); 345: static 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: 353: static void 354: push_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: 365: static rtx 366: pop_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: 382: static rtx 383: top_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! */ 393: static struct obstack *saved_rtl_obstack; 394: void 395: push_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. */ 405: static void 406: pop_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: 414: static rtx 415: push_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: 1.1.1.2 ! root 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: 1.1 root 438: entry->finalization = NULL_TREE; 1.1.1.2 ! root 439: entry->context = current_function_decl; 1.1 root 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: 450: static struct ehEntry * 451: pop_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: 468: static struct ehEntry * 469: copy_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: 480: static void 481: enqueue_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: 501: static struct ehEntry * 502: dequeue_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: 520: static void 521: new_eh_queue (queue) 522: struct ehQueue *queue; 523: { 524: queue->head = queue->tail = NULL; 525: } 526: 527: static void 528: new_eh_stack (stack) 529: struct ehStack *stack; 530: { 531: stack->top = NULL; 532: } 533: 1.1.1.2 ! root 534: /* cheesyness to save some typing. returns the return value rtx */ ! 535: rtx ! 536: do_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: 1.1 root 547: static void 1.1.1.2 ! root 548: expand_internal_throw (pc) ! 549: rtx pc; 1.1 root 550: { 1.1.1.2 ! root 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; 1.1 root 560: } 1.1.1.2 ! root 561: 1.1 root 562: /* ========================================================================= */ 563: 564: void 565: lang_interim_eh (finalization) 566: tree finalization; 567: { 568: if (finalization) 569: end_protect (finalization); 570: else 571: start_protect (); 572: } 573: 1.1.1.2 ! root 574: extern tree auto_function PROTO((tree, tree, enum built_in_function)); ! 575: 1.1 root 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: 586: void 587: init_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; 1.1.1.2 ! root 595: tree declspecs; ! 596: tree d; 1.1 root 597: 598: /* void (*)() */ 1.1.1.2 ! root 599: tree PFV = build_pointer_type (build_function_type ! 600: (void_type_node, void_list_node)); 1.1 root 601: 602: /* arg list for the build_function_type call for set_terminate () and 603: set_unexpected () */ 1.1.1.2 ! root 604: tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node); 1.1 root 605: 1.1.1.2 ! root 606: /* void (*pfvtype (void (*) ()))() */ ! 607: tree pfvtype = build_function_type (PFV, pfvlist); 1.1 root 608: 1.1.1.2 ! root 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); 1.1 root 624: 625: catch_match_fndecl = 1.1.1.2 ! root 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)))), 1.1 root 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, 1.1.1.2 ! root 648: tree_cons (NULL_TREE, ptr_type_node, ! 649: void_list_node)), 1.1 root 650: NOT_BUILT_IN, 651: pushdecl, 652: 0); 1.1.1.2 ! root 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; 1.1 root 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); 1.1.1.2 ! root 669: Throw = default_conversion (throw_fndecl); 1.1 root 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); 1.1.1.2 ! root 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); 1.1 root 700: } 701: 702: /* call this to begin a block of unwind protection (ie: when an object is 703: constructed) */ 704: void 705: start_protect () 706: { 1.1.1.2 ! root 707: if (! doing_eh (0)) ! 708: return; ! 709: ! 710: emit_label (push_eh_entry (&ehstack)); 1.1 root 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)*/ 716: void 717: end_protect (finalization) 718: tree finalization; 719: { 1.1.1.2 ! root 720: struct ehEntry *entry; 1.1 root 721: 722: if (! doing_eh (0)) 723: return; 724: 1.1.1.2 ! root 725: entry = pop_eh_entry (&ehstack); ! 726: 1.1 root 727: emit_label (entry->end_label); 1.1.1.2 ! root 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 ()); 1.1 root 734: 735: entry->finalization = finalization; 736: 737: enqueue_eh_entry (&ehqueue, entry); 738: } 739: 740: /* call this on start of a try block. */ 741: void 742: expand_start_try_stmts () 743: { 1.1.1.2 ! root 744: if (! doing_eh (1)) ! 745: return; ! 746: ! 747: start_protect (); 1.1 root 748: } 749: 750: void 751: expand_end_try_stmts () 752: { 753: end_protect (integer_zero_node); 754: } 755: 756: 757: /* call this to start processing of all the catch blocks. */ 758: void 759: expand_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 (); 1.1.1.2 ! root 769: ! 770: /* The label for the exception handling block we will save. This is ! 771: Lresume, in the documention. */ 1.1 root 772: emit_label (label); 773: 1.1.1.2 ! root 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. */ 1.1 root 779: emit_insn (gen_nop ()); 780: 1.1.1.2 ! root 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 (); 1.1 root 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: 1.1.1.2 ! root 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)); 1.1 root 806: free (entry); 807: } 808: } 809: 810: /* call this to end processing of all the catch blocks. */ 811: void 812: expand_end_all_catch () 813: { 1.1.1.2 ! root 814: rtx new_catch_clause; 1.1 root 815: 816: if (! doing_eh (1)) 817: return; 818: 1.1.1.2 ! root 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: 1.1 root 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: 1.1.1.2 ! root 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 (); 1.1 root 840: 841: /* Here we fall through into the continuation code. */ 842: } 843: 1.1.1.2 ! root 844: /* Build a type value for use at runtime for a type that is matched ! 845: against by the exception handling system. */ ! 846: static tree ! 847: build_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); 1.1 root 859: 1.1.1.2 ! root 860: /* Peel off cv qualifiers. */ ! 861: type = TYPE_MAIN_VARIANT (type); 1.1 root 862: 1.1.1.2 ! root 863: if (flag_rtti) ! 864: { ! 865: return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type)); ! 866: } 1.1 root 867: 1.1.1.2 ! root 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: } 1.1 root 872: 1.1.1.2 ! root 873: /* Build a type value for use at runtime for a exp that is thrown or ! 874: matched against by the exception handling system. */ ! 875: static tree ! 876: build_eh_type (exp) ! 877: tree exp; ! 878: { ! 879: if (flag_rtti) 1.1 root 880: { 1.1.1.2 ! root 881: exp = build_typeid (exp); ! 882: return build1 (ADDR_EXPR, ptr_type_node, exp); 1.1 root 883: } 1.1.1.2 ! root 884: return build_eh_type_type (TREE_TYPE (exp)); 1.1 root 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) */ 892: void 893: expand_start_catch_block (declspecs, declarator) 894: tree declspecs, declarator; 895: { 896: rtx false_label_rtx; 897: rtx protect_label_rtx; 1.1.1.2 ! root 898: tree decl = NULL_TREE; 1.1 root 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 (); 1.1.1.2 ! root 908: /* This is saved for the exception table. */ ! 909: push_rtl_perm (); 1.1 root 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: 1.1.1.2 ! root 915: if (declspecs) 1.1 root 916: { 1.1.1.2 ! root 917: tree exp; 1.1 root 918: rtx call_rtx, return_value_rtx; 1.1.1.2 ! root 919: tree init_type; 1.1 root 920: 1.1.1.2 ! root 921: decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, ! 922: NULL_TREE, NULL_TREE); 1.1 root 923: 1.1.1.2 ! root 924: if (decl == NULL_TREE) ! 925: { ! 926: error ("invalid catch parameter"); ! 927: return; ! 928: } 1.1 root 929: 1.1.1.2 ! root 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); 1.1 root 947: 948: /* did the throw type match function return TRUE? */ 1.1.1.2 ! root 949: emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX, 1.1 root 950: GET_MODE (return_value_rtx), 0, 0); 951: 952: /* if it returned FALSE, jump over the catch block, else fall into it */ 1.1.1.2 ! root 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); 1.1 root 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: 1.1.1.2 ! root 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. */ ! 979: static rtx ! 980: expand_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: 1.1 root 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. */ 1014: void expand_end_catch_block () 1015: { 1.1.1.2 ! root 1016: rtx start_protect_label_rtx; ! 1017: rtx end_protect_label_rtx; ! 1018: tree decls; ! 1019: struct ehEntry entry; 1.1 root 1020: 1.1.1.2 ! root 1021: if (! doing_eh (1)) ! 1022: return; 1.1 root 1023: 1.1.1.2 ! root 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)); 1.1 root 1028: 1.1.1.2 ! root 1029: /* We end the rethrow protection region as soon as we hit a label. */ ! 1030: end_protect_label_rtx = expand_leftover_cleanups (); 1.1 root 1031: 1.1.1.2 ! root 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)); 1.1 root 1074: } 1075: 1.1.1.2 ! root 1076: /* unwind the stack. */ ! 1077: static void ! 1078: do_unwind (inner_throw_label) ! 1079: rtx inner_throw_label; 1.1 root 1080: { 1.1.1.2 ! root 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 1.1 root 1153: } 1154: 1155: 1.1.1.2 ! root 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. 1.1 root 1158: 1.1.1.2 ! root 1159: expands "throw" as the following pseudo code: 1.1 root 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: */ 1.1.1.2 ! root 1172: void 1.1 root 1173: expand_builtin_throw () 1174: { 1175: tree fcall; 1176: tree params; 1177: rtx return_val_rtx; 1.1.1.2 ! root 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; 1.1 root 1191: 1.1.1.2 ! root 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); 1.1 root 1213: 1214: /* search for an exception handler for the saved_pc */ 1215: return_val_rtx = do_function_call (FirstExceptionMatch, 1.1.1.2 ! root 1216: tree_cons (NULL_TREE, saved_pc, NULL_TREE), 1.1 root 1217: ptr_type_node); 1.1.1.2 ! root 1218: assemble_external (TREE_OPERAND (FirstExceptionMatch, 0)); 1.1 root 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 () */ 1.1.1.2 ! root 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); 1.1 root 1240: fcall = build_function_call (BuiltinReturnAddress, params); 1.1.1.2 ! root 1241: return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0); ! 1242: #endif 1.1 root 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: 1.1.1.2 ! root 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: 1.1 root 1269: /* yes it did */ 1.1.1.2 ! root 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); 1.1 root 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); 1.1.1.2 ! root 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); 1.1 root 1303: } 1304: 1305: 1.1.1.2 ! root 1306: void ! 1307: expand_start_eh_spec () ! 1308: { ! 1309: start_protect (); ! 1310: } ! 1311: ! 1312: void ! 1313: expand_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: 1.1 root 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. */ 1397: void 1398: expand_exception_blocks () 1399: { 1400: static rtx funcend; 1.1.1.2 ! root 1401: rtx insns; ! 1402: ! 1403: start_sequence (); 1.1 root 1404: 1405: funcend = gen_label_rtx (); 1406: emit_jump (funcend); 1407: /* expand_null_return (); */ 1408: 1.1.1.2 ! root 1409: start_sequence (); ! 1410: ! 1411: /* Add all the catch clauses here. */ ! 1412: emit_insns (catch_clauses); ! 1413: catch_clauses = NULL_RTX; 1.1 root 1414: 1415: expand_leftover_cleanups (); 1416: 1.1.1.2 ! root 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: 1.1 root 1464: { 1.1.1.2 ! root 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) 1.1 root 1473: { 1.1.1.2 ! root 1474: insns = unwind_insns; ! 1475: emit_insns (insns); 1.1 root 1476: } 1477: } 1.1.1.2 ! root 1478: 1.1 root 1479: emit_label (funcend); 1.1.1.2 ! root 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); 1.1 root 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 1.1.1.2 ! root 1496: newly allocated stack space since we can't save the pc directly. 1.1 root 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. */ 1500: void 1501: expand_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: { 1.1.1.2 ! root 1517: tree throw_type; ! 1518: tree e; ! 1519: 1.1 root 1520: /* throw expression */ 1521: /* First, decay it. */ 1.1.1.2 ! root 1522: exp = decay_conversion (exp); 1.1 root 1523: 1.1.1.2 ! root 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); 1.1 root 1547: } 1548: else 1549: { 1550: /* rethrow current exception */ 1.1.1.2 ! root 1551: /* This part is easy, as we don't have to do anything else. */ 1.1 root 1552: } 1553: 1.1.1.2 ! root 1554: expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label)); 1.1 root 1555: } 1556: 1.1.1.2 ! root 1557: void ! 1558: end_protect_partials () { ! 1559: while (protect_list) ! 1560: { ! 1561: end_protect (TREE_VALUE (protect_list)); ! 1562: protect_list = TREE_CHAIN (protect_list); ! 1563: } ! 1564: } 1.1 root 1565: 1.1.1.2 ! root 1566: int ! 1567: might_have_exceptions_p () ! 1568: { ! 1569: if (eh_table_output_queue.head) ! 1570: return 1; ! 1571: return 0; ! 1572: } 1.1 root 1573: 1574: /* Output the exception table. 1575: Return the number of handlers. */ 1.1.1.2 ! root 1576: void ! 1577: emit_exception_table () 1.1 root 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)) 1.1.1.2 ! root 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); 1.1 root 1594: 1595: while (entry = dequeue_eh_entry (&eh_table_output_queue)) 1596: { 1.1.1.2 ! root 1597: tree context = entry->context; ! 1598: ! 1599: if (context && ! TREE_ASM_WRITTEN (context)) ! 1600: continue; ! 1601: 1.1 root 1602: count++; 1603: output_exception_table_entry (asm_out_file, 1604: entry->start_label, entry->end_label, 1605: entry->exception_handler_label); 1606: } 1607: 1.1.1.2 ! root 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); 1.1 root 1612: } 1613: 1614: void 1615: register_exception_table () 1616: { 1617: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0, 1618: VOIDmode, 1, 1619: gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"), 1620: Pmode); 1621: } 1622: 1623: /* Build a throw expression. */ 1624: tree 1625: build_throw (e) 1626: tree e; 1627: { 1.1.1.2 ! root 1628: if (e != error_mark_node) ! 1629: { ! 1630: e = build1 (THROW_EXPR, void_type_node, e); ! 1631: TREE_SIDE_EFFECTS (e) = 1; ! 1632: TREE_USED (e) = 1; ! 1633: } 1.1 root 1634: return e; 1635: } 1.1.1.2 ! root 1636: ! 1637: start_eh_unwinder () ! 1638: { ! 1639: start_protect (); ! 1640: } ! 1641: ! 1642: end_eh_unwinder (end) ! 1643: rtx end; ! 1644: { ! 1645: tree expr; ! 1646: rtx return_val_rtx, ret_val, label; ! 1647: ! 1648: if (! doing_eh (0)) ! 1649: return; ! 1650: ! 1651: expr = make_node (RTL_EXPR); ! 1652: TREE_TYPE (expr) = void_type_node; ! 1653: RTL_EXPR_RTL (expr) = const0_rtx; ! 1654: TREE_SIDE_EFFECTS (expr) = 1; ! 1655: start_sequence_for_rtl_expr (expr); ! 1656: ! 1657: ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, ! 1658: 0, hard_frame_pointer_rtx); ! 1659: return_val_rtx = copy_to_reg (ret_val); ! 1660: #ifdef NORMAL_RETURN_ADDR_OFFSET ! 1661: return_val_rtx = plus_constant (return_val_rtx, NORMAL_RETURN_ADDR_OFFSET-1); ! 1662: #else ! 1663: return_val_rtx = plus_constant (return_val_rtx, -1); ! 1664: #endif ! 1665: emit_move_insn (DECL_RTL (saved_pc), return_val_rtx); ! 1666: ! 1667: #ifdef JUMP_TO_THROW ! 1668: emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw")); ! 1669: #else ! 1670: label = gen_label_rtx (); ! 1671: emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label)); ! 1672: #endif ! 1673: ! 1674: #ifdef NORMAL_RETURN_ADDR_OFFSET ! 1675: return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET); ! 1676: if (return_val_rtx != ret_val) ! 1677: emit_move_insn (ret_val, return_val_rtx); ! 1678: #endif ! 1679: ! 1680: emit_jump (end); ! 1681: ! 1682: #ifndef JUMP_TO_THROW ! 1683: emit_label (label); ! 1684: do_function_call (Throw, NULL_TREE, NULL_TREE); ! 1685: #endif ! 1686: ! 1687: RTL_EXPR_SEQUENCE (expr) = get_insns (); ! 1688: end_sequence (); ! 1689: end_protect (expr); ! 1690: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.