|
|
1.1 ! root 1: /* Handle exceptional things in C++. ! 2: Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc. ! 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 ! 21: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 22: ! 23: ! 24: /* High-level class interface. */ ! 25: ! 26: #include "config.h" ! 27: #include "tree.h" ! 28: #include "rtl.h" ! 29: #include "cp-tree.h" ! 30: #include "flags.h" ! 31: #include "obstack.h" ! 32: #include "expr.h" ! 33: ! 34: extern void (*interim_eh_hook) PROTO((tree)); ! 35: ! 36: /* holds the fndecl for __builtin_return_address () */ ! 37: tree builtin_return_address_fndecl; ! 38: ! 39: /* Define at your own risk! */ ! 40: #ifndef CROSS_COMPILE ! 41: #ifdef sun ! 42: #ifdef sparc ! 43: #define TRY_NEW_EH ! 44: #endif ! 45: #endif ! 46: #endif ! 47: ! 48: #ifndef TRY_NEW_EH ! 49: ! 50: static void ! 51: sorry_no_eh () ! 52: { ! 53: static int warned = 0; ! 54: if (! warned) ! 55: { ! 56: sorry ("exception handling not supported"); ! 57: warned = 1; ! 58: } ! 59: } ! 60: ! 61: void ! 62: expand_exception_blocks () ! 63: { ! 64: } ! 65: ! 66: void ! 67: start_protect () ! 68: { ! 69: } ! 70: ! 71: void ! 72: end_protect (finalization) ! 73: tree finalization; ! 74: { ! 75: } ! 76: ! 77: void ! 78: expand_start_try_stmts () ! 79: { ! 80: sorry_no_eh (); ! 81: } ! 82: ! 83: void ! 84: expand_end_try_stmts () ! 85: { ! 86: } ! 87: ! 88: void ! 89: expand_start_all_catch () ! 90: { ! 91: } ! 92: ! 93: void ! 94: expand_end_all_catch () ! 95: { ! 96: } ! 97: ! 98: void ! 99: expand_start_catch_block (declspecs, declarator) ! 100: tree declspecs, declarator; ! 101: { ! 102: } ! 103: ! 104: void ! 105: expand_end_catch_block () ! 106: { ! 107: } ! 108: ! 109: void ! 110: init_exception_processing () ! 111: { ! 112: } ! 113: ! 114: void ! 115: expand_throw (exp) ! 116: tree exp; ! 117: { ! 118: sorry_no_eh (); ! 119: } ! 120: ! 121: #else ! 122: ! 123: static int ! 124: doing_eh (do_warn) ! 125: int do_warn; ! 126: { ! 127: if (! flag_handle_exceptions) ! 128: { ! 129: static int warned = 0; ! 130: if (! warned && do_warn) ! 131: { ! 132: error ("exception handling disabled, use -fhandle-exceptions to enable."); ! 133: warned = 1; ! 134: } ! 135: return 0; ! 136: } ! 137: return 1; ! 138: } ! 139: ! 140: ! 141: /* ! 142: NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer ! 143: to supporting exception handling as per Stroustrup's 2nd edition. ! 144: It is a complete rewrite of all the EH stuff that was here before ! 145: Shortcomings: ! 146: 1. The type of the throw and catch must still match ! 147: exactly (no support yet for matching base classes) ! 148: 2. Throw specifications of functions still doesnt't work. ! 149: Cool Things: ! 150: 1. Destructors are called properly :-) ! 151: 2. No overhead for the non-exception thrown case. ! 152: 3. Fixing shortcomings 1 and 2 is simple. ! 153: -Tad Hunt ([email protected]) ! 154: ! 155: */ ! 156: ! 157: /* A couple of backend routines from m88k.c */ ! 158: ! 159: /* used to cache a call to __builtin_return_address () */ ! 160: static tree BuiltinReturnAddress; ! 161: ! 162: ! 163: ! 164: ! 165: ! 166: #include <stdio.h> ! 167: ! 168: /* XXX - Tad: for EH */ ! 169: /* output an exception table entry */ ! 170: ! 171: static void ! 172: output_exception_table_entry (file, start_label, end_label, eh_label) ! 173: FILE *file; ! 174: rtx start_label, end_label, eh_label; ! 175: { ! 176: char label[100]; ! 177: ! 178: assemble_integer (start_label, BITS_PER_WORD/BITS_PER_UNIT, 1); ! 179: assemble_integer (end_label, BITS_PER_WORD/BITS_PER_UNIT, 1); ! 180: assemble_integer (eh_label, BITS_PER_WORD/BITS_PER_UNIT, 1); ! 181: putc ('\n', file); /* blank line */ ! 182: } ! 183: ! 184: static void ! 185: easy_expand_asm (str) ! 186: char *str; ! 187: { ! 188: expand_asm (build_string (strlen (str)+1, str)); ! 189: } ! 190: ! 191: /* unwind the stack. */ ! 192: static void ! 193: do_unwind (throw_label) ! 194: rtx throw_label; ! 195: { ! 196: #ifdef sparc ! 197: extern FILE *asm_out_file; ! 198: tree fcall; ! 199: tree params; ! 200: rtx return_val_rtx; ! 201: ! 202: /* call to __builtin_return_address () */ ! 203: params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); ! 204: fcall = build_function_call (BuiltinReturnAddress, params); ! 205: return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0); ! 206: /* In the return, the new pc is pc+8, as the value comming in is ! 207: really the address of the call insn, not the next insn. */ ! 208: emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF, ! 209: Pmode, ! 210: throw_label), -8)); ! 211: /* We use three values, PC, type, and value */ ! 212: easy_expand_asm ("st %l0,[%fp]"); ! 213: easy_expand_asm ("st %l1,[%fp+4]"); ! 214: easy_expand_asm ("st %l2,[%fp+8]"); ! 215: easy_expand_asm ("ret"); ! 216: easy_expand_asm ("restore"); ! 217: emit_barrier (); ! 218: #endif ! 219: #if m88k ! 220: rtx temp_frame = frame_pointer_rtx; ! 221: ! 222: temp_frame = memory_address (Pmode, temp_frame); ! 223: temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame)); ! 224: ! 225: /* hopefully this will successfully pop the frame! */ ! 226: emit_move_insn (frame_pointer_rtx, temp_frame); ! 227: emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); ! 228: emit_move_insn (arg_pointer_rtx, frame_pointer_rtx); ! 229: emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, ! 230: (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0)))); ! 231: ! 232: #if 0 ! 233: emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, ! 234: -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); ! 235: ! 236: emit_move_insn (stack_pointer_rtx, arg_pointer_rtx); ! 237: ! 238: emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, ! 239: (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); ! 240: #endif ! 241: #endif ! 242: } ! 243: ! 244: ! 245: ! 246: #if 0 ! 247: /* This is the startup, and finish stuff per exception table. */ ! 248: ! 249: /* XXX - Tad: exception handling section */ ! 250: #ifndef EXCEPT_SECTION_ASM_OP ! 251: #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits" ! 252: #endif ! 253: ! 254: #ifdef EXCEPT_SECTION_ASM_OP ! 255: typedef struct { ! 256: void *start_protect; ! 257: void *end_protect; ! 258: void *exception_handler; ! 259: } exception_table; ! 260: #endif /* EXCEPT_SECTION_ASM_OP */ ! 261: ! 262: #ifdef EXCEPT_SECTION_ASM_OP ! 263: ! 264: /* on machines which support it, the exception table lives in another section, ! 265: but it needs a label so we can reference it... This sets up that ! 266: label! */ ! 267: asm (EXCEPT_SECTION_ASM_OP); ! 268: exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 }; ! 269: asm (TEXT_SECTION_ASM_OP); ! 270: ! 271: #endif /* EXCEPT_SECTION_ASM_OP */ ! 272: ! 273: #ifdef EXCEPT_SECTION_ASM_OP ! 274: ! 275: /* we need to know where the end of the exception table is... so this ! 276: is how we do it! */ ! 277: ! 278: asm (EXCEPT_SECTION_ASM_OP); ! 279: exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 }; ! 280: asm (TEXT_SECTION_ASM_OP); ! 281: ! 282: #endif /* EXCEPT_SECTION_ASM_OP */ ! 283: ! 284: #endif ! 285: ! 286: void ! 287: exception_section () ! 288: { ! 289: #ifdef ASM_OUTPUT_SECTION_NAME ! 290: named_section (".gcc_except_table"); ! 291: #else ! 292: text_section (); ! 293: #endif ! 294: } ! 295: ! 296: ! 297: ! 298: ! 299: /* from: my-cp-except.c */ ! 300: ! 301: /* VI: ":set ts=4" */ ! 302: #if 0 ! 303: #include <stdio.h> */ ! 304: #include "config.h" ! 305: #include "tree.h" ! 306: #include "rtl.h" ! 307: #include "cp-tree.h" ! 308: #endif ! 309: #include "decl.h" ! 310: #if 0 ! 311: #include "flags.h" ! 312: #endif ! 313: #include "insn-flags.h" ! 314: #include "obstack.h" ! 315: #if 0 ! 316: #include "expr.h" ! 317: #endif ! 318: ! 319: /* ====================================================================== ! 320: Briefly the algorithm works like this: ! 321: ! 322: When a constructor or start of a try block is encountered, ! 323: push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a ! 324: new entry in the unwind protection stack and returns a label to ! 325: output to start the protection for that block. ! 326: ! 327: When a destructor or end try block is encountered, pop_eh_entry ! 328: (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it ! 329: created when push_eh_entry () was called. The ehEntry structure ! 330: contains three things at this point. The start protect label, ! 331: the end protect label, and the exception handler label. The end ! 332: protect label should be output before the call to the destructor ! 333: (if any). If it was a destructor, then its parse tree is stored ! 334: in the finalization variable in the ehEntry structure. Otherwise ! 335: the finalization variable is set to NULL to reflect the fact that ! 336: is the the end of a try block. Next, this modified ehEntry node ! 337: is enqueued in the finalizations queue by calling ! 338: enqueue_eh_entry (&queue,entry). ! 339: ! 340: +---------------------------------------------------------------+ ! 341: |XXX: Will need modification to deal with partially | ! 342: | constructed arrays of objects | ! 343: | | ! 344: | Basically, this consists of keeping track of how many | ! 345: | of the objects have been constructed already (this | ! 346: | should be in a register though, so that shouldn't be a | ! 347: | problem. | ! 348: +---------------------------------------------------------------+ ! 349: ! 350: When a catch block is encountered, there is a lot of work to be ! 351: done. ! 352: ! 353: Since we don't want to generate the catch block inline with the ! 354: regular flow of the function, we need to have some way of doing ! 355: so. Luckily, we have a couple of routines "get_last_insn ()" and ! 356: "set_last_insn ()" provided. When the start of a catch block is ! 357: encountered, we save a pointer to the last insn generated. After ! 358: the catch block is generated, we save a pointer to the first ! 359: catch block insn and the last catch block insn with the routines ! 360: "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn ! 361: to be the last insn generated before the catch block, and set the ! 362: NEXT_INSN (last_insn) to zero. ! 363: ! 364: Since catch blocks might be nested inside other catch blocks, and ! 365: we munge the chain of generated insns after the catch block is ! 366: generated, we need to store the pointers to the last insn ! 367: generated in a stack, so that when the end of a catch block is ! 368: encountered, the last insn before the current catch block can be ! 369: popped and set to be the last insn, and the first and last insns ! 370: of the catch block just generated can be enqueue'd for output at ! 371: a later time. ! 372: ! 373: Next we must insure that when the catch block is executed, all ! 374: finalizations for the matching try block have been completed. If ! 375: any of those finalizations throw an exception, we must call ! 376: terminate according to the ARM (section r.15.6.1). What this ! 377: means is that we need to dequeue and emit finalizations for each ! 378: entry in the ehQueue until we get to an entry with a NULL ! 379: finalization field. For any of the finalization entries, if it ! 380: is not a call to terminate (), we must protect it by giving it ! 381: another start label, end label, and exception handler label, ! 382: setting its finalization tree to be a call to terminate (), and ! 383: enqueue'ing this new ehEntry to be output at an outer level. ! 384: Finally, after all that is done, we can get around to outputting ! 385: the catch block which basically wraps all the "catch (...) {...}" ! 386: statements in a big if/then/else construct that matches the ! 387: correct block to call. ! 388: ! 389: ===================================================================== */ ! 390: ! 391: extern rtx emit_insn PROTO((rtx)); ! 392: extern rtx gen_nop PROTO(()); ! 393: ! 394: /* local globals for function calls ! 395: ====================================================================== */ ! 396: ! 397: /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and ! 398: "set_unexpected ()" after default_conversion. (lib-except.c) */ ! 399: static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch; ! 400: ! 401: /* used to cache __find_first_exception_table_match () ! 402: for throw (lib-except.c) */ ! 403: static tree FirstExceptionMatch; ! 404: ! 405: /* used to cache a call to __unwind_function () (lib-except.c) */ ! 406: static tree Unwind; ! 407: ! 408: /* holds a ready to emit call to "terminate ()". */ ! 409: static tree TerminateFunctionCall; ! 410: ! 411: /* ====================================================================== */ ! 412: ! 413: ! 414: ! 415: /* data structures for my various quick and dirty stacks and queues ! 416: Eventually, most of this should go away, because I think it can be ! 417: integrated with stuff already built into the compiler. */ ! 418: ! 419: /* =================================================================== */ ! 420: ! 421: struct labelNode { ! 422: rtx label; ! 423: struct labelNode *chain; ! 424: }; ! 425: ! 426: ! 427: /* this is the most important structure here. Basically this is how I store ! 428: an exception table entry internally. */ ! 429: struct ehEntry { ! 430: rtx start_label; ! 431: rtx end_label; ! 432: rtx exception_handler_label; ! 433: ! 434: tree finalization; ! 435: }; ! 436: ! 437: struct ehNode { ! 438: struct ehEntry *entry; ! 439: struct ehNode *chain; ! 440: }; ! 441: ! 442: struct ehStack { ! 443: struct ehNode *top; ! 444: }; ! 445: ! 446: struct ehQueue { ! 447: struct ehNode *head; ! 448: struct ehNode *tail; ! 449: }; ! 450: ! 451: struct exceptNode { ! 452: rtx catchstart; ! 453: rtx catchend; ! 454: ! 455: struct exceptNode *chain; ! 456: }; ! 457: ! 458: struct exceptStack { ! 459: struct exceptNode *top; ! 460: }; ! 461: /* ========================================================================= */ ! 462: ! 463: ! 464: ! 465: /* local globals - these local globals are for storing data necessary for ! 466: generating the exception table and code in the correct order. ! 467: ! 468: ========================================================================= */ ! 469: ! 470: /* Holds the pc for doing "throw" */ ! 471: rtx saved_pc; ! 472: /* Holds the type of the thing being thrown. */ ! 473: rtx saved_throw_type; ! 474: /* Holds the value being thrown. */ ! 475: rtx saved_throw_value; ! 476: ! 477: rtx throw_label; ! 478: ! 479: static struct ehStack ehstack; ! 480: static struct ehQueue ehqueue; ! 481: static struct ehQueue eh_table_output_queue; ! 482: static struct exceptStack exceptstack; ! 483: static struct labelNode *false_label_stack = NULL; ! 484: static struct labelNode *caught_return_label_stack = NULL; ! 485: /* ========================================================================= */ ! 486: ! 487: /* function prototypes */ ! 488: static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack)); ! 489: static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry)); ! 490: static void push_except_stmts PROTO((struct exceptStack *exceptstack, ! 491: rtx catchstart, rtx catchend)); ! 492: static int pop_except_stmts PROTO((struct exceptStack *exceptstack, ! 493: rtx *catchstart, rtx *catchend)); ! 494: static rtx push_eh_entry PROTO((struct ehStack *stack)); ! 495: static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue)); ! 496: static void new_eh_queue PROTO((struct ehQueue *queue)); ! 497: static void new_eh_stack PROTO((struct ehStack *stack)); ! 498: static void new_except_stack PROTO((struct exceptStack *queue)); ! 499: static void push_last_insn PROTO(()); ! 500: static rtx pop_last_insn PROTO(()); ! 501: static void push_label_entry PROTO((struct labelNode **labelstack, rtx label)); ! 502: static rtx pop_label_entry PROTO((struct labelNode **labelstack)); ! 503: static rtx top_label_entry PROTO((struct labelNode **labelstack)); ! 504: static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry)); ! 505: ! 506: ! 507: ! 508: /* All my cheesy stack/queue/misc data structure handling routines ! 509: ! 510: ========================================================================= */ ! 511: ! 512: static void ! 513: push_label_entry (labelstack, label) ! 514: struct labelNode **labelstack; ! 515: rtx label; ! 516: { ! 517: struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode)); ! 518: ! 519: newnode->label = label; ! 520: newnode->chain = *labelstack; ! 521: *labelstack = newnode; ! 522: } ! 523: ! 524: static rtx ! 525: pop_label_entry (labelstack) ! 526: struct labelNode **labelstack; ! 527: { ! 528: rtx label; ! 529: struct labelNode *tempnode; ! 530: ! 531: if (! *labelstack) return NULL_RTX; ! 532: ! 533: tempnode = *labelstack; ! 534: label = tempnode->label; ! 535: *labelstack = (*labelstack)->chain; ! 536: free (tempnode); ! 537: ! 538: return label; ! 539: } ! 540: ! 541: static rtx ! 542: top_label_entry (labelstack) ! 543: struct labelNode **labelstack; ! 544: { ! 545: if (! *labelstack) return NULL_RTX; ! 546: ! 547: return (*labelstack)->label; ! 548: } ! 549: ! 550: static void ! 551: push_except_stmts (exceptstack, catchstart, catchend) ! 552: struct exceptStack *exceptstack; ! 553: rtx catchstart, catchend; ! 554: { ! 555: struct exceptNode *newnode = (struct exceptNode*) ! 556: xmalloc (sizeof (struct exceptNode)); ! 557: ! 558: newnode->catchstart = catchstart; ! 559: newnode->catchend = catchend; ! 560: newnode->chain = exceptstack->top; ! 561: ! 562: exceptstack->top = newnode; ! 563: } ! 564: ! 565: static int ! 566: pop_except_stmts (exceptstack, catchstart, catchend) ! 567: struct exceptStack *exceptstack; ! 568: rtx *catchstart, *catchend; ! 569: { ! 570: struct exceptNode *tempnode; ! 571: ! 572: if (!exceptstack->top) { ! 573: *catchstart = *catchend = NULL_RTX; ! 574: return 0; ! 575: } ! 576: ! 577: tempnode = exceptstack->top; ! 578: exceptstack->top = exceptstack->top->chain; ! 579: ! 580: *catchstart = tempnode->catchstart; ! 581: *catchend = tempnode->catchend; ! 582: free (tempnode); ! 583: ! 584: return 1; ! 585: } ! 586: ! 587: /* Push to permanent obstack for rtl generation. ! 588: One level only! */ ! 589: static struct obstack *saved_rtl_obstack; ! 590: void ! 591: push_rtl_perm () ! 592: { ! 593: extern struct obstack permanent_obstack; ! 594: extern struct obstack *rtl_obstack; ! 595: ! 596: saved_rtl_obstack = rtl_obstack; ! 597: rtl_obstack = &permanent_obstack; ! 598: } ! 599: ! 600: /* Pop back to normal rtl handling. */ ! 601: static void ! 602: pop_rtl_from_perm () ! 603: { ! 604: extern struct obstack permanent_obstack; ! 605: extern struct obstack *rtl_obstack; ! 606: ! 607: rtl_obstack = saved_rtl_obstack; ! 608: } ! 609: ! 610: static rtx ! 611: push_eh_entry (stack) ! 612: struct ehStack *stack; ! 613: { ! 614: struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode)); ! 615: struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry)); ! 616: ! 617: if (stack == NULL) { ! 618: free (node); ! 619: free (entry); ! 620: return NULL_RTX; ! 621: } ! 622: ! 623: /* These are saved for the exception table. */ ! 624: push_rtl_perm (); ! 625: entry->start_label = gen_label_rtx (); ! 626: entry->end_label = gen_label_rtx (); ! 627: entry->exception_handler_label = gen_label_rtx (); ! 628: pop_rtl_from_perm (); ! 629: ! 630: entry->finalization = NULL_TREE; ! 631: ! 632: node->entry = entry; ! 633: node->chain = stack->top; ! 634: stack->top = node; ! 635: ! 636: enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry)); ! 637: ! 638: return entry->start_label; ! 639: } ! 640: ! 641: static struct ehEntry * ! 642: pop_eh_entry (stack) ! 643: struct ehStack *stack; ! 644: { ! 645: struct ehNode *tempnode; ! 646: struct ehEntry *tempentry; ! 647: ! 648: if (stack && (tempnode = stack->top)) { ! 649: tempentry = tempnode->entry; ! 650: stack->top = stack->top->chain; ! 651: free (tempnode); ! 652: ! 653: return tempentry; ! 654: } ! 655: ! 656: return NULL; ! 657: } ! 658: ! 659: static struct ehEntry * ! 660: copy_eh_entry (entry) ! 661: struct ehEntry *entry; ! 662: { ! 663: struct ehEntry *newentry; ! 664: ! 665: newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry)); ! 666: memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry)); ! 667: ! 668: return newentry; ! 669: } ! 670: ! 671: static void ! 672: enqueue_eh_entry (queue, entry) ! 673: struct ehQueue *queue; ! 674: struct ehEntry *entry; ! 675: { ! 676: struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode)); ! 677: ! 678: node->entry = entry; ! 679: node->chain = NULL; ! 680: ! 681: if (queue->head == NULL) ! 682: { ! 683: queue->head = node; ! 684: } ! 685: else ! 686: { ! 687: queue->tail->chain = node; ! 688: } ! 689: queue->tail = node; ! 690: } ! 691: ! 692: static struct ehEntry * ! 693: dequeue_eh_entry (queue) ! 694: struct ehQueue *queue; ! 695: { ! 696: struct ehNode *tempnode; ! 697: struct ehEntry *tempentry; ! 698: ! 699: if (queue->head == NULL) ! 700: return NULL; ! 701: ! 702: tempnode = queue->head; ! 703: queue->head = queue->head->chain; ! 704: ! 705: tempentry = tempnode->entry; ! 706: free (tempnode); ! 707: ! 708: return tempentry; ! 709: } ! 710: ! 711: static void ! 712: new_eh_queue (queue) ! 713: struct ehQueue *queue; ! 714: { ! 715: queue->head = queue->tail = NULL; ! 716: } ! 717: ! 718: static void ! 719: new_eh_stack (stack) ! 720: struct ehStack *stack; ! 721: { ! 722: stack->top = NULL; ! 723: } ! 724: ! 725: static void ! 726: new_except_stack (stack) ! 727: struct exceptStack *stack; ! 728: { ! 729: stack->top = NULL; ! 730: } ! 731: /* ========================================================================= */ ! 732: ! 733: void ! 734: lang_interim_eh (finalization) ! 735: tree finalization; ! 736: { ! 737: if (finalization) ! 738: end_protect (finalization); ! 739: else ! 740: start_protect (); ! 741: } ! 742: ! 743: /* sets up all the global eh stuff that needs to be initialized at the ! 744: start of compilation. ! 745: ! 746: This includes: ! 747: - Setting up all the function call trees ! 748: - Initializing the ehqueue ! 749: - Initializing the eh_table_output_queue ! 750: - Initializing the ehstack ! 751: - Initializing the exceptstack ! 752: */ ! 753: ! 754: void ! 755: init_exception_processing () ! 756: { ! 757: extern tree define_function (); ! 758: tree unexpected_fndecl, terminate_fndecl; ! 759: tree set_unexpected_fndecl, set_terminate_fndecl; ! 760: tree catch_match_fndecl; ! 761: tree find_first_exception_match_fndecl; ! 762: tree unwind_fndecl; ! 763: tree temp, PFV; ! 764: ! 765: interim_eh_hook = lang_interim_eh; ! 766: ! 767: /* void (*)() */ ! 768: PFV = build_pointer_type (build_function_type (void_type_node, void_list_node)); ! 769: ! 770: /* arg list for the build_function_type call for set_terminate () and ! 771: set_unexpected () */ ! 772: temp = tree_cons (NULL_TREE, PFV, void_list_node); ! 773: ! 774: push_lang_context (lang_name_c); ! 775: ! 776: set_terminate_fndecl = ! 777: define_function ("set_terminate", ! 778: build_function_type (PFV, temp), ! 779: NOT_BUILT_IN, ! 780: pushdecl, ! 781: 0); ! 782: set_unexpected_fndecl = ! 783: define_function ("set_unexpected", ! 784: build_function_type (PFV, temp), ! 785: NOT_BUILT_IN, ! 786: pushdecl, ! 787: 0); ! 788: ! 789: unexpected_fndecl = ! 790: define_function ("unexpected", ! 791: build_function_type (void_type_node, void_list_node), ! 792: NOT_BUILT_IN, ! 793: pushdecl, ! 794: 0); ! 795: terminate_fndecl = ! 796: define_function ("terminate", ! 797: build_function_type (void_type_node, void_list_node), ! 798: NOT_BUILT_IN, ! 799: pushdecl, ! 800: 0); ! 801: catch_match_fndecl = ! 802: define_function ("__throw_type_match", ! 803: build_function_type (integer_type_node, ! 804: tree_cons (NULL_TREE, string_type_node, tree_cons (NULL_TREE, ptr_type_node, void_list_node))), ! 805: NOT_BUILT_IN, ! 806: pushdecl, ! 807: 0); ! 808: find_first_exception_match_fndecl = ! 809: define_function ("__find_first_exception_table_match", ! 810: build_function_type (ptr_type_node, ! 811: tree_cons (NULL_TREE, ptr_type_node, ! 812: void_list_node)), ! 813: NOT_BUILT_IN, ! 814: pushdecl, ! 815: 0); ! 816: unwind_fndecl = ! 817: define_function ("__unwind_function", ! 818: build_function_type (void_type_node, ! 819: tree_cons (NULL_TREE, ptr_type_node, void_list_node)), ! 820: NOT_BUILT_IN, ! 821: pushdecl, ! 822: 0); ! 823: ! 824: Unexpected = default_conversion (unexpected_fndecl); ! 825: Terminate = default_conversion (terminate_fndecl); ! 826: SetTerminate = default_conversion (set_terminate_fndecl); ! 827: SetUnexpected = default_conversion (set_unexpected_fndecl); ! 828: CatchMatch = default_conversion (catch_match_fndecl); ! 829: FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl); ! 830: Unwind = default_conversion (unwind_fndecl); ! 831: BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl); ! 832: ! 833: TerminateFunctionCall = build_function_call (Terminate, NULL_TREE); ! 834: ! 835: pop_lang_context (); ! 836: throw_label = gen_label_rtx (); ! 837: saved_pc = gen_rtx (REG, Pmode, 16); ! 838: saved_throw_type = gen_rtx (REG, Pmode, 17); ! 839: saved_throw_value = gen_rtx (REG, Pmode, 18); ! 840: ! 841: new_eh_queue (&ehqueue); ! 842: new_eh_queue (&eh_table_output_queue); ! 843: new_eh_stack (&ehstack); ! 844: new_except_stack (&exceptstack); ! 845: } ! 846: ! 847: /* call this to begin a block of unwind protection (ie: when an object is ! 848: constructed) */ ! 849: void ! 850: start_protect () ! 851: { ! 852: if (doing_eh (0)) ! 853: { ! 854: emit_label (push_eh_entry (&ehstack)); ! 855: } ! 856: } ! 857: ! 858: /* call this to end a block of unwind protection. the finalization tree is ! 859: the finalization which needs to be run in order to cleanly unwind through ! 860: this level of protection. (ie: call this when a scope is exited)*/ ! 861: void ! 862: end_protect (finalization) ! 863: tree finalization; ! 864: { ! 865: struct ehEntry *entry = pop_eh_entry (&ehstack); ! 866: ! 867: if (! doing_eh (0)) ! 868: return; ! 869: ! 870: emit_label (entry->end_label); ! 871: ! 872: entry->finalization = finalization; ! 873: ! 874: enqueue_eh_entry (&ehqueue, entry); ! 875: } ! 876: ! 877: /* call this on start of a try block. */ ! 878: void ! 879: expand_start_try_stmts () ! 880: { ! 881: if (doing_eh (1)) ! 882: { ! 883: start_protect (); ! 884: } ! 885: } ! 886: ! 887: void ! 888: expand_end_try_stmts () ! 889: { ! 890: end_protect (integer_zero_node); ! 891: } ! 892: ! 893: struct insn_save_node { ! 894: rtx last; ! 895: struct insn_save_node *chain; ! 896: }; ! 897: ! 898: static struct insn_save_node *InsnSave = NULL; ! 899: ! 900: ! 901: /* Used to keep track of where the catch blocks start. */ ! 902: static void ! 903: push_last_insn () ! 904: { ! 905: struct insn_save_node *newnode = (struct insn_save_node*) ! 906: xmalloc (sizeof (struct insn_save_node)); ! 907: ! 908: newnode->last = get_last_insn (); ! 909: newnode->chain = InsnSave; ! 910: InsnSave = newnode; ! 911: } ! 912: ! 913: /* Use to keep track of where the catch blocks start. */ ! 914: static rtx ! 915: pop_last_insn () ! 916: { ! 917: struct insn_save_node *tempnode; ! 918: rtx temprtx; ! 919: ! 920: if (!InsnSave) return NULL_RTX; ! 921: ! 922: tempnode = InsnSave; ! 923: temprtx = tempnode->last; ! 924: InsnSave = InsnSave->chain; ! 925: ! 926: free (tempnode); ! 927: ! 928: return temprtx; ! 929: } ! 930: ! 931: /* call this to start processing of all the catch blocks. */ ! 932: void ! 933: expand_start_all_catch () ! 934: { ! 935: struct ehEntry *entry; ! 936: rtx label; ! 937: ! 938: if (! doing_eh (1)) ! 939: return; ! 940: ! 941: emit_line_note (input_filename, lineno); ! 942: label = gen_label_rtx (); ! 943: /* The label for the exception handling block we will save. */ ! 944: emit_label (label); ! 945: ! 946: push_label_entry (&caught_return_label_stack, label); ! 947: ! 948: /* Remember where we started. */ ! 949: push_last_insn (); ! 950: ! 951: emit_insn (gen_nop ()); ! 952: ! 953: /* Will this help us not stomp on it? */ ! 954: emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type)); ! 955: emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value)); ! 956: ! 957: while (1) ! 958: { ! 959: entry = dequeue_eh_entry (&ehqueue); ! 960: emit_label (entry->exception_handler_label); ! 961: ! 962: expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); ! 963: ! 964: /* When we get down to the matching entry, stop. */ ! 965: if (entry->finalization == integer_zero_node) ! 966: break; ! 967: ! 968: free (entry); ! 969: } ! 970: ! 971: /* This goes when the below moves out of our way. */ ! 972: #if 1 ! 973: label = gen_label_rtx (); ! 974: emit_jump (label); ! 975: #endif ! 976: ! 977: /* All this should be out of line, and saved back in the exception handler ! 978: block area. */ ! 979: #if 1 ! 980: entry->start_label = entry->exception_handler_label; ! 981: /* These are saved for the exception table. */ ! 982: push_rtl_perm (); ! 983: entry->end_label = gen_label_rtx (); ! 984: entry->exception_handler_label = gen_label_rtx (); ! 985: entry->finalization = TerminateFunctionCall; ! 986: pop_rtl_from_perm (); ! 987: emit_label (entry->end_label); ! 988: ! 989: enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry)); ! 990: ! 991: /* After running the finalization, continue on out to the next ! 992: cleanup, if we have nothing better to do. */ ! 993: emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label)); ! 994: /* Will this help us not stomp on it? */ ! 995: emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type)); ! 996: emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value)); ! 997: emit_jump (throw_label); ! 998: emit_label (entry->exception_handler_label); ! 999: expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); ! 1000: emit_barrier (); ! 1001: #endif ! 1002: emit_label (label); ! 1003: } ! 1004: ! 1005: /* call this to end processing of all the catch blocks. */ ! 1006: void ! 1007: expand_end_all_catch () ! 1008: { ! 1009: rtx catchstart, catchend, last; ! 1010: rtx label; ! 1011: ! 1012: if (! doing_eh (1)) ! 1013: return; ! 1014: ! 1015: /* Find the start of the catch block. */ ! 1016: last = pop_last_insn (); ! 1017: catchstart = NEXT_INSN (last); ! 1018: catchend = get_last_insn (); ! 1019: ! 1020: NEXT_INSN (last) = 0; ! 1021: set_last_insn (last); ! 1022: ! 1023: /* this level of catch blocks is done, so set up the successful catch jump ! 1024: label for the next layer of catch blocks. */ ! 1025: pop_label_entry (&caught_return_label_stack); ! 1026: ! 1027: push_except_stmts (&exceptstack, catchstart, catchend); ! 1028: ! 1029: /* Here we fall through into the continuation code. */ ! 1030: } ! 1031: ! 1032: ! 1033: /* this is called from expand_exception_blocks () to expand the toplevel ! 1034: finalizations for a function. */ ! 1035: void ! 1036: expand_leftover_cleanups () ! 1037: { ! 1038: struct ehEntry *entry; ! 1039: rtx first_label = NULL_RTX; ! 1040: ! 1041: if (! doing_eh (0)) ! 1042: return; ! 1043: ! 1044: /* Will this help us not stomp on it? */ ! 1045: emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type)); ! 1046: emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value)); ! 1047: ! 1048: while ((entry = dequeue_eh_entry (&ehqueue)) != 0) ! 1049: { ! 1050: if (! first_label) ! 1051: first_label = entry->exception_handler_label; ! 1052: emit_label (entry->exception_handler_label); ! 1053: ! 1054: expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); ! 1055: ! 1056: /* leftover try block, opps. */ ! 1057: if (entry->finalization == integer_zero_node) ! 1058: abort (); ! 1059: ! 1060: free (entry); ! 1061: } ! 1062: if (first_label) ! 1063: { ! 1064: rtx label; ! 1065: struct ehEntry entry; ! 1066: /* These are saved for the exception table. */ ! 1067: push_rtl_perm (); ! 1068: label = gen_label_rtx (); ! 1069: entry.start_label = first_label; ! 1070: entry.end_label = label; ! 1071: entry.exception_handler_label = gen_label_rtx (); ! 1072: entry.finalization = TerminateFunctionCall; ! 1073: pop_rtl_from_perm (); ! 1074: emit_label (label); ! 1075: ! 1076: enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry)); ! 1077: ! 1078: /* After running the finalization, continue on out to the next ! 1079: cleanup, if we have nothing better to do. */ ! 1080: emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label)); ! 1081: /* Will this help us not stomp on it? */ ! 1082: emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type)); ! 1083: emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value)); ! 1084: emit_jump (throw_label); ! 1085: emit_label (entry.exception_handler_label); ! 1086: expand_expr (entry.finalization, const0_rtx, VOIDmode, 0); ! 1087: emit_barrier (); ! 1088: } ! 1089: } ! 1090: ! 1091: /* call this to start a catch block. Typename is the typename, and identifier ! 1092: is the variable to place the object in or NULL if the variable doesn't ! 1093: matter. If typename is NULL, that means its a "catch (...)" or catch ! 1094: everything. In that case we don't need to do any type checking. ! 1095: (ie: it ends up as the "else" clause rather than an "else if" clause) */ ! 1096: void ! 1097: expand_start_catch_block (declspecs, declarator) ! 1098: tree declspecs, declarator; ! 1099: { ! 1100: rtx false_label_rtx; ! 1101: rtx protect_label_rtx; ! 1102: tree type; ! 1103: tree decl; ! 1104: tree init; ! 1105: ! 1106: if (! doing_eh (1)) ! 1107: return; ! 1108: ! 1109: /* Create a binding level for the parm. */ ! 1110: expand_start_bindings (0); ! 1111: ! 1112: if (declspecs) ! 1113: { ! 1114: tree init_type; ! 1115: decl = grokdeclarator (declarator, declspecs, NORMAL, 1, NULL_TREE); ! 1116: ! 1117: /* Figure out the type that the initializer is. */ ! 1118: init_type = TREE_TYPE (decl); ! 1119: if (TREE_CODE (init_type) != REFERENCE_TYPE) ! 1120: init_type = build_reference_type (init_type); ! 1121: ! 1122: init = convert_from_reference (save_expr (make_tree (init_type, saved_throw_value))); ! 1123: ! 1124: /* Do we need the below two lines? */ ! 1125: /* Let `finish_decl' know that this initializer is ok. */ ! 1126: DECL_INITIAL (decl) = init; ! 1127: /* This needs to be preallocated under the try block, ! 1128: in a union of all catch variables. */ ! 1129: pushdecl (decl); ! 1130: type = TREE_TYPE (decl); ! 1131: ! 1132: /* peel back references, so they match. */ ! 1133: if (TREE_CODE (type) == REFERENCE_TYPE) ! 1134: type = TREE_TYPE (type); ! 1135: } ! 1136: else ! 1137: type = NULL_TREE; ! 1138: ! 1139: /* These are saved for the exception table. */ ! 1140: push_rtl_perm (); ! 1141: false_label_rtx = gen_label_rtx (); ! 1142: protect_label_rtx = gen_label_rtx (); ! 1143: pop_rtl_from_perm (); ! 1144: push_label_entry (&false_label_stack, false_label_rtx); ! 1145: push_label_entry (&false_label_stack, protect_label_rtx); ! 1146: ! 1147: if (type) ! 1148: { ! 1149: tree params; ! 1150: char *typestring; ! 1151: rtx call_rtx, return_value_rtx; ! 1152: tree catch_match_fcall; ! 1153: tree catchmatch_arg, argval; ! 1154: ! 1155: typestring = build_overload_name (type, 1, 1); ! 1156: ! 1157: params = tree_cons (NULL_TREE, ! 1158: combine_strings (build_string (strlen (typestring)+1, typestring)), ! 1159: tree_cons (NULL_TREE, ! 1160: make_tree (ptr_type_node, saved_throw_type), ! 1161: NULL_TREE)); ! 1162: catch_match_fcall = build_function_call (CatchMatch, params); ! 1163: call_rtx = expand_call (catch_match_fcall, NULL_RTX, 0); ! 1164: ! 1165: return_value_rtx = ! 1166: hard_function_value (integer_type_node, catch_match_fcall); ! 1167: ! 1168: /* did the throw type match function return TRUE? */ ! 1169: emit_cmp_insn (return_value_rtx, const0_rtx, NE, NULL_RTX, ! 1170: GET_MODE (return_value_rtx), 0, 0); ! 1171: ! 1172: /* if it returned FALSE, jump over the catch block, else fall into it */ ! 1173: emit_jump_insn (gen_bne (false_label_rtx)); ! 1174: finish_decl (decl, init, NULL_TREE, 0); ! 1175: } ! 1176: else ! 1177: { ! 1178: /* Fall into the catch all section. */ ! 1179: } ! 1180: ! 1181: /* This is the starting of something to protect. */ ! 1182: emit_label (protect_label_rtx); ! 1183: ! 1184: emit_line_note (input_filename, lineno); ! 1185: } ! 1186: ! 1187: ! 1188: /* Call this to end a catch block. Its responsible for emitting the ! 1189: code to handle jumping back to the correct place, and for emitting ! 1190: the label to jump to if this catch block didn't match. */ ! 1191: void expand_end_catch_block () ! 1192: { ! 1193: if (doing_eh (1)) ! 1194: { ! 1195: rtx start_protect_label_rtx; ! 1196: rtx end_protect_label_rtx; ! 1197: tree decls; ! 1198: struct ehEntry entry; ! 1199: ! 1200: /* label we jump to if we caught the exception */ ! 1201: emit_jump (top_label_entry (&caught_return_label_stack)); ! 1202: ! 1203: /* Code to throw out to outer context, if we get an throw from within ! 1204: our catch handler. */ ! 1205: /* These are saved for the exception table. */ ! 1206: push_rtl_perm (); ! 1207: entry.exception_handler_label = gen_label_rtx (); ! 1208: pop_rtl_from_perm (); ! 1209: emit_label (entry.exception_handler_label); ! 1210: emit_move_insn (saved_pc, gen_rtx (LABEL_REF, ! 1211: Pmode, ! 1212: top_label_entry (&caught_return_label_stack))); ! 1213: emit_jump (throw_label); ! 1214: /* No associated finalization. */ ! 1215: entry.finalization = NULL_TREE; ! 1216: ! 1217: /* Because we are reordered out of line, we have to protect this. */ ! 1218: /* label for the start of the protection region. */ ! 1219: start_protect_label_rtx = pop_label_entry (&false_label_stack); ! 1220: ! 1221: /* Cleanup the EH paramater. */ ! 1222: expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0); ! 1223: ! 1224: /* label we emit to jump to if this catch block didn't match. */ ! 1225: emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack)); ! 1226: ! 1227: /* Because we are reordered out of line, we have to protect this. */ ! 1228: entry.start_label = start_protect_label_rtx; ! 1229: entry.end_label = end_protect_label_rtx; ! 1230: ! 1231: /* These set up a call to throw the caught exception into the outer ! 1232: context. */ ! 1233: enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry)); ! 1234: } ! 1235: } ! 1236: ! 1237: /* cheesyness to save some typing. returns the return value rtx */ ! 1238: rtx ! 1239: do_function_call (func, params, return_type) ! 1240: tree func, params, return_type; ! 1241: { ! 1242: tree func_call; ! 1243: func_call = build_function_call (func, params); ! 1244: expand_call (func_call, NULL_RTX, 0); ! 1245: if (return_type != NULL_TREE) ! 1246: return hard_function_value (return_type, func_call); ! 1247: return NULL_RTX; ! 1248: } ! 1249: ! 1250: ! 1251: /* is called from expand_excpetion_blocks () to generate the code in a function ! 1252: to "throw" if anything in the function needs to preform a throw. ! 1253: ! 1254: expands "throw" as the following psuedo code: ! 1255: ! 1256: throw: ! 1257: eh = find_first_exception_match (saved_pc); ! 1258: if (!eh) goto gotta_rethrow_it; ! 1259: goto eh; ! 1260: ! 1261: gotta_rethrow_it: ! 1262: saved_pc = __builtin_return_address (0); ! 1263: pop_to_previous_level (); ! 1264: goto throw; ! 1265: ! 1266: */ ! 1267: static void ! 1268: expand_builtin_throw () ! 1269: { ! 1270: tree fcall; ! 1271: tree params; ! 1272: rtx return_val_rtx; ! 1273: rtx gotta_rethrow_it = gen_label_rtx (); ! 1274: rtx gotta_call_terminate = gen_label_rtx (); ! 1275: rtx unwind_and_throw = gen_label_rtx (); ! 1276: rtx goto_unwind_and_throw = gen_label_rtx (); ! 1277: ! 1278: emit_label (throw_label); ! 1279: ! 1280: /* search for an exception handler for the saved_pc */ ! 1281: return_val_rtx = do_function_call (FirstExceptionMatch, ! 1282: tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE), ! 1283: ptr_type_node); ! 1284: ! 1285: /* did we find one? */ ! 1286: emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, ! 1287: GET_MODE (return_val_rtx), 0, 0); ! 1288: ! 1289: /* if not, jump to gotta_rethrow_it */ ! 1290: emit_jump_insn (gen_beq (gotta_rethrow_it)); ! 1291: ! 1292: /* we found it, so jump to it */ ! 1293: emit_indirect_jump (return_val_rtx); ! 1294: ! 1295: /* code to deal with unwinding and looking for it again */ ! 1296: emit_label (gotta_rethrow_it); ! 1297: ! 1298: /* call to __builtin_return_address () */ ! 1299: params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); ! 1300: fcall = build_function_call (BuiltinReturnAddress, params); ! 1301: return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0); ! 1302: ! 1303: /* did __builtin_return_address () return a valid address? */ ! 1304: emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, ! 1305: GET_MODE (return_val_rtx), 0, 0); ! 1306: ! 1307: emit_jump_insn (gen_beq (gotta_call_terminate)); ! 1308: ! 1309: /* yes it did */ ! 1310: emit_move_insn (saved_pc, return_val_rtx); ! 1311: do_unwind (throw_label); ! 1312: emit_jump (throw_label); ! 1313: ! 1314: /* no it didn't --> therefore we need to call terminate */ ! 1315: emit_label (gotta_call_terminate); ! 1316: do_function_call (Terminate, NULL_TREE, NULL_TREE); ! 1317: } ! 1318: ! 1319: ! 1320: /* This is called to expand all the toplevel exception handling ! 1321: finalization for a function. It should only be called once per ! 1322: function. */ ! 1323: void ! 1324: expand_exception_blocks () ! 1325: { ! 1326: rtx catchstart, catchend; ! 1327: rtx last; ! 1328: static rtx funcend; ! 1329: ! 1330: funcend = gen_label_rtx (); ! 1331: emit_jump (funcend); ! 1332: /* expand_null_return (); */ ! 1333: ! 1334: while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) { ! 1335: last = get_last_insn (); ! 1336: NEXT_INSN (last) = catchstart; ! 1337: PREV_INSN (catchstart) = last; ! 1338: NEXT_INSN (catchend) = 0; ! 1339: set_last_insn (catchend); ! 1340: } ! 1341: ! 1342: expand_leftover_cleanups (); ! 1343: ! 1344: { ! 1345: static int have_done = 0; ! 1346: if (! have_done && TREE_PUBLIC (current_function_decl) ! 1347: && ! DECL_INLINE (current_function_decl)) ! 1348: { ! 1349: have_done = 1; ! 1350: expand_builtin_throw (); ! 1351: } ! 1352: } ! 1353: emit_label (funcend); ! 1354: } ! 1355: ! 1356: ! 1357: /* call this to expand a throw statement. This follows the following ! 1358: algorithm: ! 1359: ! 1360: 1. Allocate space to save the current PC onto the stack. ! 1361: 2. Generate and emit a label and save its address into the ! 1362: newly allocate stack space since we can't save the pc directly. ! 1363: 3. If this is the first call to throw in this function: ! 1364: generate a label for the throw block ! 1365: 4. jump to the throw block label. */ ! 1366: void ! 1367: expand_throw (exp) ! 1368: tree exp; ! 1369: { ! 1370: rtx label; ! 1371: tree type; ! 1372: ! 1373: if (! doing_eh (1)) ! 1374: return; ! 1375: ! 1376: /* This is the label that represents where in the code we were, when ! 1377: we got an exception. This needs to be updated when we rethrow an ! 1378: exception, so that the matching routine knows to search out. */ ! 1379: label = gen_label_rtx (); ! 1380: emit_label (label); ! 1381: emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label)); ! 1382: ! 1383: if (exp) ! 1384: { ! 1385: /* throw expression */ ! 1386: /* First, decay it. */ ! 1387: exp = default_conversion (exp); ! 1388: type = TREE_TYPE (exp); ! 1389: ! 1390: { ! 1391: char *typestring = build_overload_name (type, 1, 1); ! 1392: tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring))); ! 1393: rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0); ! 1394: rtx throw_value_rtx; ! 1395: ! 1396: emit_move_insn (saved_throw_type, throw_type_rtx); ! 1397: exp = convert_to_reference (build_reference_type (build_type_variant (TREE_TYPE (exp), 1, 0)), exp, CONV_STATIC, LOOKUP_COMPLAIN, NULL_TREE); ! 1398: if (exp == error_mark_node) ! 1399: error (" in thrown expression"); ! 1400: throw_value_rtx = expand_expr (build_unary_op (ADDR_EXPR, exp, 0), NULL_RTX, VOIDmode, 0); ! 1401: emit_move_insn (saved_throw_value, throw_value_rtx); ! 1402: } ! 1403: } ! 1404: else ! 1405: { ! 1406: /* rethrow current exception */ ! 1407: /* This part is easy, as we dont' have to do anything else. */ ! 1408: } ! 1409: ! 1410: emit_jump (throw_label); ! 1411: } ! 1412: ! 1413: /* end of: my-cp-except.c */ ! 1414: #endif ! 1415: ! 1416: ! 1417: /* Output the exception table. ! 1418: Return the number of handlers. */ ! 1419: int ! 1420: build_exception_table () ! 1421: { ! 1422: int count = 0; ! 1423: #ifdef TRY_NEW_EH ! 1424: extern FILE *asm_out_file; ! 1425: struct ehEntry *entry; ! 1426: tree eh_node_decl; ! 1427: ! 1428: if (! doing_eh (0)) ! 1429: return 0; ! 1430: ! 1431: while (entry = dequeue_eh_entry (&eh_table_output_queue)) ! 1432: { ! 1433: if (count == 0) ! 1434: { ! 1435: exception_section (); ! 1436: ! 1437: /* Beginning marker for table. */ ! 1438: ASM_OUTPUT_ALIGN (asm_out_file, 2); ! 1439: ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_TABLE__"); ! 1440: fprintf (asm_out_file, " .word 0, 0, 0\n"); ! 1441: } ! 1442: count++; ! 1443: output_exception_table_entry (asm_out_file, ! 1444: entry->start_label, entry->end_label, ! 1445: entry->exception_handler_label); ! 1446: } ! 1447: ! 1448: if (count) ! 1449: { ! 1450: /* Ending marker for table. */ ! 1451: ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_END__"); ! 1452: fprintf (asm_out_file, " .word -1, -1, -1\n"); ! 1453: } ! 1454: ! 1455: #endif /* TRY_NEW_EH */ ! 1456: return count; ! 1457: } ! 1458: ! 1459: void ! 1460: register_exception_table () ! 1461: { ! 1462: #ifdef TRY_NEW_EH ! 1463: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0, ! 1464: VOIDmode, 1, ! 1465: gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"), ! 1466: Pmode); ! 1467: #endif /* TRY_NEW_EH */ ! 1468: } ! 1469: ! 1470: /* Build a throw expression. */ ! 1471: tree ! 1472: build_throw (e) ! 1473: tree e; ! 1474: { ! 1475: e = build1 (THROW_EXPR, void_type_node, e); ! 1476: TREE_SIDE_EFFECTS (e) = 1; ! 1477: return e; ! 1478: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.