OSDN Git Service

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