OSDN Git Service

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