source: trunk/third/gcc/cp/except.c @ 8834

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