home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gcc-2.7.2.1-base.tgz / gcc-2.7.2.1-base.tar / fsf / gcc / cp / except.c < prev    next >
C/C++ Source or Header  |  1995-10-11  |  48KB  |  1,691 lines

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