except.c revision 34229
178556Sobrien/* Handle exceptional things in C++.
278556Sobrien   Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
378556Sobrien   Contributed by Michael Tiemann <tiemann@cygnus.com>
478556Sobrien   Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
578556Sobrien   initial re-implementation courtesy Tad Hunt.
6167977Sdelphij
7167977SdelphijThis file is part of GNU CC.
8167977Sdelphij
978556SobrienGNU CC is free software; you can redistribute it and/or modify
10167977Sdelphijit under the terms of the GNU General Public License as published by
11167977Sdelphijthe Free Software Foundation; either version 2, or (at your option)
1278556Sobrienany later version.
13167977Sdelphij
14167977SdelphijGNU CC is distributed in the hope that it will be useful,
1578556Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
16167977SdelphijMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17167977SdelphijGNU General Public License for more details.
18167977Sdelphij
1978556SobrienYou should have received a copy of the GNU General Public License
2078556Sobrienalong with GNU CC; see the file COPYING.  If not, write to
21167977Sdelphijthe Free Software Foundation, 59 Temple Place - Suite 330,
22167977SdelphijBoston, MA 02111-1307, USA.  */
23167977Sdelphij
24167977Sdelphij
25167977Sdelphij/* High-level class interface. */
2678556Sobrien
2778556Sobrien#include "config.h"
2878556Sobrien#include "tree.h"
2978556Sobrien#include "rtl.h"
3078556Sobrien#include "cp-tree.h"
3190067Ssobomax#include "flags.h"
3290067Ssobomax#include "obstack.h"
3390067Ssobomax#include "expr.h"
3478556Sobrien
3578556Sobrientree protect_list;
3678556Sobrien
3778556Sobrienextern void (*interim_eh_hook)	PROTO((tree));
3878556Sobrienrtx expand_builtin_return_addr	PROTO((enum built_in_function, int, rtx));
3978556Sobrien
4078556Sobrien/* holds the fndecl for __builtin_return_address () */
4178556Sobrientree builtin_return_address_fndecl;
4278556Sobrientree throw_fndecl;
4378556Sobrien
4478556Sobrienstatic int
4578556Sobriendoing_eh (do_warn)
4678556Sobrien     int do_warn;
4778556Sobrien{
4878556Sobrien  if (! flag_handle_exceptions)
4978556Sobrien    {
5078556Sobrien      static int warned = 0;
5178556Sobrien      if (! warned && do_warn)
5278556Sobrien	{
5378556Sobrien	  error ("exception handling disabled, use -fhandle-exceptions to enable.");
5478556Sobrien	  warned = 1;
5578556Sobrien	}
5678556Sobrien      return 0;
5778556Sobrien    }
5878556Sobrien  return 1;
5978556Sobrien}
6078556Sobrien
6178556Sobrien
6278556Sobrien/*
6378556SobrienNO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
6478556Sobriento supporting exception handling as per ANSI C++ working draft.
6578556SobrienIt is a complete rewrite of all the EH stuff that was here before
6678556Sobrien	Shortcomings:
6778556Sobrien		1. Throw specifications of functions still don't work.
6878556Sobrien	Cool Things:
6978556Sobrien		1. Destructors are called properly :-)
7090067Ssobomax		2. No overhead for the non-exception thrown case.
7178556Sobrien		3. Fixing shortcoming 1 is simple.
7278556Sobrien			-Tad Hunt	(tad@mail.csh.rit.edu)
7378556Sobrien
7478556Sobrien*/
7578556Sobrien
7678556Sobrien/* A couple of backend routines from m88k.c */
7778556Sobrien
7878556Sobrien/* used to cache a call to __builtin_return_address () */
7978556Sobrienstatic tree BuiltinReturnAddress;
8090067Ssobomax
8190067Ssobomax
8278556Sobrien#include <stdio.h>
8378556Sobrien
8478556Sobrien/* XXX - Tad: for EH */
8578556Sobrien/* output an exception table entry */
8678556Sobrien
8778556Sobrienstatic void
8878556Sobrienoutput_exception_table_entry (file, start_label, end_label, eh_label)
8978556Sobrien     FILE *file;
9078556Sobrien     rtx start_label, end_label, eh_label;
9178556Sobrien{
9278556Sobrien  char label[100];
9378556Sobrien
9478556Sobrien  assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1);
9578556Sobrien  assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1);
9690067Ssobomax  assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1);
9778556Sobrien  putc ('\n', file);		/* blank line */
9878556Sobrien}
9978556Sobrien
10078556Sobrienstatic void
10190067Ssobomaxeasy_expand_asm (str)
10278556Sobrien     char *str;
10390067Ssobomax{
10478556Sobrien  expand_asm (build_string (strlen (str)+1, str));
10578556Sobrien}
10678556Sobrien
10778556Sobrien
10890067Ssobomax#if 0
10978556Sobrien/* This is the startup, and finish stuff per exception table. */
11078556Sobrien
11178556Sobrien/* XXX - Tad: exception handling section */
11290067Ssobomax#ifndef EXCEPT_SECTION_ASM_OP
11378556Sobrien#define EXCEPT_SECTION_ASM_OP	"section\t.gcc_except_table,\"a\",@progbits"
11478556Sobrien#endif
11578556Sobrien
11678556Sobrien#ifdef EXCEPT_SECTION_ASM_OP
11778556Sobrientypedef struct {
11878556Sobrien    void *start_protect;
11978556Sobrien    void *end_protect;
12090067Ssobomax    void *exception_handler;
12178556Sobrien } exception_table;
12278556Sobrien#endif /* EXCEPT_SECTION_ASM_OP */
12378556Sobrien
12490067Ssobomax#ifdef EXCEPT_SECTION_ASM_OP
12578556Sobrien
12678556Sobrien /* on machines which support it, the exception table lives in another section,
12778556Sobrien	but it needs a label so we can reference it...  This sets up that
12878556Sobrien    label! */
12978556Sobrienasm (EXCEPT_SECTION_ASM_OP);
13078556Sobrienexception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
13178556Sobrienasm (TEXT_SECTION_ASM_OP);
13278556Sobrien
13378556Sobrien#endif /* EXCEPT_SECTION_ASM_OP */
13478556Sobrien
13578556Sobrien#ifdef EXCEPT_SECTION_ASM_OP
13678556Sobrien
13790067Ssobomax /* we need to know where the end of the exception table is... so this
13890067Ssobomax    is how we do it! */
13978556Sobrien
14078556Sobrienasm (EXCEPT_SECTION_ASM_OP);
14178556Sobrienexception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
14278556Sobrienasm (TEXT_SECTION_ASM_OP);
14378556Sobrien
14478556Sobrien#endif /* EXCEPT_SECTION_ASM_OP */
14578556Sobrien
14678556Sobrien#endif
14778556Sobrien
14878556Sobrienvoid
14990067Ssobomaxexception_section ()
15078556Sobrien{
15178556Sobrien#ifdef EXCEPTION_SECTION_FUNCTION
15278556Sobrien  EXCEPTION_SECTION_FUNCTION;
15390067Ssobomax#else
15478556Sobrien#ifdef ASM_OUTPUT_SECTION_NAME
15578556Sobrien  named_section (NULL_TREE, ".gcc_except_table");
15678556Sobrien#else
15778556Sobrien  if (flag_pic)
15878556Sobrien    data_section ();
15978556Sobrien  else
16078556Sobrien#if defined(TARGET_POWERPC) /* are we on a __rs6000? */
16178556Sobrien    data_section ();
16278556Sobrien#else
16378556Sobrien    readonly_data_section ();
16478556Sobrien#endif
16578556Sobrien#endif
16678556Sobrien#endif
16778556Sobrien}
16878556Sobrien
16978556Sobrien
17078556Sobrien
17178556Sobrien
17278556Sobrien/* from: my-cp-except.c */
17378556Sobrien
17478556Sobrien/* VI: ":set ts=4" */
17578556Sobrien#if 0
17678556Sobrien#include <stdio.h> */
17778556Sobrien#include "config.h"
17878556Sobrien#include "tree.h"
17978556Sobrien#include "rtl.h"
18078556Sobrien#include "cp-tree.h"
18178556Sobrien#endif
18278556Sobrien#include "decl.h"
18378556Sobrien#if 0
18478556Sobrien#include "flags.h"
18578556Sobrien#endif
18678556Sobrien#include "insn-flags.h"
18778556Sobrien#include "obstack.h"
18878556Sobrien#if 0
18978556Sobrien#include "expr.h"
19078556Sobrien#endif
19178556Sobrien
19278556Sobrien/* ======================================================================
19378556Sobrien   Briefly the algorithm works like this:
19478556Sobrien
19578556Sobrien     When a constructor or start of a try block is encountered,
19678556Sobrien     push_eh_entry (&eh_stack) is called.  Push_eh_entry () creates a
19778556Sobrien     new entry in the unwind protection stack and returns a label to
19878556Sobrien     output to start the protection for that block.
19978556Sobrien
20078556Sobrien     When a destructor or end try block is encountered, pop_eh_entry
20178556Sobrien     (&eh_stack) is called.  Pop_eh_entry () returns the ehEntry it
20278556Sobrien     created when push_eh_entry () was called.  The ehEntry structure
20378556Sobrien     contains three things at this point.  The start protect label,
20478556Sobrien     the end protect label, and the exception handler label.  The end
20578556Sobrien     protect label should be output before the call to the destructor
20678556Sobrien     (if any). If it was a destructor, then its parse tree is stored
20778556Sobrien     in the finalization variable in the ehEntry structure.  Otherwise
20878556Sobrien     the finalization variable is set to NULL to reflect the fact that
20978556Sobrien     is the the end of a try block.  Next, this modified ehEntry node
21078556Sobrien     is enqueued in the finalizations queue by calling
21178556Sobrien     enqueue_eh_entry (&queue,entry).
21278556Sobrien
213167977Sdelphij	+---------------------------------------------------------------+
214167977Sdelphij	|XXX: Will need modification to deal with partially		|
215167977Sdelphij	|			constructed arrays of objects		|
216167977Sdelphij	|								|
217167977Sdelphij	|	Basically, this consists of keeping track of how many	|
218167977Sdelphij	|	of the objects have been constructed already (this	|
219167977Sdelphij	|	should be in a register though, so that shouldn't be a	|
22078556Sobrien	|	problem.						|
22178556Sobrien	+---------------------------------------------------------------+
22278556Sobrien
223167977Sdelphij     When a catch block is encountered, there is a lot of work to be
22478556Sobrien     done.
22578556Sobrien
22678556Sobrien     Since we don't want to generate the catch block inline with the
22778556Sobrien     regular flow of the function, we need to have some way of doing
22878556Sobrien     so.  Luckily, we can use sequences to defer the catch sections.
22978556Sobrien     When the start of a catch block is encountered, we start the
23078556Sobrien     sequence.  After the catch block is generated, we end the
23178556Sobrien     sequence.
23278556Sobrien
23378556Sobrien     Next we must insure that when the catch block is executed, all
23478556Sobrien     finalizations for the matching try block have been completed.  If
23578556Sobrien     any of those finalizations throw an exception, we must call
23690067Ssobomax     terminate according to the ARM (section r.15.6.1).  What this
23778556Sobrien     means is that we need to dequeue and emit finalizations for each
23878556Sobrien     entry in the ehQueue until we get to an entry with a NULL
23978556Sobrien     finalization field.  For any of the finalization entries, if it
24078556Sobrien     is not a call to terminate (), we must protect it by giving it
24178556Sobrien     another start label, end label, and exception handler label,
24278556Sobrien     setting its finalization tree to be a call to terminate (), and
24378556Sobrien     enqueue'ing this new ehEntry to be output at an outer level.
24478556Sobrien     Finally, after all that is done, we can get around to outputting
24578556Sobrien     the catch block which basically wraps all the "catch (...) {...}"
24678556Sobrien     statements in a big if/then/else construct that matches the
24778556Sobrien     correct block to call.
24878556Sobrien
24978556Sobrien     ===================================================================== */
25090067Ssobomax
25178556Sobrienextern rtx emit_insn		PROTO((rtx));
25278556Sobrienextern rtx gen_nop		PROTO(());
25378556Sobrien
25478556Sobrien/* local globals for function calls
25578556Sobrien   ====================================================================== */
25678556Sobrien
25778556Sobrien/* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
25878556Sobrien   "set_unexpected ()" after default_conversion. (lib-except.c)  */
25978556Sobrienstatic tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw;
26078556Sobrien
26178556Sobrien/* used to cache __find_first_exception_table_match ()
26278556Sobrien   for throw (lib-except.c)  */
26378556Sobrienstatic tree FirstExceptionMatch;
26478556Sobrien
26578556Sobrien/* used to cache a call to __unwind_function () (lib-except.c)  */
26678556Sobrienstatic tree Unwind;
26778556Sobrien
26878556Sobrien/* holds a ready to emit call to "terminate ()".  */
26978556Sobrienstatic tree TerminateFunctionCall;
27078556Sobrien
27178556Sobrien/* ====================================================================== */
27278556Sobrien
27378556Sobrien
27490067Ssobomax
27590067Ssobomax/* data structures for my various quick and dirty stacks and queues
27690067Ssobomax   Eventually, most of this should go away, because I think it can be
27778556Sobrien   integrated with stuff already built into the compiler.  */
27878556Sobrien
27990067Ssobomax/* =================================================================== */
28078556Sobrien
28190067Ssobomaxstruct labelNode {
28290067Ssobomax  rtx label;
28390067Ssobomax  struct labelNode *chain;
28490067Ssobomax};
28590067Ssobomax
28690067Ssobomax
28790067Ssobomax/* this is the most important structure here.  Basically this is how I store
28890067Ssobomax   an exception table entry internally. */
28978556Sobrienstruct ehEntry {
29078556Sobrien  rtx start_label;
29178556Sobrien  rtx end_label;
29278556Sobrien  rtx exception_handler_label;
29378556Sobrien
29478556Sobrien  tree finalization;
29578556Sobrien  tree context;
29678556Sobrien};
29778556Sobrien
29878556Sobrienstruct ehNode {
29978556Sobrien  struct ehEntry *entry;
30078556Sobrien  struct ehNode *chain;
30178556Sobrien};
30278556Sobrien
30378556Sobrienstruct ehStack {
30478556Sobrien  struct ehNode *top;
30578556Sobrien};
30678556Sobrien
30790067Ssobomaxstruct ehQueue {
30890067Ssobomax  struct ehNode *head;
30978556Sobrien  struct ehNode *tail;
31078556Sobrien};
31178556Sobrien/* ========================================================================= */
31278556Sobrien
31378556Sobrien
31478556Sobrien
31578556Sobrien/* local globals - these local globals are for storing data necessary for
31678556Sobrien   generating the exception table and code in the correct order.
31778556Sobrien
31878556Sobrien   ========================================================================= */
31978556Sobrien
32078556Sobrien/* Holds the pc for doing "throw" */
32178556Sobrientree saved_pc;
32278556Sobrien/* Holds the type of the thing being thrown. */
32378556Sobrientree saved_throw_type;
32478556Sobrien/* Holds the value being thrown.  */
32578556Sobrientree saved_throw_value;
32678556Sobrien
32778556Sobrienint throw_used;
32878556Sobrien
32978556Sobrienstatic rtx catch_clauses;
33078556Sobrienstatic first_catch_label;
33178556Sobrien
33278556Sobrienstatic struct ehStack ehstack;
33378556Sobrienstatic struct ehQueue ehqueue;
33478556Sobrienstatic struct ehQueue eh_table_output_queue;
33578556Sobrienstatic struct labelNode *false_label_stack = NULL;
33678556Sobrienstatic struct labelNode *caught_return_label_stack = NULL;
33778556Sobrien/* ========================================================================= */
33878556Sobrien
33978556Sobrien/* function prototypes */
34078556Sobrienstatic struct ehEntry *pop_eh_entry	PROTO((struct ehStack *stack));
34178556Sobrienstatic void enqueue_eh_entry		PROTO((struct ehQueue *queue, struct ehEntry *entry));
34278556Sobrienstatic rtx push_eh_entry		PROTO((struct ehStack *stack));
34378556Sobrienstatic struct ehEntry *dequeue_eh_entry	PROTO((struct ehQueue *queue));
34478556Sobrienstatic void new_eh_queue		PROTO((struct ehQueue *queue));
34578556Sobrienstatic void new_eh_stack		PROTO((struct ehStack *stack));
34678556Sobrienstatic void push_label_entry		PROTO((struct labelNode **labelstack, rtx label));
34778556Sobrienstatic rtx pop_label_entry		PROTO((struct labelNode **labelstack));
34878556Sobrienstatic rtx top_label_entry		PROTO((struct labelNode **labelstack));
34978556Sobrienstatic struct ehEntry *copy_eh_entry	PROTO((struct ehEntry *entry));
35078556Sobrien
35178556Sobrien
35278556Sobrien
35378556Sobrien/* All my cheesy stack/queue/misc data structure handling routines
35478556Sobrien
35578556Sobrien   ========================================================================= */
35678556Sobrien
35778556Sobrienstatic void
35878556Sobrienpush_label_entry (labelstack, label)
35978556Sobrien     struct labelNode **labelstack;
36078556Sobrien     rtx label;
36178556Sobrien{
36278556Sobrien  struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
36378556Sobrien
36478556Sobrien  newnode->label = label;
36578556Sobrien  newnode->chain = *labelstack;
36678556Sobrien  *labelstack = newnode;
36778556Sobrien}
36878556Sobrien
369167977Sdelphijstatic rtx
370147666Ssimonpop_label_entry (labelstack)
371167977Sdelphij     struct labelNode **labelstack;
37278556Sobrien{
37390067Ssobomax  rtx label;
37478556Sobrien  struct labelNode *tempnode;
37578556Sobrien
37690067Ssobomax  if (! *labelstack) return NULL_RTX;
37778556Sobrien
37878556Sobrien  tempnode = *labelstack;
37978556Sobrien  label = tempnode->label;
38078556Sobrien  *labelstack = (*labelstack)->chain;
38178556Sobrien  free (tempnode);
38290067Ssobomax
38390067Ssobomax  return label;
38490067Ssobomax}
38590067Ssobomax
38690067Ssobomaxstatic rtx
38790067Ssobomaxtop_label_entry (labelstack)
38890067Ssobomax     struct labelNode **labelstack;
38990067Ssobomax{
39090067Ssobomax  if (! *labelstack) return NULL_RTX;
39190067Ssobomax
39290067Ssobomax  return (*labelstack)->label;
39390067Ssobomax}
39490067Ssobomax
39590067Ssobomax/* Push to permanent obstack for rtl generation.
39690067Ssobomax   One level only!  */
39790067Ssobomaxstatic struct obstack *saved_rtl_obstack;
39890067Ssobomaxvoid
39990067Ssobomaxpush_rtl_perm ()
40090067Ssobomax{
40190067Ssobomax  extern struct obstack permanent_obstack;
40290067Ssobomax  extern struct obstack *rtl_obstack;
40390067Ssobomax
40490067Ssobomax  saved_rtl_obstack = rtl_obstack;
40578556Sobrien  rtl_obstack = &permanent_obstack;
40678556Sobrien}
40778556Sobrien
40878556Sobrien/* Pop back to normal rtl handling.  */
40978556Sobrienstatic void
41078556Sobrienpop_rtl_from_perm ()
41178556Sobrien{
41278556Sobrien  extern struct obstack permanent_obstack;
41378556Sobrien  extern struct obstack *rtl_obstack;
41478556Sobrien
41578556Sobrien  rtl_obstack = saved_rtl_obstack;
41678556Sobrien}
41778556Sobrien
41878556Sobrienstatic rtx
41978556Sobrienpush_eh_entry (stack)
42078556Sobrien     struct ehStack *stack;
42178556Sobrien{
42278556Sobrien  struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
42378556Sobrien  struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
42478556Sobrien
42578556Sobrien  if (stack == NULL) {
42678556Sobrien    free (node);
42778556Sobrien    free (entry);
42878556Sobrien    return NULL_RTX;
42978556Sobrien  }
43078556Sobrien
43178556Sobrien  /* These are saved for the exception table.  */
43278556Sobrien  push_rtl_perm ();
43378556Sobrien  entry->start_label = gen_label_rtx ();
43478556Sobrien  entry->end_label = gen_label_rtx ();
43578556Sobrien  entry->exception_handler_label = gen_label_rtx ();
43678556Sobrien  pop_rtl_from_perm ();
43778556Sobrien
43878556Sobrien  LABEL_PRESERVE_P (entry->start_label) = 1;
43978556Sobrien  LABEL_PRESERVE_P (entry->end_label) = 1;
440146293Sobrien  LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
44178556Sobrien
44278556Sobrien  entry->finalization = NULL_TREE;
44378556Sobrien  entry->context = current_function_decl;
44478556Sobrien
44578556Sobrien  node->entry = entry;
44678556Sobrien  node->chain = stack->top;
44778556Sobrien  stack->top = node;
44878556Sobrien
44978556Sobrien  enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
45078556Sobrien
45178556Sobrien  return entry->start_label;
45278556Sobrien}
45378556Sobrien
45478556Sobrienstatic struct ehEntry *
45578556Sobrienpop_eh_entry (stack)
45678556Sobrien     struct ehStack *stack;
45778556Sobrien{
45878556Sobrien  struct ehNode *tempnode;
45978556Sobrien  struct ehEntry *tempentry;
46078556Sobrien
46178556Sobrien  if (stack && (tempnode = stack->top)) {
46278556Sobrien    tempentry = tempnode->entry;
46390067Ssobomax    stack->top = stack->top->chain;
46478556Sobrien    free (tempnode);
46578556Sobrien
46678556Sobrien    return tempentry;
46778556Sobrien  }
46878556Sobrien
46978556Sobrien  return NULL;
470146293Sobrien}
47178556Sobrien
47278556Sobrienstatic struct ehEntry *
473146293Sobriencopy_eh_entry (entry)
47478556Sobrien     struct ehEntry *entry;
47578556Sobrien{
47678556Sobrien  struct ehEntry *newentry;
47778556Sobrien
47878556Sobrien  newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
47978556Sobrien  memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
48078556Sobrien
48178556Sobrien  return newentry;
48290067Ssobomax}
48378556Sobrien
484167977Sdelphijstatic void
485167977Sdelphijenqueue_eh_entry (queue, entry)
486147666Ssimon     struct ehQueue *queue;
487167977Sdelphij     struct ehEntry *entry;
488147666Ssimon{
48978556Sobrien  struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
49078556Sobrien
49178556Sobrien  node->entry = entry;
49278556Sobrien  node->chain = NULL;
49378556Sobrien
49478556Sobrien  if (queue->head == NULL)
49578556Sobrien    {
49678556Sobrien      queue->head = node;
49790067Ssobomax    }
49878556Sobrien  else
49978556Sobrien    {
50090067Ssobomax      queue->tail->chain = node;
50178556Sobrien    }
50278556Sobrien  queue->tail = node;
50378556Sobrien}
50490067Ssobomax
50590067Ssobomaxstatic struct ehEntry *
50690067Ssobomaxdequeue_eh_entry (queue)
50790067Ssobomax     struct ehQueue *queue;
50890067Ssobomax{
50990067Ssobomax  struct ehNode *tempnode;
51090067Ssobomax  struct ehEntry *tempentry;
51190067Ssobomax
51290067Ssobomax  if (queue->head == NULL)
51390067Ssobomax    return NULL;
51490067Ssobomax
51590067Ssobomax  tempnode = queue->head;
51690067Ssobomax  queue->head = queue->head->chain;
51778556Sobrien
51878556Sobrien  tempentry = tempnode->entry;
51978556Sobrien  free (tempnode);
52078556Sobrien
52178556Sobrien  return tempentry;
52278556Sobrien}
52378556Sobrien
52478556Sobrienstatic void
52578556Sobriennew_eh_queue (queue)
52678556Sobrien     struct ehQueue *queue;
52778556Sobrien{
52878556Sobrien  queue->head = queue->tail = NULL;
52978556Sobrien}
53078556Sobrien
53178556Sobrienstatic void
53278556Sobriennew_eh_stack (stack)
53378556Sobrien     struct ehStack *stack;
53478556Sobrien{
53578556Sobrien  stack->top = NULL;
53678556Sobrien}
53778556Sobrien
53878556Sobrien/* cheesyness to save some typing. returns the return value rtx */
53978556Sobrienrtx
54078556Sobriendo_function_call (func, params, return_type)
54178556Sobrien     tree func, params, return_type;
54278556Sobrien{
54378556Sobrien  tree func_call;
54478556Sobrien  func_call = build_function_call (func, params);
54578556Sobrien  expand_call (func_call, NULL_RTX, 0);
54678556Sobrien  if (return_type != NULL_TREE)
54778556Sobrien    return hard_function_value (return_type, func_call);
54878556Sobrien  return NULL_RTX;
54978556Sobrien}
55078556Sobrien
55178556Sobrienstatic void
55278556Sobrienexpand_internal_throw (pc)
55378556Sobrien     rtx pc;
55478556Sobrien{
55578556Sobrien  tree params;
55678556Sobrien
55778556Sobrien  emit_move_insn (DECL_RTL (saved_pc), pc);
55878556Sobrien#ifdef JUMP_TO_THROW
55978556Sobrien  emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
56078556Sobrien#else
561146293Sobrien  do_function_call (Throw, NULL_TREE, NULL_TREE);
56278556Sobrien#endif
56378556Sobrien  throw_used = 1;
56478556Sobrien}
56578556Sobrien
56678556Sobrien/* ========================================================================= */
56778556Sobrien
56878556Sobrienvoid
56978556Sobrienlang_interim_eh (finalization)
57078556Sobrien     tree finalization;
57178556Sobrien{
57278556Sobrien  if (finalization)
57378556Sobrien    end_protect (finalization);
57478556Sobrien  else
57578556Sobrien    start_protect ();
57678556Sobrien}
57778556Sobrien
57878556Sobrienextern tree auto_function PROTO((tree, tree, enum built_in_function));
57978556Sobrien
58078556Sobrien/* sets up all the global eh stuff that needs to be initialized at the
58178556Sobrien   start of compilation.
58278556Sobrien
58378556Sobrien   This includes:
58478556Sobrien		- Setting up all the function call trees
585146293Sobrien		- Initializing the ehqueue
58678556Sobrien		- Initializing the eh_table_output_queue
58778556Sobrien		- Initializing the ehstack
588146293Sobrien*/
58978556Sobrien
59078556Sobrienvoid
59178556Sobrieninit_exception_processing ()
59278556Sobrien{
59378556Sobrien  extern tree define_function ();
59478556Sobrien  tree unexpected_fndecl, terminate_fndecl;
59578556Sobrien  tree set_unexpected_fndecl, set_terminate_fndecl;
59678556Sobrien  tree catch_match_fndecl;
59778556Sobrien  tree find_first_exception_match_fndecl;
59878556Sobrien  tree unwind_fndecl;
59978556Sobrien  tree declspecs;
60078556Sobrien  tree d;
60178556Sobrien
60278556Sobrien  /* void (*)() */
60378556Sobrien  tree PFV = build_pointer_type (build_function_type
60478556Sobrien				 (void_type_node, void_list_node));
60578556Sobrien
60678556Sobrien  /* arg list for the build_function_type call for set_terminate () and
60778556Sobrien     set_unexpected () */
60878556Sobrien  tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
60978556Sobrien
61078556Sobrien  /* void (*pfvtype (void (*) ()))() */
61178556Sobrien  tree pfvtype = build_function_type (PFV, pfvlist);
61278556Sobrien
61378556Sobrien  /* void vtype () */
61478556Sobrien  tree vtype = build_function_type (void_type_node, void_list_node);
61578556Sobrien
61678556Sobrien  set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
61778556Sobrien					pfvtype, NOT_BUILT_IN);
61878556Sobrien  set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
61978556Sobrien					 pfvtype, NOT_BUILT_IN);
62078556Sobrien  unexpected_fndecl = auto_function (get_identifier ("unexpected"),
62178556Sobrien				     vtype, NOT_BUILT_IN);
62278556Sobrien  terminate_fndecl = auto_function (get_identifier ("terminate"),
62378556Sobrien				    vtype, NOT_BUILT_IN);
62478556Sobrien
62578556Sobrien  interim_eh_hook = lang_interim_eh;
62678556Sobrien
62778556Sobrien  push_lang_context (lang_name_c);
62878556Sobrien
62978556Sobrien  catch_match_fndecl =
63078556Sobrien    define_function (flag_rtti
63178556Sobrien		     ? "__throw_type_match_rtti"
63278556Sobrien		     : "__throw_type_match",
63378556Sobrien		     build_function_type (ptr_type_node,
63478556Sobrien					  tree_cons (NULL_TREE, ptr_type_node,
63578556Sobrien						     tree_cons (NULL_TREE, ptr_type_node,
63678556Sobrien								tree_cons (NULL_TREE, ptr_type_node,
63778556Sobrien									   void_list_node)))),
63878556Sobrien		     NOT_BUILT_IN,
63978556Sobrien		     pushdecl,
64078556Sobrien		     0);
64178556Sobrien  find_first_exception_match_fndecl =
64278556Sobrien    define_function ("__find_first_exception_table_match",
64378556Sobrien		     build_function_type (ptr_type_node,
64478556Sobrien					  tree_cons (NULL_TREE, ptr_type_node,
64578556Sobrien						     void_list_node)),
64678556Sobrien		     NOT_BUILT_IN,
64778556Sobrien		     pushdecl,
64878556Sobrien		     0);
64978556Sobrien  unwind_fndecl =
65078556Sobrien    define_function ("__unwind_function",
65178556Sobrien		     build_function_type (void_type_node,
65278556Sobrien					  tree_cons (NULL_TREE, ptr_type_node,
65378556Sobrien						     void_list_node)),
65478556Sobrien		     NOT_BUILT_IN,
65578556Sobrien		     pushdecl,
65678556Sobrien		     0);
65778556Sobrien  throw_fndecl =
65878556Sobrien    define_function ("__throw",
65978556Sobrien		     build_function_type (void_type_node, void_list_node),
66078556Sobrien		     NOT_BUILT_IN,
66178556Sobrien		     pushdecl,
66278556Sobrien		     0);
66378556Sobrien  DECL_EXTERNAL (throw_fndecl) = 0;
66478556Sobrien  TREE_PUBLIC (throw_fndecl) = 0;
66578556Sobrien
66690067Ssobomax  Unexpected = default_conversion (unexpected_fndecl);
66778556Sobrien  Terminate = default_conversion (terminate_fndecl);
66878556Sobrien  SetTerminate = default_conversion (set_terminate_fndecl);
66978556Sobrien  SetUnexpected = default_conversion (set_unexpected_fndecl);
67078556Sobrien  CatchMatch = default_conversion (catch_match_fndecl);
67178556Sobrien  FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
67278556Sobrien  Unwind = default_conversion (unwind_fndecl);
67378556Sobrien  Throw = default_conversion (throw_fndecl);
67478556Sobrien  BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
67578556Sobrien
67678556Sobrien  TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
67778556Sobrien
67878556Sobrien  pop_lang_context ();
67978556Sobrien
68078556Sobrien  new_eh_queue (&ehqueue);
68178556Sobrien  new_eh_queue (&eh_table_output_queue);
68278556Sobrien  new_eh_stack (&ehstack);
68378556Sobrien
68478556Sobrien  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
68578556Sobrien  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
68678556Sobrien  d = start_decl (d, declspecs, 0, NULL_TREE);
68778556Sobrien  DECL_COMMON (d) = 1;
68878556Sobrien  cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
68990067Ssobomax  saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
69090067Ssobomax
69178556Sobrien  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
69278556Sobrien  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
69378556Sobrien  d = start_decl (d, declspecs, 0, NULL_TREE);
69478556Sobrien  DECL_COMMON (d) = 1;
69590067Ssobomax  cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
69690067Ssobomax  saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
69790067Ssobomax
69890067Ssobomax  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
69990067Ssobomax  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
70090067Ssobomax  d = start_decl (d, declspecs, 0, NULL_TREE);
70190067Ssobomax  DECL_COMMON (d) = 1;
70290067Ssobomax  cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
70390067Ssobomax  saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
70490067Ssobomax}
70590067Ssobomax
70690067Ssobomax/* call this to begin a block of unwind protection (ie: when an object is
70790067Ssobomax   constructed) */
70890067Ssobomaxvoid
70990067Ssobomaxstart_protect ()
71090067Ssobomax{
71190067Ssobomax  if (! doing_eh (0))
71290067Ssobomax    return;
71390067Ssobomax
71490067Ssobomax  emit_label (push_eh_entry (&ehstack));
71590067Ssobomax}
71678556Sobrien
71790067Ssobomax/* call this to end a block of unwind protection.  the finalization tree is
71890067Ssobomax   the finalization which needs to be run in order to cleanly unwind through
71990067Ssobomax   this level of protection. (ie: call this when a scope is exited)*/
72090067Ssobomaxvoid
72178556Sobrienend_protect (finalization)
72290067Ssobomax     tree finalization;
72390067Ssobomax{
72490067Ssobomax  struct ehEntry *entry;
72590067Ssobomax
72690067Ssobomax  if (! doing_eh (0))
72790067Ssobomax    return;
72890067Ssobomax
72990067Ssobomax  entry = pop_eh_entry (&ehstack);
73078556Sobrien
73190067Ssobomax  emit_label (entry->end_label);
73278556Sobrien  /* Put in something that takes up space, as otherwise the end
73378556Sobrien     address for the EH region could have the exact same address as
73478556Sobrien     the outer region, causing us to miss the fact that resuming
73590067Ssobomax     exception handling with this PC value would be inside the outer
73690067Ssobomax     region.  */
73790067Ssobomax  emit_insn (gen_nop ());
73878556Sobrien
73978556Sobrien  entry->finalization = finalization;
74078556Sobrien
74178556Sobrien  enqueue_eh_entry (&ehqueue, entry);
74278556Sobrien}
74378556Sobrien
74478556Sobrien/* call this on start of a try block. */
74578556Sobrienvoid
746167977Sdelphijexpand_start_try_stmts ()
74778556Sobrien{
74878556Sobrien  if (! doing_eh (1))
74978556Sobrien    return;
75078556Sobrien
75178556Sobrien  start_protect ();
752146293Sobrien}
75378556Sobrien
75478556Sobrienvoid
75578556Sobrienexpand_end_try_stmts ()
75678556Sobrien{
75778556Sobrien  end_protect (integer_zero_node);
75878556Sobrien}
75978556Sobrien
76078556Sobrien
76178556Sobrien/* call this to start processing of all the catch blocks. */
76278556Sobrienvoid
76378556Sobrienexpand_start_all_catch ()
76478556Sobrien{
76578556Sobrien  struct ehEntry *entry;
76678556Sobrien  rtx label;
76778556Sobrien
76878556Sobrien  if (! doing_eh (1))
76978556Sobrien    return;
77078556Sobrien
77178556Sobrien  emit_line_note (input_filename, lineno);
77278556Sobrien  label = gen_label_rtx ();
77378556Sobrien
77478556Sobrien  /* The label for the exception handling block we will save.  This is
77578556Sobrien     Lresume, in the documention.  */
77690067Ssobomax  emit_label (label);
77790067Ssobomax
77890067Ssobomax  /* Put in something that takes up space, as otherwise the end
77990067Ssobomax     address for the EH region could have the exact same address as
78090067Ssobomax     the outer region, causing us to miss the fact that resuming
78190067Ssobomax     exception handling with this PC value would be inside the outer
78290067Ssobomax     region.  */
78390067Ssobomax  emit_insn (gen_nop ());
78490067Ssobomax
78590067Ssobomax  push_label_entry (&caught_return_label_stack, label);
78678556Sobrien
78778556Sobrien  /* Start a new sequence for all the catch blocks.  We will add this
78878556Sobrien     to the gloabl sequence catch_clauses, when we have completed all
78978556Sobrien     the handlers in this handler-seq.  */
79078556Sobrien  start_sequence ();
79178556Sobrien
79278556Sobrien  while (1)
79378556Sobrien    {
79478556Sobrien      entry = dequeue_eh_entry (&ehqueue);
79578556Sobrien      emit_label (entry->exception_handler_label);
79678556Sobrien
79778556Sobrien      expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
79878556Sobrien
79978556Sobrien      /* When we get down to the matching entry, stop.  */
80078556Sobrien      if (entry->finalization == integer_zero_node)
80178556Sobrien	break;
80278556Sobrien
80378556Sobrien      /* The below can be optimized away, and we could just fall into the
80478556Sobrien	 next EH handler, if we are certain they are nested.  */
80578556Sobrien      /* Code to throw out to outer context, if we fall off end of the
80678556Sobrien	 handler.  */
80778556Sobrien      expand_internal_throw (gen_rtx (LABEL_REF,
80878556Sobrien				      Pmode,
80978556Sobrien				      entry->end_label));
81078556Sobrien      free (entry);
81178556Sobrien    }
81278556Sobrien}
81378556Sobrien
81478556Sobrien/* call this to end processing of all the catch blocks. */
81578556Sobrienvoid
81678556Sobrienexpand_end_all_catch ()
81778556Sobrien{
81878556Sobrien  rtx new_catch_clause;
81978556Sobrien
82078556Sobrien  if (! doing_eh (1))
82178556Sobrien    return;
82278556Sobrien
82378556Sobrien  /* Code to throw out to outer context, if we fall off end of catch
82478556Sobrien     handlers.  This is rethrow (Lresume, same id, same obj); in the
82578556Sobrien     documentation.  */
82678556Sobrien  expand_internal_throw (gen_rtx (LABEL_REF,
82778556Sobrien				  Pmode,
82878556Sobrien				  top_label_entry (&caught_return_label_stack)));
82978556Sobrien
83078556Sobrien  /* Now we have the complete catch sequence.  */
83178556Sobrien  new_catch_clause = get_insns ();
832146293Sobrien  end_sequence ();
83378556Sobrien
83478556Sobrien  /* this level of catch blocks is done, so set up the successful catch jump
83578556Sobrien     label for the next layer of catch blocks. */
83678556Sobrien  pop_label_entry (&caught_return_label_stack);
83778556Sobrien
83878556Sobrien  /* Add the new sequence of catchs to the main one for this
83978556Sobrien     function.  */
84078556Sobrien  push_to_sequence (catch_clauses);
84178556Sobrien  emit_insns (new_catch_clause);
84278556Sobrien  catch_clauses = get_insns ();
84378556Sobrien  end_sequence ();
84478556Sobrien
84578556Sobrien  /* Here we fall through into the continuation code.  */
84678556Sobrien}
84778556Sobrien
84878556Sobrien/* Build a type value for use at runtime for a type that is matched
84978556Sobrien   against by the exception handling system.  */
85078556Sobrienstatic tree
85178556Sobrienbuild_eh_type_type (type)
85278556Sobrien     tree type;
85378556Sobrien{
85478556Sobrien  char *typestring;
855146293Sobrien  tree exp;
85678556Sobrien
85778556Sobrien  if (type == error_mark_node)
85878556Sobrien    return error_mark_node;
85978556Sobrien
86078556Sobrien  /* peel back references, so they match. */
86178556Sobrien  if (TREE_CODE (type) == REFERENCE_TYPE)
86278556Sobrien    type = TREE_TYPE (type);
86378556Sobrien
86478556Sobrien  /* Peel off cv qualifiers. */
86578556Sobrien  type = TYPE_MAIN_VARIANT (type);
86678556Sobrien
86778556Sobrien  if (flag_rtti)
86878556Sobrien    {
86978556Sobrien      return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
87078556Sobrien    }
87178556Sobrien
87278556Sobrien  typestring = build_overload_name (type, 1, 1);
87378556Sobrien  exp = combine_strings (build_string (strlen (typestring)+1, typestring));
87478556Sobrien  return build1 (ADDR_EXPR, ptr_type_node, exp);
87578556Sobrien}
87678556Sobrien
87778556Sobrien/* Build a type value for use at runtime for a exp that is thrown or
87878556Sobrien   matched against by the exception handling system.  */
87978556Sobrienstatic tree
88078556Sobrienbuild_eh_type (exp)
88178556Sobrien     tree exp;
88278556Sobrien{
88378556Sobrien  if (flag_rtti)
88478556Sobrien    {
88578556Sobrien      exp = build_typeid (exp);
88678556Sobrien      return build1 (ADDR_EXPR, ptr_type_node, exp);
88778556Sobrien    }
88878556Sobrien  return build_eh_type_type (TREE_TYPE (exp));
88978556Sobrien}
89078556Sobrien
89178556Sobrien/* call this to start a catch block. Typename is the typename, and identifier
89278556Sobrien   is the variable to place the object in or NULL if the variable doesn't
89378556Sobrien   matter.  If typename is NULL, that means its a "catch (...)" or catch
89478556Sobrien   everything.  In that case we don't need to do any type checking.
89578556Sobrien   (ie: it ends up as the "else" clause rather than an "else if" clause) */
89678556Sobrienvoid
89778556Sobrienexpand_start_catch_block (declspecs, declarator)
89878556Sobrien     tree declspecs, declarator;
89978556Sobrien{
90078556Sobrien  rtx false_label_rtx;
90190067Ssobomax  rtx protect_label_rtx;
90290067Ssobomax  tree decl = NULL_TREE;
90390067Ssobomax  tree init;
90490067Ssobomax
90590067Ssobomax  if (! doing_eh (1))
90678556Sobrien    return;
90778556Sobrien
90878556Sobrien  /* Create a binding level for the parm.  */
90978556Sobrien  expand_start_bindings (0);
91078556Sobrien
91178556Sobrien  false_label_rtx = gen_label_rtx ();
91278556Sobrien  /* This is saved for the exception table.  */
91378556Sobrien  push_rtl_perm ();
91478556Sobrien  protect_label_rtx = gen_label_rtx ();
91578556Sobrien  pop_rtl_from_perm ();
91678556Sobrien  push_label_entry (&false_label_stack, false_label_rtx);
91778556Sobrien  push_label_entry (&false_label_stack, protect_label_rtx);
91878556Sobrien
91978556Sobrien  if (declspecs)
92078556Sobrien    {
92178556Sobrien      tree exp;
92278556Sobrien      rtx call_rtx, return_value_rtx;
92378556Sobrien      tree init_type;
92478556Sobrien
92578556Sobrien      decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
92678556Sobrien			     NULL_TREE, NULL_TREE);
92778556Sobrien
92878556Sobrien      if (decl == NULL_TREE)
92978556Sobrien	{
93078556Sobrien	  error ("invalid catch parameter");
93178556Sobrien	  return;
93278556Sobrien	}
93378556Sobrien
93478556Sobrien      /* Figure out the type that the initializer is. */
93578556Sobrien      init_type = TREE_TYPE (decl);
93678556Sobrien      if (TREE_CODE (init_type) != REFERENCE_TYPE
93778556Sobrien	  && TREE_CODE (init_type) != POINTER_TYPE)
93878556Sobrien	init_type = build_reference_type (init_type);
93978556Sobrien
94078556Sobrien      exp = saved_throw_value;
94178556Sobrien      exp = tree_cons (NULL_TREE,
94278556Sobrien		       build_eh_type_type (TREE_TYPE (decl)),
94378556Sobrien		       tree_cons (NULL_TREE,
94478556Sobrien				  saved_throw_type,
94578556Sobrien				  tree_cons (NULL_TREE, exp, NULL_TREE)));
94678556Sobrien      exp = build_function_call (CatchMatch, exp);
94778556Sobrien      call_rtx = expand_call (exp, NULL_RTX, 0);
94878556Sobrien      assemble_external (TREE_OPERAND (CatchMatch, 0));
94978556Sobrien
95090067Ssobomax      return_value_rtx = hard_function_value (ptr_type_node, exp);
95190067Ssobomax
95290067Ssobomax      /* did the throw type match function return TRUE? */
95390067Ssobomax      emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
95490067Ssobomax		    GET_MODE (return_value_rtx), 0, 0);
95590067Ssobomax
95690067Ssobomax      /* if it returned FALSE, jump over the catch block, else fall into it */
95790067Ssobomax      emit_jump_insn (gen_beq (false_label_rtx));
95890067Ssobomax
959167977Sdelphij      init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
96090067Ssobomax
96190067Ssobomax      /* Do we need the below two lines? */
96290067Ssobomax      /* Let `cp_finish_decl' know that this initializer is ok.  */
96390067Ssobomax      DECL_INITIAL (decl) = init;
96490067Ssobomax      decl = pushdecl (decl);
96590067Ssobomax      cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
96690067Ssobomax    }
96790067Ssobomax  else
96890067Ssobomax    {
96990067Ssobomax      /* Fall into the catch all section. */
97090067Ssobomax    }
97190067Ssobomax
97290067Ssobomax  /* This is the starting of something to protect.  */
97390067Ssobomax  emit_label (protect_label_rtx);
97490067Ssobomax
97590067Ssobomax  emit_line_note (input_filename, lineno);
97690067Ssobomax}
97778556Sobrien
97878556Sobrien
97978556Sobrien/* this is called from expand_exception_blocks and
98078556Sobrien   expand_end_catch_block to expand the toplevel finalizations for a
98178556Sobrien   function.  We return the first label emitted, if any, otherwise
98278556Sobrien   return NULL_RTX.  */
98378556Sobrienstatic rtx
98478556Sobrienexpand_leftover_cleanups ()
98578556Sobrien{
98678556Sobrien  struct ehEntry *entry;
98778556Sobrien  rtx first_label = NULL_RTX;
98890067Ssobomax
98978556Sobrien  while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
99078556Sobrien    {
99178556Sobrien      if (! first_label)
99278556Sobrien	first_label = entry->exception_handler_label;
99378556Sobrien      emit_label (entry->exception_handler_label);
99478556Sobrien
99578556Sobrien      expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
99678556Sobrien
99778556Sobrien      /* The below can be optimized away, and we could just fall into the
99878556Sobrien	 next EH handler, if we are certain they are nested.  */
99978556Sobrien      /* Code to throw out to outer context, if we fall off end of the
100078556Sobrien	 handler.  */
100178556Sobrien      expand_internal_throw (gen_rtx (LABEL_REF,
100278556Sobrien				      Pmode,
100378556Sobrien				      entry->end_label));
100478556Sobrien
100578556Sobrien      /* leftover try block, opps.  */
100678556Sobrien      if (entry->finalization == integer_zero_node)
100778556Sobrien	abort ();
100878556Sobrien
100978556Sobrien      free (entry);
101090067Ssobomax    }
101190067Ssobomax
101290067Ssobomax  return first_label;
101390067Ssobomax}
101490067Ssobomax
101590067Ssobomax/* Call this to end a catch block.  Its responsible for emitting the
101690067Ssobomax   code to handle jumping back to the correct place, and for emitting
101790067Ssobomax   the label to jump to if this catch block didn't match.  */
101890067Ssobomaxvoid expand_end_catch_block ()
101990067Ssobomax{
102090067Ssobomax  rtx start_protect_label_rtx;
102190067Ssobomax  rtx end_protect_label_rtx;
102290067Ssobomax  tree decls;
102390067Ssobomax  struct ehEntry entry;
102490067Ssobomax
102590067Ssobomax  if (! doing_eh (1))
102690067Ssobomax    return;
102790067Ssobomax
102890067Ssobomax  /* fall to outside the try statement when done executing handler and
102990067Ssobomax     we fall off end of handler.  This is jump Lresume in the
103090067Ssobomax     documentation.  */
103190067Ssobomax  emit_jump (top_label_entry (&caught_return_label_stack));
103290067Ssobomax
103378556Sobrien  /* We end the rethrow protection region as soon as we hit a label. */
103490067Ssobomax  end_protect_label_rtx = expand_leftover_cleanups ();
103590067Ssobomax
103690067Ssobomax  /* Code to throw out to outer context, if we get a throw from within
103790067Ssobomax     our catch handler. */
103890067Ssobomax  /* These are saved for the exception table.  */
103978556Sobrien  push_rtl_perm ();
104090067Ssobomax  entry.exception_handler_label = gen_label_rtx ();
104190067Ssobomax  pop_rtl_from_perm ();
104290067Ssobomax  /* This label is Lhandler in the documentation.  */
104390067Ssobomax  emit_label (entry.exception_handler_label);
104490067Ssobomax  expand_internal_throw (gen_rtx (LABEL_REF,
104590067Ssobomax				  Pmode,
104690067Ssobomax				  top_label_entry (&caught_return_label_stack)));
104790067Ssobomax
104890067Ssobomax  /* No associated finalization.  */
104990067Ssobomax  entry.finalization = NULL_TREE;
1050147666Ssimon  entry.context = current_function_decl;
105190067Ssobomax
105290067Ssobomax  if (end_protect_label_rtx == NULL_RTX)
105378556Sobrien    end_protect_label_rtx = entry.exception_handler_label;
105478556Sobrien
105578556Sobrien  /* Because we are emitted out of line, we have to protect this. */
105690067Ssobomax  /* label for the start of the protection region.  */
105790067Ssobomax  start_protect_label_rtx = pop_label_entry (&false_label_stack);
105878556Sobrien
105978556Sobrien  /* Cleanup the EH parameter.  */
106078556Sobrien  decls = getdecls ();
1061147666Ssimon  expand_end_bindings (decls, decls != NULL_TREE, 0);
1062147666Ssimon
106378556Sobrien  /* label we emit to jump to if this catch block didn't match. */
1064147666Ssimon  /* This the closing } in the `if (eq) {' of the documentation.  */
1065167977Sdelphij  emit_label (pop_label_entry (&false_label_stack));
1066147666Ssimon
1067147666Ssimon  /* Because we are reordered out of line, we have to protect this. */
1068167977Sdelphij  entry.start_label = start_protect_label_rtx;
1069147666Ssimon  entry.end_label = end_protect_label_rtx;
1070147666Ssimon
1071167977Sdelphij  LABEL_PRESERVE_P (entry.start_label) = 1;
1072147666Ssimon  LABEL_PRESERVE_P (entry.end_label) = 1;
1073147666Ssimon  LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
107478556Sobrien
107578556Sobrien  /* These set up a call to throw the caught exception into the outer
107678556Sobrien     context.  */
107790067Ssobomax  enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
107878556Sobrien}
107978556Sobrien
108078556Sobrien/* unwind the stack. */
108178556Sobrienstatic void
108278556Sobriendo_unwind (inner_throw_label)
108378556Sobrien     rtx inner_throw_label;
108478556Sobrien{
108590067Ssobomax#if defined(SPARC_STACK_ALIGN) /* was sparc */
108690067Ssobomax  tree fcall;
108790067Ssobomax  tree params;
108890067Ssobomax  rtx return_val_rtx;
108990067Ssobomax  rtx temp;
109090067Ssobomax
109190067Ssobomax  /* call to  __builtin_return_address () */
109290067Ssobomax  params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
109390067Ssobomax  fcall = build_function_call (BuiltinReturnAddress, params);
109478556Sobrien  return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
109590067Ssobomax  /* In the return, the new pc is pc+8, as the value coming in is
109690067Ssobomax     really the address of the call insn, not the next insn.  */
109790067Ssobomax  temp = gen_reg_rtx (Pmode);
109878556Sobrien  emit_move_insn (temp, inner_throw_label);
109978556Sobrien  emit_move_insn (return_val_rtx, plus_constant (temp, -8));
110078556Sobrien  easy_expand_asm ("ret");
110178556Sobrien  easy_expand_asm ("restore");
110278556Sobrien  emit_barrier ();
110378556Sobrien#endif
1104167977Sdelphij#if defined(ARM_FRAME_RTX)  /* was __arm */
110578556Sobrien  if (flag_omit_frame_pointer)
1106167977Sdelphij    sorry ("this implementation of exception handling requires a frame pointer");
110778556Sobrien
110878556Sobrien  emit_move_insn (stack_pointer_rtx,
110978556Sobrien		  gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
1110167977Sdelphij  emit_move_insn (hard_frame_pointer_rtx,
111178556Sobrien		  gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
111278556Sobrien#endif
111378556Sobrien#if defined(TARGET_88000) /* was m88k */
111478556Sobrien  rtx temp_frame = frame_pointer_rtx;
111578556Sobrien
111678556Sobrien  temp_frame = memory_address (Pmode, temp_frame);
111778556Sobrien  temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
111878556Sobrien
111978556Sobrien  /* hopefully this will successfully pop the frame! */
112078556Sobrien  emit_move_insn (frame_pointer_rtx, temp_frame);
1121167977Sdelphij  emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
1122167977Sdelphij  emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
112378556Sobrien  emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
112478556Sobrien						     (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
112578556Sobrien
112678556Sobrien#if 0
112778556Sobrien  emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
112878556Sobrien						   -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
112978556Sobrien
113078556Sobrien  emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
113178556Sobrien
113278556Sobrien  emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
113378556Sobrien						     (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
113478556Sobrien#endif
113578556Sobrien#endif
113678556Sobrien#if !defined(TARGET_88000) && !defined(ARM_FRAME_RTX) && !defined(SPARC_STACK_ALIGN)
113778556Sobrien  tree fcall;
113890067Ssobomax  tree params;
113978556Sobrien  rtx return_val_rtx;
114078556Sobrien
114178556Sobrien  /* call to  __builtin_return_address () */
114278556Sobrien  params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
114378556Sobrien  fcall = build_function_call (BuiltinReturnAddress, params);
114478556Sobrien  return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
114578556Sobrien#if 0
114678556Sobrien  /* I would like to do this here, but doesn't seem to work. */
1147167977Sdelphij  emit_move_insn (return_val_rtx, inner_throw_label);
1148167977Sdelphij  /* So, for now, just pass throw label to stack unwinder. */
114978556Sobrien#endif
115078556Sobrien  params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
115178556Sobrien					    inner_throw_label), NULL_TREE);
115278556Sobrien
115378556Sobrien  do_function_call (Unwind, params, NULL_TREE);
115478556Sobrien  assemble_external (TREE_OPERAND (Unwind, 0));
115578556Sobrien  emit_barrier ();
115678556Sobrien#endif
1157167977Sdelphij}
115878556Sobrien
115978556Sobrien
116078556Sobrien/* is called from expand_exception_blocks () to generate the code in a function
116178556Sobrien   to "throw" if anything in the function needs to perform a throw.
116278556Sobrien
116378556Sobrien   expands "throw" as the following pseudo code:
116478556Sobrien
116578556Sobrien	throw:
116678556Sobrien		eh = find_first_exception_match (saved_pc);
116778556Sobrien	    if (!eh) goto gotta_rethrow_it;
116878556Sobrien		goto eh;
116978556Sobrien
117078556Sobrien	gotta_rethrow_it:
117178556Sobrien		saved_pc = __builtin_return_address (0);
117278556Sobrien		pop_to_previous_level ();
117378556Sobrien		goto throw;
117478556Sobrien
117578556Sobrien */
117678556Sobrienvoid
117778556Sobrienexpand_builtin_throw ()
117878556Sobrien{
117978556Sobrien  tree fcall;
118078556Sobrien  tree params;
118178556Sobrien  rtx return_val_rtx;
118278556Sobrien  rtx gotta_rethrow_it;
118378556Sobrien  rtx gotta_call_terminate;
118490067Ssobomax  rtx unwind_and_throw;
118590067Ssobomax  rtx goto_unwind_and_throw;
118690067Ssobomax  rtx top_of_loop;
118790067Ssobomax  rtx unwind_first;
118890067Ssobomax  tree t;
118990067Ssobomax
119090067Ssobomax  if (! doing_eh (0))
119190067Ssobomax    return;
119290067Ssobomax
119390067Ssobomax  if (! throw_used)
119478556Sobrien    return;
119578556Sobrien
119678556Sobrien  params = void_list_node;
119778556Sobrien  t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
119878556Sobrien  start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
119978556Sobrien				  void_list_node),
120078556Sobrien		  t, NULL_TREE, NULL_TREE, 0);
120190067Ssobomax  store_parm_decls ();
120290067Ssobomax  pushlevel (0);
120390067Ssobomax  clear_last_expr ();
120490067Ssobomax  push_momentary ();
120590067Ssobomax  expand_start_bindings (0);
120690067Ssobomax
120790067Ssobomax  gotta_rethrow_it = gen_label_rtx ();
120890067Ssobomax  gotta_call_terminate = gen_label_rtx ();
120990067Ssobomax  unwind_and_throw = gen_label_rtx ();
121078556Sobrien  goto_unwind_and_throw = gen_label_rtx ();
121178556Sobrien  top_of_loop = gen_label_rtx ();
121278556Sobrien  unwind_first = gen_label_rtx ();
121378556Sobrien
121478556Sobrien  emit_jump (unwind_first);
121578556Sobrien
121678556Sobrien  emit_label (top_of_loop);
121778556Sobrien
121878556Sobrien  /* search for an exception handler for the saved_pc */
121990067Ssobomax  return_val_rtx = do_function_call (FirstExceptionMatch,
122090067Ssobomax				     tree_cons (NULL_TREE, saved_pc, NULL_TREE),
122190067Ssobomax				     ptr_type_node);
122290067Ssobomax  assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
122390067Ssobomax
122490067Ssobomax  /* did we find one? */
122578556Sobrien  emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
122678556Sobrien		 GET_MODE (return_val_rtx), 0, 0);
122778556Sobrien
122878556Sobrien  /* if not, jump to gotta_rethrow_it */
122978556Sobrien  emit_jump_insn (gen_beq (gotta_rethrow_it));
123078556Sobrien
123178556Sobrien  /* we found it, so jump to it */
123278556Sobrien  emit_indirect_jump (return_val_rtx);
123378556Sobrien
123478556Sobrien  /* code to deal with unwinding and looking for it again */
123578556Sobrien  emit_label (gotta_rethrow_it);
123678556Sobrien
123778556Sobrien  /* call to  __builtin_return_address () */
123878556Sobrien#if defined(ARM_FRAME_RTX)  /* was __arm */
123978556Sobrien/* This replaces a 'call' to __builtin_return_address */
124078556Sobrien  return_val_rtx = gen_reg_rtx (Pmode);
124178556Sobrien  emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
124278556Sobrien#else
124378556Sobrien  params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
124478556Sobrien  fcall = build_function_call (BuiltinReturnAddress, params);
124578556Sobrien  return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
124678556Sobrien#endif
124778556Sobrien
124878556Sobrien  /* did __builtin_return_address () return a valid address? */
124978556Sobrien  emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
125078556Sobrien		 GET_MODE (return_val_rtx), 0, 0);
125178556Sobrien
125278556Sobrien  emit_jump_insn (gen_beq (gotta_call_terminate));
125378556Sobrien
125478556Sobrien#if defined(ARM_FRAME_RTX)  /* was __arm */
125578556Sobrien  /* On the ARM, '__builtin_return_address',  must have 4
125678556Sobrien     subtracted from it. */
125778556Sobrien  emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-4)));
125878556Sobrien
125978556Sobrien  /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit
126078556Sobrien     mode, the condition codes must be masked out of the return value, or else
126178556Sobrien     they will confuse BuiltinReturnAddress.  This does not apply to ARM6 and
126278556Sobrien     later processors when running in 32 bit mode. */
126378556Sobrien  if (!TARGET_6)
126490067Ssobomax    emit_insn (gen_rtx (SET, Pmode, return_val_rtx, gen_rtx (AND, Pmode, return_val_rtx, GEN_INT (0x03fffffc))));
126578556Sobrien#else
126678556Sobrien#if !defined(SPARC_STACK_ALIGN) /* was sparc */
126778556Sobrien  /* On the SPARC, __builtin_return_address is already -8, no need to
126878556Sobrien     subtract any more from it. */
126978556Sobrien  return_val_rtx = plus_constant (return_val_rtx, -1);
127078556Sobrien#endif
127178556Sobrien#endif
127278556Sobrien
127378556Sobrien  /* yes it did */
127478556Sobrien  t = build_modify_expr (saved_pc, NOP_EXPR, make_tree (ptr_type_node, return_val_rtx));
127578556Sobrien  expand_expr (t, const0_rtx, VOIDmode, 0);
127678556Sobrien
127778556Sobrien  do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
127878556Sobrien  emit_jump (top_of_loop);
127978556Sobrien
128078556Sobrien  /* no it didn't --> therefore we need to call terminate */
128178556Sobrien  emit_label (gotta_call_terminate);
128278556Sobrien  do_function_call (Terminate, NULL_TREE, NULL_TREE);
128378556Sobrien  assemble_external (TREE_OPERAND (Terminate, 0));
128478556Sobrien
128578556Sobrien  {
128678556Sobrien    rtx ret_val, return_val_rtx;
128778556Sobrien    emit_label (unwind_first);
128878556Sobrien    ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
128978556Sobrien					  0, hard_frame_pointer_rtx);
129078556Sobrien
129178556Sobrien    /* Set it up so that we continue inside, at the top of the loop.  */
129278556Sobrien    emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
129378556Sobrien#ifdef NORMAL_RETURN_ADDR_OFFSET
129478556Sobrien  return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET);
129578556Sobrien    if (return_val_rtx != ret_val)
129678556Sobrien      emit_move_insn (ret_val, return_val_rtx);
129778556Sobrien#endif
129878556Sobrien
129978556Sobrien    /* Fall into epilogue to unwind prologue. */
1300147666Ssimon  }
130178556Sobrien
130278556Sobrien  expand_end_bindings (getdecls(), 1, 0);
130378556Sobrien  poplevel (1, 0, 0);
130478556Sobrien  pop_momentary ();
130578556Sobrien
130678556Sobrien  finish_function (lineno, 0, 0);
130778556Sobrien}
130878556Sobrien
130978556Sobrien
131078556Sobrienvoid
131178556Sobrienexpand_start_eh_spec ()
131278556Sobrien{
131378556Sobrien  start_protect ();
131478556Sobrien}
131578556Sobrien
131678556Sobrienvoid
131778556Sobrienexpand_end_eh_spec (raises)
131878556Sobrien     tree raises;
131978556Sobrien{
132078556Sobrien  tree expr, second_try;
132190067Ssobomax  rtx check = gen_label_rtx ();
132278556Sobrien  rtx cont;
132378556Sobrien  rtx ret = gen_reg_rtx (Pmode);
132478556Sobrien  rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
132578556Sobrien  rtx end = gen_label_rtx ();
132678556Sobrien
132778556Sobrien  expr = make_node (RTL_EXPR);
132878556Sobrien  TREE_TYPE (expr) = void_type_node;
132978556Sobrien  RTL_EXPR_RTL (expr) = const0_rtx;
133078556Sobrien  TREE_SIDE_EFFECTS (expr) = 1;
1331167977Sdelphij  start_sequence_for_rtl_expr (expr);
1332167977Sdelphij  cont = gen_label_rtx ();
133378556Sobrien  emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
133478556Sobrien  emit_jump (check);
133578556Sobrien  emit_label (cont);
133678556Sobrien  jumpif (make_tree (integer_type_node, flag), end);
133778556Sobrien  do_function_call (Terminate, NULL_TREE, NULL_TREE);
133878556Sobrien  assemble_external (TREE_OPERAND (Terminate, 0));
133978556Sobrien  emit_barrier ();
134078556Sobrien  RTL_EXPR_SEQUENCE (expr) = get_insns ();
134178556Sobrien  end_sequence ();
134278556Sobrien
134378556Sobrien  second_try = expr;
134478556Sobrien
1345167977Sdelphij  expr = make_node (RTL_EXPR);
134678556Sobrien  TREE_TYPE (expr) = void_type_node;
134778556Sobrien  RTL_EXPR_RTL (expr) = const0_rtx;
134878556Sobrien  TREE_SIDE_EFFECTS (expr) = 1;
134978556Sobrien  start_sequence_for_rtl_expr (expr);
135078556Sobrien
135178556Sobrien  cont = gen_label_rtx ();
135278556Sobrien  emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
135378556Sobrien  emit_jump (check);
135478556Sobrien  emit_label (cont);
135578556Sobrien  jumpif (make_tree (integer_type_node, flag), end);
135678556Sobrien  start_protect ();
135778556Sobrien  do_function_call (Unexpected, NULL_TREE, NULL_TREE);
135878556Sobrien  assemble_external (TREE_OPERAND (Unexpected, 0));
135978556Sobrien  emit_barrier ();
136078556Sobrien  end_protect (second_try);
136178556Sobrien
136278556Sobrien  emit_label (check);
136390067Ssobomax  emit_move_insn (flag, const1_rtx);
136490067Ssobomax  cont = gen_label_rtx ();
136590067Ssobomax  while (raises)
136690067Ssobomax    {
136790067Ssobomax      tree exp;
136890067Ssobomax      tree match_type = TREE_VALUE (raises);
136990067Ssobomax
137090067Ssobomax      if (match_type)
137190067Ssobomax	{
137290067Ssobomax	  /* check TREE_VALUE (raises) here */
137378556Sobrien	  exp = saved_throw_value;
137478556Sobrien	  exp = tree_cons (NULL_TREE,
137578556Sobrien			   build_eh_type_type (match_type),
137678556Sobrien			   tree_cons (NULL_TREE,
137778556Sobrien				      saved_throw_type,
137878556Sobrien				      tree_cons (NULL_TREE, exp, NULL_TREE)));
137978556Sobrien	  exp = build_function_call (CatchMatch, exp);
138078556Sobrien	  assemble_external (TREE_OPERAND (CatchMatch, 0));
138178556Sobrien
138278556Sobrien	  jumpif (exp, cont);
138378556Sobrien	}
138478556Sobrien
138578556Sobrien      raises = TREE_CHAIN (raises);
138678556Sobrien    }
138790067Ssobomax  emit_move_insn (flag, const0_rtx);
138890067Ssobomax  emit_label (cont);
138990067Ssobomax  emit_indirect_jump (ret);
139090067Ssobomax  emit_label (end);
139190067Ssobomax
139290067Ssobomax  RTL_EXPR_SEQUENCE (expr) = get_insns ();
139390067Ssobomax  end_sequence ();
139490067Ssobomax
139590067Ssobomax  end_protect (expr);
139678556Sobrien}
139778556Sobrien
139878556Sobrien/* This is called to expand all the toplevel exception handling
139978556Sobrien   finalization for a function.  It should only be called once per
140078556Sobrien   function.  */
140178556Sobrienvoid
140278556Sobrienexpand_exception_blocks ()
140378556Sobrien{
140478556Sobrien  static rtx funcend;
140590067Ssobomax  rtx insns;
140690067Ssobomax
140790067Ssobomax  start_sequence ();
140890067Ssobomax
140990067Ssobomax  funcend = gen_label_rtx ();
141090067Ssobomax  emit_jump (funcend);
141178556Sobrien  /* expand_null_return (); */
141278556Sobrien
141378556Sobrien  start_sequence ();
141478556Sobrien
141578556Sobrien  /* Add all the catch clauses here.  */
141678556Sobrien  emit_insns (catch_clauses);
141778556Sobrien  catch_clauses = NULL_RTX;
141878556Sobrien
141978556Sobrien  expand_leftover_cleanups ();
142078556Sobrien
142178556Sobrien  insns = get_insns ();
142278556Sobrien  end_sequence ();
142378556Sobrien
142478556Sobrien  /* Do this after we expand leftover cleanups, so that the end_protect
142578556Sobrien     that expand_end_eh_spec does will match the right start_protect,
142678556Sobrien     and make sure it comes out before the terminate protected region.  */
142778556Sobrien  if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
142878556Sobrien    {
142978556Sobrien      expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
143078556Sobrien      push_to_sequence (insns);
143178556Sobrien
143278556Sobrien      /* Now expand any new ones.  */
143378556Sobrien      expand_leftover_cleanups ();
143478556Sobrien
143578556Sobrien      insns = get_insns ();
143678556Sobrien      end_sequence ();
143778556Sobrien    }
143878556Sobrien
143978556Sobrien  if (insns)
144078556Sobrien    {
144190067Ssobomax      struct ehEntry entry;
144278556Sobrien
144378556Sobrien      /* These are saved for the exception table.  */
144478556Sobrien      push_rtl_perm ();
144578556Sobrien      entry.start_label = gen_label_rtx ();
144678556Sobrien      entry.end_label = gen_label_rtx ();
144778556Sobrien      entry.exception_handler_label = gen_label_rtx ();
144878556Sobrien      entry.finalization = TerminateFunctionCall;
144978556Sobrien      entry.context = current_function_decl;
145078556Sobrien      assemble_external (TREE_OPERAND (Terminate, 0));
145178556Sobrien      pop_rtl_from_perm ();
145278556Sobrien
145378556Sobrien      LABEL_PRESERVE_P (entry.start_label) = 1;
145478556Sobrien      LABEL_PRESERVE_P (entry.end_label) = 1;
145578556Sobrien      LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
145678556Sobrien
145778556Sobrien      emit_label (entry.start_label);
145878556Sobrien      emit_insns (insns);
145978556Sobrien
146078556Sobrien      enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
146178556Sobrien
146278556Sobrien      emit_label (entry.exception_handler_label);
146378556Sobrien      expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
146478556Sobrien      emit_label (entry.end_label);
146578556Sobrien      emit_barrier ();
146678556Sobrien    }
146778556Sobrien
146878556Sobrien  {
146978556Sobrien    /* Mark the end of the stack unwinder.  */
147078556Sobrien    rtx unwind_insns;
147178556Sobrien    start_sequence ();
147278556Sobrien    end_eh_unwinder (funcend);
147378556Sobrien    expand_leftover_cleanups ();
147478556Sobrien    unwind_insns = get_insns ();
147578556Sobrien    end_sequence ();
147678556Sobrien    if (unwind_insns)
147778556Sobrien      {
1478147666Ssimon	insns = unwind_insns;
147978556Sobrien	emit_insns (insns);
148078556Sobrien      }
148178556Sobrien  }
148278556Sobrien
148378556Sobrien  emit_label (funcend);
148478556Sobrien
148578556Sobrien  /* Only if we had previous insns do we want to emit the jump around
148678556Sobrien     them.  If there weren't any, then insns will remain NULL_RTX.  */
148778556Sobrien  if (insns)
148878556Sobrien    insns = get_insns ();
148978556Sobrien  end_sequence ();
149078556Sobrien
149178556Sobrien  emit_insns (insns);
149278556Sobrien}
149378556Sobrien
149478556Sobrien
149578556Sobrien/* call this to expand a throw statement.  This follows the following
149678556Sobrien   algorithm:
149778556Sobrien
149878556Sobrien	1. Allocate space to save the current PC onto the stack.
149978556Sobrien	2. Generate and emit a label and save its address into the
150078556Sobrien		newly allocated stack space since we can't save the pc directly.
150178556Sobrien	3. If this is the first call to throw in this function:
150278556Sobrien		generate a label for the throw block
150378556Sobrien	4. jump to the throw block label.  */
150478556Sobrienvoid
150578556Sobrienexpand_throw (exp)
150678556Sobrien     tree exp;
150778556Sobrien{
150878556Sobrien  rtx label;
150978556Sobrien
151078556Sobrien  if (! doing_eh (1))
151178556Sobrien    return;
151278556Sobrien
151378556Sobrien  /* This is the label that represents where in the code we were, when
151478556Sobrien     we got an exception.  This needs to be updated when we rethrow an
151578556Sobrien     exception, so that the matching routine knows to search out.  */
151690067Ssobomax  label = gen_label_rtx ();
151778556Sobrien  emit_label (label);
151878556Sobrien
151978556Sobrien  if (exp)
152078556Sobrien    {
152178556Sobrien      tree throw_type;
152278556Sobrien      tree e;
1523167977Sdelphij
152478556Sobrien      /* throw expression */
1525167977Sdelphij      /* First, decay it. */
152678556Sobrien      exp = decay_conversion (exp);
152778556Sobrien
152878556Sobrien      if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
152978556Sobrien	{
153078556Sobrien	  throw_type = build_eh_type (exp);
153178556Sobrien	  exp = build_reinterpret_cast (ptr_type_node, exp);
153278556Sobrien	}
153378556Sobrien      else
153478556Sobrien	{
153578556Sobrien	  /* Make a copy of the thrown object.  WP 15.1.5  */
153678556Sobrien	  exp = build_new (NULL_TREE, TREE_TYPE (exp),
153778556Sobrien			   build_tree_list (NULL_TREE, exp),
153878556Sobrien			   0);
153978556Sobrien
154078556Sobrien	  if (exp == error_mark_node)
154178556Sobrien	    error ("  in thrown expression");
154278556Sobrien
154390067Ssobomax	  throw_type = build_eh_type (build_indirect_ref (exp, NULL_PTR));
154490067Ssobomax	}
154590067Ssobomax
154690067Ssobomax      e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
154790067Ssobomax      expand_expr (e, const0_rtx, VOIDmode, 0);
154890067Ssobomax      e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
154990067Ssobomax      e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
155090067Ssobomax      expand_expr (e, const0_rtx, VOIDmode, 0);
155190067Ssobomax    }
155290067Ssobomax  else
155378556Sobrien    {
155478556Sobrien      /* rethrow current exception */
155578556Sobrien      /* This part is easy, as we don't have to do anything else.  */
155678556Sobrien    }
155778556Sobrien
155878556Sobrien  expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
155978556Sobrien}
156078556Sobrien
156178556Sobrienvoid
156278556Sobrienend_protect_partials () {
156378556Sobrien  while (protect_list)
156478556Sobrien    {
156578556Sobrien      end_protect (TREE_VALUE (protect_list));
156678556Sobrien      protect_list = TREE_CHAIN (protect_list);
156778556Sobrien    }
156878556Sobrien}
156978556Sobrien
157078556Sobrienint
157178556Sobrienmight_have_exceptions_p ()
157278556Sobrien{
157378556Sobrien  if (eh_table_output_queue.head)
157478556Sobrien    return 1;
157578556Sobrien  return 0;
157678556Sobrien}
157778556Sobrien
157878556Sobrien/* Output the exception table.
157978556Sobrien Return the number of handlers.  */
158078556Sobrienvoid
158178556Sobrienemit_exception_table ()
158278556Sobrien{
158378556Sobrien  int count = 0;
158478556Sobrien  extern FILE *asm_out_file;
158578556Sobrien  struct ehEntry *entry;
158678556Sobrien  tree eh_node_decl;
158778556Sobrien
158878556Sobrien  if (! doing_eh (0))
158978556Sobrien    return;
159078556Sobrien
159190067Ssobomax  exception_section ();
159278556Sobrien
159378556Sobrien  /* Beginning marker for table. */
159478556Sobrien  assemble_align (GET_MODE_ALIGNMENT (Pmode));
159578556Sobrien  assemble_label ("__EXCEPTION_TABLE__");
159678556Sobrien  output_exception_table_entry (asm_out_file,
159778556Sobrien				const0_rtx, const0_rtx, const0_rtx);
159878556Sobrien
159978556Sobrien while (entry = dequeue_eh_entry (&eh_table_output_queue))
160078556Sobrien   {
160178556Sobrien     tree context = entry->context;
160278556Sobrien
160378556Sobrien     if (context && ! TREE_ASM_WRITTEN (context))
160478556Sobrien       continue;
160578556Sobrien
160678556Sobrien     count++;
160778556Sobrien     output_exception_table_entry (asm_out_file,
1608167977Sdelphij				   entry->start_label, entry->end_label,
160978556Sobrien				   entry->exception_handler_label);
161078556Sobrien  }
161178556Sobrien
1612167977Sdelphij  /* Ending marker for table. */
161378556Sobrien  assemble_label ("__EXCEPTION_END__");
161478556Sobrien  output_exception_table_entry (asm_out_file,
161578556Sobrien				constm1_rtx, constm1_rtx, constm1_rtx);
161678556Sobrien}
161778556Sobrien
161878556Sobrienvoid
161978556Sobrienregister_exception_table ()
162078556Sobrien{
162178556Sobrien  rtx addr = gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__");
162278556Sobrien
162378556Sobrien#ifdef MARK_LOCAL_ADDRESS
162478556Sobrien  MARK_LOCAL_ADDRESS(addr);
162578556Sobrien#endif
162678556Sobrien
162778556Sobrien  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
162878556Sobrien		     VOIDmode, 1,
162978556Sobrien		     addr,
163078556Sobrien		     Pmode);
163178556Sobrien}
163278556Sobrien
163378556Sobrien/* Build a throw expression.  */
163478556Sobrientree
163578556Sobrienbuild_throw (e)
163678556Sobrien     tree e;
163778556Sobrien{
163878556Sobrien  if (e != error_mark_node)
163978556Sobrien    {
164078556Sobrien      e = build1 (THROW_EXPR, void_type_node, e);
164178556Sobrien      TREE_SIDE_EFFECTS (e) = 1;
164278556Sobrien      TREE_USED (e) = 1;
164378556Sobrien    }
164478556Sobrien  return e;
164578556Sobrien}
164678556Sobrien
164790067Ssobomaxstart_eh_unwinder ()
164890067Ssobomax{
164978556Sobrien  start_protect ();
165078556Sobrien}
165178556Sobrien
165278556Sobrienend_eh_unwinder (end)
165378556Sobrien     rtx end;
165478556Sobrien{
165578556Sobrien  tree expr;
165678556Sobrien  rtx return_val_rtx, ret_val, label;
165790067Ssobomax
165878556Sobrien  if (! doing_eh (0))
165990067Ssobomax    return;
166078556Sobrien
166178556Sobrien  expr = make_node (RTL_EXPR);
166278556Sobrien  TREE_TYPE (expr) = void_type_node;
166378556Sobrien  RTL_EXPR_RTL (expr) = const0_rtx;
166478556Sobrien  TREE_SIDE_EFFECTS (expr) = 1;
166578556Sobrien  start_sequence_for_rtl_expr (expr);
166678556Sobrien
166778556Sobrien  ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
166878556Sobrien					0, hard_frame_pointer_rtx);
166978556Sobrien  return_val_rtx = copy_to_reg (ret_val);
167078556Sobrien#ifdef NORMAL_RETURN_ADDR_OFFSET
167178556Sobrien  return_val_rtx = plus_constant (return_val_rtx, NORMAL_RETURN_ADDR_OFFSET-1);
167278556Sobrien#else
167378556Sobrien  return_val_rtx = plus_constant (return_val_rtx, -1);
167478556Sobrien#endif
167578556Sobrien  emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
167678556Sobrien
167778556Sobrien#ifdef JUMP_TO_THROW
167878556Sobrien  emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
167978556Sobrien#else
168078556Sobrien  label = gen_label_rtx ();
168178556Sobrien  emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
168278556Sobrien#endif
168378556Sobrien
168478556Sobrien#ifdef NORMAL_RETURN_ADDR_OFFSET
168578556Sobrien  return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET);
168678556Sobrien  if (return_val_rtx != ret_val)
168778556Sobrien    emit_move_insn (ret_val, return_val_rtx);
168878556Sobrien#endif
168978556Sobrien
169078556Sobrien  emit_jump (end);
169178556Sobrien
169278556Sobrien#ifndef JUMP_TO_THROW
169378556Sobrien  emit_label (label);
169478556Sobrien  do_function_call (Throw, NULL_TREE, NULL_TREE);
169578556Sobrien#endif
169678556Sobrien
169778556Sobrien  RTL_EXPR_SEQUENCE (expr) = get_insns ();
169878556Sobrien  end_sequence ();
169978556Sobrien  end_protect (expr);
170078556Sobrien}
170178556Sobrien