OSDN Git Service

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