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