Annotation of gcc/cp/except.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.