📄 except.c
字号:
/* Handle exceptional things in C++. Copyright (C) 1989, 1992, 1993, 1994, 1995 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 modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, 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"tree protect_list;extern void (*interim_eh_hook) PROTO((tree));rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));/* holds the fndecl for __builtin_return_address () */tree builtin_return_address_fndecl;tree throw_fndecl;static intdoing_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 closerto supporting exception handling as per ANSI C++ working draft.It is a complete rewrite of all the EH stuff that was here before Shortcomings: 1. Throw specifications of functions still don't work. Cool Things: 1. Destructors are called properly :-) 2. No overhead for the non-exception thrown case. 3. Fixing shortcoming 1 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 voidoutput_exception_table_entry (file, start_label, end_label, eh_label) FILE *file; rtx start_label, end_label, eh_label;{ char label[100]; assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1); assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1); assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1); putc ('\n', file); /* blank line */} static voideasy_expand_asm (str) char *str;{ expand_asm (build_string (strlen (str)+1, str));}#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_OPtypedef 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 */#endifvoidexception_section (){#ifdef ASM_OUTPUT_SECTION_NAME named_section (NULL_TREE, ".gcc_except_table");#else if (flag_pic) data_section (); else#if defined(TARGET_POWERPC) /* are we on a __rs6000? */ data_section ();#else readonly_data_section ();#endif#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 can use sequences to defer the catch sections. When the start of a catch block is encountered, we start the sequence. After the catch block is generated, we end the sequence. 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, Throw;/* 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; tree context;};struct ehNode { struct ehEntry *entry; struct ehNode *chain;};struct ehStack { struct ehNode *top;};struct ehQueue { struct ehNode *head; struct ehNode *tail;};/* ========================================================================= *//* 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" */tree saved_pc;/* Holds the type of the thing being thrown. */tree saved_throw_type;/* Holds the value being thrown. */tree saved_throw_value;int throw_used;static rtx catch_clauses;static first_catch_label;static struct ehStack ehstack;static struct ehQueue ehqueue;static struct ehQueue eh_table_output_queue;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 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 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 voidpush_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 rtxpop_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 rtxtop_label_entry (labelstack) struct labelNode **labelstack;{ if (! *labelstack) return NULL_RTX; return (*labelstack)->label;}/* Push to permanent obstack for rtl generation. One level only! */static struct obstack *saved_rtl_obstack;voidpush_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 voidpop_rtl_from_perm (){ extern struct obstack permanent_obstack; extern struct obstack *rtl_obstack; rtl_obstack = saved_rtl_obstack;}static rtxpush_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -