home *** CD-ROM | disk | FTP | other *** search
- /* Handle exceptional things in C++.
- Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
- Contributed by Michael Tiemann <tiemann@cygnus.com>
- Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
- initial re-implementation courtesy Tad Hunt.
-
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- /* High-level class interface. */
-
- #include "config.h"
- #include "tree.h"
- #include "rtl.h"
- #include "cp-tree.h"
- #include "flags.h"
- #include "obstack.h"
- #include "expr.h"
-
- extern void (*interim_eh_hook) PROTO((tree));
-
- /* holds the fndecl for __builtin_return_address () */
- tree builtin_return_address_fndecl;
-
- /* Define at your own risk! */
- #ifndef CROSS_COMPILE
- #ifdef sun
- #ifdef sparc
- #define TRY_NEW_EH
- #endif
- #endif
- #endif
-
- #ifndef TRY_NEW_EH
-
- static void
- sorry_no_eh ()
- {
- static int warned = 0;
- if (! warned)
- {
- sorry ("exception handling not supported");
- warned = 1;
- }
- }
-
- void
- build_exception_table ()
- {
- }
-
- void
- expand_exception_blocks ()
- {
- }
-
- void
- start_protect ()
- {
- }
-
- void
- end_protect (finalization)
- tree finalization;
- {
- }
-
- void
- expand_start_try_stmts ()
- {
- sorry_no_eh ();
- }
-
- void
- expand_end_try_stmts ()
- {
- }
-
- void
- expand_start_all_catch ()
- {
- }
-
- void
- expand_end_all_catch ()
- {
- }
-
- void
- expand_start_catch_block (declspecs, declarator)
- tree declspecs, declarator;
- {
- }
-
- void
- expand_end_catch_block ()
- {
- }
-
- void
- init_exception_processing ()
- {
- }
-
- void
- expand_throw (exp)
- tree exp;
- {
- sorry_no_eh ();
- }
-
- #else
-
- static int
- doing_eh (do_warn)
- int do_warn;
- {
- if (! flag_handle_exceptions)
- {
- static int warned = 0;
- if (! warned && do_warn)
- {
- error ("exception handling disabled, use -fhandle-exceptions to enable.");
- warned = 1;
- }
- return 0;
- }
- return 1;
- }
-
-
- /*
- NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
- to supporting exception handling as per Stroustrup's 2nd edition.
- It is a complete rewrite of all the EH stuff that was here before
- Shortcomings:
- 1. The type of the throw and catch must still match
- exactly (no support yet for matching base classes)
- 2. Throw specifications of functions still doesnt't work.
- Cool Things:
- 1. Destructors are called properly :-)
- 2. No overhead for the non-exception thrown case.
- 3. Fixing shortcomings 1 and 2 is simple.
- -Tad Hunt (tad@mail.csh.rit.edu)
-
- */
-
- /* A couple of backend routines from m88k.c */
-
- /* used to cache a call to __builtin_return_address () */
- static tree BuiltinReturnAddress;
-
-
-
-
-
- #include <stdio.h>
-
- /* XXX - Tad: for EH */
- /* output an exception table entry */
-
- static void
- output_exception_table_entry (file, start_label, end_label, eh_label)
- FILE *file;
- rtx start_label, end_label, eh_label;
- {
- char label[100];
-
- fprintf (file, "\t%s\t ", ASM_LONG);
- if (GET_CODE (start_label) == CODE_LABEL)
- {
- ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (start_label));
- assemble_name (file, label);
- }
- else if (GET_CODE (start_label) == SYMBOL_REF)
- {
- fprintf (stderr, "YYYYYYYYYEEEEEEEESSSSSSSSSSSS!!!!!!!!!!\n");
- assemble_name (file, XSTR (start_label, 0));
- }
- putc ('\n', file);
-
- fprintf (file, "\t%s\t ", ASM_LONG);
- ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (end_label));
- assemble_name (file, label);
- putc ('\n', file);
-
- fprintf (file, "\t%s\t ", ASM_LONG);
- ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (eh_label));
- assemble_name (file, label);
- putc ('\n', file);
-
- putc ('\n', file); /* blank line */
- }
-
- static void
- easy_expand_asm (str)
- char *str;
- {
- expand_asm (build_string (strlen (str)+1, str));
- }
-
- /* unwind the stack. */
- static void
- do_unwind (throw_label)
- rtx throw_label;
- {
- #ifdef sparc
- extern FILE *asm_out_file;
- tree fcall;
- tree params;
- rtx return_val_rtx;
-
- /* call to __builtin_return_address () */
- params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
- fcall = build_function_call (BuiltinReturnAddress, params);
- return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
- /* In the return, the new pc is pc+8, as the value comming in is
- really the address of the call insn, not the next insn. */
- emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF,
- Pmode,
- throw_label), -8));
- /* We use three values, PC, type, and value */
- easy_expand_asm ("st %l0,[%fp]");
- easy_expand_asm ("st %l1,[%fp+4]");
- easy_expand_asm ("st %l2,[%fp+8]");
- easy_expand_asm ("ret");
- easy_expand_asm ("restore");
- emit_barrier ();
- #endif
- #if m88k
- rtx temp_frame = frame_pointer_rtx;
-
- temp_frame = memory_address (Pmode, temp_frame);
- temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
-
- /* hopefully this will successfully pop the frame! */
- emit_move_insn (frame_pointer_rtx, temp_frame);
- emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
- emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
- emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
- (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
-
- #if 0
- emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
- -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
-
- emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
-
- emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
- (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
- #endif
- #endif
- }
-
-
-
- #if 0
- /* This is the startup, and finish stuff per exception table. */
-
- /* XXX - Tad: exception handling section */
- #ifndef EXCEPT_SECTION_ASM_OP
- #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
- #endif
-
- #ifdef EXCEPT_SECTION_ASM_OP
- typedef struct {
- void *start_protect;
- void *end_protect;
- void *exception_handler;
- } exception_table;
- #endif /* EXCEPT_SECTION_ASM_OP */
-
- #ifdef EXCEPT_SECTION_ASM_OP
-
- /* on machines which support it, the exception table lives in another section,
- but it needs a label so we can reference it... This sets up that
- label! */
- asm (EXCEPT_SECTION_ASM_OP);
- exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
- asm (TEXT_SECTION_ASM_OP);
-
- #endif /* EXCEPT_SECTION_ASM_OP */
-
- #ifdef EXCEPT_SECTION_ASM_OP
-
- /* we need to know where the end of the exception table is... so this
- is how we do it! */
-
- asm (EXCEPT_SECTION_ASM_OP);
- exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
- asm (TEXT_SECTION_ASM_OP);
-
- #endif /* EXCEPT_SECTION_ASM_OP */
-
- #endif
-
- void
- exception_section ()
- {
- #ifdef ASM_OUTPUT_SECTION_NAME
- named_section (".gcc_except_table");
- #else
- text_section ();
- #endif
- }
-
-
-
-
- /* from: my-cp-except.c */
-
- /* VI: ":set ts=4" */
- #if 0
- #include <stdio.h> */
- #include "config.h"
- #include "tree.h"
- #include "rtl.h"
- #include "cp-tree.h"
- #endif
- #include "decl.h"
- #if 0
- #include "flags.h"
- #endif
- #include "insn-flags.h"
- #include "obstack.h"
- #if 0
- #include "expr.h"
- #endif
-
- /* ======================================================================
- Briefly the algorithm works like this:
-
- When a constructor or start of a try block is encountered,
- push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
- new entry in the unwind protection stack and returns a label to
- output to start the protection for that block.
-
- When a destructor or end try block is encountered, pop_eh_entry
- (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
- created when push_eh_entry () was called. The ehEntry structure
- contains three things at this point. The start protect label,
- the end protect label, and the exception handler label. The end
- protect label should be output before the call to the destructor
- (if any). If it was a destructor, then its parse tree is stored
- in the finalization variable in the ehEntry structure. Otherwise
- the finalization variable is set to NULL to reflect the fact that
- is the the end of a try block. Next, this modified ehEntry node
- is enqueued in the finalizations queue by calling
- enqueue_eh_entry (&queue,entry).
-
- +---------------------------------------------------------------+
- |XXX: Will need modification to deal with partially |
- | constructed arrays of objects |
- | |
- | Basically, this consists of keeping track of how many |
- | of the objects have been constructed already (this |
- | should be in a register though, so that shouldn't be a |
- | problem. |
- +---------------------------------------------------------------+
-
- When a catch block is encountered, there is a lot of work to be
- done.
-
- Since we don't want to generate the catch block inline with the
- regular flow of the function, we need to have some way of doing
- so. Luckily, we have a couple of routines "get_last_insn ()" and
- "set_last_insn ()" provided. When the start of a catch block is
- encountered, we save a pointer to the last insn generated. After
- the catch block is generated, we save a pointer to the first
- catch block insn and the last catch block insn with the routines
- "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn
- to be the last insn generated before the catch block, and set the
- NEXT_INSN (last_insn) to zero.
-
- Since catch blocks might be nested inside other catch blocks, and
- we munge the chain of generated insns after the catch block is
- generated, we need to store the pointers to the last insn
- generated in a stack, so that when the end of a catch block is
- encountered, the last insn before the current catch block can be
- popped and set to be the last insn, and the first and last insns
- of the catch block just generated can be enqueue'd for output at
- a later time.
-
- Next we must insure that when the catch block is executed, all
- finalizations for the matching try block have been completed. If
- any of those finalizations throw an exception, we must call
- terminate according to the ARM (section r.15.6.1). What this
- means is that we need to dequeue and emit finalizations for each
- entry in the ehQueue until we get to an entry with a NULL
- finalization field. For any of the finalization entries, if it
- is not a call to terminate (), we must protect it by giving it
- another start label, end label, and exception handler label,
- setting its finalization tree to be a call to terminate (), and
- enqueue'ing this new ehEntry to be output at an outer level.
- Finally, after all that is done, we can get around to outputting
- the catch block which basically wraps all the "catch (...) {...}"
- statements in a big if/then/else construct that matches the
- correct block to call.
-
- ===================================================================== */
-
- extern rtx emit_insn PROTO((rtx));
- extern rtx gen_nop PROTO(());
-
- /* local globals for function calls
- ====================================================================== */
-
- /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
- "set_unexpected ()" after default_conversion. (lib-except.c) */
- static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
-
- /* used to cache __find_first_exception_table_match ()
- for throw (lib-except.c) */
- static tree FirstExceptionMatch;
-
- /* used to cache a call to __unwind_function () (lib-except.c) */
- static tree Unwind;
-
- /* holds a ready to emit call to "terminate ()". */
- static tree TerminateFunctionCall;
-
- /* ====================================================================== */
-
-
-
- /* data structures for my various quick and dirty stacks and queues
- Eventually, most of this should go away, because I think it can be
- integrated with stuff already built into the compiler. */
-
- /* =================================================================== */
-
- struct labelNode {
- rtx label;
- struct labelNode *chain;
- };
-
-
- /* this is the most important structure here. Basically this is how I store
- an exception table entry internally. */
- struct ehEntry {
- rtx start_label;
- rtx end_label;
- rtx exception_handler_label;
-
- tree finalization;
- };
-
- struct ehNode {
- struct ehEntry *entry;
- struct ehNode *chain;
- };
-
- struct ehStack {
- struct ehNode *top;
- };
-
- struct ehQueue {
- struct ehNode *head;
- struct ehNode *tail;
- };
-
- struct exceptNode {
- rtx catchstart;
- rtx catchend;
-
- struct exceptNode *chain;
- };
-
- struct exceptStack {
- struct exceptNode *top;
- };
- /* ========================================================================= */
-
-
-
- /* local globals - these local globals are for storing data necessary for
- generating the exception table and code in the correct order.
-
- ========================================================================= */
-
- /* Holds the pc for doing "throw" */
- rtx saved_pc;
- /* Holds the type of the thing being thrown. */
- rtx saved_throw_type;
- /* Holds the value being thrown. */
- rtx saved_throw_value;
-
- rtx throw_label;
-
- static struct ehStack ehstack;
- static struct ehQueue ehqueue;
- static struct ehQueue eh_table_output_queue;
- static struct exceptStack exceptstack;
- static struct labelNode *false_label_stack = NULL;
- static struct labelNode *caught_return_label_stack = NULL;
- /* ========================================================================= */
-
- /* function prototypes */
- static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
- static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
- static void push_except_stmts PROTO((struct exceptStack *exceptstack,
- rtx catchstart, rtx catchend));
- static int pop_except_stmts PROTO((struct exceptStack *exceptstack,
- rtx *catchstart, rtx *catchend));
- static rtx push_eh_entry PROTO((struct ehStack *stack));
- static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
- static void new_eh_queue PROTO((struct ehQueue *queue));
- static void new_eh_stack PROTO((struct ehStack *stack));
- static void new_except_stack PROTO((struct exceptStack *queue));
- static void push_last_insn PROTO(());
- static rtx pop_last_insn PROTO(());
- static void push_label_entry PROTO((struct labelNode **labelstack, rtx label));
- static rtx pop_label_entry PROTO((struct labelNode **labelstack));
- static rtx top_label_entry PROTO((struct labelNode **labelstack));
- static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
-
-
-
- /* All my cheesy stack/queue/misc data structure handling routines
-
- ========================================================================= */
-
- static void
- push_label_entry (labelstack, label)
- struct labelNode **labelstack;
- rtx label;
- {
- struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
-
- newnode->label = label;
- newnode->chain = *labelstack;
- *labelstack = newnode;
- }
-
- static rtx
- pop_label_entry (labelstack)
- struct labelNode **labelstack;
- {
- rtx label;
- struct labelNode *tempnode;
-
- if (! *labelstack) return NULL_RTX;
-
- tempnode = *labelstack;
- label = tempnode->label;
- *labelstack = (*labelstack)->chain;
- free (tempnode);
-
- return label;
- }
-
- static rtx
- top_label_entry (labelstack)
- struct labelNode **labelstack;
- {
- if (! *labelstack) return NULL_RTX;
-
- return (*labelstack)->label;
- }
-
- static void
- push_except_stmts (exceptstack, catchstart, catchend)
- struct exceptStack *exceptstack;
- rtx catchstart, catchend;
- {
- struct exceptNode *newnode = (struct exceptNode*)
- xmalloc (sizeof (struct exceptNode));
-
- newnode->catchstart = catchstart;
- newnode->catchend = catchend;
- newnode->chain = exceptstack->top;
-
- exceptstack->top = newnode;
- }
-
- static int
- pop_except_stmts (exceptstack, catchstart, catchend)
- struct exceptStack *exceptstack;
- rtx *catchstart, *catchend;
- {
- struct exceptNode *tempnode;
-
- if (!exceptstack->top) {
- *catchstart = *catchend = NULL_RTX;
- return 0;
- }
-
- tempnode = exceptstack->top;
- exceptstack->top = exceptstack->top->chain;
-
- *catchstart = tempnode->catchstart;
- *catchend = tempnode->catchend;
- free (tempnode);
-
- return 1;
- }
-
- /* Push to permanent obstack for rtl generation.
- One level only! */
- static struct obstack *saved_rtl_obstack;
- void
- push_rtl_perm ()
- {
- extern struct obstack permanent_obstack;
- extern struct obstack *rtl_obstack;
-
- saved_rtl_obstack = rtl_obstack;
- rtl_obstack = &permanent_obstack;
- }
-
- /* Pop back to normal rtl handling. */
- static void
- pop_rtl_from_perm ()
- {
- extern struct obstack permanent_obstack;
- extern struct obstack *rtl_obstack;
-
- rtl_obstack = saved_rtl_obstack;
- }
-
- static rtx
- push_eh_entry (stack)
- struct ehStack *stack;
- {
- struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
- struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
-
- if (stack == NULL) {
- free (node);
- free (entry);
- return NULL_RTX;
- }
-
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry->start_label = gen_label_rtx ();
- entry->end_label = gen_label_rtx ();
- entry->exception_handler_label = gen_label_rtx ();
- pop_rtl_from_perm ();
-
- entry->finalization = NULL_TREE;
-
- node->entry = entry;
- node->chain = stack->top;
- stack->top = node;
-
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
-
- return entry->start_label;
- }
-
- static struct ehEntry *
- pop_eh_entry (stack)
- struct ehStack *stack;
- {
- struct ehNode *tempnode;
- struct ehEntry *tempentry;
-
- if (stack && (tempnode = stack->top)) {
- tempentry = tempnode->entry;
- stack->top = stack->top->chain;
- free (tempnode);
-
- return tempentry;
- }
-
- return NULL;
- }
-
- static struct ehEntry *
- copy_eh_entry (entry)
- struct ehEntry *entry;
- {
- struct ehEntry *newentry;
-
- newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
- memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
-
- return newentry;
- }
-
- static void
- enqueue_eh_entry (queue, entry)
- struct ehQueue *queue;
- struct ehEntry *entry;
- {
- struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
-
- node->entry = entry;
- node->chain = NULL;
-
- if (queue->head == NULL)
- {
- queue->head = node;
- }
- else
- {
- queue->tail->chain = node;
- }
- queue->tail = node;
- }
-
- static struct ehEntry *
- dequeue_eh_entry (queue)
- struct ehQueue *queue;
- {
- struct ehNode *tempnode;
- struct ehEntry *tempentry;
-
- if (queue->head == NULL)
- return NULL;
-
- tempnode = queue->head;
- queue->head = queue->head->chain;
-
- tempentry = tempnode->entry;
- free (tempnode);
-
- return tempentry;
- }
-
- static void
- new_eh_queue (queue)
- struct ehQueue *queue;
- {
- queue->head = queue->tail = NULL;
- }
-
- static void
- new_eh_stack (stack)
- struct ehStack *stack;
- {
- stack->top = NULL;
- }
-
- static void
- new_except_stack (stack)
- struct exceptStack *stack;
- {
- stack->top = NULL;
- }
- /* ========================================================================= */
-
- void
- lang_interim_eh (finalization)
- tree finalization;
- {
- if (finalization)
- end_protect (finalization);
- else
- start_protect ();
- }
-
- /* sets up all the global eh stuff that needs to be initialized at the
- start of compilation.
-
- This includes:
- - Setting up all the function call trees
- - Initializing the ehqueue
- - Initializing the eh_table_output_queue
- - Initializing the ehstack
- - Initializing the exceptstack
- */
-
- void
- init_exception_processing ()
- {
- extern tree define_function ();
- tree unexpected_fndecl, terminate_fndecl;
- tree set_unexpected_fndecl, set_terminate_fndecl;
- tree catch_match_fndecl;
- tree find_first_exception_match_fndecl;
- tree unwind_fndecl;
- tree temp, PFV;
-
- interim_eh_hook = lang_interim_eh;
-
- /* void (*)() */
- PFV = build_pointer_type (build_function_type (void_type_node, void_list_node));
-
- /* arg list for the build_function_type call for set_terminate () and
- set_unexpected () */
- temp = tree_cons (NULL_TREE, PFV, void_list_node);
-
- push_lang_context (lang_name_c);
-
- set_terminate_fndecl =
- define_function ("set_terminate",
- build_function_type (PFV, temp),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- set_unexpected_fndecl =
- define_function ("set_unexpected",
- build_function_type (PFV, temp),
- NOT_BUILT_IN,
- pushdecl,
- 0);
-
- unexpected_fndecl =
- define_function ("unexpected",
- build_function_type (void_type_node, void_list_node),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- terminate_fndecl =
- define_function ("terminate",
- build_function_type (void_type_node, void_list_node),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- catch_match_fndecl =
- define_function ("__throw_type_match",
- build_function_type (integer_type_node,
- tree_cons (NULL_TREE, string_type_node, tree_cons (NULL_TREE, ptr_type_node, void_list_node))),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- find_first_exception_match_fndecl =
- define_function ("__find_first_exception_table_match",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- unwind_fndecl =
- define_function ("__unwind_function",
- build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node, void_list_node)),
- NOT_BUILT_IN,
- pushdecl,
- 0);
-
- Unexpected = default_conversion (unexpected_fndecl);
- Terminate = default_conversion (terminate_fndecl);
- SetTerminate = default_conversion (set_terminate_fndecl);
- SetUnexpected = default_conversion (set_unexpected_fndecl);
- CatchMatch = default_conversion (catch_match_fndecl);
- FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
- Unwind = default_conversion (unwind_fndecl);
- BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
-
- TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
-
- pop_lang_context ();
- throw_label = gen_label_rtx ();
- saved_pc = gen_rtx (REG, Pmode, 16);
- saved_throw_type = gen_rtx (REG, Pmode, 17);
- saved_throw_value = gen_rtx (REG, Pmode, 18);
-
- new_eh_queue (&ehqueue);
- new_eh_queue (&eh_table_output_queue);
- new_eh_stack (&ehstack);
- new_except_stack (&exceptstack);
- }
-
- /* call this to begin a block of unwind protection (ie: when an object is
- constructed) */
- void
- start_protect ()
- {
- if (doing_eh (0))
- {
- emit_label (push_eh_entry (&ehstack));
- }
- }
-
- /* call this to end a block of unwind protection. the finalization tree is
- the finalization which needs to be run in order to cleanly unwind through
- this level of protection. (ie: call this when a scope is exited)*/
- void
- end_protect (finalization)
- tree finalization;
- {
- struct ehEntry *entry = pop_eh_entry (&ehstack);
-
- if (! doing_eh (0))
- return;
-
- emit_label (entry->end_label);
-
- entry->finalization = finalization;
-
- enqueue_eh_entry (&ehqueue, entry);
- }
-
- /* call this on start of a try block. */
- void
- expand_start_try_stmts ()
- {
- if (doing_eh (1))
- {
- start_protect ();
- }
- }
-
- void
- expand_end_try_stmts ()
- {
- end_protect (integer_zero_node);
- }
-
- struct insn_save_node {
- rtx last;
- struct insn_save_node *chain;
- };
-
- static struct insn_save_node *InsnSave = NULL;
-
-
- /* Used to keep track of where the catch blocks start. */
- static void
- push_last_insn ()
- {
- struct insn_save_node *newnode = (struct insn_save_node*)
- xmalloc (sizeof (struct insn_save_node));
-
- newnode->last = get_last_insn ();
- newnode->chain = InsnSave;
- InsnSave = newnode;
- }
-
- /* Use to keep track of where the catch blocks start. */
- static rtx
- pop_last_insn ()
- {
- struct insn_save_node *tempnode;
- rtx temprtx;
-
- if (!InsnSave) return NULL_RTX;
-
- tempnode = InsnSave;
- temprtx = tempnode->last;
- InsnSave = InsnSave->chain;
-
- free (tempnode);
-
- return temprtx;
- }
-
- /* call this to start processing of all the catch blocks. */
- void
- expand_start_all_catch ()
- {
- struct ehEntry *entry;
- rtx label;
-
- if (! doing_eh (1))
- return;
-
- emit_line_note (input_filename, lineno);
- label = gen_label_rtx ();
- /* The label for the exception handling block we will save. */
- emit_label (label);
-
- push_label_entry (&caught_return_label_stack, label);
-
- /* Remember where we started. */
- push_last_insn ();
-
- emit_insn (gen_nop ());
-
- /* Will this help us not stomp on it? */
- emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
- emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
-
- while (1)
- {
- entry = dequeue_eh_entry (&ehqueue);
- emit_label (entry->exception_handler_label);
-
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
- /* When we get down to the matching entry, stop. */
- if (entry->finalization == integer_zero_node)
- break;
-
- free (entry);
- }
-
- /* This goes when the below moves out of our way. */
- #if 1
- label = gen_label_rtx ();
- emit_jump (label);
- #endif
-
- /* All this should be out of line, and saved back in the exception handler
- block area. */
- #if 1
- entry->start_label = entry->exception_handler_label;
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry->end_label = gen_label_rtx ();
- entry->exception_handler_label = gen_label_rtx ();
- entry->finalization = TerminateFunctionCall;
- pop_rtl_from_perm ();
- emit_label (entry->end_label);
-
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
-
- /* After running the finalization, continue on out to the next
- cleanup, if we have nothing better to do. */
- emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label));
- /* Will this help us not stomp on it? */
- emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
- emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
- emit_jump (throw_label);
- emit_label (entry->exception_handler_label);
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
- emit_barrier ();
- #endif
- emit_label (label);
- }
-
- /* call this to end processing of all the catch blocks. */
- void
- expand_end_all_catch ()
- {
- rtx catchstart, catchend, last;
- rtx label;
-
- if (! doing_eh (1))
- return;
-
- /* Find the start of the catch block. */
- last = pop_last_insn ();
- catchstart = NEXT_INSN (last);
- catchend = get_last_insn ();
-
- NEXT_INSN (last) = 0;
- set_last_insn (last);
-
- /* this level of catch blocks is done, so set up the successful catch jump
- label for the next layer of catch blocks. */
- pop_label_entry (&caught_return_label_stack);
-
- push_except_stmts (&exceptstack, catchstart, catchend);
-
- /* Here we fall through into the continuation code. */
- }
-
-
- /* this is called from expand_exception_blocks () to expand the toplevel
- finalizations for a function. */
- void
- expand_leftover_cleanups ()
- {
- struct ehEntry *entry;
- rtx first_label = NULL_RTX;
-
- if (! doing_eh (0))
- return;
-
- /* Will this help us not stomp on it? */
- emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
- emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
-
- while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
- {
- if (! first_label)
- first_label = entry->exception_handler_label;
- emit_label (entry->exception_handler_label);
-
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
- /* leftover try block, opps. */
- if (entry->finalization == integer_zero_node)
- abort ();
-
- free (entry);
- }
- if (first_label)
- {
- rtx label;
- struct ehEntry entry;
- /* These are saved for the exception table. */
- push_rtl_perm ();
- label = gen_label_rtx ();
- entry.start_label = first_label;
- entry.end_label = label;
- entry.exception_handler_label = gen_label_rtx ();
- entry.finalization = TerminateFunctionCall;
- pop_rtl_from_perm ();
- emit_label (label);
-
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
-
- /* After running the finalization, continue on out to the next
- cleanup, if we have nothing better to do. */
- emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label));
- /* Will this help us not stomp on it? */
- emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
- emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
- emit_jump (throw_label);
- emit_label (entry.exception_handler_label);
- expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
- emit_barrier ();
- }
- }
-
- /* call this to start a catch block. Typename is the typename, and identifier
- is the variable to place the object in or NULL if the variable doesn't
- matter. If typename is NULL, that means its a "catch (...)" or catch
- everything. In that case we don't need to do any type checking.
- (ie: it ends up as the "else" clause rather than an "else if" clause) */
- void
- expand_start_catch_block (declspecs, declarator)
- tree declspecs, declarator;
- {
- rtx false_label_rtx;
- rtx protect_label_rtx;
- tree type;
- tree decl;
- tree init;
-
- if (! doing_eh (1))
- return;
-
- /* Create a binding level for the parm. */
- expand_start_bindings (0);
-
- if (declspecs)
- {
- tree init_type;
- decl = grokdeclarator (declarator, declspecs, NORMAL, 1, NULL_TREE);
-
- /* Figure out the type that the initializer is. */
- init_type = TREE_TYPE (decl);
- if (TREE_CODE (init_type) != REFERENCE_TYPE)
- init_type = build_reference_type (init_type);
-
- init = convert_from_reference (save_expr (make_tree (init_type, saved_throw_value)));
-
- /* Do we need the below two lines? */
- /* Let `finish_decl' know that this initializer is ok. */
- DECL_INITIAL (decl) = init;
- /* This needs to be preallocated under the try block,
- in a union of all catch variables. */
- pushdecl (decl);
- type = TREE_TYPE (decl);
-
- /* peel back references, so they match. */
- if (TREE_CODE (type) == REFERENCE_TYPE)
- type = TREE_TYPE (type);
- }
- else
- type = NULL_TREE;
-
- false_label_rtx = gen_label_rtx ();
- push_label_entry (&false_label_stack, false_label_rtx);
-
- /* This is saved for the exception table. */
- push_rtl_perm ();
- protect_label_rtx = gen_label_rtx ();
- pop_rtl_from_perm ();
- push_label_entry (&false_label_stack, protect_label_rtx);
-
- if (type)
- {
- tree params;
- char *typestring;
- rtx call_rtx, return_value_rtx;
- tree catch_match_fcall;
- tree catchmatch_arg, argval;
-
- typestring = build_overload_name (type, 1, 1);
-
- params = tree_cons (NULL_TREE,
- combine_strings (build_string (strlen (typestring)+1, typestring)),
- tree_cons (NULL_TREE,
- make_tree (ptr_type_node, saved_throw_type),
- NULL_TREE));
- catch_match_fcall = build_function_call (CatchMatch, params);
- call_rtx = expand_call (catch_match_fcall, NULL_RTX, 0);
-
- return_value_rtx =
- hard_function_value (integer_type_node, catch_match_fcall);
-
- /* did the throw type match function return TRUE? */
- emit_cmp_insn (return_value_rtx, const0_rtx, NE, NULL_RTX,
- GET_MODE (return_value_rtx), 0, 0);
-
- /* if it returned FALSE, jump over the catch block, else fall into it */
- emit_jump_insn (gen_bne (false_label_rtx));
- finish_decl (decl, init, NULL_TREE, 0);
- }
- else
- {
- /* Fall into the catch all section. */
- }
-
- /* This is the starting of something to protect. */
- emit_label (protect_label_rtx);
-
- emit_line_note (input_filename, lineno);
- }
-
-
- /* Call this to end a catch block. Its responsible for emitting the
- code to handle jumping back to the correct place, and for emitting
- the label to jump to if this catch block didn't match. */
- void expand_end_catch_block ()
- {
- if (doing_eh (1))
- {
- rtx start_protect_label_rtx;
- rtx end_protect_label_rtx;
- tree decls;
- struct ehEntry entry;
-
- /* label we jump to if we caught the exception */
- emit_jump (top_label_entry (&caught_return_label_stack));
-
- /* Code to throw out to outer context, if we get an throw from within
- our catch handler. */
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry.exception_handler_label = gen_label_rtx ();
- pop_rtl_from_perm ();
- emit_label (entry.exception_handler_label);
- emit_move_insn (saved_pc, gen_rtx (LABEL_REF,
- Pmode,
- top_label_entry (&caught_return_label_stack)));
- emit_jump (throw_label);
- /* No associated finalization. */
- entry.finalization = NULL_TREE;
-
- /* Because we are reordered out of line, we have to protect this. */
- /* label for the start of the protection region. */
- start_protect_label_rtx = pop_label_entry (&false_label_stack);
-
- /* Cleanup the EH paramater. */
- expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0);
-
- /* label we emit to jump to if this catch block didn't match. */
- emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack));
-
- /* Because we are reordered out of line, we have to protect this. */
- entry.start_label = start_protect_label_rtx;
- entry.end_label = end_protect_label_rtx;
-
- /* These set up a call to throw the caught exception into the outer
- context. */
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
- }
- }
-
- /* cheesyness to save some typing. returns the return value rtx */
- rtx
- do_function_call (func, params, return_type)
- tree func, params, return_type;
- {
- tree func_call;
- func_call = build_function_call (func, params);
- expand_call (func_call, NULL_RTX, 0);
- if (return_type != NULL_TREE)
- return hard_function_value (return_type, func_call);
- return NULL_RTX;
- }
-
-
- /* is called from expand_excpetion_blocks () to generate the code in a function
- to "throw" if anything in the function needs to preform a throw.
-
- expands "throw" as the following psuedo code:
-
- throw:
- eh = find_first_exception_match (saved_pc);
- if (!eh) goto gotta_rethrow_it;
- goto eh;
-
- gotta_rethrow_it:
- saved_pc = __builtin_return_address (0);
- pop_to_previous_level ();
- goto throw;
-
- */
- static void
- expand_builtin_throw ()
- {
- tree fcall;
- tree params;
- rtx return_val_rtx;
- rtx gotta_rethrow_it = gen_label_rtx ();
- rtx gotta_call_terminate = gen_label_rtx ();
- rtx unwind_and_throw = gen_label_rtx ();
- rtx goto_unwind_and_throw = gen_label_rtx ();
-
- emit_label (throw_label);
-
- /* search for an exception handler for the saved_pc */
- return_val_rtx = do_function_call (FirstExceptionMatch,
- tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE),
- ptr_type_node);
-
- /* did we find one? */
- emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
- GET_MODE (return_val_rtx), 0, 0);
-
- /* if not, jump to gotta_rethrow_it */
- emit_jump_insn (gen_beq (gotta_rethrow_it));
-
- /* we found it, so jump to it */
- emit_indirect_jump (return_val_rtx);
-
- /* code to deal with unwinding and looking for it again */
- emit_label (gotta_rethrow_it);
-
- /* call to __builtin_return_address () */
- params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
- fcall = build_function_call (BuiltinReturnAddress, params);
- return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
-
- /* did __builtin_return_address () return a valid address? */
- emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
- GET_MODE (return_val_rtx), 0, 0);
-
- emit_jump_insn (gen_beq (gotta_call_terminate));
-
- /* yes it did */
- emit_move_insn (saved_pc, return_val_rtx);
- do_unwind (throw_label);
- emit_jump (throw_label);
-
- /* no it didn't --> therefore we need to call terminate */
- emit_label (gotta_call_terminate);
- do_function_call (Terminate, NULL_TREE, NULL_TREE);
- }
-
-
- /* This is called to expand all the toplevel exception handling
- finalization for a function. It should only be called once per
- function. */
- void
- expand_exception_blocks ()
- {
- rtx catchstart, catchend;
- rtx last;
- static rtx funcend;
-
- funcend = gen_label_rtx ();
- emit_jump (funcend);
- /* expand_null_return (); */
-
- while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) {
- last = get_last_insn ();
- NEXT_INSN (last) = catchstart;
- PREV_INSN (catchstart) = last;
- NEXT_INSN (catchend) = 0;
- set_last_insn (catchend);
- }
-
- expand_leftover_cleanups ();
-
- {
- static int have_done = 0;
- if (! have_done && TREE_PUBLIC (current_function_decl)
- && ! DECL_INLINE (current_function_decl))
- {
- have_done = 1;
- expand_builtin_throw ();
- }
- }
- emit_label (funcend);
- }
-
-
- /* call this to expand a throw statement. This follows the following
- algorithm:
-
- 1. Allocate space to save the current PC onto the stack.
- 2. Generate and emit a label and save its address into the
- newly allocate stack space since we can't save the pc directly.
- 3. If this is the first call to throw in this function:
- generate a label for the throw block
- 4. jump to the throw block label. */
- void
- expand_throw (exp)
- tree exp;
- {
- rtx label;
- tree type;
-
- if (! doing_eh (1))
- return;
-
- /* This is the label that represents where in the code we were, when
- we got an exception. This needs to be updated when we rethrow an
- exception, so that the matching routine knows to search out. */
- label = gen_label_rtx ();
- emit_label (label);
- emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label));
-
- if (exp)
- {
- /* throw expression */
- /* First, decay it. */
- exp = default_conversion (exp);
- type = TREE_TYPE (exp);
-
- {
- char *typestring = build_overload_name (type, 1, 1);
- tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring)));
- rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
- rtx throw_value_rtx;
-
- emit_move_insn (saved_throw_type, throw_type_rtx);
- exp = convert_to_reference (build_reference_type (build_type_variant (TREE_TYPE (exp), 1, 0)), exp, CONV_STATIC, LOOKUP_COMPLAIN, NULL_TREE);
- if (exp == error_mark_node)
- error (" in thrown expression");
- throw_value_rtx = expand_expr (build_unary_op (ADDR_EXPR, exp, 0), NULL_RTX, VOIDmode, 0);
- emit_move_insn (saved_throw_value, throw_value_rtx);
- }
- }
- else
- {
- /* rethrow current exception */
- /* This part is easy, as we dont' have to do anything else. */
- }
-
- emit_jump (throw_label);
- }
-
-
- /* output the exception table */
- void
- build_exception_table ()
- {
- extern FILE *asm_out_file;
- struct ehEntry *entry;
-
- if (! doing_eh (0))
- return;
-
- exception_section ();
-
- /* Beginning marker for table. */
- fprintf (asm_out_file, " .global ___EXCEPTION_TABLE__\n");
- fprintf (asm_out_file, " .align 4\n");
- fprintf (asm_out_file, "___EXCEPTION_TABLE__:\n");
- fprintf (asm_out_file, " .word 0, 0, 0\n");
-
- while (entry = dequeue_eh_entry (&eh_table_output_queue)) {
- output_exception_table_entry (asm_out_file,
- entry->start_label, entry->end_label, entry->exception_handler_label);
- }
-
- /* Ending marker for table. */
- fprintf (asm_out_file, " .global ___EXCEPTION_END__\n");
- fprintf (asm_out_file, "___EXCEPTION_END__:\n");
- fprintf (asm_out_file, " .word -1, -1, -1\n");
- }
-
- /* end of: my-cp-except.c */
- #endif
-
-
- /* Build a throw expression. */
- tree
- build_throw (e)
- tree e;
- {
- e = build1 (THROW_EXPR, void_type_node, e);
- TREE_SIDE_EFFECTS (e) = 1;
- return e;
- }
-