except.c revision 96263
150397Sobrien/* Implements exception handling. 290075Sobrien Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 390075Sobrien 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 450397Sobrien Contributed by Mike Stump <mrs@cygnus.com>. 550397Sobrien 690075SobrienThis file is part of GCC. 750397Sobrien 890075SobrienGCC is free software; you can redistribute it and/or modify it under 990075Sobrienthe terms of the GNU General Public License as published by the Free 1090075SobrienSoftware Foundation; either version 2, or (at your option) any later 1190075Sobrienversion. 1250397Sobrien 1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1590075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1690075Sobrienfor more details. 1750397Sobrien 1850397SobrienYou should have received a copy of the GNU General Public License 1990075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 2090075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2190075Sobrien02111-1307, USA. */ 2250397Sobrien 2350397Sobrien 2450397Sobrien/* An exception is an event that can be signaled from within a 2550397Sobrien function. This event can then be "caught" or "trapped" by the 2650397Sobrien callers of this function. This potentially allows program flow to 2750397Sobrien be transferred to any arbitrary code associated with a function call 2850397Sobrien several levels up the stack. 2950397Sobrien 3050397Sobrien The intended use for this mechanism is for signaling "exceptional 3150397Sobrien events" in an out-of-band fashion, hence its name. The C++ language 3250397Sobrien (and many other OO-styled or functional languages) practically 3350397Sobrien requires such a mechanism, as otherwise it becomes very difficult 3450397Sobrien or even impossible to signal failure conditions in complex 3550397Sobrien situations. The traditional C++ example is when an error occurs in 3650397Sobrien the process of constructing an object; without such a mechanism, it 3750397Sobrien is impossible to signal that the error occurs without adding global 3850397Sobrien state variables and error checks around every object construction. 3950397Sobrien 4050397Sobrien The act of causing this event to occur is referred to as "throwing 4150397Sobrien an exception". (Alternate terms include "raising an exception" or 4250397Sobrien "signaling an exception".) The term "throw" is used because control 4350397Sobrien is returned to the callers of the function that is signaling the 4450397Sobrien exception, and thus there is the concept of "throwing" the 4550397Sobrien exception up the call stack. 4650397Sobrien 4790075Sobrien [ Add updated documentation on how to use this. ] */ 4850397Sobrien 4950397Sobrien 5090075Sobrien#include "config.h" 5190075Sobrien#include "system.h" 5290075Sobrien#include "rtl.h" 5390075Sobrien#include "tree.h" 5490075Sobrien#include "flags.h" 5590075Sobrien#include "function.h" 5690075Sobrien#include "expr.h" 5790075Sobrien#include "libfuncs.h" 5890075Sobrien#include "insn-config.h" 5990075Sobrien#include "except.h" 6090075Sobrien#include "integrate.h" 6190075Sobrien#include "hard-reg-set.h" 6290075Sobrien#include "basic-block.h" 6390075Sobrien#include "output.h" 6490075Sobrien#include "dwarf2asm.h" 6590075Sobrien#include "dwarf2out.h" 6690075Sobrien#include "dwarf2.h" 6790075Sobrien#include "toplev.h" 6890075Sobrien#include "hashtab.h" 6990075Sobrien#include "intl.h" 7090075Sobrien#include "ggc.h" 7190075Sobrien#include "tm_p.h" 7290075Sobrien#include "target.h" 7350397Sobrien 7490075Sobrien/* Provide defaults for stuff that may not be defined when using 7590075Sobrien sjlj exceptions. */ 7690075Sobrien#ifndef EH_RETURN_STACKADJ_RTX 7790075Sobrien#define EH_RETURN_STACKADJ_RTX 0 7890075Sobrien#endif 7990075Sobrien#ifndef EH_RETURN_HANDLER_RTX 8090075Sobrien#define EH_RETURN_HANDLER_RTX 0 8190075Sobrien#endif 8290075Sobrien#ifndef EH_RETURN_DATA_REGNO 8390075Sobrien#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM 8490075Sobrien#endif 8550397Sobrien 8650397Sobrien 8790075Sobrien/* Nonzero means enable synchronous exceptions for non-call instructions. */ 8890075Sobrienint flag_non_call_exceptions; 8950397Sobrien 9090075Sobrien/* Protect cleanup actions with must-not-throw regions, with a call 9190075Sobrien to the given failure handler. */ 9290075Sobrientree (*lang_protect_cleanup_actions) PARAMS ((void)); 9350397Sobrien 9490075Sobrien/* Return true if type A catches type B. */ 9590075Sobrienint (*lang_eh_type_covers) PARAMS ((tree a, tree b)); 9650397Sobrien 9790075Sobrien/* Map a type to a runtime object to match type. */ 9890075Sobrientree (*lang_eh_runtime_type) PARAMS ((tree)); 9950397Sobrien 10096263Sobrien/* A hash table of label to region number. */ 10150397Sobrien 10296263Sobrienstruct ehl_map_entry 10396263Sobrien{ 10496263Sobrien rtx label; 10596263Sobrien struct eh_region *region; 10696263Sobrien}; 10796263Sobrien 10896263Sobrienstatic htab_t exception_handler_label_map; 10996263Sobrien 11090075Sobrienstatic int call_site_base; 11190075Sobrienstatic unsigned int sjlj_funcdef_number; 11290075Sobrienstatic htab_t type_to_runtime_map; 11350397Sobrien 11490075Sobrien/* Describe the SjLj_Function_Context structure. */ 11590075Sobrienstatic tree sjlj_fc_type_node; 11690075Sobrienstatic int sjlj_fc_call_site_ofs; 11790075Sobrienstatic int sjlj_fc_data_ofs; 11890075Sobrienstatic int sjlj_fc_personality_ofs; 11990075Sobrienstatic int sjlj_fc_lsda_ofs; 12090075Sobrienstatic int sjlj_fc_jbuf_ofs; 12190075Sobrien 12290075Sobrien/* Describes one exception region. */ 12390075Sobrienstruct eh_region 12490075Sobrien{ 12590075Sobrien /* The immediately surrounding region. */ 12690075Sobrien struct eh_region *outer; 12750397Sobrien 12890075Sobrien /* The list of immediately contained regions. */ 12990075Sobrien struct eh_region *inner; 13090075Sobrien struct eh_region *next_peer; 13150397Sobrien 13290075Sobrien /* An identifier for this region. */ 13390075Sobrien int region_number; 13450397Sobrien 13596263Sobrien /* When a region is deleted, its parents inherit the REG_EH_REGION 13696263Sobrien numbers already assigned. */ 13796263Sobrien bitmap aka; 13896263Sobrien 13990075Sobrien /* Each region does exactly one thing. */ 14090075Sobrien enum eh_region_type 14190075Sobrien { 14290075Sobrien ERT_UNKNOWN = 0, 14390075Sobrien ERT_CLEANUP, 14490075Sobrien ERT_TRY, 14590075Sobrien ERT_CATCH, 14690075Sobrien ERT_ALLOWED_EXCEPTIONS, 14790075Sobrien ERT_MUST_NOT_THROW, 14890075Sobrien ERT_THROW, 14990075Sobrien ERT_FIXUP 15090075Sobrien } type; 15150397Sobrien 15290075Sobrien /* Holds the action to perform based on the preceding type. */ 15390075Sobrien union { 15490075Sobrien /* A list of catch blocks, a surrounding try block, 15590075Sobrien and the label for continuing after a catch. */ 15690075Sobrien struct { 15790075Sobrien struct eh_region *catch; 15890075Sobrien struct eh_region *last_catch; 15990075Sobrien struct eh_region *prev_try; 16090075Sobrien rtx continue_label; 16190075Sobrien } try; 16250397Sobrien 16390075Sobrien /* The list through the catch handlers, the list of type objects 16490075Sobrien matched, and the list of associated filters. */ 16590075Sobrien struct { 16690075Sobrien struct eh_region *next_catch; 16790075Sobrien struct eh_region *prev_catch; 16890075Sobrien tree type_list; 16990075Sobrien tree filter_list; 17090075Sobrien } catch; 17150397Sobrien 17290075Sobrien /* A tree_list of allowed types. */ 17390075Sobrien struct { 17490075Sobrien tree type_list; 17590075Sobrien int filter; 17690075Sobrien } allowed; 17750397Sobrien 17890075Sobrien /* The type given by a call to "throw foo();", or discovered 17990075Sobrien for a throw. */ 18090075Sobrien struct { 18190075Sobrien tree type; 18290075Sobrien } throw; 18350397Sobrien 18490075Sobrien /* Retain the cleanup expression even after expansion so that 18590075Sobrien we can match up fixup regions. */ 18690075Sobrien struct { 18790075Sobrien tree exp; 18890075Sobrien } cleanup; 18950397Sobrien 19090075Sobrien /* The real region (by expression and by pointer) that fixup code 19190075Sobrien should live in. */ 19290075Sobrien struct { 19390075Sobrien tree cleanup_exp; 19490075Sobrien struct eh_region *real_region; 19590075Sobrien } fixup; 19690075Sobrien } u; 19750397Sobrien 19890075Sobrien /* Entry point for this region's handler before landing pads are built. */ 19990075Sobrien rtx label; 20050397Sobrien 20190075Sobrien /* Entry point for this region's handler from the runtime eh library. */ 20290075Sobrien rtx landing_pad; 20350397Sobrien 20490075Sobrien /* Entry point for this region's handler from an inner region. */ 20590075Sobrien rtx post_landing_pad; 20650397Sobrien 20790075Sobrien /* The RESX insn for handing off control to the next outermost handler, 20890075Sobrien if appropriate. */ 20990075Sobrien rtx resume; 21090075Sobrien}; 21150397Sobrien 21290075Sobrien/* Used to save exception status for each function. */ 21390075Sobrienstruct eh_status 21490075Sobrien{ 21590075Sobrien /* The tree of all regions for this function. */ 21690075Sobrien struct eh_region *region_tree; 21750397Sobrien 21890075Sobrien /* The same information as an indexable array. */ 21990075Sobrien struct eh_region **region_array; 22050397Sobrien 22190075Sobrien /* The most recently open region. */ 22290075Sobrien struct eh_region *cur_region; 22350397Sobrien 22490075Sobrien /* This is the region for which we are processing catch blocks. */ 22590075Sobrien struct eh_region *try_region; 22650397Sobrien 22790075Sobrien /* A stack (TREE_LIST) of lists of handlers. The TREE_VALUE of each 22890075Sobrien node is itself a TREE_CHAINed list of handlers for regions that 22990075Sobrien are not yet closed. The TREE_VALUE of each entry contains the 23090075Sobrien handler for the corresponding entry on the ehstack. */ 23190075Sobrien tree protect_list; 23250397Sobrien 23390075Sobrien rtx filter; 23490075Sobrien rtx exc_ptr; 23550397Sobrien 23690075Sobrien int built_landing_pads; 23790075Sobrien int last_region_number; 23850397Sobrien 23990075Sobrien varray_type ttype_data; 24090075Sobrien varray_type ehspec_data; 24190075Sobrien varray_type action_record_data; 24250397Sobrien 24390075Sobrien struct call_site_record 24490075Sobrien { 24590075Sobrien rtx landing_pad; 24690075Sobrien int action; 24790075Sobrien } *call_site_data; 24890075Sobrien int call_site_data_used; 24990075Sobrien int call_site_data_size; 25050397Sobrien 25190075Sobrien rtx ehr_stackadj; 25290075Sobrien rtx ehr_handler; 25390075Sobrien rtx ehr_label; 25450397Sobrien 25590075Sobrien rtx sjlj_fc; 25690075Sobrien rtx sjlj_exit_after; 25790075Sobrien}; 25850397Sobrien 25990075Sobrien 26090075Sobrienstatic void mark_eh_region PARAMS ((struct eh_region *)); 26196263Sobrienstatic int mark_ehl_map_entry PARAMS ((PTR *, PTR)); 26296263Sobrienstatic void mark_ehl_map PARAMS ((void *)); 26350397Sobrien 26496263Sobrienstatic void free_region PARAMS ((struct eh_region *)); 26596263Sobrien 26690075Sobrienstatic int t2r_eq PARAMS ((const PTR, 26790075Sobrien const PTR)); 26890075Sobrienstatic hashval_t t2r_hash PARAMS ((const PTR)); 26990075Sobrienstatic int t2r_mark_1 PARAMS ((PTR *, PTR)); 27090075Sobrienstatic void t2r_mark PARAMS ((PTR)); 27190075Sobrienstatic void add_type_for_runtime PARAMS ((tree)); 27290075Sobrienstatic tree lookup_type_for_runtime PARAMS ((tree)); 27350397Sobrien 27490075Sobrienstatic struct eh_region *expand_eh_region_end PARAMS ((void)); 27550397Sobrien 27690075Sobrienstatic rtx get_exception_filter PARAMS ((struct function *)); 27750397Sobrien 27890075Sobrienstatic void collect_eh_region_array PARAMS ((void)); 27990075Sobrienstatic void resolve_fixup_regions PARAMS ((void)); 28090075Sobrienstatic void remove_fixup_regions PARAMS ((void)); 28190075Sobrienstatic void remove_unreachable_regions PARAMS ((rtx)); 28290075Sobrienstatic void convert_from_eh_region_ranges_1 PARAMS ((rtx *, int *, int)); 28350397Sobrien 28490075Sobrienstatic struct eh_region *duplicate_eh_region_1 PARAMS ((struct eh_region *, 28590075Sobrien struct inline_remap *)); 28690075Sobrienstatic void duplicate_eh_region_2 PARAMS ((struct eh_region *, 28790075Sobrien struct eh_region **)); 28890075Sobrienstatic int ttypes_filter_eq PARAMS ((const PTR, 28990075Sobrien const PTR)); 29090075Sobrienstatic hashval_t ttypes_filter_hash PARAMS ((const PTR)); 29190075Sobrienstatic int ehspec_filter_eq PARAMS ((const PTR, 29290075Sobrien const PTR)); 29390075Sobrienstatic hashval_t ehspec_filter_hash PARAMS ((const PTR)); 29490075Sobrienstatic int add_ttypes_entry PARAMS ((htab_t, tree)); 29590075Sobrienstatic int add_ehspec_entry PARAMS ((htab_t, htab_t, 29690075Sobrien tree)); 29790075Sobrienstatic void assign_filter_values PARAMS ((void)); 29890075Sobrienstatic void build_post_landing_pads PARAMS ((void)); 29990075Sobrienstatic void connect_post_landing_pads PARAMS ((void)); 30090075Sobrienstatic void dw2_build_landing_pads PARAMS ((void)); 30150397Sobrien 30290075Sobrienstruct sjlj_lp_info; 30390075Sobrienstatic bool sjlj_find_directly_reachable_regions 30490075Sobrien PARAMS ((struct sjlj_lp_info *)); 30590075Sobrienstatic void sjlj_assign_call_site_values 30690075Sobrien PARAMS ((rtx, struct sjlj_lp_info *)); 30790075Sobrienstatic void sjlj_mark_call_sites 30890075Sobrien PARAMS ((struct sjlj_lp_info *)); 30990075Sobrienstatic void sjlj_emit_function_enter PARAMS ((rtx)); 31090075Sobrienstatic void sjlj_emit_function_exit PARAMS ((void)); 31190075Sobrienstatic void sjlj_emit_dispatch_table 31290075Sobrien PARAMS ((rtx, struct sjlj_lp_info *)); 31390075Sobrienstatic void sjlj_build_landing_pads PARAMS ((void)); 31450397Sobrien 31596263Sobrienstatic hashval_t ehl_hash PARAMS ((const PTR)); 31696263Sobrienstatic int ehl_eq PARAMS ((const PTR, 31796263Sobrien const PTR)); 31896263Sobrienstatic void ehl_free PARAMS ((PTR)); 31996263Sobrienstatic void add_ehl_entry PARAMS ((rtx, 32096263Sobrien struct eh_region *)); 32190075Sobrienstatic void remove_exception_handler_label PARAMS ((rtx)); 32290075Sobrienstatic void remove_eh_handler PARAMS ((struct eh_region *)); 32396263Sobrienstatic int for_each_eh_label_1 PARAMS ((PTR *, PTR)); 32450397Sobrien 32590075Sobrienstruct reachable_info; 32650397Sobrien 32790075Sobrien/* The return value of reachable_next_level. */ 32890075Sobrienenum reachable_code 32990075Sobrien{ 33090075Sobrien /* The given exception is not processed by the given region. */ 33190075Sobrien RNL_NOT_CAUGHT, 33290075Sobrien /* The given exception may need processing by the given region. */ 33390075Sobrien RNL_MAYBE_CAUGHT, 33490075Sobrien /* The given exception is completely processed by the given region. */ 33590075Sobrien RNL_CAUGHT, 33690075Sobrien /* The given exception is completely processed by the runtime. */ 33790075Sobrien RNL_BLOCKED 33890075Sobrien}; 33950397Sobrien 34090075Sobrienstatic int check_handled PARAMS ((tree, tree)); 34190075Sobrienstatic void add_reachable_handler 34290075Sobrien PARAMS ((struct reachable_info *, struct eh_region *, 34390075Sobrien struct eh_region *)); 34490075Sobrienstatic enum reachable_code reachable_next_level 34590075Sobrien PARAMS ((struct eh_region *, tree, struct reachable_info *)); 34650397Sobrien 34790075Sobrienstatic int action_record_eq PARAMS ((const PTR, 34890075Sobrien const PTR)); 34990075Sobrienstatic hashval_t action_record_hash PARAMS ((const PTR)); 35090075Sobrienstatic int add_action_record PARAMS ((htab_t, int, int)); 35190075Sobrienstatic int collect_one_action_chain PARAMS ((htab_t, 35290075Sobrien struct eh_region *)); 35390075Sobrienstatic int add_call_site PARAMS ((rtx, int)); 35450397Sobrien 35590075Sobrienstatic void push_uleb128 PARAMS ((varray_type *, 35690075Sobrien unsigned int)); 35790075Sobrienstatic void push_sleb128 PARAMS ((varray_type *, int)); 35890075Sobrien#ifndef HAVE_AS_LEB128 35990075Sobrienstatic int dw2_size_of_call_site_table PARAMS ((void)); 36090075Sobrienstatic int sjlj_size_of_call_site_table PARAMS ((void)); 36190075Sobrien#endif 36290075Sobrienstatic void dw2_output_call_site_table PARAMS ((void)); 36390075Sobrienstatic void sjlj_output_call_site_table PARAMS ((void)); 36450397Sobrien 36590075Sobrien 36690075Sobrien/* Routine to see if exception handling is turned on. 36790075Sobrien DO_WARN is non-zero if we want to inform the user that exception 36890075Sobrien handling is turned off. 36950397Sobrien 37090075Sobrien This is used to ensure that -fexceptions has been specified if the 37190075Sobrien compiler tries to use any exception-specific functions. */ 37250397Sobrien 37390075Sobrienint 37490075Sobriendoing_eh (do_warn) 37590075Sobrien int do_warn; 37690075Sobrien{ 37790075Sobrien if (! flag_exceptions) 37890075Sobrien { 37990075Sobrien static int warned = 0; 38090075Sobrien if (! warned && do_warn) 38190075Sobrien { 38290075Sobrien error ("exception handling disabled, use -fexceptions to enable"); 38390075Sobrien warned = 1; 38490075Sobrien } 38590075Sobrien return 0; 38690075Sobrien } 38790075Sobrien return 1; 38890075Sobrien} 38950397Sobrien 39090075Sobrien 39190075Sobrienvoid 39290075Sobrieninit_eh () 39390075Sobrien{ 39496263Sobrien ggc_add_root (&exception_handler_label_map, 1, 1, mark_ehl_map); 39550397Sobrien 39690075Sobrien if (! flag_exceptions) 39790075Sobrien return; 39850397Sobrien 39990075Sobrien type_to_runtime_map = htab_create (31, t2r_hash, t2r_eq, NULL); 40090075Sobrien ggc_add_root (&type_to_runtime_map, 1, sizeof (htab_t), t2r_mark); 40150397Sobrien 40290075Sobrien /* Create the SjLj_Function_Context structure. This should match 40390075Sobrien the definition in unwind-sjlj.c. */ 40490075Sobrien if (USING_SJLJ_EXCEPTIONS) 40590075Sobrien { 40690075Sobrien tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp; 40750397Sobrien 40890075Sobrien sjlj_fc_type_node = make_lang_type (RECORD_TYPE); 40990075Sobrien ggc_add_tree_root (&sjlj_fc_type_node, 1); 41050397Sobrien 41190075Sobrien f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"), 41290075Sobrien build_pointer_type (sjlj_fc_type_node)); 41390075Sobrien DECL_FIELD_CONTEXT (f_prev) = sjlj_fc_type_node; 41450397Sobrien 41590075Sobrien f_cs = build_decl (FIELD_DECL, get_identifier ("__call_site"), 41690075Sobrien integer_type_node); 41790075Sobrien DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node; 41850397Sobrien 41990075Sobrien tmp = build_index_type (build_int_2 (4 - 1, 0)); 42090075Sobrien tmp = build_array_type (type_for_mode (word_mode, 1), tmp); 42190075Sobrien f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp); 42290075Sobrien DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node; 42350397Sobrien 42490075Sobrien f_per = build_decl (FIELD_DECL, get_identifier ("__personality"), 42590075Sobrien ptr_type_node); 42690075Sobrien DECL_FIELD_CONTEXT (f_per) = sjlj_fc_type_node; 42750397Sobrien 42890075Sobrien f_lsda = build_decl (FIELD_DECL, get_identifier ("__lsda"), 42990075Sobrien ptr_type_node); 43090075Sobrien DECL_FIELD_CONTEXT (f_lsda) = sjlj_fc_type_node; 43150397Sobrien 43290075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP 43390075Sobrien#ifdef JMP_BUF_SIZE 43490075Sobrien tmp = build_int_2 (JMP_BUF_SIZE - 1, 0); 43590075Sobrien#else 43690075Sobrien /* Should be large enough for most systems, if it is not, 43790075Sobrien JMP_BUF_SIZE should be defined with the proper value. It will 43890075Sobrien also tend to be larger than necessary for most systems, a more 43990075Sobrien optimal port will define JMP_BUF_SIZE. */ 44090075Sobrien tmp = build_int_2 (FIRST_PSEUDO_REGISTER + 2 - 1, 0); 44190075Sobrien#endif 44290075Sobrien#else 44390075Sobrien /* This is 2 for builtin_setjmp, plus whatever the target requires 44490075Sobrien via STACK_SAVEAREA_MODE (SAVE_NONLOCAL). */ 44590075Sobrien tmp = build_int_2 ((GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL)) 44690075Sobrien / GET_MODE_SIZE (Pmode)) + 2 - 1, 0); 44790075Sobrien#endif 44890075Sobrien tmp = build_index_type (tmp); 44990075Sobrien tmp = build_array_type (ptr_type_node, tmp); 45090075Sobrien f_jbuf = build_decl (FIELD_DECL, get_identifier ("__jbuf"), tmp); 45190075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP 45290075Sobrien /* We don't know what the alignment requirements of the 45390075Sobrien runtime's jmp_buf has. Overestimate. */ 45490075Sobrien DECL_ALIGN (f_jbuf) = BIGGEST_ALIGNMENT; 45590075Sobrien DECL_USER_ALIGN (f_jbuf) = 1; 45690075Sobrien#endif 45790075Sobrien DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node; 45850397Sobrien 45990075Sobrien TYPE_FIELDS (sjlj_fc_type_node) = f_prev; 46090075Sobrien TREE_CHAIN (f_prev) = f_cs; 46190075Sobrien TREE_CHAIN (f_cs) = f_data; 46290075Sobrien TREE_CHAIN (f_data) = f_per; 46390075Sobrien TREE_CHAIN (f_per) = f_lsda; 46490075Sobrien TREE_CHAIN (f_lsda) = f_jbuf; 46550397Sobrien 46690075Sobrien layout_type (sjlj_fc_type_node); 46750397Sobrien 46890075Sobrien /* Cache the interesting field offsets so that we have 46990075Sobrien easy access from rtl. */ 47090075Sobrien sjlj_fc_call_site_ofs 47190075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_cs), 1) 47290075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_cs), 1) / BITS_PER_UNIT); 47390075Sobrien sjlj_fc_data_ofs 47490075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_data), 1) 47590075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_data), 1) / BITS_PER_UNIT); 47690075Sobrien sjlj_fc_personality_ofs 47790075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_per), 1) 47890075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_per), 1) / BITS_PER_UNIT); 47990075Sobrien sjlj_fc_lsda_ofs 48090075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_lsda), 1) 48190075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_lsda), 1) / BITS_PER_UNIT); 48290075Sobrien sjlj_fc_jbuf_ofs 48390075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_jbuf), 1) 48490075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_jbuf), 1) / BITS_PER_UNIT); 48590075Sobrien } 48690075Sobrien} 48750397Sobrien 48890075Sobrienvoid 48990075Sobrieninit_eh_for_function () 49090075Sobrien{ 49190075Sobrien cfun->eh = (struct eh_status *) xcalloc (1, sizeof (struct eh_status)); 49290075Sobrien} 49350397Sobrien 49490075Sobrien/* Mark EH for GC. */ 49550397Sobrien 49690075Sobrienstatic void 49790075Sobrienmark_eh_region (region) 49890075Sobrien struct eh_region *region; 49990075Sobrien{ 50090075Sobrien if (! region) 50190075Sobrien return; 50250397Sobrien 50390075Sobrien switch (region->type) 50490075Sobrien { 50590075Sobrien case ERT_UNKNOWN: 50690075Sobrien /* This can happen if a nested function is inside the body of a region 50790075Sobrien and we do a GC as part of processing it. */ 50890075Sobrien break; 50990075Sobrien case ERT_CLEANUP: 51090075Sobrien ggc_mark_tree (region->u.cleanup.exp); 51190075Sobrien break; 51290075Sobrien case ERT_TRY: 51390075Sobrien ggc_mark_rtx (region->u.try.continue_label); 51490075Sobrien break; 51590075Sobrien case ERT_CATCH: 51690075Sobrien ggc_mark_tree (region->u.catch.type_list); 51790075Sobrien ggc_mark_tree (region->u.catch.filter_list); 51890075Sobrien break; 51990075Sobrien case ERT_ALLOWED_EXCEPTIONS: 52090075Sobrien ggc_mark_tree (region->u.allowed.type_list); 52190075Sobrien break; 52290075Sobrien case ERT_MUST_NOT_THROW: 52390075Sobrien break; 52490075Sobrien case ERT_THROW: 52590075Sobrien ggc_mark_tree (region->u.throw.type); 52690075Sobrien break; 52790075Sobrien case ERT_FIXUP: 52890075Sobrien ggc_mark_tree (region->u.fixup.cleanup_exp); 52990075Sobrien break; 53090075Sobrien default: 53190075Sobrien abort (); 53290075Sobrien } 53350397Sobrien 53490075Sobrien ggc_mark_rtx (region->label); 53590075Sobrien ggc_mark_rtx (region->resume); 53690075Sobrien ggc_mark_rtx (region->landing_pad); 53790075Sobrien ggc_mark_rtx (region->post_landing_pad); 53890075Sobrien} 53950397Sobrien 54096263Sobrienstatic int 54196263Sobrienmark_ehl_map_entry (pentry, data) 54296263Sobrien PTR *pentry; 54396263Sobrien PTR data ATTRIBUTE_UNUSED; 54496263Sobrien{ 54596263Sobrien struct ehl_map_entry *entry = *(struct ehl_map_entry **) pentry; 54696263Sobrien ggc_mark_rtx (entry->label); 54796263Sobrien return 1; 54896263Sobrien} 54996263Sobrien 55096263Sobrienstatic void 55196263Sobrienmark_ehl_map (pp) 55296263Sobrien void *pp; 55396263Sobrien{ 55496263Sobrien htab_t map = *(htab_t *) pp; 55596263Sobrien if (map) 55696263Sobrien htab_traverse (map, mark_ehl_map_entry, NULL); 55796263Sobrien} 55896263Sobrien 55990075Sobrienvoid 56090075Sobrienmark_eh_status (eh) 56190075Sobrien struct eh_status *eh; 56290075Sobrien{ 56390075Sobrien int i; 56450397Sobrien 56590075Sobrien if (eh == 0) 56690075Sobrien return; 56750397Sobrien 56890075Sobrien /* If we've called collect_eh_region_array, use it. Otherwise walk 56990075Sobrien the tree non-recursively. */ 57090075Sobrien if (eh->region_array) 57190075Sobrien { 57290075Sobrien for (i = eh->last_region_number; i > 0; --i) 57390075Sobrien { 57490075Sobrien struct eh_region *r = eh->region_array[i]; 57590075Sobrien if (r && r->region_number == i) 57690075Sobrien mark_eh_region (r); 57790075Sobrien } 57890075Sobrien } 57990075Sobrien else if (eh->region_tree) 58090075Sobrien { 58190075Sobrien struct eh_region *r = eh->region_tree; 58290075Sobrien while (1) 58390075Sobrien { 58490075Sobrien mark_eh_region (r); 58590075Sobrien if (r->inner) 58690075Sobrien r = r->inner; 58790075Sobrien else if (r->next_peer) 58890075Sobrien r = r->next_peer; 58990075Sobrien else 59090075Sobrien { 59190075Sobrien do { 59290075Sobrien r = r->outer; 59390075Sobrien if (r == NULL) 59490075Sobrien goto tree_done; 59590075Sobrien } while (r->next_peer == NULL); 59690075Sobrien r = r->next_peer; 59790075Sobrien } 59890075Sobrien } 59990075Sobrien tree_done:; 60090075Sobrien } 60150397Sobrien 60290075Sobrien ggc_mark_tree (eh->protect_list); 60390075Sobrien ggc_mark_rtx (eh->filter); 60490075Sobrien ggc_mark_rtx (eh->exc_ptr); 60590075Sobrien ggc_mark_tree_varray (eh->ttype_data); 60650397Sobrien 60790075Sobrien if (eh->call_site_data) 60890075Sobrien { 60990075Sobrien for (i = eh->call_site_data_used - 1; i >= 0; --i) 61090075Sobrien ggc_mark_rtx (eh->call_site_data[i].landing_pad); 61190075Sobrien } 61250397Sobrien 61390075Sobrien ggc_mark_rtx (eh->ehr_stackadj); 61490075Sobrien ggc_mark_rtx (eh->ehr_handler); 61590075Sobrien ggc_mark_rtx (eh->ehr_label); 61650397Sobrien 61790075Sobrien ggc_mark_rtx (eh->sjlj_fc); 61890075Sobrien ggc_mark_rtx (eh->sjlj_exit_after); 61990075Sobrien} 62050397Sobrien 62196263Sobrienstatic inline void 62296263Sobrienfree_region (r) 62396263Sobrien struct eh_region *r; 62496263Sobrien{ 62596263Sobrien /* Note that the aka bitmap is freed by regset_release_memory. But if 62696263Sobrien we ever replace with a non-obstack implementation, this would be 62796263Sobrien the place to do it. */ 62896263Sobrien free (r); 62996263Sobrien} 63096263Sobrien 63190075Sobrienvoid 63290075Sobrienfree_eh_status (f) 63390075Sobrien struct function *f; 63490075Sobrien{ 63590075Sobrien struct eh_status *eh = f->eh; 63650397Sobrien 63790075Sobrien if (eh->region_array) 63890075Sobrien { 63990075Sobrien int i; 64090075Sobrien for (i = eh->last_region_number; i > 0; --i) 64190075Sobrien { 64290075Sobrien struct eh_region *r = eh->region_array[i]; 64390075Sobrien /* Mind we don't free a region struct more than once. */ 64490075Sobrien if (r && r->region_number == i) 64596263Sobrien free_region (r); 64690075Sobrien } 64790075Sobrien free (eh->region_array); 64890075Sobrien } 64990075Sobrien else if (eh->region_tree) 65090075Sobrien { 65190075Sobrien struct eh_region *next, *r = eh->region_tree; 65290075Sobrien while (1) 65390075Sobrien { 65490075Sobrien if (r->inner) 65590075Sobrien r = r->inner; 65690075Sobrien else if (r->next_peer) 65790075Sobrien { 65890075Sobrien next = r->next_peer; 65996263Sobrien free_region (r); 66090075Sobrien r = next; 66190075Sobrien } 66290075Sobrien else 66390075Sobrien { 66490075Sobrien do { 66590075Sobrien next = r->outer; 66696263Sobrien free_region (r); 66790075Sobrien r = next; 66890075Sobrien if (r == NULL) 66990075Sobrien goto tree_done; 67090075Sobrien } while (r->next_peer == NULL); 67190075Sobrien next = r->next_peer; 67296263Sobrien free_region (r); 67390075Sobrien r = next; 67490075Sobrien } 67590075Sobrien } 67690075Sobrien tree_done:; 67790075Sobrien } 67850397Sobrien 67990075Sobrien VARRAY_FREE (eh->ttype_data); 68090075Sobrien VARRAY_FREE (eh->ehspec_data); 68190075Sobrien VARRAY_FREE (eh->action_record_data); 68290075Sobrien if (eh->call_site_data) 68390075Sobrien free (eh->call_site_data); 68450397Sobrien 68590075Sobrien free (eh); 68690075Sobrien f->eh = NULL; 68796263Sobrien 68896263Sobrien if (exception_handler_label_map) 68996263Sobrien { 69096263Sobrien htab_delete (exception_handler_label_map); 69196263Sobrien exception_handler_label_map = NULL; 69296263Sobrien } 69390075Sobrien} 69450397Sobrien 69590075Sobrien 69690075Sobrien/* Start an exception handling region. All instructions emitted 69790075Sobrien after this point are considered to be part of the region until 69890075Sobrien expand_eh_region_end is invoked. */ 69950397Sobrien 70090075Sobrienvoid 70190075Sobrienexpand_eh_region_start () 70290075Sobrien{ 70390075Sobrien struct eh_region *new_region; 70490075Sobrien struct eh_region *cur_region; 70590075Sobrien rtx note; 70652284Sobrien 70790075Sobrien if (! doing_eh (0)) 70890075Sobrien return; 70952284Sobrien 71090075Sobrien /* Insert a new blank region as a leaf in the tree. */ 71190075Sobrien new_region = (struct eh_region *) xcalloc (1, sizeof (*new_region)); 71290075Sobrien cur_region = cfun->eh->cur_region; 71390075Sobrien new_region->outer = cur_region; 71490075Sobrien if (cur_region) 71590075Sobrien { 71690075Sobrien new_region->next_peer = cur_region->inner; 71790075Sobrien cur_region->inner = new_region; 71890075Sobrien } 71990075Sobrien else 72090075Sobrien { 72190075Sobrien new_region->next_peer = cfun->eh->region_tree; 72290075Sobrien cfun->eh->region_tree = new_region; 72390075Sobrien } 72490075Sobrien cfun->eh->cur_region = new_region; 72552284Sobrien 72690075Sobrien /* Create a note marking the start of this region. */ 72790075Sobrien new_region->region_number = ++cfun->eh->last_region_number; 72890075Sobrien note = emit_note (NULL, NOTE_INSN_EH_REGION_BEG); 72990075Sobrien NOTE_EH_HANDLER (note) = new_region->region_number; 73090075Sobrien} 73152284Sobrien 73290075Sobrien/* Common code to end a region. Returns the region just ended. */ 73352284Sobrien 73490075Sobrienstatic struct eh_region * 73590075Sobrienexpand_eh_region_end () 73690075Sobrien{ 73790075Sobrien struct eh_region *cur_region = cfun->eh->cur_region; 73890075Sobrien rtx note; 73952284Sobrien 74090075Sobrien /* Create a note marking the end of this region. */ 74190075Sobrien note = emit_note (NULL, NOTE_INSN_EH_REGION_END); 74290075Sobrien NOTE_EH_HANDLER (note) = cur_region->region_number; 74352284Sobrien 74490075Sobrien /* Pop. */ 74590075Sobrien cfun->eh->cur_region = cur_region->outer; 74652284Sobrien 74790075Sobrien return cur_region; 74890075Sobrien} 74950397Sobrien 75090075Sobrien/* End an exception handling region for a cleanup. HANDLER is an 75190075Sobrien expression to expand for the cleanup. */ 75250397Sobrien 75390075Sobrienvoid 75490075Sobrienexpand_eh_region_end_cleanup (handler) 75590075Sobrien tree handler; 75652284Sobrien{ 75790075Sobrien struct eh_region *region; 75890075Sobrien tree protect_cleanup_actions; 75990075Sobrien rtx around_label; 76090075Sobrien rtx data_save[2]; 76152284Sobrien 76290075Sobrien if (! doing_eh (0)) 76390075Sobrien return; 76452284Sobrien 76590075Sobrien region = expand_eh_region_end (); 76690075Sobrien region->type = ERT_CLEANUP; 76790075Sobrien region->label = gen_label_rtx (); 76890075Sobrien region->u.cleanup.exp = handler; 76952284Sobrien 77090075Sobrien around_label = gen_label_rtx (); 77190075Sobrien emit_jump (around_label); 77252284Sobrien 77390075Sobrien emit_label (region->label); 77450397Sobrien 77590075Sobrien /* Give the language a chance to specify an action to be taken if an 77690075Sobrien exception is thrown that would propagate out of the HANDLER. */ 77790075Sobrien protect_cleanup_actions 77890075Sobrien = (lang_protect_cleanup_actions 77990075Sobrien ? (*lang_protect_cleanup_actions) () 78090075Sobrien : NULL_TREE); 78150397Sobrien 78290075Sobrien if (protect_cleanup_actions) 78390075Sobrien expand_eh_region_start (); 78450397Sobrien 78590075Sobrien /* In case this cleanup involves an inline destructor with a try block in 78690075Sobrien it, we need to save the EH return data registers around it. */ 78790075Sobrien data_save[0] = gen_reg_rtx (Pmode); 78890075Sobrien emit_move_insn (data_save[0], get_exception_pointer (cfun)); 78990075Sobrien data_save[1] = gen_reg_rtx (word_mode); 79090075Sobrien emit_move_insn (data_save[1], get_exception_filter (cfun)); 79150397Sobrien 79290075Sobrien expand_expr (handler, const0_rtx, VOIDmode, 0); 79350397Sobrien 79490075Sobrien emit_move_insn (cfun->eh->exc_ptr, data_save[0]); 79590075Sobrien emit_move_insn (cfun->eh->filter, data_save[1]); 79650397Sobrien 79790075Sobrien if (protect_cleanup_actions) 79890075Sobrien expand_eh_region_end_must_not_throw (protect_cleanup_actions); 79950397Sobrien 80090075Sobrien /* We need any stack adjustment complete before the around_label. */ 80190075Sobrien do_pending_stack_adjust (); 80290075Sobrien 80390075Sobrien /* We delay the generation of the _Unwind_Resume until we generate 80490075Sobrien landing pads. We emit a marker here so as to get good control 80590075Sobrien flow data in the meantime. */ 80690075Sobrien region->resume 80790075Sobrien = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number)); 80890075Sobrien emit_barrier (); 80990075Sobrien 81090075Sobrien emit_label (around_label); 81150397Sobrien} 81250397Sobrien 81390075Sobrien/* End an exception handling region for a try block, and prepares 81490075Sobrien for subsequent calls to expand_start_catch. */ 81550397Sobrien 81690075Sobrienvoid 81790075Sobrienexpand_start_all_catch () 81850397Sobrien{ 81990075Sobrien struct eh_region *region; 82050397Sobrien 82190075Sobrien if (! doing_eh (1)) 82290075Sobrien return; 82350397Sobrien 82490075Sobrien region = expand_eh_region_end (); 82590075Sobrien region->type = ERT_TRY; 82690075Sobrien region->u.try.prev_try = cfun->eh->try_region; 82790075Sobrien region->u.try.continue_label = gen_label_rtx (); 82850397Sobrien 82990075Sobrien cfun->eh->try_region = region; 83090075Sobrien 83190075Sobrien emit_jump (region->u.try.continue_label); 83250397Sobrien} 83350397Sobrien 83490075Sobrien/* Begin a catch clause. TYPE is the type caught, a list of such types, or 83590075Sobrien null if this is a catch-all clause. Providing a type list enables to 83690075Sobrien associate the catch region with potentially several exception types, which 83790075Sobrien is useful e.g. for Ada. */ 83850397Sobrien 83990075Sobrienvoid 84090075Sobrienexpand_start_catch (type_or_list) 84190075Sobrien tree type_or_list; 84250397Sobrien{ 84390075Sobrien struct eh_region *t, *c, *l; 84490075Sobrien tree type_list; 84550397Sobrien 84690075Sobrien if (! doing_eh (0)) 84790075Sobrien return; 84890075Sobrien 84990075Sobrien type_list = type_or_list; 85090075Sobrien 85190075Sobrien if (type_or_list) 85290075Sobrien { 85390075Sobrien /* Ensure to always end up with a type list to normalize further 85490075Sobrien processing, then register each type against the runtime types 85590075Sobrien map. */ 85690075Sobrien tree type_node; 85790075Sobrien 85890075Sobrien if (TREE_CODE (type_or_list) != TREE_LIST) 85990075Sobrien type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE); 86090075Sobrien 86190075Sobrien type_node = type_list; 86290075Sobrien for (; type_node; type_node = TREE_CHAIN (type_node)) 86390075Sobrien add_type_for_runtime (TREE_VALUE (type_node)); 86490075Sobrien } 86590075Sobrien 86690075Sobrien expand_eh_region_start (); 86790075Sobrien 86890075Sobrien t = cfun->eh->try_region; 86990075Sobrien c = cfun->eh->cur_region; 87090075Sobrien c->type = ERT_CATCH; 87190075Sobrien c->u.catch.type_list = type_list; 87290075Sobrien c->label = gen_label_rtx (); 87390075Sobrien 87490075Sobrien l = t->u.try.last_catch; 87590075Sobrien c->u.catch.prev_catch = l; 87690075Sobrien if (l) 87790075Sobrien l->u.catch.next_catch = c; 87852284Sobrien else 87990075Sobrien t->u.try.catch = c; 88090075Sobrien t->u.try.last_catch = c; 88150397Sobrien 88290075Sobrien emit_label (c->label); 88350397Sobrien} 88450397Sobrien 88590075Sobrien/* End a catch clause. Control will resume after the try/catch block. */ 88690075Sobrien 88790075Sobrienvoid 88890075Sobrienexpand_end_catch () 88950397Sobrien{ 89090075Sobrien struct eh_region *try_region, *catch_region; 89150397Sobrien 89290075Sobrien if (! doing_eh (0)) 89390075Sobrien return; 89450397Sobrien 89590075Sobrien catch_region = expand_eh_region_end (); 89690075Sobrien try_region = cfun->eh->try_region; 89750397Sobrien 89890075Sobrien emit_jump (try_region->u.try.continue_label); 89950397Sobrien} 90050397Sobrien 90190075Sobrien/* End a sequence of catch handlers for a try block. */ 90250397Sobrien 90390075Sobrienvoid 90490075Sobrienexpand_end_all_catch () 90550397Sobrien{ 90690075Sobrien struct eh_region *try_region; 90750397Sobrien 90890075Sobrien if (! doing_eh (0)) 90990075Sobrien return; 91050397Sobrien 91190075Sobrien try_region = cfun->eh->try_region; 91290075Sobrien cfun->eh->try_region = try_region->u.try.prev_try; 91390075Sobrien 91490075Sobrien emit_label (try_region->u.try.continue_label); 91550397Sobrien} 91650397Sobrien 91790075Sobrien/* End an exception region for an exception type filter. ALLOWED is a 91890075Sobrien TREE_LIST of types to be matched by the runtime. FAILURE is an 91990075Sobrien expression to invoke if a mismatch occurs. 92050397Sobrien 92190075Sobrien ??? We could use these semantics for calls to rethrow, too; if we can 92290075Sobrien see the surrounding catch clause, we know that the exception we're 92390075Sobrien rethrowing satisfies the "filter" of the catch type. */ 92490075Sobrien 92590075Sobrienvoid 92690075Sobrienexpand_eh_region_end_allowed (allowed, failure) 92790075Sobrien tree allowed, failure; 92850397Sobrien{ 92990075Sobrien struct eh_region *region; 93090075Sobrien rtx around_label; 93150397Sobrien 93290075Sobrien if (! doing_eh (0)) 93390075Sobrien return; 93450397Sobrien 93590075Sobrien region = expand_eh_region_end (); 93690075Sobrien region->type = ERT_ALLOWED_EXCEPTIONS; 93790075Sobrien region->u.allowed.type_list = allowed; 93890075Sobrien region->label = gen_label_rtx (); 93950397Sobrien 94090075Sobrien for (; allowed ; allowed = TREE_CHAIN (allowed)) 94190075Sobrien add_type_for_runtime (TREE_VALUE (allowed)); 94250397Sobrien 94390075Sobrien /* We must emit the call to FAILURE here, so that if this function 94490075Sobrien throws a different exception, that it will be processed by the 94590075Sobrien correct region. */ 94690075Sobrien 94790075Sobrien around_label = gen_label_rtx (); 94890075Sobrien emit_jump (around_label); 94990075Sobrien 95090075Sobrien emit_label (region->label); 95190075Sobrien expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL); 95290075Sobrien /* We must adjust the stack before we reach the AROUND_LABEL because 95390075Sobrien the call to FAILURE does not occur on all paths to the 95490075Sobrien AROUND_LABEL. */ 95590075Sobrien do_pending_stack_adjust (); 95690075Sobrien 95790075Sobrien emit_label (around_label); 95850397Sobrien} 95950397Sobrien 96090075Sobrien/* End an exception region for a must-not-throw filter. FAILURE is an 96190075Sobrien expression invoke if an uncaught exception propagates this far. 96290075Sobrien 96390075Sobrien This is conceptually identical to expand_eh_region_end_allowed with 96490075Sobrien an empty allowed list (if you passed "std::terminate" instead of 96590075Sobrien "__cxa_call_unexpected"), but they are represented differently in 96690075Sobrien the C++ LSDA. */ 96790075Sobrien 96890075Sobrienvoid 96990075Sobrienexpand_eh_region_end_must_not_throw (failure) 97090075Sobrien tree failure; 97150397Sobrien{ 97290075Sobrien struct eh_region *region; 97390075Sobrien rtx around_label; 97474722Sobrien 97590075Sobrien if (! doing_eh (0)) 97690075Sobrien return; 97774722Sobrien 97890075Sobrien region = expand_eh_region_end (); 97990075Sobrien region->type = ERT_MUST_NOT_THROW; 98090075Sobrien region->label = gen_label_rtx (); 98174722Sobrien 98290075Sobrien /* We must emit the call to FAILURE here, so that if this function 98390075Sobrien throws a different exception, that it will be processed by the 98490075Sobrien correct region. */ 98590075Sobrien 98690075Sobrien around_label = gen_label_rtx (); 98790075Sobrien emit_jump (around_label); 98890075Sobrien 98990075Sobrien emit_label (region->label); 99090075Sobrien expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL); 99190075Sobrien 99290075Sobrien emit_label (around_label); 99350397Sobrien} 99450397Sobrien 99590075Sobrien/* End an exception region for a throw. No handling goes on here, 99690075Sobrien but it's the easiest way for the front-end to indicate what type 99790075Sobrien is being thrown. */ 99890075Sobrien 99990075Sobrienvoid 100090075Sobrienexpand_eh_region_end_throw (type) 100190075Sobrien tree type; 100250397Sobrien{ 100390075Sobrien struct eh_region *region; 100450397Sobrien 100590075Sobrien if (! doing_eh (0)) 100690075Sobrien return; 100750397Sobrien 100890075Sobrien region = expand_eh_region_end (); 100990075Sobrien region->type = ERT_THROW; 101090075Sobrien region->u.throw.type = type; 101190075Sobrien} 101250397Sobrien 101390075Sobrien/* End a fixup region. Within this region the cleanups for the immediately 101490075Sobrien enclosing region are _not_ run. This is used for goto cleanup to avoid 101590075Sobrien destroying an object twice. 101650397Sobrien 101790075Sobrien This would be an extraordinarily simple prospect, were it not for the 101890075Sobrien fact that we don't actually know what the immediately enclosing region 101990075Sobrien is. This surprising fact is because expand_cleanups is currently 102090075Sobrien generating a sequence that it will insert somewhere else. We collect 102190075Sobrien the proper notion of "enclosing" in convert_from_eh_region_ranges. */ 102250397Sobrien 102390075Sobrienvoid 102490075Sobrienexpand_eh_region_end_fixup (handler) 102590075Sobrien tree handler; 102650397Sobrien{ 102790075Sobrien struct eh_region *fixup; 102850397Sobrien 102990075Sobrien if (! doing_eh (0)) 103090075Sobrien return; 103190075Sobrien 103290075Sobrien fixup = expand_eh_region_end (); 103390075Sobrien fixup->type = ERT_FIXUP; 103490075Sobrien fixup->u.fixup.cleanup_exp = handler; 103550397Sobrien} 103650397Sobrien 103790075Sobrien/* Return an rtl expression for a pointer to the exception object 103890075Sobrien within a handler. */ 103950397Sobrien 104090075Sobrienrtx 104190075Sobrienget_exception_pointer (fun) 104290075Sobrien struct function *fun; 104350397Sobrien{ 104490075Sobrien rtx exc_ptr = fun->eh->exc_ptr; 104590075Sobrien if (fun == cfun && ! exc_ptr) 104650397Sobrien { 104790075Sobrien exc_ptr = gen_reg_rtx (Pmode); 104890075Sobrien fun->eh->exc_ptr = exc_ptr; 104950397Sobrien } 105090075Sobrien return exc_ptr; 105150397Sobrien} 105250397Sobrien 105390075Sobrien/* Return an rtl expression for the exception dispatch filter 105490075Sobrien within a handler. */ 105550397Sobrien 105690075Sobrienstatic rtx 105790075Sobrienget_exception_filter (fun) 105890075Sobrien struct function *fun; 105950397Sobrien{ 106090075Sobrien rtx filter = fun->eh->filter; 106190075Sobrien if (fun == cfun && ! filter) 106250397Sobrien { 106390075Sobrien filter = gen_reg_rtx (word_mode); 106490075Sobrien fun->eh->filter = filter; 106550397Sobrien } 106690075Sobrien return filter; 106750397Sobrien} 106890075Sobrien 106990075Sobrien/* Begin a region that will contain entries created with 107090075Sobrien add_partial_entry. */ 107150397Sobrien 107290075Sobrienvoid 107390075Sobrienbegin_protect_partials () 107450397Sobrien{ 107590075Sobrien /* Push room for a new list. */ 107690075Sobrien cfun->eh->protect_list 107790075Sobrien = tree_cons (NULL_TREE, NULL_TREE, cfun->eh->protect_list); 107890075Sobrien} 107950397Sobrien 108090075Sobrien/* Start a new exception region for a region of code that has a 108190075Sobrien cleanup action and push the HANDLER for the region onto 108290075Sobrien protect_list. All of the regions created with add_partial_entry 108390075Sobrien will be ended when end_protect_partials is invoked. 108450397Sobrien 108590075Sobrien ??? The only difference between this purpose and that of 108690075Sobrien expand_decl_cleanup is that in this case, we only want the cleanup to 108790075Sobrien run if an exception is thrown. This should also be handled using 108890075Sobrien binding levels. */ 108950397Sobrien 109090075Sobrienvoid 109190075Sobrienadd_partial_entry (handler) 109290075Sobrien tree handler; 109390075Sobrien{ 109490075Sobrien expand_eh_region_start (); 109550397Sobrien 109690075Sobrien /* Add this entry to the front of the list. */ 109790075Sobrien TREE_VALUE (cfun->eh->protect_list) 109890075Sobrien = tree_cons (NULL_TREE, handler, TREE_VALUE (cfun->eh->protect_list)); 109990075Sobrien} 110050397Sobrien 110190075Sobrien/* End all the pending exception regions on protect_list. */ 110250397Sobrien 110390075Sobrienvoid 110490075Sobrienend_protect_partials () 110590075Sobrien{ 110690075Sobrien tree t; 110750397Sobrien 110890075Sobrien /* Pop the topmost entry. */ 110990075Sobrien t = TREE_VALUE (cfun->eh->protect_list); 111090075Sobrien cfun->eh->protect_list = TREE_CHAIN (cfun->eh->protect_list); 111190075Sobrien 111290075Sobrien /* End all the exception regions. */ 111390075Sobrien for (; t; t = TREE_CHAIN (t)) 111490075Sobrien expand_eh_region_end_cleanup (TREE_VALUE (t)); 111550397Sobrien} 111650397Sobrien 111790075Sobrien 111890075Sobrien/* This section is for the exception handling specific optimization pass. */ 111950397Sobrien 112090075Sobrien/* Random access the exception region tree. It's just as simple to 112190075Sobrien collect the regions this way as in expand_eh_region_start, but 112290075Sobrien without having to realloc memory. */ 112390075Sobrien 112490075Sobrienstatic void 112590075Sobriencollect_eh_region_array () 112650397Sobrien{ 112790075Sobrien struct eh_region **array, *i; 112850397Sobrien 112990075Sobrien i = cfun->eh->region_tree; 113090075Sobrien if (! i) 113190075Sobrien return; 113250397Sobrien 113390075Sobrien array = xcalloc (cfun->eh->last_region_number + 1, sizeof (*array)); 113490075Sobrien cfun->eh->region_array = array; 113550397Sobrien 113690075Sobrien while (1) 113790075Sobrien { 113890075Sobrien array[i->region_number] = i; 113950397Sobrien 114090075Sobrien /* If there are sub-regions, process them. */ 114190075Sobrien if (i->inner) 114290075Sobrien i = i->inner; 114390075Sobrien /* If there are peers, process them. */ 114490075Sobrien else if (i->next_peer) 114590075Sobrien i = i->next_peer; 114690075Sobrien /* Otherwise, step back up the tree to the next peer. */ 114790075Sobrien else 114890075Sobrien { 114990075Sobrien do { 115090075Sobrien i = i->outer; 115190075Sobrien if (i == NULL) 115290075Sobrien return; 115390075Sobrien } while (i->next_peer == NULL); 115490075Sobrien i = i->next_peer; 115590075Sobrien } 115690075Sobrien } 115790075Sobrien} 115850397Sobrien 115990075Sobrienstatic void 116090075Sobrienresolve_fixup_regions () 116150397Sobrien{ 116290075Sobrien int i, j, n = cfun->eh->last_region_number; 116350397Sobrien 116490075Sobrien for (i = 1; i <= n; ++i) 116590075Sobrien { 116690075Sobrien struct eh_region *fixup = cfun->eh->region_array[i]; 116790075Sobrien struct eh_region *cleanup = 0; 116850397Sobrien 116990075Sobrien if (! fixup || fixup->type != ERT_FIXUP) 117090075Sobrien continue; 117150397Sobrien 117290075Sobrien for (j = 1; j <= n; ++j) 117390075Sobrien { 117490075Sobrien cleanup = cfun->eh->region_array[j]; 117590075Sobrien if (cleanup->type == ERT_CLEANUP 117690075Sobrien && cleanup->u.cleanup.exp == fixup->u.fixup.cleanup_exp) 117790075Sobrien break; 117890075Sobrien } 117990075Sobrien if (j > n) 118090075Sobrien abort (); 118190075Sobrien 118290075Sobrien fixup->u.fixup.real_region = cleanup->outer; 118390075Sobrien } 118450397Sobrien} 118550397Sobrien 118690075Sobrien/* Now that we've discovered what region actually encloses a fixup, 118790075Sobrien we can shuffle pointers and remove them from the tree. */ 118850397Sobrien 118950397Sobrienstatic void 119090075Sobrienremove_fixup_regions () 119150397Sobrien{ 119290075Sobrien int i; 119390075Sobrien rtx insn, note; 119490075Sobrien struct eh_region *fixup; 119590075Sobrien 119690075Sobrien /* Walk the insn chain and adjust the REG_EH_REGION numbers 119790075Sobrien for instructions referencing fixup regions. This is only 119890075Sobrien strictly necessary for fixup regions with no parent, but 119990075Sobrien doesn't hurt to do it for all regions. */ 120090075Sobrien for (insn = get_insns(); insn ; insn = NEXT_INSN (insn)) 120190075Sobrien if (INSN_P (insn) 120290075Sobrien && (note = find_reg_note (insn, REG_EH_REGION, NULL)) 120390075Sobrien && INTVAL (XEXP (note, 0)) > 0 120490075Sobrien && (fixup = cfun->eh->region_array[INTVAL (XEXP (note, 0))]) 120590075Sobrien && fixup->type == ERT_FIXUP) 120650397Sobrien { 120790075Sobrien if (fixup->u.fixup.real_region) 120890075Sobrien XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number); 120990075Sobrien else 121090075Sobrien remove_note (insn, note); 121150397Sobrien } 121250397Sobrien 121390075Sobrien /* Remove the fixup regions from the tree. */ 121490075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 121590075Sobrien { 121690075Sobrien fixup = cfun->eh->region_array[i]; 121790075Sobrien if (! fixup) 121890075Sobrien continue; 121950397Sobrien 122090075Sobrien /* Allow GC to maybe free some memory. */ 122190075Sobrien if (fixup->type == ERT_CLEANUP) 122290075Sobrien fixup->u.cleanup.exp = NULL_TREE; 122350397Sobrien 122490075Sobrien if (fixup->type != ERT_FIXUP) 122590075Sobrien continue; 122650397Sobrien 122790075Sobrien if (fixup->inner) 122890075Sobrien { 122990075Sobrien struct eh_region *parent, *p, **pp; 123050397Sobrien 123190075Sobrien parent = fixup->u.fixup.real_region; 123252284Sobrien 123390075Sobrien /* Fix up the children's parent pointers; find the end of 123490075Sobrien the list. */ 123590075Sobrien for (p = fixup->inner; ; p = p->next_peer) 123690075Sobrien { 123790075Sobrien p->outer = parent; 123890075Sobrien if (! p->next_peer) 123990075Sobrien break; 124090075Sobrien } 124150397Sobrien 124290075Sobrien /* In the tree of cleanups, only outer-inner ordering matters. 124390075Sobrien So link the children back in anywhere at the correct level. */ 124490075Sobrien if (parent) 124590075Sobrien pp = &parent->inner; 124690075Sobrien else 124790075Sobrien pp = &cfun->eh->region_tree; 124890075Sobrien p->next_peer = *pp; 124990075Sobrien *pp = fixup->inner; 125090075Sobrien fixup->inner = NULL; 125190075Sobrien } 125290075Sobrien 125390075Sobrien remove_eh_handler (fixup); 125450397Sobrien } 125550397Sobrien} 125650397Sobrien 125790075Sobrien/* Remove all regions whose labels are not reachable from insns. */ 125852284Sobrien 125990075Sobrienstatic void 126090075Sobrienremove_unreachable_regions (insns) 126190075Sobrien rtx insns; 126252284Sobrien{ 126390075Sobrien int i, *uid_region_num; 126490075Sobrien bool *reachable; 126590075Sobrien struct eh_region *r; 126690075Sobrien rtx insn; 126752284Sobrien 126890075Sobrien uid_region_num = xcalloc (get_max_uid (), sizeof(int)); 126990075Sobrien reachable = xcalloc (cfun->eh->last_region_number + 1, sizeof(bool)); 127052284Sobrien 127190075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 127290075Sobrien { 127390075Sobrien r = cfun->eh->region_array[i]; 127490075Sobrien if (!r || r->region_number != i) 127590075Sobrien continue; 127652284Sobrien 127790075Sobrien if (r->resume) 127890075Sobrien { 127990075Sobrien if (uid_region_num[INSN_UID (r->resume)]) 128090075Sobrien abort (); 128190075Sobrien uid_region_num[INSN_UID (r->resume)] = i; 128290075Sobrien } 128390075Sobrien if (r->label) 128490075Sobrien { 128590075Sobrien if (uid_region_num[INSN_UID (r->label)]) 128690075Sobrien abort (); 128790075Sobrien uid_region_num[INSN_UID (r->label)] = i; 128890075Sobrien } 128990075Sobrien if (r->type == ERT_TRY && r->u.try.continue_label) 129090075Sobrien { 129190075Sobrien if (uid_region_num[INSN_UID (r->u.try.continue_label)]) 129290075Sobrien abort (); 129390075Sobrien uid_region_num[INSN_UID (r->u.try.continue_label)] = i; 129490075Sobrien } 129552284Sobrien } 129652284Sobrien 129790075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 129890075Sobrien reachable[uid_region_num[INSN_UID (insn)]] = true; 129950397Sobrien 130090075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 130150397Sobrien { 130290075Sobrien r = cfun->eh->region_array[i]; 130390075Sobrien if (r && r->region_number == i && !reachable[i]) 130450397Sobrien { 130590075Sobrien /* Don't remove ERT_THROW regions if their outer region 130690075Sobrien is reachable. */ 130790075Sobrien if (r->type == ERT_THROW 130890075Sobrien && r->outer 130990075Sobrien && reachable[r->outer->region_number]) 131090075Sobrien continue; 131190075Sobrien 131290075Sobrien remove_eh_handler (r); 131350397Sobrien } 131450397Sobrien } 131590075Sobrien 131690075Sobrien free (reachable); 131790075Sobrien free (uid_region_num); 131850397Sobrien} 131950397Sobrien 132090075Sobrien/* Turn NOTE_INSN_EH_REGION notes into REG_EH_REGION notes for each 132190075Sobrien can_throw instruction in the region. */ 132250397Sobrien 132390075Sobrienstatic void 132490075Sobrienconvert_from_eh_region_ranges_1 (pinsns, orig_sp, cur) 132590075Sobrien rtx *pinsns; 132690075Sobrien int *orig_sp; 132790075Sobrien int cur; 132850397Sobrien{ 132990075Sobrien int *sp = orig_sp; 133090075Sobrien rtx insn, next; 133150397Sobrien 133290075Sobrien for (insn = *pinsns; insn ; insn = next) 133390075Sobrien { 133490075Sobrien next = NEXT_INSN (insn); 133590075Sobrien if (GET_CODE (insn) == NOTE) 133690075Sobrien { 133790075Sobrien int kind = NOTE_LINE_NUMBER (insn); 133890075Sobrien if (kind == NOTE_INSN_EH_REGION_BEG 133990075Sobrien || kind == NOTE_INSN_EH_REGION_END) 134090075Sobrien { 134190075Sobrien if (kind == NOTE_INSN_EH_REGION_BEG) 134290075Sobrien { 134390075Sobrien struct eh_region *r; 134450397Sobrien 134590075Sobrien *sp++ = cur; 134690075Sobrien cur = NOTE_EH_HANDLER (insn); 134750397Sobrien 134890075Sobrien r = cfun->eh->region_array[cur]; 134990075Sobrien if (r->type == ERT_FIXUP) 135090075Sobrien { 135190075Sobrien r = r->u.fixup.real_region; 135290075Sobrien cur = r ? r->region_number : 0; 135390075Sobrien } 135490075Sobrien else if (r->type == ERT_CATCH) 135590075Sobrien { 135690075Sobrien r = r->outer; 135790075Sobrien cur = r ? r->region_number : 0; 135890075Sobrien } 135990075Sobrien } 136090075Sobrien else 136190075Sobrien cur = *--sp; 136250397Sobrien 136390075Sobrien /* Removing the first insn of a CALL_PLACEHOLDER sequence 136490075Sobrien requires extra care to adjust sequence start. */ 136590075Sobrien if (insn == *pinsns) 136690075Sobrien *pinsns = next; 136790075Sobrien remove_insn (insn); 136890075Sobrien continue; 136990075Sobrien } 137090075Sobrien } 137190075Sobrien else if (INSN_P (insn)) 137290075Sobrien { 137390075Sobrien if (cur > 0 137490075Sobrien && ! find_reg_note (insn, REG_EH_REGION, NULL_RTX) 137590075Sobrien /* Calls can always potentially throw exceptions, unless 137690075Sobrien they have a REG_EH_REGION note with a value of 0 or less. 137790075Sobrien Which should be the only possible kind so far. */ 137890075Sobrien && (GET_CODE (insn) == CALL_INSN 137990075Sobrien /* If we wanted exceptions for non-call insns, then 138090075Sobrien any may_trap_p instruction could throw. */ 138190075Sobrien || (flag_non_call_exceptions 138290075Sobrien && GET_CODE (PATTERN (insn)) != CLOBBER 138390075Sobrien && GET_CODE (PATTERN (insn)) != USE 138490075Sobrien && may_trap_p (PATTERN (insn))))) 138590075Sobrien { 138690075Sobrien REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (cur), 138790075Sobrien REG_NOTES (insn)); 138890075Sobrien } 138950397Sobrien 139090075Sobrien if (GET_CODE (insn) == CALL_INSN 139190075Sobrien && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) 139290075Sobrien { 139390075Sobrien convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 0), 139490075Sobrien sp, cur); 139590075Sobrien convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 1), 139690075Sobrien sp, cur); 139790075Sobrien convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 2), 139890075Sobrien sp, cur); 139990075Sobrien } 140090075Sobrien } 140190075Sobrien } 140250397Sobrien 140390075Sobrien if (sp != orig_sp) 140490075Sobrien abort (); 140550397Sobrien} 140650397Sobrien 140790075Sobrienvoid 140890075Sobrienconvert_from_eh_region_ranges () 140950397Sobrien{ 141090075Sobrien int *stack; 141190075Sobrien rtx insns; 141250397Sobrien 141390075Sobrien collect_eh_region_array (); 141490075Sobrien resolve_fixup_regions (); 141550397Sobrien 141690075Sobrien stack = xmalloc (sizeof (int) * (cfun->eh->last_region_number + 1)); 141790075Sobrien insns = get_insns (); 141890075Sobrien convert_from_eh_region_ranges_1 (&insns, stack, 0); 141990075Sobrien free (stack); 142050397Sobrien 142190075Sobrien remove_fixup_regions (); 142290075Sobrien remove_unreachable_regions (insns); 142350397Sobrien} 142450397Sobrien 142596263Sobrienstatic void 142696263Sobrienadd_ehl_entry (label, region) 142796263Sobrien rtx label; 142896263Sobrien struct eh_region *region; 142996263Sobrien{ 143096263Sobrien struct ehl_map_entry **slot, *entry; 143196263Sobrien 143296263Sobrien LABEL_PRESERVE_P (label) = 1; 143396263Sobrien 143496263Sobrien entry = (struct ehl_map_entry *) xmalloc (sizeof (*entry)); 143596263Sobrien entry->label = label; 143696263Sobrien entry->region = region; 143796263Sobrien 143896263Sobrien slot = (struct ehl_map_entry **) 143996263Sobrien htab_find_slot (exception_handler_label_map, entry, INSERT); 144096263Sobrien 144196263Sobrien /* Before landing pad creation, each exception handler has its own 144296263Sobrien label. After landing pad creation, the exception handlers may 144396263Sobrien share landing pads. This is ok, since maybe_remove_eh_handler 144496263Sobrien only requires the 1-1 mapping before landing pad creation. */ 144596263Sobrien if (*slot && !cfun->eh->built_landing_pads) 144696263Sobrien abort (); 144796263Sobrien 144896263Sobrien *slot = entry; 144996263Sobrien} 145096263Sobrien 145196263Sobrienstatic void 145296263Sobrienehl_free (pentry) 145396263Sobrien PTR pentry; 145496263Sobrien{ 145596263Sobrien struct ehl_map_entry *entry = (struct ehl_map_entry *)pentry; 145696263Sobrien LABEL_PRESERVE_P (entry->label) = 0; 145796263Sobrien free (entry); 145896263Sobrien} 145996263Sobrien 146090075Sobrienvoid 146190075Sobrienfind_exception_handler_labels () 146290075Sobrien{ 146390075Sobrien int i; 146450397Sobrien 146596263Sobrien if (exception_handler_label_map) 146696263Sobrien htab_empty (exception_handler_label_map); 146796263Sobrien else 146896263Sobrien { 146996263Sobrien /* ??? The expansion factor here (3/2) must be greater than the htab 147096263Sobrien occupancy factor (4/3) to avoid unnecessary resizing. */ 147196263Sobrien exception_handler_label_map 147296263Sobrien = htab_create (cfun->eh->last_region_number * 3 / 2, 147396263Sobrien ehl_hash, ehl_eq, ehl_free); 147496263Sobrien } 147550397Sobrien 147690075Sobrien if (cfun->eh->region_tree == NULL) 147790075Sobrien return; 147890075Sobrien 147990075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 148050397Sobrien { 148190075Sobrien struct eh_region *region = cfun->eh->region_array[i]; 148290075Sobrien rtx lab; 148350397Sobrien 148490075Sobrien if (! region || region->region_number != i) 148590075Sobrien continue; 148690075Sobrien if (cfun->eh->built_landing_pads) 148790075Sobrien lab = region->landing_pad; 148890075Sobrien else 148990075Sobrien lab = region->label; 149050397Sobrien 149190075Sobrien if (lab) 149296263Sobrien add_ehl_entry (lab, region); 149350397Sobrien } 149490075Sobrien 149590075Sobrien /* For sjlj exceptions, need the return label to remain live until 149690075Sobrien after landing pad generation. */ 149790075Sobrien if (USING_SJLJ_EXCEPTIONS && ! cfun->eh->built_landing_pads) 149896263Sobrien add_ehl_entry (return_label, NULL); 149996263Sobrien} 150090075Sobrien 150196263Sobrienbool 150296263Sobriencurrent_function_has_exception_handlers () 150396263Sobrien{ 150496263Sobrien int i; 150596263Sobrien 150696263Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 150796263Sobrien { 150896263Sobrien struct eh_region *region = cfun->eh->region_array[i]; 150996263Sobrien 151096263Sobrien if (! region || region->region_number != i) 151196263Sobrien continue; 151296263Sobrien if (region->type != ERT_THROW) 151396263Sobrien return true; 151496263Sobrien } 151596263Sobrien 151696263Sobrien return false; 151750397Sobrien} 151890075Sobrien 151990075Sobrienstatic struct eh_region * 152090075Sobrienduplicate_eh_region_1 (o, map) 152190075Sobrien struct eh_region *o; 152290075Sobrien struct inline_remap *map; 152350397Sobrien{ 152490075Sobrien struct eh_region *n 152590075Sobrien = (struct eh_region *) xcalloc (1, sizeof (struct eh_region)); 152650397Sobrien 152790075Sobrien n->region_number = o->region_number + cfun->eh->last_region_number; 152890075Sobrien n->type = o->type; 152950397Sobrien 153090075Sobrien switch (n->type) 153190075Sobrien { 153290075Sobrien case ERT_CLEANUP: 153390075Sobrien case ERT_MUST_NOT_THROW: 153490075Sobrien break; 153550397Sobrien 153690075Sobrien case ERT_TRY: 153790075Sobrien if (o->u.try.continue_label) 153890075Sobrien n->u.try.continue_label 153990075Sobrien = get_label_from_map (map, 154090075Sobrien CODE_LABEL_NUMBER (o->u.try.continue_label)); 154190075Sobrien break; 154250397Sobrien 154390075Sobrien case ERT_CATCH: 154490075Sobrien n->u.catch.type_list = o->u.catch.type_list; 154590075Sobrien break; 154650397Sobrien 154790075Sobrien case ERT_ALLOWED_EXCEPTIONS: 154890075Sobrien n->u.allowed.type_list = o->u.allowed.type_list; 154990075Sobrien break; 155050397Sobrien 155190075Sobrien case ERT_THROW: 155290075Sobrien n->u.throw.type = o->u.throw.type; 155350397Sobrien 155490075Sobrien default: 155590075Sobrien abort (); 155690075Sobrien } 155750397Sobrien 155890075Sobrien if (o->label) 155990075Sobrien n->label = get_label_from_map (map, CODE_LABEL_NUMBER (o->label)); 156090075Sobrien if (o->resume) 156190075Sobrien { 156290075Sobrien n->resume = map->insn_map[INSN_UID (o->resume)]; 156390075Sobrien if (n->resume == NULL) 156490075Sobrien abort (); 156590075Sobrien } 156650397Sobrien 156790075Sobrien return n; 156850397Sobrien} 156950397Sobrien 157050397Sobrienstatic void 157190075Sobrienduplicate_eh_region_2 (o, n_array) 157290075Sobrien struct eh_region *o; 157390075Sobrien struct eh_region **n_array; 157450397Sobrien{ 157590075Sobrien struct eh_region *n = n_array[o->region_number]; 157650397Sobrien 157790075Sobrien switch (n->type) 157890075Sobrien { 157990075Sobrien case ERT_TRY: 158090075Sobrien n->u.try.catch = n_array[o->u.try.catch->region_number]; 158190075Sobrien n->u.try.last_catch = n_array[o->u.try.last_catch->region_number]; 158290075Sobrien break; 158350397Sobrien 158490075Sobrien case ERT_CATCH: 158590075Sobrien if (o->u.catch.next_catch) 158690075Sobrien n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number]; 158790075Sobrien if (o->u.catch.prev_catch) 158890075Sobrien n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number]; 158990075Sobrien break; 159050397Sobrien 159190075Sobrien default: 159290075Sobrien break; 159390075Sobrien } 159490075Sobrien 159590075Sobrien if (o->outer) 159690075Sobrien n->outer = n_array[o->outer->region_number]; 159790075Sobrien if (o->inner) 159890075Sobrien n->inner = n_array[o->inner->region_number]; 159990075Sobrien if (o->next_peer) 160090075Sobrien n->next_peer = n_array[o->next_peer->region_number]; 160190075Sobrien} 160290075Sobrien 160390075Sobrienint 160490075Sobrienduplicate_eh_regions (ifun, map) 160590075Sobrien struct function *ifun; 160690075Sobrien struct inline_remap *map; 160750397Sobrien{ 160890075Sobrien int ifun_last_region_number = ifun->eh->last_region_number; 160990075Sobrien struct eh_region **n_array, *root, *cur; 161090075Sobrien int i; 161150397Sobrien 161290075Sobrien if (ifun_last_region_number == 0) 161390075Sobrien return 0; 161450397Sobrien 161590075Sobrien n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array)); 161650397Sobrien 161790075Sobrien for (i = 1; i <= ifun_last_region_number; ++i) 161890075Sobrien { 161990075Sobrien cur = ifun->eh->region_array[i]; 162090075Sobrien if (!cur || cur->region_number != i) 162190075Sobrien continue; 162290075Sobrien n_array[i] = duplicate_eh_region_1 (cur, map); 162390075Sobrien } 162490075Sobrien for (i = 1; i <= ifun_last_region_number; ++i) 162590075Sobrien { 162690075Sobrien cur = ifun->eh->region_array[i]; 162790075Sobrien if (!cur || cur->region_number != i) 162890075Sobrien continue; 162990075Sobrien duplicate_eh_region_2 (cur, n_array); 163090075Sobrien } 163150397Sobrien 163290075Sobrien root = n_array[ifun->eh->region_tree->region_number]; 163390075Sobrien cur = cfun->eh->cur_region; 163490075Sobrien if (cur) 163590075Sobrien { 163690075Sobrien struct eh_region *p = cur->inner; 163790075Sobrien if (p) 163890075Sobrien { 163990075Sobrien while (p->next_peer) 164090075Sobrien p = p->next_peer; 164190075Sobrien p->next_peer = root; 164290075Sobrien } 164390075Sobrien else 164490075Sobrien cur->inner = root; 164550397Sobrien 164690075Sobrien for (i = 1; i <= ifun_last_region_number; ++i) 164790075Sobrien if (n_array[i] && n_array[i]->outer == NULL) 164890075Sobrien n_array[i]->outer = cur; 164990075Sobrien } 165090075Sobrien else 165190075Sobrien { 165290075Sobrien struct eh_region *p = cfun->eh->region_tree; 165390075Sobrien if (p) 165490075Sobrien { 165590075Sobrien while (p->next_peer) 165690075Sobrien p = p->next_peer; 165790075Sobrien p->next_peer = root; 165890075Sobrien } 165990075Sobrien else 166090075Sobrien cfun->eh->region_tree = root; 166190075Sobrien } 166250397Sobrien 166390075Sobrien free (n_array); 166450397Sobrien 166590075Sobrien i = cfun->eh->last_region_number; 166690075Sobrien cfun->eh->last_region_number = i + ifun_last_region_number; 166790075Sobrien return i; 166890075Sobrien} 166950397Sobrien 167090075Sobrien 167190075Sobrienstatic int 167290075Sobrient2r_eq (pentry, pdata) 167390075Sobrien const PTR pentry; 167490075Sobrien const PTR pdata; 167590075Sobrien{ 167690075Sobrien tree entry = (tree) pentry; 167790075Sobrien tree data = (tree) pdata; 167850397Sobrien 167990075Sobrien return TREE_PURPOSE (entry) == data; 168090075Sobrien} 168150397Sobrien 168290075Sobrienstatic hashval_t 168390075Sobrient2r_hash (pentry) 168490075Sobrien const PTR pentry; 168590075Sobrien{ 168690075Sobrien tree entry = (tree) pentry; 168790075Sobrien return TYPE_HASH (TREE_PURPOSE (entry)); 168850397Sobrien} 168950397Sobrien 169090075Sobrienstatic int 169190075Sobrient2r_mark_1 (slot, data) 169290075Sobrien PTR *slot; 169390075Sobrien PTR data ATTRIBUTE_UNUSED; 169490075Sobrien{ 169590075Sobrien tree contents = (tree) *slot; 169690075Sobrien ggc_mark_tree (contents); 169790075Sobrien return 1; 169890075Sobrien} 169950397Sobrien 170050397Sobrienstatic void 170190075Sobrient2r_mark (addr) 170290075Sobrien PTR addr; 170350397Sobrien{ 170490075Sobrien htab_traverse (*(htab_t *)addr, t2r_mark_1, NULL); 170590075Sobrien} 170650397Sobrien 170790075Sobrienstatic void 170890075Sobrienadd_type_for_runtime (type) 170990075Sobrien tree type; 171090075Sobrien{ 171190075Sobrien tree *slot; 171250397Sobrien 171390075Sobrien slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, 171490075Sobrien TYPE_HASH (type), INSERT); 171590075Sobrien if (*slot == NULL) 171690075Sobrien { 171790075Sobrien tree runtime = (*lang_eh_runtime_type) (type); 171890075Sobrien *slot = tree_cons (type, runtime, NULL_TREE); 171990075Sobrien } 172090075Sobrien} 172150397Sobrien 172290075Sobrienstatic tree 172390075Sobrienlookup_type_for_runtime (type) 172490075Sobrien tree type; 172590075Sobrien{ 172690075Sobrien tree *slot; 172750397Sobrien 172890075Sobrien slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, 172990075Sobrien TYPE_HASH (type), NO_INSERT); 173050397Sobrien 173190075Sobrien /* We should have always inserted the data earlier. */ 173290075Sobrien return TREE_VALUE (*slot); 173390075Sobrien} 173450397Sobrien 173590075Sobrien 173690075Sobrien/* Represent an entry in @TTypes for either catch actions 173790075Sobrien or exception filter actions. */ 173890075Sobrienstruct ttypes_filter 173990075Sobrien{ 174090075Sobrien tree t; 174190075Sobrien int filter; 174290075Sobrien}; 174350397Sobrien 174490075Sobrien/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA 174590075Sobrien (a tree) for a @TTypes type node we are thinking about adding. */ 174650397Sobrien 174790075Sobrienstatic int 174890075Sobrienttypes_filter_eq (pentry, pdata) 174990075Sobrien const PTR pentry; 175090075Sobrien const PTR pdata; 175190075Sobrien{ 175290075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 175390075Sobrien tree data = (tree) pdata; 175450397Sobrien 175590075Sobrien return entry->t == data; 175650397Sobrien} 175750397Sobrien 175890075Sobrienstatic hashval_t 175990075Sobrienttypes_filter_hash (pentry) 176090075Sobrien const PTR pentry; 176190075Sobrien{ 176290075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 176390075Sobrien return TYPE_HASH (entry->t); 176490075Sobrien} 176550397Sobrien 176690075Sobrien/* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes 176790075Sobrien exception specification list we are thinking about adding. */ 176890075Sobrien/* ??? Currently we use the type lists in the order given. Someone 176990075Sobrien should put these in some canonical order. */ 177050397Sobrien 177190075Sobrienstatic int 177290075Sobrienehspec_filter_eq (pentry, pdata) 177390075Sobrien const PTR pentry; 177490075Sobrien const PTR pdata; 177550397Sobrien{ 177690075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 177790075Sobrien const struct ttypes_filter *data = (const struct ttypes_filter *) pdata; 177850397Sobrien 177990075Sobrien return type_list_equal (entry->t, data->t); 178090075Sobrien} 178150397Sobrien 178290075Sobrien/* Hash function for exception specification lists. */ 178350397Sobrien 178490075Sobrienstatic hashval_t 178590075Sobrienehspec_filter_hash (pentry) 178690075Sobrien const PTR pentry; 178790075Sobrien{ 178890075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 178990075Sobrien hashval_t h = 0; 179090075Sobrien tree list; 179150397Sobrien 179290075Sobrien for (list = entry->t; list ; list = TREE_CHAIN (list)) 179390075Sobrien h = (h << 5) + (h >> 27) + TYPE_HASH (TREE_VALUE (list)); 179490075Sobrien return h; 179550397Sobrien} 179650397Sobrien 179790075Sobrien/* Add TYPE to cfun->eh->ttype_data, using TYPES_HASH to speed 179890075Sobrien up the search. Return the filter value to be used. */ 179950397Sobrien 180090075Sobrienstatic int 180190075Sobrienadd_ttypes_entry (ttypes_hash, type) 180290075Sobrien htab_t ttypes_hash; 180390075Sobrien tree type; 180450397Sobrien{ 180590075Sobrien struct ttypes_filter **slot, *n; 180650397Sobrien 180790075Sobrien slot = (struct ttypes_filter **) 180890075Sobrien htab_find_slot_with_hash (ttypes_hash, type, TYPE_HASH (type), INSERT); 180950397Sobrien 181090075Sobrien if ((n = *slot) == NULL) 181150397Sobrien { 181290075Sobrien /* Filter value is a 1 based table index. */ 181350397Sobrien 181490075Sobrien n = (struct ttypes_filter *) xmalloc (sizeof (*n)); 181590075Sobrien n->t = type; 181690075Sobrien n->filter = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) + 1; 181790075Sobrien *slot = n; 181850397Sobrien 181990075Sobrien VARRAY_PUSH_TREE (cfun->eh->ttype_data, type); 182050397Sobrien } 182150397Sobrien 182290075Sobrien return n->filter; 182350397Sobrien} 182450397Sobrien 182590075Sobrien/* Add LIST to cfun->eh->ehspec_data, using EHSPEC_HASH and TYPES_HASH 182690075Sobrien to speed up the search. Return the filter value to be used. */ 182750397Sobrien 182890075Sobrienstatic int 182990075Sobrienadd_ehspec_entry (ehspec_hash, ttypes_hash, list) 183090075Sobrien htab_t ehspec_hash; 183190075Sobrien htab_t ttypes_hash; 183290075Sobrien tree list; 183350397Sobrien{ 183490075Sobrien struct ttypes_filter **slot, *n; 183590075Sobrien struct ttypes_filter dummy; 183650397Sobrien 183790075Sobrien dummy.t = list; 183890075Sobrien slot = (struct ttypes_filter **) 183990075Sobrien htab_find_slot (ehspec_hash, &dummy, INSERT); 184050397Sobrien 184190075Sobrien if ((n = *slot) == NULL) 184290075Sobrien { 184390075Sobrien /* Filter value is a -1 based byte index into a uleb128 buffer. */ 184450397Sobrien 184590075Sobrien n = (struct ttypes_filter *) xmalloc (sizeof (*n)); 184690075Sobrien n->t = list; 184790075Sobrien n->filter = -(VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) + 1); 184890075Sobrien *slot = n; 184950397Sobrien 185090075Sobrien /* Look up each type in the list and encode its filter 185190075Sobrien value as a uleb128. Terminate the list with 0. */ 185290075Sobrien for (; list ; list = TREE_CHAIN (list)) 185390075Sobrien push_uleb128 (&cfun->eh->ehspec_data, 185490075Sobrien add_ttypes_entry (ttypes_hash, TREE_VALUE (list))); 185590075Sobrien VARRAY_PUSH_UCHAR (cfun->eh->ehspec_data, 0); 185690075Sobrien } 185790075Sobrien 185890075Sobrien return n->filter; 185990075Sobrien} 186090075Sobrien 186190075Sobrien/* Generate the action filter values to be used for CATCH and 186290075Sobrien ALLOWED_EXCEPTIONS regions. When using dwarf2 exception regions, 186390075Sobrien we use lots of landing pads, and so every type or list can share 186490075Sobrien the same filter value, which saves table space. */ 186590075Sobrien 186690075Sobrienstatic void 186790075Sobrienassign_filter_values () 186850397Sobrien{ 186990075Sobrien int i; 187090075Sobrien htab_t ttypes, ehspec; 187150397Sobrien 187290075Sobrien VARRAY_TREE_INIT (cfun->eh->ttype_data, 16, "ttype_data"); 187390075Sobrien VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data"); 187450397Sobrien 187590075Sobrien ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free); 187690075Sobrien ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free); 187750397Sobrien 187890075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 187950397Sobrien { 188090075Sobrien struct eh_region *r = cfun->eh->region_array[i]; 188150397Sobrien 188290075Sobrien /* Mind we don't process a region more than once. */ 188390075Sobrien if (!r || r->region_number != i) 188490075Sobrien continue; 188550397Sobrien 188690075Sobrien switch (r->type) 188790075Sobrien { 188890075Sobrien case ERT_CATCH: 188990075Sobrien /* Whatever type_list is (NULL or true list), we build a list 189090075Sobrien of filters for the region. */ 189190075Sobrien r->u.catch.filter_list = NULL_TREE; 189250397Sobrien 189390075Sobrien if (r->u.catch.type_list != NULL) 189490075Sobrien { 189590075Sobrien /* Get a filter value for each of the types caught and store 189690075Sobrien them in the region's dedicated list. */ 189790075Sobrien tree tp_node = r->u.catch.type_list; 189850397Sobrien 189990075Sobrien for (;tp_node; tp_node = TREE_CHAIN (tp_node)) 190090075Sobrien { 190190075Sobrien int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node)); 190290075Sobrien tree flt_node = build_int_2 (flt, 0); 190350397Sobrien 190490075Sobrien r->u.catch.filter_list 190590075Sobrien = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list); 190690075Sobrien } 190790075Sobrien } 190890075Sobrien else 190990075Sobrien { 191090075Sobrien /* Get a filter value for the NULL list also since it will need 191190075Sobrien an action record anyway. */ 191290075Sobrien int flt = add_ttypes_entry (ttypes, NULL); 191390075Sobrien tree flt_node = build_int_2 (flt, 0); 191450397Sobrien 191590075Sobrien r->u.catch.filter_list 191690075Sobrien = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list); 191790075Sobrien } 191850397Sobrien 191990075Sobrien break; 192050397Sobrien 192190075Sobrien case ERT_ALLOWED_EXCEPTIONS: 192290075Sobrien r->u.allowed.filter 192390075Sobrien = add_ehspec_entry (ehspec, ttypes, r->u.allowed.type_list); 192490075Sobrien break; 192550397Sobrien 192690075Sobrien default: 192790075Sobrien break; 192890075Sobrien } 192950397Sobrien } 193090075Sobrien 193190075Sobrien htab_delete (ttypes); 193290075Sobrien htab_delete (ehspec); 193350397Sobrien} 193450397Sobrien 193590075Sobrienstatic void 193690075Sobrienbuild_post_landing_pads () 193750397Sobrien{ 193890075Sobrien int i; 193950397Sobrien 194090075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 194190075Sobrien { 194290075Sobrien struct eh_region *region = cfun->eh->region_array[i]; 194390075Sobrien rtx seq; 194450397Sobrien 194590075Sobrien /* Mind we don't process a region more than once. */ 194690075Sobrien if (!region || region->region_number != i) 194790075Sobrien continue; 194850397Sobrien 194990075Sobrien switch (region->type) 195090075Sobrien { 195190075Sobrien case ERT_TRY: 195290075Sobrien /* ??? Collect the set of all non-overlapping catch handlers 195390075Sobrien all the way up the chain until blocked by a cleanup. */ 195490075Sobrien /* ??? Outer try regions can share landing pads with inner 195590075Sobrien try regions if the types are completely non-overlapping, 195690075Sobrien and there are no intervening cleanups. */ 195750397Sobrien 195890075Sobrien region->post_landing_pad = gen_label_rtx (); 195950397Sobrien 196090075Sobrien start_sequence (); 196150397Sobrien 196290075Sobrien emit_label (region->post_landing_pad); 196350397Sobrien 196490075Sobrien /* ??? It is mighty inconvenient to call back into the 196590075Sobrien switch statement generation code in expand_end_case. 196690075Sobrien Rapid prototyping sez a sequence of ifs. */ 196790075Sobrien { 196890075Sobrien struct eh_region *c; 196990075Sobrien for (c = region->u.try.catch; c ; c = c->u.catch.next_catch) 197090075Sobrien { 197190075Sobrien /* ??? _Unwind_ForcedUnwind wants no match here. */ 197290075Sobrien if (c->u.catch.type_list == NULL) 197390075Sobrien emit_jump (c->label); 197490075Sobrien else 197590075Sobrien { 197690075Sobrien /* Need for one cmp/jump per type caught. Each type 197790075Sobrien list entry has a matching entry in the filter list 197890075Sobrien (see assign_filter_values). */ 197990075Sobrien tree tp_node = c->u.catch.type_list; 198090075Sobrien tree flt_node = c->u.catch.filter_list; 198150397Sobrien 198290075Sobrien for (; tp_node; ) 198390075Sobrien { 198490075Sobrien emit_cmp_and_jump_insns 198590075Sobrien (cfun->eh->filter, 198690075Sobrien GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)), 198790075Sobrien EQ, NULL_RTX, word_mode, 0, c->label); 198850397Sobrien 198990075Sobrien tp_node = TREE_CHAIN (tp_node); 199090075Sobrien flt_node = TREE_CHAIN (flt_node); 199190075Sobrien } 199290075Sobrien } 199390075Sobrien } 199490075Sobrien } 199550397Sobrien 199690075Sobrien /* We delay the generation of the _Unwind_Resume until we generate 199790075Sobrien landing pads. We emit a marker here so as to get good control 199890075Sobrien flow data in the meantime. */ 199990075Sobrien region->resume 200090075Sobrien = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number)); 200190075Sobrien emit_barrier (); 200250397Sobrien 200390075Sobrien seq = get_insns (); 200490075Sobrien end_sequence (); 200550397Sobrien 200690075Sobrien emit_insns_before (seq, region->u.try.catch->label); 200790075Sobrien break; 200850397Sobrien 200990075Sobrien case ERT_ALLOWED_EXCEPTIONS: 201090075Sobrien region->post_landing_pad = gen_label_rtx (); 201150397Sobrien 201290075Sobrien start_sequence (); 201350397Sobrien 201490075Sobrien emit_label (region->post_landing_pad); 201550397Sobrien 201690075Sobrien emit_cmp_and_jump_insns (cfun->eh->filter, 201790075Sobrien GEN_INT (region->u.allowed.filter), 201890075Sobrien EQ, NULL_RTX, word_mode, 0, region->label); 201950397Sobrien 202090075Sobrien /* We delay the generation of the _Unwind_Resume until we generate 202190075Sobrien landing pads. We emit a marker here so as to get good control 202290075Sobrien flow data in the meantime. */ 202390075Sobrien region->resume 202490075Sobrien = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number)); 202590075Sobrien emit_barrier (); 202650397Sobrien 202790075Sobrien seq = get_insns (); 202890075Sobrien end_sequence (); 202990075Sobrien 203090075Sobrien emit_insns_before (seq, region->label); 203190075Sobrien break; 203290075Sobrien 203390075Sobrien case ERT_CLEANUP: 203490075Sobrien case ERT_MUST_NOT_THROW: 203590075Sobrien region->post_landing_pad = region->label; 203690075Sobrien break; 203790075Sobrien 203890075Sobrien case ERT_CATCH: 203990075Sobrien case ERT_THROW: 204090075Sobrien /* Nothing to do. */ 204190075Sobrien break; 204290075Sobrien 204390075Sobrien default: 204490075Sobrien abort (); 204590075Sobrien } 204690075Sobrien } 204750397Sobrien} 204850397Sobrien 204990075Sobrien/* Replace RESX patterns with jumps to the next handler if any, or calls to 205090075Sobrien _Unwind_Resume otherwise. */ 205150397Sobrien 205290075Sobrienstatic void 205390075Sobrienconnect_post_landing_pads () 205450397Sobrien{ 205590075Sobrien int i; 205650397Sobrien 205790075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 205850397Sobrien { 205990075Sobrien struct eh_region *region = cfun->eh->region_array[i]; 206090075Sobrien struct eh_region *outer; 206190075Sobrien rtx seq; 206250397Sobrien 206390075Sobrien /* Mind we don't process a region more than once. */ 206490075Sobrien if (!region || region->region_number != i) 206590075Sobrien continue; 206650397Sobrien 206790075Sobrien /* If there is no RESX, or it has been deleted by flow, there's 206890075Sobrien nothing to fix up. */ 206990075Sobrien if (! region->resume || INSN_DELETED_P (region->resume)) 207090075Sobrien continue; 207150397Sobrien 207290075Sobrien /* Search for another landing pad in this function. */ 207390075Sobrien for (outer = region->outer; outer ; outer = outer->outer) 207490075Sobrien if (outer->post_landing_pad) 207590075Sobrien break; 207650397Sobrien 207790075Sobrien start_sequence (); 207850397Sobrien 207990075Sobrien if (outer) 208090075Sobrien emit_jump (outer->post_landing_pad); 208190075Sobrien else 208290075Sobrien emit_library_call (unwind_resume_libfunc, LCT_THROW, 208390075Sobrien VOIDmode, 1, cfun->eh->exc_ptr, Pmode); 208450397Sobrien 208590075Sobrien seq = get_insns (); 208690075Sobrien end_sequence (); 208790075Sobrien emit_insns_before (seq, region->resume); 208890075Sobrien delete_insn (region->resume); 208950397Sobrien } 209050397Sobrien} 209150397Sobrien 209290075Sobrien 209390075Sobrienstatic void 209490075Sobriendw2_build_landing_pads () 209550397Sobrien{ 209690075Sobrien int i; 209790075Sobrien unsigned int j; 209850397Sobrien 209990075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 210090075Sobrien { 210190075Sobrien struct eh_region *region = cfun->eh->region_array[i]; 210290075Sobrien rtx seq; 210390075Sobrien bool clobbers_hard_regs = false; 210450397Sobrien 210590075Sobrien /* Mind we don't process a region more than once. */ 210690075Sobrien if (!region || region->region_number != i) 210790075Sobrien continue; 210850397Sobrien 210990075Sobrien if (region->type != ERT_CLEANUP 211090075Sobrien && region->type != ERT_TRY 211190075Sobrien && region->type != ERT_ALLOWED_EXCEPTIONS) 211290075Sobrien continue; 211350397Sobrien 211490075Sobrien start_sequence (); 211550397Sobrien 211690075Sobrien region->landing_pad = gen_label_rtx (); 211790075Sobrien emit_label (region->landing_pad); 211850397Sobrien 211990075Sobrien#ifdef HAVE_exception_receiver 212090075Sobrien if (HAVE_exception_receiver) 212190075Sobrien emit_insn (gen_exception_receiver ()); 212290075Sobrien else 212390075Sobrien#endif 212490075Sobrien#ifdef HAVE_nonlocal_goto_receiver 212590075Sobrien if (HAVE_nonlocal_goto_receiver) 212690075Sobrien emit_insn (gen_nonlocal_goto_receiver ()); 212790075Sobrien else 212890075Sobrien#endif 212990075Sobrien { /* Nothing */ } 213050397Sobrien 213190075Sobrien /* If the eh_return data registers are call-saved, then we 213290075Sobrien won't have considered them clobbered from the call that 213390075Sobrien threw. Kill them now. */ 213490075Sobrien for (j = 0; ; ++j) 213590075Sobrien { 213690075Sobrien unsigned r = EH_RETURN_DATA_REGNO (j); 213790075Sobrien if (r == INVALID_REGNUM) 213890075Sobrien break; 213990075Sobrien if (! call_used_regs[r]) 214090075Sobrien { 214190075Sobrien emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, r))); 214290075Sobrien clobbers_hard_regs = true; 214390075Sobrien } 214490075Sobrien } 214552284Sobrien 214690075Sobrien if (clobbers_hard_regs) 214790075Sobrien { 214890075Sobrien /* @@@ This is a kludge. Not all machine descriptions define a 214990075Sobrien blockage insn, but we must not allow the code we just generated 215090075Sobrien to be reordered by scheduling. So emit an ASM_INPUT to act as 215190075Sobrien blockage insn. */ 215290075Sobrien emit_insn (gen_rtx_ASM_INPUT (VOIDmode, "")); 215390075Sobrien } 215452284Sobrien 215590075Sobrien emit_move_insn (cfun->eh->exc_ptr, 215690075Sobrien gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (0))); 215790075Sobrien emit_move_insn (cfun->eh->filter, 215890075Sobrien gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1))); 215952284Sobrien 216090075Sobrien seq = get_insns (); 216190075Sobrien end_sequence (); 216252284Sobrien 216390075Sobrien emit_insns_before (seq, region->post_landing_pad); 216452284Sobrien } 216550397Sobrien} 216650397Sobrien 216790075Sobrien 216890075Sobrienstruct sjlj_lp_info 216990075Sobrien{ 217090075Sobrien int directly_reachable; 217190075Sobrien int action_index; 217290075Sobrien int dispatch_index; 217390075Sobrien int call_site_index; 217490075Sobrien}; 217552284Sobrien 217690075Sobrienstatic bool 217790075Sobriensjlj_find_directly_reachable_regions (lp_info) 217890075Sobrien struct sjlj_lp_info *lp_info; 217952284Sobrien{ 218090075Sobrien rtx insn; 218190075Sobrien bool found_one = false; 218252284Sobrien 218390075Sobrien for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) 218452284Sobrien { 218590075Sobrien struct eh_region *region; 218690075Sobrien enum reachable_code rc; 218790075Sobrien tree type_thrown; 218890075Sobrien rtx note; 218990075Sobrien 219090075Sobrien if (! INSN_P (insn)) 219190075Sobrien continue; 219290075Sobrien 219390075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 219490075Sobrien if (!note || INTVAL (XEXP (note, 0)) <= 0) 219590075Sobrien continue; 219690075Sobrien 219790075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 219890075Sobrien 219990075Sobrien type_thrown = NULL_TREE; 220090075Sobrien if (region->type == ERT_THROW) 220190075Sobrien { 220290075Sobrien type_thrown = region->u.throw.type; 220390075Sobrien region = region->outer; 220490075Sobrien } 220590075Sobrien 220690075Sobrien /* Find the first containing region that might handle the exception. 220790075Sobrien That's the landing pad to which we will transfer control. */ 220890075Sobrien rc = RNL_NOT_CAUGHT; 220990075Sobrien for (; region; region = region->outer) 221090075Sobrien { 221190075Sobrien rc = reachable_next_level (region, type_thrown, 0); 221290075Sobrien if (rc != RNL_NOT_CAUGHT) 221390075Sobrien break; 221490075Sobrien } 221590075Sobrien if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT) 221690075Sobrien { 221790075Sobrien lp_info[region->region_number].directly_reachable = 1; 221890075Sobrien found_one = true; 221990075Sobrien } 222052284Sobrien } 222152284Sobrien 222290075Sobrien return found_one; 222352284Sobrien} 222452284Sobrien 222590075Sobrienstatic void 222690075Sobriensjlj_assign_call_site_values (dispatch_label, lp_info) 222790075Sobrien rtx dispatch_label; 222890075Sobrien struct sjlj_lp_info *lp_info; 222990075Sobrien{ 223090075Sobrien htab_t ar_hash; 223190075Sobrien int i, index; 223250397Sobrien 223390075Sobrien /* First task: build the action table. */ 223450397Sobrien 223590075Sobrien VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data"); 223690075Sobrien ar_hash = htab_create (31, action_record_hash, action_record_eq, free); 223750397Sobrien 223890075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 223990075Sobrien if (lp_info[i].directly_reachable) 224090075Sobrien { 224190075Sobrien struct eh_region *r = cfun->eh->region_array[i]; 224290075Sobrien r->landing_pad = dispatch_label; 224390075Sobrien lp_info[i].action_index = collect_one_action_chain (ar_hash, r); 224490075Sobrien if (lp_info[i].action_index != -1) 224590075Sobrien cfun->uses_eh_lsda = 1; 224690075Sobrien } 224750397Sobrien 224890075Sobrien htab_delete (ar_hash); 224950397Sobrien 225090075Sobrien /* Next: assign dispatch values. In dwarf2 terms, this would be the 225190075Sobrien landing pad label for the region. For sjlj though, there is one 225290075Sobrien common landing pad from which we dispatch to the post-landing pads. 225350397Sobrien 225490075Sobrien A region receives a dispatch index if it is directly reachable 225590075Sobrien and requires in-function processing. Regions that share post-landing 225690075Sobrien pads may share dispatch indices. */ 225790075Sobrien /* ??? Post-landing pad sharing doesn't actually happen at the moment 225890075Sobrien (see build_post_landing_pads) so we don't bother checking for it. */ 225950397Sobrien 226090075Sobrien index = 0; 226190075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 226290075Sobrien if (lp_info[i].directly_reachable) 226390075Sobrien lp_info[i].dispatch_index = index++; 226450397Sobrien 226590075Sobrien /* Finally: assign call-site values. If dwarf2 terms, this would be 226690075Sobrien the region number assigned by convert_to_eh_region_ranges, but 226790075Sobrien handles no-action and must-not-throw differently. */ 226850397Sobrien 226990075Sobrien call_site_base = 1; 227090075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 227190075Sobrien if (lp_info[i].directly_reachable) 227290075Sobrien { 227390075Sobrien int action = lp_info[i].action_index; 227490075Sobrien 227590075Sobrien /* Map must-not-throw to otherwise unused call-site index 0. */ 227690075Sobrien if (action == -2) 227790075Sobrien index = 0; 227890075Sobrien /* Map no-action to otherwise unused call-site index -1. */ 227990075Sobrien else if (action == -1) 228090075Sobrien index = -1; 228190075Sobrien /* Otherwise, look it up in the table. */ 228290075Sobrien else 228390075Sobrien index = add_call_site (GEN_INT (lp_info[i].dispatch_index), action); 228490075Sobrien 228590075Sobrien lp_info[i].call_site_index = index; 228690075Sobrien } 228790075Sobrien} 228890075Sobrien 228990075Sobrienstatic void 229090075Sobriensjlj_mark_call_sites (lp_info) 229190075Sobrien struct sjlj_lp_info *lp_info; 229290075Sobrien{ 229390075Sobrien int last_call_site = -2; 229490075Sobrien rtx insn, mem; 229590075Sobrien 229690075Sobrien for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) 229750397Sobrien { 229890075Sobrien struct eh_region *region; 229990075Sobrien int this_call_site; 230090075Sobrien rtx note, before, p; 230150397Sobrien 230290075Sobrien /* Reset value tracking at extended basic block boundaries. */ 230390075Sobrien if (GET_CODE (insn) == CODE_LABEL) 230490075Sobrien last_call_site = -2; 230550397Sobrien 230690075Sobrien if (! INSN_P (insn)) 230790075Sobrien continue; 230850397Sobrien 230990075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 231090075Sobrien if (!note) 231190075Sobrien { 231290075Sobrien /* Calls (and trapping insns) without notes are outside any 231390075Sobrien exception handling region in this function. Mark them as 231490075Sobrien no action. */ 231590075Sobrien if (GET_CODE (insn) == CALL_INSN 231690075Sobrien || (flag_non_call_exceptions 231790075Sobrien && may_trap_p (PATTERN (insn)))) 231890075Sobrien this_call_site = -1; 231990075Sobrien else 232090075Sobrien continue; 232190075Sobrien } 232290075Sobrien else 232390075Sobrien { 232490075Sobrien /* Calls that are known to not throw need not be marked. */ 232590075Sobrien if (INTVAL (XEXP (note, 0)) <= 0) 232690075Sobrien continue; 232750397Sobrien 232890075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 232990075Sobrien this_call_site = lp_info[region->region_number].call_site_index; 233090075Sobrien } 233150397Sobrien 233290075Sobrien if (this_call_site == last_call_site) 233390075Sobrien continue; 233450397Sobrien 233590075Sobrien /* Don't separate a call from it's argument loads. */ 233690075Sobrien before = insn; 233790075Sobrien if (GET_CODE (insn) == CALL_INSN) 233890075Sobrien before = find_first_parameter_load (insn, NULL_RTX); 233950397Sobrien 234090075Sobrien start_sequence (); 234190075Sobrien mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node), 234290075Sobrien sjlj_fc_call_site_ofs); 234390075Sobrien emit_move_insn (mem, GEN_INT (this_call_site)); 234490075Sobrien p = get_insns (); 234590075Sobrien end_sequence (); 234650397Sobrien 234790075Sobrien emit_insns_before (p, before); 234890075Sobrien last_call_site = this_call_site; 234950397Sobrien } 235050397Sobrien} 235150397Sobrien 235290075Sobrien/* Construct the SjLj_Function_Context. */ 235350397Sobrien 235490075Sobrienstatic void 235590075Sobriensjlj_emit_function_enter (dispatch_label) 235690075Sobrien rtx dispatch_label; 235750397Sobrien{ 235890075Sobrien rtx fn_begin, fc, mem, seq; 235950397Sobrien 236090075Sobrien fc = cfun->eh->sjlj_fc; 236150397Sobrien 236290075Sobrien start_sequence (); 236350397Sobrien 236490075Sobrien /* We're storing this libcall's address into memory instead of 236590075Sobrien calling it directly. Thus, we must call assemble_external_libcall 236690075Sobrien here, as we can not depend on emit_library_call to do it for us. */ 236790075Sobrien assemble_external_libcall (eh_personality_libfunc); 236890075Sobrien mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs); 236990075Sobrien emit_move_insn (mem, eh_personality_libfunc); 237090075Sobrien 237190075Sobrien mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs); 237290075Sobrien if (cfun->uses_eh_lsda) 237350397Sobrien { 237490075Sobrien char buf[20]; 237590075Sobrien ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", sjlj_funcdef_number); 237690075Sobrien emit_move_insn (mem, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf))); 237750397Sobrien } 237890075Sobrien else 237990075Sobrien emit_move_insn (mem, const0_rtx); 238050397Sobrien 238190075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP 238290075Sobrien { 238390075Sobrien rtx x, note; 238490075Sobrien x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE, 238590075Sobrien TYPE_MODE (integer_type_node), 1, 238690075Sobrien plus_constant (XEXP (fc, 0), 238790075Sobrien sjlj_fc_jbuf_ofs), Pmode); 238850397Sobrien 238990075Sobrien note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE); 239090075Sobrien NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx); 239150397Sobrien 239290075Sobrien emit_cmp_and_jump_insns (x, const0_rtx, NE, 0, 239390075Sobrien TYPE_MODE (integer_type_node), 0, dispatch_label); 239490075Sobrien } 239590075Sobrien#else 239690075Sobrien expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs), 239790075Sobrien dispatch_label); 239890075Sobrien#endif 239950397Sobrien 240090075Sobrien emit_library_call (unwind_sjlj_register_libfunc, LCT_NORMAL, VOIDmode, 240190075Sobrien 1, XEXP (fc, 0), Pmode); 240290075Sobrien 240390075Sobrien seq = get_insns (); 240450397Sobrien end_sequence (); 240550397Sobrien 240690075Sobrien /* ??? Instead of doing this at the beginning of the function, 240790075Sobrien do this in a block that is at loop level 0 and dominates all 240890075Sobrien can_throw_internal instructions. */ 240950397Sobrien 241090075Sobrien for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin)) 241190075Sobrien if (GET_CODE (fn_begin) == NOTE 241290075Sobrien && NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG) 241390075Sobrien break; 241490075Sobrien emit_insns_after (seq, fn_begin); 241550397Sobrien} 241650397Sobrien 241790075Sobrien/* Call back from expand_function_end to know where we should put 241890075Sobrien the call to unwind_sjlj_unregister_libfunc if needed. */ 241950397Sobrien 242050397Sobrienvoid 242190075Sobriensjlj_emit_function_exit_after (after) 242290075Sobrien rtx after; 242350397Sobrien{ 242490075Sobrien cfun->eh->sjlj_exit_after = after; 242550397Sobrien} 242650397Sobrien 242790075Sobrienstatic void 242890075Sobriensjlj_emit_function_exit () 242950397Sobrien{ 243090075Sobrien rtx seq; 243150397Sobrien 243290075Sobrien start_sequence (); 243350397Sobrien 243490075Sobrien emit_library_call (unwind_sjlj_unregister_libfunc, LCT_NORMAL, VOIDmode, 243590075Sobrien 1, XEXP (cfun->eh->sjlj_fc, 0), Pmode); 243650397Sobrien 243790075Sobrien seq = get_insns (); 243890075Sobrien end_sequence (); 243950397Sobrien 244090075Sobrien /* ??? Really this can be done in any block at loop level 0 that 244190075Sobrien post-dominates all can_throw_internal instructions. This is 244290075Sobrien the last possible moment. */ 244350397Sobrien 244490075Sobrien emit_insns_after (seq, cfun->eh->sjlj_exit_after); 244590075Sobrien} 244650397Sobrien 244790075Sobrienstatic void 244890075Sobriensjlj_emit_dispatch_table (dispatch_label, lp_info) 244990075Sobrien rtx dispatch_label; 245090075Sobrien struct sjlj_lp_info *lp_info; 245190075Sobrien{ 245290075Sobrien int i, first_reachable; 245390075Sobrien rtx mem, dispatch, seq, fc; 245450397Sobrien 245590075Sobrien fc = cfun->eh->sjlj_fc; 245650397Sobrien 245790075Sobrien start_sequence (); 245850397Sobrien 245990075Sobrien emit_label (dispatch_label); 246050397Sobrien 246190075Sobrien#ifndef DONT_USE_BUILTIN_SETJMP 246290075Sobrien expand_builtin_setjmp_receiver (dispatch_label); 246390075Sobrien#endif 246450397Sobrien 246590075Sobrien /* Load up dispatch index, exc_ptr and filter values from the 246690075Sobrien function context. */ 246790075Sobrien mem = adjust_address (fc, TYPE_MODE (integer_type_node), 246890075Sobrien sjlj_fc_call_site_ofs); 246990075Sobrien dispatch = copy_to_reg (mem); 247050397Sobrien 247190075Sobrien mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs); 247290075Sobrien if (word_mode != Pmode) 247350397Sobrien { 247490075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED 247590075Sobrien mem = convert_memory_address (Pmode, mem); 247690075Sobrien#else 247790075Sobrien mem = convert_to_mode (Pmode, mem, 0); 247890075Sobrien#endif 247990075Sobrien } 248090075Sobrien emit_move_insn (cfun->eh->exc_ptr, mem); 248150397Sobrien 248290075Sobrien mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs + UNITS_PER_WORD); 248390075Sobrien emit_move_insn (cfun->eh->filter, mem); 248450397Sobrien 248590075Sobrien /* Jump to one of the directly reachable regions. */ 248690075Sobrien /* ??? This really ought to be using a switch statement. */ 248790075Sobrien 248890075Sobrien first_reachable = 0; 248990075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 249090075Sobrien { 249190075Sobrien if (! lp_info[i].directly_reachable) 249290075Sobrien continue; 249390075Sobrien 249490075Sobrien if (! first_reachable) 249550397Sobrien { 249690075Sobrien first_reachable = i; 249790075Sobrien continue; 249850397Sobrien } 249990075Sobrien 250090075Sobrien emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index), 250190075Sobrien EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0, 250290075Sobrien cfun->eh->region_array[i]->post_landing_pad); 250350397Sobrien } 250450397Sobrien 250590075Sobrien seq = get_insns (); 250690075Sobrien end_sequence (); 250750397Sobrien 250890075Sobrien emit_insns_before (seq, (cfun->eh->region_array[first_reachable] 250990075Sobrien ->post_landing_pad)); 251050397Sobrien} 251150397Sobrien 251250397Sobrienstatic void 251390075Sobriensjlj_build_landing_pads () 251450397Sobrien{ 251590075Sobrien struct sjlj_lp_info *lp_info; 251650397Sobrien 251790075Sobrien lp_info = (struct sjlj_lp_info *) xcalloc (cfun->eh->last_region_number + 1, 251890075Sobrien sizeof (struct sjlj_lp_info)); 251950397Sobrien 252090075Sobrien if (sjlj_find_directly_reachable_regions (lp_info)) 252150397Sobrien { 252290075Sobrien rtx dispatch_label = gen_label_rtx (); 252352284Sobrien 252490075Sobrien cfun->eh->sjlj_fc 252590075Sobrien = assign_stack_local (TYPE_MODE (sjlj_fc_type_node), 252690075Sobrien int_size_in_bytes (sjlj_fc_type_node), 252790075Sobrien TYPE_ALIGN (sjlj_fc_type_node)); 252850397Sobrien 252990075Sobrien sjlj_assign_call_site_values (dispatch_label, lp_info); 253090075Sobrien sjlj_mark_call_sites (lp_info); 253150397Sobrien 253290075Sobrien sjlj_emit_function_enter (dispatch_label); 253390075Sobrien sjlj_emit_dispatch_table (dispatch_label, lp_info); 253490075Sobrien sjlj_emit_function_exit (); 253550397Sobrien } 253650397Sobrien 253790075Sobrien free (lp_info); 253850397Sobrien} 253950397Sobrien 254052284Sobrienvoid 254190075Sobrienfinish_eh_generation () 254250397Sobrien{ 254390075Sobrien /* Nothing to do if no regions created. */ 254490075Sobrien if (cfun->eh->region_tree == NULL) 254590075Sobrien return; 254650397Sobrien 254790075Sobrien /* The object here is to provide find_basic_blocks with detailed 254890075Sobrien information (via reachable_handlers) on how exception control 254990075Sobrien flows within the function. In this first pass, we can include 255090075Sobrien type information garnered from ERT_THROW and ERT_ALLOWED_EXCEPTIONS 255190075Sobrien regions, and hope that it will be useful in deleting unreachable 255290075Sobrien handlers. Subsequently, we will generate landing pads which will 255390075Sobrien connect many of the handlers, and then type information will not 255490075Sobrien be effective. Still, this is a win over previous implementations. */ 255550397Sobrien 255690075Sobrien rebuild_jump_labels (get_insns ()); 255790075Sobrien find_basic_blocks (get_insns (), max_reg_num (), 0); 255890075Sobrien cleanup_cfg (CLEANUP_PRE_LOOP); 255950397Sobrien 256090075Sobrien /* These registers are used by the landing pads. Make sure they 256190075Sobrien have been generated. */ 256290075Sobrien get_exception_pointer (cfun); 256390075Sobrien get_exception_filter (cfun); 256450397Sobrien 256590075Sobrien /* Construct the landing pads. */ 256650397Sobrien 256790075Sobrien assign_filter_values (); 256890075Sobrien build_post_landing_pads (); 256990075Sobrien connect_post_landing_pads (); 257090075Sobrien if (USING_SJLJ_EXCEPTIONS) 257190075Sobrien sjlj_build_landing_pads (); 257290075Sobrien else 257390075Sobrien dw2_build_landing_pads (); 257450397Sobrien 257590075Sobrien cfun->eh->built_landing_pads = 1; 257650397Sobrien 257790075Sobrien /* We've totally changed the CFG. Start over. */ 257890075Sobrien find_exception_handler_labels (); 257990075Sobrien rebuild_jump_labels (get_insns ()); 258090075Sobrien find_basic_blocks (get_insns (), max_reg_num (), 0); 258190075Sobrien cleanup_cfg (CLEANUP_PRE_LOOP); 258290075Sobrien} 258390075Sobrien 258496263Sobrienstatic hashval_t 258596263Sobrienehl_hash (pentry) 258696263Sobrien const PTR pentry; 258796263Sobrien{ 258896263Sobrien struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry; 258996263Sobrien 259096263Sobrien /* 2^32 * ((sqrt(5) - 1) / 2) */ 259196263Sobrien const hashval_t scaled_golden_ratio = 0x9e3779b9; 259296263Sobrien return CODE_LABEL_NUMBER (entry->label) * scaled_golden_ratio; 259396263Sobrien} 259496263Sobrien 259596263Sobrienstatic int 259696263Sobrienehl_eq (pentry, pdata) 259796263Sobrien const PTR pentry; 259896263Sobrien const PTR pdata; 259996263Sobrien{ 260096263Sobrien struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry; 260196263Sobrien struct ehl_map_entry *data = (struct ehl_map_entry *) pdata; 260296263Sobrien 260396263Sobrien return entry->label == data->label; 260496263Sobrien} 260596263Sobrien 260690075Sobrien/* This section handles removing dead code for flow. */ 260752284Sobrien 260896263Sobrien/* Remove LABEL from exception_handler_label_map. */ 260950397Sobrien 261090075Sobrienstatic void 261190075Sobrienremove_exception_handler_label (label) 261290075Sobrien rtx label; 261390075Sobrien{ 261496263Sobrien struct ehl_map_entry **slot, tmp; 261550397Sobrien 261696263Sobrien /* If exception_handler_label_map was not built yet, 261790075Sobrien there is nothing to do. */ 261896263Sobrien if (exception_handler_label_map == NULL) 261990075Sobrien return; 262050397Sobrien 262196263Sobrien tmp.label = label; 262296263Sobrien slot = (struct ehl_map_entry **) 262396263Sobrien htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT); 262496263Sobrien if (! slot) 262596263Sobrien abort (); 262650397Sobrien 262796263Sobrien htab_clear_slot (exception_handler_label_map, (void **) slot); 262850397Sobrien} 262950397Sobrien 263090075Sobrien/* Splice REGION from the region tree etc. */ 263150397Sobrien 263290075Sobrienstatic void 263390075Sobrienremove_eh_handler (region) 263490075Sobrien struct eh_region *region; 263550397Sobrien{ 263696263Sobrien struct eh_region **pp, **pp_start, *p, *outer, *inner; 263790075Sobrien rtx lab; 263850397Sobrien 263990075Sobrien /* For the benefit of efficiently handling REG_EH_REGION notes, 264090075Sobrien replace this region in the region array with its containing 264190075Sobrien region. Note that previous region deletions may result in 264296263Sobrien multiple copies of this region in the array, so we have a 264396263Sobrien list of alternate numbers by which we are known. */ 264450397Sobrien 264596263Sobrien outer = region->outer; 264696263Sobrien cfun->eh->region_array[region->region_number] = outer; 264796263Sobrien if (region->aka) 264896263Sobrien { 264996263Sobrien int i; 265096263Sobrien EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i, 265196263Sobrien { cfun->eh->region_array[i] = outer; }); 265296263Sobrien } 265396263Sobrien 265496263Sobrien if (outer) 265596263Sobrien { 265696263Sobrien if (!outer->aka) 265796263Sobrien outer->aka = BITMAP_XMALLOC (); 265896263Sobrien if (region->aka) 265996263Sobrien bitmap_a_or_b (outer->aka, outer->aka, region->aka); 266096263Sobrien bitmap_set_bit (outer->aka, region->region_number); 266196263Sobrien } 266296263Sobrien 266390075Sobrien if (cfun->eh->built_landing_pads) 266490075Sobrien lab = region->landing_pad; 266590075Sobrien else 266690075Sobrien lab = region->label; 266790075Sobrien if (lab) 266890075Sobrien remove_exception_handler_label (lab); 266950397Sobrien 267096263Sobrien if (outer) 267196263Sobrien pp_start = &outer->inner; 267290075Sobrien else 267396263Sobrien pp_start = &cfun->eh->region_tree; 267496263Sobrien for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp) 267590075Sobrien continue; 267696263Sobrien *pp = region->next_peer; 267750397Sobrien 267896263Sobrien inner = region->inner; 267996263Sobrien if (inner) 268090075Sobrien { 268196263Sobrien for (p = inner; p->next_peer ; p = p->next_peer) 268296263Sobrien p->outer = outer; 268396263Sobrien p->outer = outer; 268496263Sobrien 268596263Sobrien p->next_peer = *pp_start; 268696263Sobrien *pp_start = inner; 268790075Sobrien } 268850397Sobrien 268990075Sobrien if (region->type == ERT_CATCH) 269090075Sobrien { 269190075Sobrien struct eh_region *try, *next, *prev; 269252284Sobrien 269390075Sobrien for (try = region->next_peer; 269490075Sobrien try->type == ERT_CATCH; 269590075Sobrien try = try->next_peer) 269690075Sobrien continue; 269790075Sobrien if (try->type != ERT_TRY) 269890075Sobrien abort (); 269990075Sobrien 270090075Sobrien next = region->u.catch.next_catch; 270190075Sobrien prev = region->u.catch.prev_catch; 270290075Sobrien 270390075Sobrien if (next) 270490075Sobrien next->u.catch.prev_catch = prev; 270590075Sobrien else 270690075Sobrien try->u.try.last_catch = prev; 270790075Sobrien if (prev) 270890075Sobrien prev->u.catch.next_catch = next; 270990075Sobrien else 271090075Sobrien { 271190075Sobrien try->u.try.catch = next; 271290075Sobrien if (! next) 271390075Sobrien remove_eh_handler (try); 271490075Sobrien } 271590075Sobrien } 271690075Sobrien 271796263Sobrien free_region (region); 271850397Sobrien} 271950397Sobrien 272090075Sobrien/* LABEL heads a basic block that is about to be deleted. If this 272190075Sobrien label corresponds to an exception region, we may be able to 272290075Sobrien delete the region. */ 272350397Sobrien 272450397Sobrienvoid 272590075Sobrienmaybe_remove_eh_handler (label) 272690075Sobrien rtx label; 272750397Sobrien{ 272896263Sobrien struct ehl_map_entry **slot, tmp; 272996263Sobrien struct eh_region *region; 273050397Sobrien 273190075Sobrien /* ??? After generating landing pads, it's not so simple to determine 273290075Sobrien if the region data is completely unused. One must examine the 273390075Sobrien landing pad and the post landing pad, and whether an inner try block 273490075Sobrien is referencing the catch handlers directly. */ 273590075Sobrien if (cfun->eh->built_landing_pads) 273650397Sobrien return; 273750397Sobrien 273896263Sobrien tmp.label = label; 273996263Sobrien slot = (struct ehl_map_entry **) 274096263Sobrien htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT); 274196263Sobrien if (! slot) 274296263Sobrien return; 274396263Sobrien region = (*slot)->region; 274496263Sobrien if (! region) 274596263Sobrien return; 274696263Sobrien 274796263Sobrien /* Flow will want to remove MUST_NOT_THROW regions as unreachable 274896263Sobrien because there is no path to the fallback call to terminate. 274996263Sobrien But the region continues to affect call-site data until there 275096263Sobrien are no more contained calls, which we don't see here. */ 275196263Sobrien if (region->type == ERT_MUST_NOT_THROW) 275250397Sobrien { 275396263Sobrien htab_clear_slot (exception_handler_label_map, (void **) slot); 275496263Sobrien region->label = NULL_RTX; 275550397Sobrien } 275696263Sobrien else 275796263Sobrien remove_eh_handler (region); 275850397Sobrien} 275950397Sobrien 276096263Sobrien/* Invokes CALLBACK for every exception handler label. Only used by old 276196263Sobrien loop hackery; should not be used by new code. */ 276296263Sobrien 276396263Sobrienvoid 276496263Sobrienfor_each_eh_label (callback) 276596263Sobrien void (*callback) PARAMS ((rtx)); 276696263Sobrien{ 276796263Sobrien htab_traverse (exception_handler_label_map, for_each_eh_label_1, 276896263Sobrien (void *)callback); 276996263Sobrien} 277096263Sobrien 277196263Sobrienstatic int 277296263Sobrienfor_each_eh_label_1 (pentry, data) 277396263Sobrien PTR *pentry; 277496263Sobrien PTR data; 277596263Sobrien{ 277696263Sobrien struct ehl_map_entry *entry = *(struct ehl_map_entry **)pentry; 277796263Sobrien void (*callback) PARAMS ((rtx)) = (void (*) PARAMS ((rtx))) data; 277896263Sobrien 277996263Sobrien (*callback) (entry->label); 278096263Sobrien return 1; 278196263Sobrien} 278290075Sobrien 278390075Sobrien/* This section describes CFG exception edges for flow. */ 278450397Sobrien 278590075Sobrien/* For communicating between calls to reachable_next_level. */ 278690075Sobrienstruct reachable_info 278750397Sobrien{ 278890075Sobrien tree types_caught; 278990075Sobrien tree types_allowed; 279090075Sobrien rtx handlers; 279190075Sobrien}; 279290075Sobrien 279390075Sobrien/* A subroutine of reachable_next_level. Return true if TYPE, or a 279490075Sobrien base class of TYPE, is in HANDLED. */ 279590075Sobrien 279690075Sobrienstatic int 279790075Sobriencheck_handled (handled, type) 279890075Sobrien tree handled, type; 279990075Sobrien{ 280090075Sobrien tree t; 280190075Sobrien 280290075Sobrien /* We can check for exact matches without front-end help. */ 280390075Sobrien if (! lang_eh_type_covers) 280490075Sobrien { 280590075Sobrien for (t = handled; t ; t = TREE_CHAIN (t)) 280690075Sobrien if (TREE_VALUE (t) == type) 280790075Sobrien return 1; 280890075Sobrien } 280990075Sobrien else 281090075Sobrien { 281190075Sobrien for (t = handled; t ; t = TREE_CHAIN (t)) 281290075Sobrien if ((*lang_eh_type_covers) (TREE_VALUE (t), type)) 281390075Sobrien return 1; 281490075Sobrien } 281590075Sobrien 281650397Sobrien return 0; 281750397Sobrien} 281850397Sobrien 281990075Sobrien/* A subroutine of reachable_next_level. If we are collecting a list 282090075Sobrien of handlers, add one. After landing pad generation, reference 282190075Sobrien it instead of the handlers themselves. Further, the handlers are 282290075Sobrien all wired together, so by referencing one, we've got them all. 282390075Sobrien Before landing pad generation we reference each handler individually. 282450397Sobrien 282590075Sobrien LP_REGION contains the landing pad; REGION is the handler. */ 282650397Sobrien 282790075Sobrienstatic void 282890075Sobrienadd_reachable_handler (info, lp_region, region) 282990075Sobrien struct reachable_info *info; 283090075Sobrien struct eh_region *lp_region; 283190075Sobrien struct eh_region *region; 283250397Sobrien{ 283390075Sobrien if (! info) 283450397Sobrien return; 283550397Sobrien 283690075Sobrien if (cfun->eh->built_landing_pads) 283750397Sobrien { 283890075Sobrien if (! info->handlers) 283990075Sobrien info->handlers = alloc_INSN_LIST (lp_region->landing_pad, NULL_RTX); 284050397Sobrien } 284190075Sobrien else 284290075Sobrien info->handlers = alloc_INSN_LIST (region->label, info->handlers); 284350397Sobrien} 284450397Sobrien 284590075Sobrien/* Process one level of exception regions for reachability. 284690075Sobrien If TYPE_THROWN is non-null, then it is the *exact* type being 284790075Sobrien propagated. If INFO is non-null, then collect handler labels 284890075Sobrien and caught/allowed type information between invocations. */ 284950397Sobrien 285090075Sobrienstatic enum reachable_code 285190075Sobrienreachable_next_level (region, type_thrown, info) 285290075Sobrien struct eh_region *region; 285390075Sobrien tree type_thrown; 285490075Sobrien struct reachable_info *info; 285550397Sobrien{ 285690075Sobrien switch (region->type) 285790075Sobrien { 285890075Sobrien case ERT_CLEANUP: 285990075Sobrien /* Before landing-pad generation, we model control flow 286090075Sobrien directly to the individual handlers. In this way we can 286190075Sobrien see that catch handler types may shadow one another. */ 286290075Sobrien add_reachable_handler (info, region, region); 286390075Sobrien return RNL_MAYBE_CAUGHT; 286450397Sobrien 286590075Sobrien case ERT_TRY: 286690075Sobrien { 286790075Sobrien struct eh_region *c; 286890075Sobrien enum reachable_code ret = RNL_NOT_CAUGHT; 286950397Sobrien 287090075Sobrien for (c = region->u.try.catch; c ; c = c->u.catch.next_catch) 287190075Sobrien { 287290075Sobrien /* A catch-all handler ends the search. */ 287390075Sobrien /* ??? _Unwind_ForcedUnwind will want outer cleanups 287490075Sobrien to be run as well. */ 287590075Sobrien if (c->u.catch.type_list == NULL) 287690075Sobrien { 287790075Sobrien add_reachable_handler (info, region, c); 287890075Sobrien return RNL_CAUGHT; 287990075Sobrien } 288050397Sobrien 288190075Sobrien if (type_thrown) 288290075Sobrien { 288390075Sobrien /* If we have at least one type match, end the search. */ 288490075Sobrien tree tp_node = c->u.catch.type_list; 288550397Sobrien 288690075Sobrien for (; tp_node; tp_node = TREE_CHAIN (tp_node)) 288790075Sobrien { 288890075Sobrien tree type = TREE_VALUE (tp_node); 288950397Sobrien 289090075Sobrien if (type == type_thrown 289190075Sobrien || (lang_eh_type_covers 289290075Sobrien && (*lang_eh_type_covers) (type, type_thrown))) 289390075Sobrien { 289490075Sobrien add_reachable_handler (info, region, c); 289590075Sobrien return RNL_CAUGHT; 289690075Sobrien } 289790075Sobrien } 289850397Sobrien 289990075Sobrien /* If we have definitive information of a match failure, 290090075Sobrien the catch won't trigger. */ 290190075Sobrien if (lang_eh_type_covers) 290290075Sobrien return RNL_NOT_CAUGHT; 290390075Sobrien } 290450397Sobrien 290590075Sobrien /* At this point, we either don't know what type is thrown or 290690075Sobrien don't have front-end assistance to help deciding if it is 290790075Sobrien covered by one of the types in the list for this region. 290850397Sobrien 290990075Sobrien We'd then like to add this region to the list of reachable 291090075Sobrien handlers since it is indeed potentially reachable based on the 291190075Sobrien information we have. 291250397Sobrien 291390075Sobrien Actually, this handler is for sure not reachable if all the 291490075Sobrien types it matches have already been caught. That is, it is only 291590075Sobrien potentially reachable if at least one of the types it catches 291690075Sobrien has not been previously caught. */ 291750397Sobrien 291890075Sobrien if (! info) 291990075Sobrien ret = RNL_MAYBE_CAUGHT; 292090075Sobrien else 292190075Sobrien { 292290075Sobrien tree tp_node = c->u.catch.type_list; 292390075Sobrien bool maybe_reachable = false; 292450397Sobrien 292590075Sobrien /* Compute the potential reachability of this handler and 292690075Sobrien update the list of types caught at the same time. */ 292790075Sobrien for (; tp_node; tp_node = TREE_CHAIN (tp_node)) 292890075Sobrien { 292990075Sobrien tree type = TREE_VALUE (tp_node); 293090075Sobrien 293190075Sobrien if (! check_handled (info->types_caught, type)) 293290075Sobrien { 293390075Sobrien info->types_caught 293490075Sobrien = tree_cons (NULL, type, info->types_caught); 293590075Sobrien 293690075Sobrien maybe_reachable = true; 293790075Sobrien } 293890075Sobrien } 293990075Sobrien 294090075Sobrien if (maybe_reachable) 294190075Sobrien { 294290075Sobrien add_reachable_handler (info, region, c); 294390075Sobrien 294490075Sobrien /* ??? If the catch type is a base class of every allowed 294590075Sobrien type, then we know we can stop the search. */ 294690075Sobrien ret = RNL_MAYBE_CAUGHT; 294790075Sobrien } 294890075Sobrien } 294990075Sobrien } 295090075Sobrien 295190075Sobrien return ret; 295290075Sobrien } 295390075Sobrien 295490075Sobrien case ERT_ALLOWED_EXCEPTIONS: 295590075Sobrien /* An empty list of types definitely ends the search. */ 295690075Sobrien if (region->u.allowed.type_list == NULL_TREE) 295790075Sobrien { 295890075Sobrien add_reachable_handler (info, region, region); 295990075Sobrien return RNL_CAUGHT; 296090075Sobrien } 296190075Sobrien 296290075Sobrien /* Collect a list of lists of allowed types for use in detecting 296390075Sobrien when a catch may be transformed into a catch-all. */ 296490075Sobrien if (info) 296590075Sobrien info->types_allowed = tree_cons (NULL_TREE, 296690075Sobrien region->u.allowed.type_list, 296790075Sobrien info->types_allowed); 296890075Sobrien 296990075Sobrien /* If we have definitive information about the type hierarchy, 297090075Sobrien then we can tell if the thrown type will pass through the 297190075Sobrien filter. */ 297290075Sobrien if (type_thrown && lang_eh_type_covers) 297390075Sobrien { 297490075Sobrien if (check_handled (region->u.allowed.type_list, type_thrown)) 297590075Sobrien return RNL_NOT_CAUGHT; 297690075Sobrien else 297790075Sobrien { 297890075Sobrien add_reachable_handler (info, region, region); 297990075Sobrien return RNL_CAUGHT; 298090075Sobrien } 298190075Sobrien } 298290075Sobrien 298390075Sobrien add_reachable_handler (info, region, region); 298490075Sobrien return RNL_MAYBE_CAUGHT; 298590075Sobrien 298690075Sobrien case ERT_CATCH: 298790075Sobrien /* Catch regions are handled by their controling try region. */ 298890075Sobrien return RNL_NOT_CAUGHT; 298990075Sobrien 299090075Sobrien case ERT_MUST_NOT_THROW: 299190075Sobrien /* Here we end our search, since no exceptions may propagate. 299290075Sobrien If we've touched down at some landing pad previous, then the 299390075Sobrien explicit function call we generated may be used. Otherwise 299490075Sobrien the call is made by the runtime. */ 299590075Sobrien if (info && info->handlers) 299690075Sobrien { 299790075Sobrien add_reachable_handler (info, region, region); 299890075Sobrien return RNL_CAUGHT; 299990075Sobrien } 300090075Sobrien else 300190075Sobrien return RNL_BLOCKED; 300290075Sobrien 300390075Sobrien case ERT_THROW: 300490075Sobrien case ERT_FIXUP: 300590075Sobrien case ERT_UNKNOWN: 300690075Sobrien /* Shouldn't see these here. */ 300790075Sobrien break; 300890075Sobrien } 300990075Sobrien 301090075Sobrien abort (); 301150397Sobrien} 301250397Sobrien 301390075Sobrien/* Retrieve a list of labels of exception handlers which can be 301490075Sobrien reached by a given insn. */ 301550397Sobrien 301690075Sobrienrtx 301790075Sobrienreachable_handlers (insn) 301850397Sobrien rtx insn; 301950397Sobrien{ 302090075Sobrien struct reachable_info info; 302190075Sobrien struct eh_region *region; 302290075Sobrien tree type_thrown; 302390075Sobrien int region_number; 302450397Sobrien 302590075Sobrien if (GET_CODE (insn) == JUMP_INSN 302690075Sobrien && GET_CODE (PATTERN (insn)) == RESX) 302790075Sobrien region_number = XINT (PATTERN (insn), 0); 302890075Sobrien else 302950397Sobrien { 303090075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 303190075Sobrien if (!note || INTVAL (XEXP (note, 0)) <= 0) 303290075Sobrien return NULL; 303390075Sobrien region_number = INTVAL (XEXP (note, 0)); 303450397Sobrien } 303550397Sobrien 303690075Sobrien memset (&info, 0, sizeof (info)); 303750397Sobrien 303890075Sobrien region = cfun->eh->region_array[region_number]; 303950397Sobrien 304090075Sobrien type_thrown = NULL_TREE; 304190075Sobrien if (GET_CODE (insn) == JUMP_INSN 304290075Sobrien && GET_CODE (PATTERN (insn)) == RESX) 304390075Sobrien { 304490075Sobrien /* A RESX leaves a region instead of entering it. Thus the 304590075Sobrien region itself may have been deleted out from under us. */ 304690075Sobrien if (region == NULL) 304790075Sobrien return NULL; 304890075Sobrien region = region->outer; 304990075Sobrien } 305090075Sobrien else if (region->type == ERT_THROW) 305190075Sobrien { 305290075Sobrien type_thrown = region->u.throw.type; 305390075Sobrien region = region->outer; 305490075Sobrien } 305550397Sobrien 305690075Sobrien for (; region; region = region->outer) 305790075Sobrien if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT) 305890075Sobrien break; 305950397Sobrien 306090075Sobrien return info.handlers; 306190075Sobrien} 306250397Sobrien 306390075Sobrien/* Determine if the given INSN can throw an exception that is caught 306490075Sobrien within the function. */ 306590075Sobrien 306690075Sobrienbool 306790075Sobriencan_throw_internal (insn) 306850397Sobrien rtx insn; 306950397Sobrien{ 307090075Sobrien struct eh_region *region; 307190075Sobrien tree type_thrown; 307290075Sobrien rtx note; 307350397Sobrien 307490075Sobrien if (! INSN_P (insn)) 307590075Sobrien return false; 307650397Sobrien 307790075Sobrien if (GET_CODE (insn) == INSN 307890075Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 307990075Sobrien insn = XVECEXP (PATTERN (insn), 0, 0); 308052284Sobrien 308190075Sobrien if (GET_CODE (insn) == CALL_INSN 308290075Sobrien && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) 308350397Sobrien { 308490075Sobrien int i; 308590075Sobrien for (i = 0; i < 3; ++i) 308650397Sobrien { 308790075Sobrien rtx sub = XEXP (PATTERN (insn), i); 308890075Sobrien for (; sub ; sub = NEXT_INSN (sub)) 308990075Sobrien if (can_throw_internal (sub)) 309090075Sobrien return true; 309150397Sobrien } 309290075Sobrien return false; 309390075Sobrien } 309450397Sobrien 309590075Sobrien /* Every insn that might throw has an EH_REGION note. */ 309690075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 309790075Sobrien if (!note || INTVAL (XEXP (note, 0)) <= 0) 309890075Sobrien return false; 309950397Sobrien 310090075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 310190075Sobrien 310290075Sobrien type_thrown = NULL_TREE; 310390075Sobrien if (region->type == ERT_THROW) 310490075Sobrien { 310590075Sobrien type_thrown = region->u.throw.type; 310690075Sobrien region = region->outer; 310750397Sobrien } 310850397Sobrien 310990075Sobrien /* If this exception is ignored by each and every containing region, 311090075Sobrien then control passes straight out. The runtime may handle some 311190075Sobrien regions, which also do not require processing internally. */ 311290075Sobrien for (; region; region = region->outer) 311350397Sobrien { 311490075Sobrien enum reachable_code how = reachable_next_level (region, type_thrown, 0); 311590075Sobrien if (how == RNL_BLOCKED) 311690075Sobrien return false; 311790075Sobrien if (how != RNL_NOT_CAUGHT) 311890075Sobrien return true; 311990075Sobrien } 312050397Sobrien 312190075Sobrien return false; 312290075Sobrien} 312350397Sobrien 312490075Sobrien/* Determine if the given INSN can throw an exception that is 312590075Sobrien visible outside the function. */ 312650397Sobrien 312790075Sobrienbool 312890075Sobriencan_throw_external (insn) 312990075Sobrien rtx insn; 313090075Sobrien{ 313190075Sobrien struct eh_region *region; 313290075Sobrien tree type_thrown; 313390075Sobrien rtx note; 313450397Sobrien 313590075Sobrien if (! INSN_P (insn)) 313690075Sobrien return false; 313790075Sobrien 313890075Sobrien if (GET_CODE (insn) == INSN 313990075Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 314090075Sobrien insn = XVECEXP (PATTERN (insn), 0, 0); 314190075Sobrien 314290075Sobrien if (GET_CODE (insn) == CALL_INSN 314390075Sobrien && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) 314490075Sobrien { 314590075Sobrien int i; 314690075Sobrien for (i = 0; i < 3; ++i) 314790075Sobrien { 314890075Sobrien rtx sub = XEXP (PATTERN (insn), i); 314990075Sobrien for (; sub ; sub = NEXT_INSN (sub)) 315090075Sobrien if (can_throw_external (sub)) 315190075Sobrien return true; 315250397Sobrien } 315390075Sobrien return false; 315450397Sobrien } 315590075Sobrien 315690075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 315790075Sobrien if (!note) 315890075Sobrien { 315990075Sobrien /* Calls (and trapping insns) without notes are outside any 316090075Sobrien exception handling region in this function. We have to 316190075Sobrien assume it might throw. Given that the front end and middle 316290075Sobrien ends mark known NOTHROW functions, this isn't so wildly 316390075Sobrien inaccurate. */ 316490075Sobrien return (GET_CODE (insn) == CALL_INSN 316590075Sobrien || (flag_non_call_exceptions 316690075Sobrien && may_trap_p (PATTERN (insn)))); 316790075Sobrien } 316890075Sobrien if (INTVAL (XEXP (note, 0)) <= 0) 316990075Sobrien return false; 317090075Sobrien 317190075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 317290075Sobrien 317390075Sobrien type_thrown = NULL_TREE; 317490075Sobrien if (region->type == ERT_THROW) 317590075Sobrien { 317690075Sobrien type_thrown = region->u.throw.type; 317790075Sobrien region = region->outer; 317890075Sobrien } 317990075Sobrien 318090075Sobrien /* If the exception is caught or blocked by any containing region, 318190075Sobrien then it is not seen by any calling function. */ 318290075Sobrien for (; region ; region = region->outer) 318390075Sobrien if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT) 318490075Sobrien return false; 318590075Sobrien 318690075Sobrien return true; 318750397Sobrien} 318850397Sobrien 318990075Sobrien/* True if nothing in this function can throw outside this function. */ 319050397Sobrien 319190075Sobrienbool 319290075Sobriennothrow_function_p () 319350397Sobrien{ 319450397Sobrien rtx insn; 319550397Sobrien 319690075Sobrien if (! flag_exceptions) 319790075Sobrien return true; 319890075Sobrien 319950397Sobrien for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 320090075Sobrien if (can_throw_external (insn)) 320190075Sobrien return false; 320290075Sobrien for (insn = current_function_epilogue_delay_list; insn; 320390075Sobrien insn = XEXP (insn, 1)) 320490075Sobrien if (can_throw_external (insn)) 320590075Sobrien return false; 320690075Sobrien 320790075Sobrien return true; 320850397Sobrien} 320990075Sobrien 321050397Sobrien 321190075Sobrien/* Various hooks for unwind library. */ 321250397Sobrien 321350397Sobrien/* Do any necessary initialization to access arbitrary stack frames. 321450397Sobrien On the SPARC, this means flushing the register windows. */ 321550397Sobrien 321650397Sobrienvoid 321750397Sobrienexpand_builtin_unwind_init () 321850397Sobrien{ 321950397Sobrien /* Set this so all the registers get saved in our frame; we need to be 322090075Sobrien able to copy the saved values for any registers from frames we unwind. */ 322150397Sobrien current_function_has_nonlocal_label = 1; 322250397Sobrien 322350397Sobrien#ifdef SETUP_FRAME_ADDRESSES 322450397Sobrien SETUP_FRAME_ADDRESSES (); 322550397Sobrien#endif 322650397Sobrien} 322750397Sobrien 322890075Sobrienrtx 322990075Sobrienexpand_builtin_eh_return_data_regno (arglist) 323090075Sobrien tree arglist; 323190075Sobrien{ 323290075Sobrien tree which = TREE_VALUE (arglist); 323390075Sobrien unsigned HOST_WIDE_INT iwhich; 323490075Sobrien 323590075Sobrien if (TREE_CODE (which) != INTEGER_CST) 323690075Sobrien { 323790075Sobrien error ("argument of `__builtin_eh_return_regno' must be constant"); 323890075Sobrien return constm1_rtx; 323990075Sobrien } 324090075Sobrien 324190075Sobrien iwhich = tree_low_cst (which, 1); 324290075Sobrien iwhich = EH_RETURN_DATA_REGNO (iwhich); 324390075Sobrien if (iwhich == INVALID_REGNUM) 324490075Sobrien return constm1_rtx; 324590075Sobrien 324690075Sobrien#ifdef DWARF_FRAME_REGNUM 324790075Sobrien iwhich = DWARF_FRAME_REGNUM (iwhich); 324890075Sobrien#else 324990075Sobrien iwhich = DBX_REGISTER_NUMBER (iwhich); 325090075Sobrien#endif 325190075Sobrien 325290075Sobrien return GEN_INT (iwhich); 325390075Sobrien} 325490075Sobrien 325550397Sobrien/* Given a value extracted from the return address register or stack slot, 325650397Sobrien return the actual address encoded in that value. */ 325750397Sobrien 325850397Sobrienrtx 325950397Sobrienexpand_builtin_extract_return_addr (addr_tree) 326050397Sobrien tree addr_tree; 326150397Sobrien{ 326250397Sobrien rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0); 326390075Sobrien 326490075Sobrien /* First mask out any unwanted bits. */ 326590075Sobrien#ifdef MASK_RETURN_ADDR 326696263Sobrien expand_and (Pmode, addr, MASK_RETURN_ADDR, addr); 326790075Sobrien#endif 326890075Sobrien 326990075Sobrien /* Then adjust to find the real return address. */ 327090075Sobrien#if defined (RETURN_ADDR_OFFSET) 327190075Sobrien addr = plus_constant (addr, RETURN_ADDR_OFFSET); 327290075Sobrien#endif 327390075Sobrien 327490075Sobrien return addr; 327550397Sobrien} 327650397Sobrien 327750397Sobrien/* Given an actual address in addr_tree, do any necessary encoding 327850397Sobrien and return the value to be stored in the return address register or 327950397Sobrien stack slot so the epilogue will return to that address. */ 328050397Sobrien 328150397Sobrienrtx 328250397Sobrienexpand_builtin_frob_return_addr (addr_tree) 328350397Sobrien tree addr_tree; 328450397Sobrien{ 328590075Sobrien rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0); 328690075Sobrien 328790075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED 328890075Sobrien if (GET_MODE (addr) != Pmode) 328990075Sobrien addr = convert_memory_address (Pmode, addr); 329090075Sobrien#endif 329190075Sobrien 329250397Sobrien#ifdef RETURN_ADDR_OFFSET 329390075Sobrien addr = force_reg (Pmode, addr); 329450397Sobrien addr = plus_constant (addr, -RETURN_ADDR_OFFSET); 329550397Sobrien#endif 329690075Sobrien 329750397Sobrien return addr; 329850397Sobrien} 329950397Sobrien 330090075Sobrien/* Set up the epilogue with the magic bits we'll need to return to the 330190075Sobrien exception handler. */ 330250397Sobrien 330390075Sobrienvoid 330490075Sobrienexpand_builtin_eh_return (stackadj_tree, handler_tree) 330590075Sobrien tree stackadj_tree, handler_tree; 330690075Sobrien{ 330790075Sobrien rtx stackadj, handler; 330850397Sobrien 330990075Sobrien stackadj = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0); 331090075Sobrien handler = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0); 331150397Sobrien 331290075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED 331390075Sobrien if (GET_MODE (stackadj) != Pmode) 331490075Sobrien stackadj = convert_memory_address (Pmode, stackadj); 331550397Sobrien 331690075Sobrien if (GET_MODE (handler) != Pmode) 331790075Sobrien handler = convert_memory_address (Pmode, handler); 331850397Sobrien#endif 331950397Sobrien 332090075Sobrien if (! cfun->eh->ehr_label) 332190075Sobrien { 332290075Sobrien cfun->eh->ehr_stackadj = copy_to_reg (stackadj); 332390075Sobrien cfun->eh->ehr_handler = copy_to_reg (handler); 332490075Sobrien cfun->eh->ehr_label = gen_label_rtx (); 332590075Sobrien } 332650397Sobrien else 332790075Sobrien { 332890075Sobrien if (stackadj != cfun->eh->ehr_stackadj) 332990075Sobrien emit_move_insn (cfun->eh->ehr_stackadj, stackadj); 333090075Sobrien if (handler != cfun->eh->ehr_handler) 333190075Sobrien emit_move_insn (cfun->eh->ehr_handler, handler); 333290075Sobrien } 333350397Sobrien 333490075Sobrien emit_jump (cfun->eh->ehr_label); 333590075Sobrien} 333690075Sobrien 333790075Sobrienvoid 333890075Sobrienexpand_eh_return () 333990075Sobrien{ 334090075Sobrien rtx sa, ra, around_label; 334190075Sobrien 334290075Sobrien if (! cfun->eh->ehr_label) 334390075Sobrien return; 334490075Sobrien 334590075Sobrien sa = EH_RETURN_STACKADJ_RTX; 334690075Sobrien if (! sa) 334750397Sobrien { 334890075Sobrien error ("__builtin_eh_return not supported on this target"); 334990075Sobrien return; 335090075Sobrien } 335150397Sobrien 335290075Sobrien current_function_calls_eh_return = 1; 335390075Sobrien 335490075Sobrien around_label = gen_label_rtx (); 335590075Sobrien emit_move_insn (sa, const0_rtx); 335690075Sobrien emit_jump (around_label); 335790075Sobrien 335890075Sobrien emit_label (cfun->eh->ehr_label); 335990075Sobrien clobber_return_register (); 336090075Sobrien 336190075Sobrien#ifdef HAVE_eh_return 336290075Sobrien if (HAVE_eh_return) 336390075Sobrien emit_insn (gen_eh_return (cfun->eh->ehr_stackadj, cfun->eh->ehr_handler)); 336490075Sobrien else 336590075Sobrien#endif 336690075Sobrien { 336790075Sobrien ra = EH_RETURN_HANDLER_RTX; 336890075Sobrien if (! ra) 336990075Sobrien { 337090075Sobrien error ("__builtin_eh_return not supported on this target"); 337190075Sobrien ra = gen_reg_rtx (Pmode); 337290075Sobrien } 337390075Sobrien 337490075Sobrien emit_move_insn (sa, cfun->eh->ehr_stackadj); 337590075Sobrien emit_move_insn (ra, cfun->eh->ehr_handler); 337650397Sobrien } 337750397Sobrien 337890075Sobrien emit_label (around_label); 337990075Sobrien} 338090075Sobrien 338190075Sobrien/* In the following functions, we represent entries in the action table 338290075Sobrien as 1-based indices. Special cases are: 338352284Sobrien 338490075Sobrien 0: null action record, non-null landing pad; implies cleanups 338590075Sobrien -1: null action record, null landing pad; implies no action 338690075Sobrien -2: no call-site entry; implies must_not_throw 338790075Sobrien -3: we have yet to process outer regions 338852284Sobrien 338990075Sobrien Further, no special cases apply to the "next" field of the record. 339090075Sobrien For next, 0 means end of list. */ 339190075Sobrien 339290075Sobrienstruct action_record 339390075Sobrien{ 339490075Sobrien int offset; 339590075Sobrien int filter; 339690075Sobrien int next; 339790075Sobrien}; 339890075Sobrien 339990075Sobrienstatic int 340090075Sobrienaction_record_eq (pentry, pdata) 340190075Sobrien const PTR pentry; 340290075Sobrien const PTR pdata; 340390075Sobrien{ 340490075Sobrien const struct action_record *entry = (const struct action_record *) pentry; 340590075Sobrien const struct action_record *data = (const struct action_record *) pdata; 340690075Sobrien return entry->filter == data->filter && entry->next == data->next; 340750397Sobrien} 340850397Sobrien 340990075Sobrienstatic hashval_t 341090075Sobrienaction_record_hash (pentry) 341190075Sobrien const PTR pentry; 341290075Sobrien{ 341390075Sobrien const struct action_record *entry = (const struct action_record *) pentry; 341490075Sobrien return entry->next * 1009 + entry->filter; 341590075Sobrien} 341650397Sobrien 341790075Sobrienstatic int 341890075Sobrienadd_action_record (ar_hash, filter, next) 341990075Sobrien htab_t ar_hash; 342090075Sobrien int filter, next; 342150397Sobrien{ 342290075Sobrien struct action_record **slot, *new, tmp; 342390075Sobrien 342490075Sobrien tmp.filter = filter; 342590075Sobrien tmp.next = next; 342690075Sobrien slot = (struct action_record **) htab_find_slot (ar_hash, &tmp, INSERT); 342790075Sobrien 342890075Sobrien if ((new = *slot) == NULL) 342990075Sobrien { 343090075Sobrien new = (struct action_record *) xmalloc (sizeof (*new)); 343190075Sobrien new->offset = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1; 343290075Sobrien new->filter = filter; 343390075Sobrien new->next = next; 343490075Sobrien *slot = new; 343590075Sobrien 343690075Sobrien /* The filter value goes in untouched. The link to the next 343790075Sobrien record is a "self-relative" byte offset, or zero to indicate 343890075Sobrien that there is no next record. So convert the absolute 1 based 343990075Sobrien indices we've been carrying around into a displacement. */ 344090075Sobrien 344190075Sobrien push_sleb128 (&cfun->eh->action_record_data, filter); 344290075Sobrien if (next) 344390075Sobrien next -= VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1; 344490075Sobrien push_sleb128 (&cfun->eh->action_record_data, next); 344590075Sobrien } 344690075Sobrien 344790075Sobrien return new->offset; 344850397Sobrien} 344950397Sobrien 345090075Sobrienstatic int 345190075Sobriencollect_one_action_chain (ar_hash, region) 345290075Sobrien htab_t ar_hash; 345390075Sobrien struct eh_region *region; 345490075Sobrien{ 345590075Sobrien struct eh_region *c; 345690075Sobrien int next; 345750397Sobrien 345890075Sobrien /* If we've reached the top of the region chain, then we have 345990075Sobrien no actions, and require no landing pad. */ 346090075Sobrien if (region == NULL) 346190075Sobrien return -1; 346290075Sobrien 346390075Sobrien switch (region->type) 346490075Sobrien { 346590075Sobrien case ERT_CLEANUP: 346690075Sobrien /* A cleanup adds a zero filter to the beginning of the chain, but 346790075Sobrien there are special cases to look out for. If there are *only* 346890075Sobrien cleanups along a path, then it compresses to a zero action. 346990075Sobrien Further, if there are multiple cleanups along a path, we only 347090075Sobrien need to represent one of them, as that is enough to trigger 347190075Sobrien entry to the landing pad at runtime. */ 347290075Sobrien next = collect_one_action_chain (ar_hash, region->outer); 347390075Sobrien if (next <= 0) 347490075Sobrien return 0; 347590075Sobrien for (c = region->outer; c ; c = c->outer) 347690075Sobrien if (c->type == ERT_CLEANUP) 347790075Sobrien return next; 347890075Sobrien return add_action_record (ar_hash, 0, next); 347990075Sobrien 348090075Sobrien case ERT_TRY: 348190075Sobrien /* Process the associated catch regions in reverse order. 348290075Sobrien If there's a catch-all handler, then we don't need to 348390075Sobrien search outer regions. Use a magic -3 value to record 348490075Sobrien that we haven't done the outer search. */ 348590075Sobrien next = -3; 348690075Sobrien for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch) 348790075Sobrien { 348890075Sobrien if (c->u.catch.type_list == NULL) 348990075Sobrien { 349090075Sobrien /* Retrieve the filter from the head of the filter list 349190075Sobrien where we have stored it (see assign_filter_values). */ 349290075Sobrien int filter 349390075Sobrien = TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list)); 349490075Sobrien 349590075Sobrien next = add_action_record (ar_hash, filter, 0); 349690075Sobrien } 349790075Sobrien else 349890075Sobrien { 349990075Sobrien /* Once the outer search is done, trigger an action record for 350090075Sobrien each filter we have. */ 350190075Sobrien tree flt_node; 350290075Sobrien 350390075Sobrien if (next == -3) 350490075Sobrien { 350590075Sobrien next = collect_one_action_chain (ar_hash, region->outer); 350690075Sobrien 350790075Sobrien /* If there is no next action, terminate the chain. */ 350890075Sobrien if (next == -1) 350990075Sobrien next = 0; 351090075Sobrien /* If all outer actions are cleanups or must_not_throw, 351190075Sobrien we'll have no action record for it, since we had wanted 351290075Sobrien to encode these states in the call-site record directly. 351390075Sobrien Add a cleanup action to the chain to catch these. */ 351490075Sobrien else if (next <= 0) 351590075Sobrien next = add_action_record (ar_hash, 0, 0); 351690075Sobrien } 351790075Sobrien 351890075Sobrien flt_node = c->u.catch.filter_list; 351990075Sobrien for (; flt_node; flt_node = TREE_CHAIN (flt_node)) 352090075Sobrien { 352190075Sobrien int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node)); 352290075Sobrien next = add_action_record (ar_hash, filter, next); 352390075Sobrien } 352490075Sobrien } 352590075Sobrien } 352690075Sobrien return next; 352790075Sobrien 352890075Sobrien case ERT_ALLOWED_EXCEPTIONS: 352990075Sobrien /* An exception specification adds its filter to the 353090075Sobrien beginning of the chain. */ 353190075Sobrien next = collect_one_action_chain (ar_hash, region->outer); 353290075Sobrien return add_action_record (ar_hash, region->u.allowed.filter, 353390075Sobrien next < 0 ? 0 : next); 353490075Sobrien 353590075Sobrien case ERT_MUST_NOT_THROW: 353690075Sobrien /* A must-not-throw region with no inner handlers or cleanups 353790075Sobrien requires no call-site entry. Note that this differs from 353890075Sobrien the no handler or cleanup case in that we do require an lsda 353990075Sobrien to be generated. Return a magic -2 value to record this. */ 354090075Sobrien return -2; 354190075Sobrien 354290075Sobrien case ERT_CATCH: 354390075Sobrien case ERT_THROW: 354490075Sobrien /* CATCH regions are handled in TRY above. THROW regions are 354590075Sobrien for optimization information only and produce no output. */ 354690075Sobrien return collect_one_action_chain (ar_hash, region->outer); 354790075Sobrien 354890075Sobrien default: 354990075Sobrien abort (); 355090075Sobrien } 355190075Sobrien} 355290075Sobrien 355390075Sobrienstatic int 355490075Sobrienadd_call_site (landing_pad, action) 355590075Sobrien rtx landing_pad; 355690075Sobrien int action; 355750397Sobrien{ 355890075Sobrien struct call_site_record *data = cfun->eh->call_site_data; 355990075Sobrien int used = cfun->eh->call_site_data_used; 356090075Sobrien int size = cfun->eh->call_site_data_size; 356150397Sobrien 356290075Sobrien if (used >= size) 356390075Sobrien { 356490075Sobrien size = (size ? size * 2 : 64); 356590075Sobrien data = (struct call_site_record *) 356690075Sobrien xrealloc (data, sizeof (*data) * size); 356790075Sobrien cfun->eh->call_site_data = data; 356890075Sobrien cfun->eh->call_site_data_size = size; 356990075Sobrien } 357090075Sobrien 357190075Sobrien data[used].landing_pad = landing_pad; 357290075Sobrien data[used].action = action; 357390075Sobrien 357490075Sobrien cfun->eh->call_site_data_used = used + 1; 357590075Sobrien 357690075Sobrien return used + call_site_base; 357750397Sobrien} 357850397Sobrien 357990075Sobrien/* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes. 358090075Sobrien The new note numbers will not refer to region numbers, but 358190075Sobrien instead to call site entries. */ 358290075Sobrien 358352284Sobrienvoid 358490075Sobrienconvert_to_eh_region_ranges () 358550397Sobrien{ 358690075Sobrien rtx insn, iter, note; 358790075Sobrien htab_t ar_hash; 358890075Sobrien int last_action = -3; 358990075Sobrien rtx last_action_insn = NULL_RTX; 359090075Sobrien rtx last_landing_pad = NULL_RTX; 359190075Sobrien rtx first_no_action_insn = NULL_RTX; 359290075Sobrien int call_site = 0; 359350397Sobrien 359490075Sobrien if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL) 359552284Sobrien return; 359650397Sobrien 359790075Sobrien VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data"); 359850397Sobrien 359990075Sobrien ar_hash = htab_create (31, action_record_hash, action_record_eq, free); 360050397Sobrien 360190075Sobrien for (iter = get_insns (); iter ; iter = NEXT_INSN (iter)) 360290075Sobrien if (INSN_P (iter)) 360390075Sobrien { 360490075Sobrien struct eh_region *region; 360590075Sobrien int this_action; 360690075Sobrien rtx this_landing_pad; 360750397Sobrien 360890075Sobrien insn = iter; 360990075Sobrien if (GET_CODE (insn) == INSN 361090075Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 361190075Sobrien insn = XVECEXP (PATTERN (insn), 0, 0); 361250397Sobrien 361390075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 361490075Sobrien if (!note) 361590075Sobrien { 361690075Sobrien if (! (GET_CODE (insn) == CALL_INSN 361790075Sobrien || (flag_non_call_exceptions 361890075Sobrien && may_trap_p (PATTERN (insn))))) 361990075Sobrien continue; 362090075Sobrien this_action = -1; 362190075Sobrien region = NULL; 362290075Sobrien } 362390075Sobrien else 362490075Sobrien { 362590075Sobrien if (INTVAL (XEXP (note, 0)) <= 0) 362690075Sobrien continue; 362790075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 362890075Sobrien this_action = collect_one_action_chain (ar_hash, region); 362990075Sobrien } 363050397Sobrien 363190075Sobrien /* Existence of catch handlers, or must-not-throw regions 363290075Sobrien implies that an lsda is needed (even if empty). */ 363390075Sobrien if (this_action != -1) 363490075Sobrien cfun->uses_eh_lsda = 1; 363550397Sobrien 363690075Sobrien /* Delay creation of region notes for no-action regions 363790075Sobrien until we're sure that an lsda will be required. */ 363890075Sobrien else if (last_action == -3) 363990075Sobrien { 364090075Sobrien first_no_action_insn = iter; 364190075Sobrien last_action = -1; 364290075Sobrien } 364350397Sobrien 364490075Sobrien /* Cleanups and handlers may share action chains but not 364590075Sobrien landing pads. Collect the landing pad for this region. */ 364690075Sobrien if (this_action >= 0) 364790075Sobrien { 364890075Sobrien struct eh_region *o; 364990075Sobrien for (o = region; ! o->landing_pad ; o = o->outer) 365090075Sobrien continue; 365190075Sobrien this_landing_pad = o->landing_pad; 365290075Sobrien } 365390075Sobrien else 365490075Sobrien this_landing_pad = NULL_RTX; 365550397Sobrien 365690075Sobrien /* Differing actions or landing pads implies a change in call-site 365790075Sobrien info, which implies some EH_REGION note should be emitted. */ 365890075Sobrien if (last_action != this_action 365990075Sobrien || last_landing_pad != this_landing_pad) 366090075Sobrien { 366190075Sobrien /* If we'd not seen a previous action (-3) or the previous 366290075Sobrien action was must-not-throw (-2), then we do not need an 366390075Sobrien end note. */ 366490075Sobrien if (last_action >= -1) 366590075Sobrien { 366690075Sobrien /* If we delayed the creation of the begin, do it now. */ 366790075Sobrien if (first_no_action_insn) 366890075Sobrien { 366990075Sobrien call_site = add_call_site (NULL_RTX, 0); 367090075Sobrien note = emit_note_before (NOTE_INSN_EH_REGION_BEG, 367190075Sobrien first_no_action_insn); 367290075Sobrien NOTE_EH_HANDLER (note) = call_site; 367390075Sobrien first_no_action_insn = NULL_RTX; 367490075Sobrien } 367550397Sobrien 367690075Sobrien note = emit_note_after (NOTE_INSN_EH_REGION_END, 367790075Sobrien last_action_insn); 367890075Sobrien NOTE_EH_HANDLER (note) = call_site; 367990075Sobrien } 368052284Sobrien 368190075Sobrien /* If the new action is must-not-throw, then no region notes 368290075Sobrien are created. */ 368390075Sobrien if (this_action >= -1) 368490075Sobrien { 368590075Sobrien call_site = add_call_site (this_landing_pad, 368690075Sobrien this_action < 0 ? 0 : this_action); 368790075Sobrien note = emit_note_before (NOTE_INSN_EH_REGION_BEG, iter); 368890075Sobrien NOTE_EH_HANDLER (note) = call_site; 368990075Sobrien } 369052284Sobrien 369190075Sobrien last_action = this_action; 369290075Sobrien last_landing_pad = this_landing_pad; 369390075Sobrien } 369490075Sobrien last_action_insn = iter; 369590075Sobrien } 369652284Sobrien 369790075Sobrien if (last_action >= -1 && ! first_no_action_insn) 369890075Sobrien { 369990075Sobrien note = emit_note_after (NOTE_INSN_EH_REGION_END, last_action_insn); 370090075Sobrien NOTE_EH_HANDLER (note) = call_site; 370190075Sobrien } 370252284Sobrien 370390075Sobrien htab_delete (ar_hash); 370450397Sobrien} 370590075Sobrien 370650397Sobrien 370790075Sobrienstatic void 370890075Sobrienpush_uleb128 (data_area, value) 370990075Sobrien varray_type *data_area; 371090075Sobrien unsigned int value; 371190075Sobrien{ 371290075Sobrien do 371390075Sobrien { 371490075Sobrien unsigned char byte = value & 0x7f; 371590075Sobrien value >>= 7; 371690075Sobrien if (value) 371790075Sobrien byte |= 0x80; 371890075Sobrien VARRAY_PUSH_UCHAR (*data_area, byte); 371990075Sobrien } 372090075Sobrien while (value); 372190075Sobrien} 372250397Sobrien 372390075Sobrienstatic void 372490075Sobrienpush_sleb128 (data_area, value) 372590075Sobrien varray_type *data_area; 372690075Sobrien int value; 372790075Sobrien{ 372890075Sobrien unsigned char byte; 372990075Sobrien int more; 373050397Sobrien 373190075Sobrien do 373290075Sobrien { 373390075Sobrien byte = value & 0x7f; 373490075Sobrien value >>= 7; 373590075Sobrien more = ! ((value == 0 && (byte & 0x40) == 0) 373690075Sobrien || (value == -1 && (byte & 0x40) != 0)); 373790075Sobrien if (more) 373890075Sobrien byte |= 0x80; 373990075Sobrien VARRAY_PUSH_UCHAR (*data_area, byte); 374090075Sobrien } 374190075Sobrien while (more); 374290075Sobrien} 374350397Sobrien 374490075Sobrien 374590075Sobrien#ifndef HAVE_AS_LEB128 374690075Sobrienstatic int 374790075Sobriendw2_size_of_call_site_table () 374850397Sobrien{ 374990075Sobrien int n = cfun->eh->call_site_data_used; 375090075Sobrien int size = n * (4 + 4 + 4); 375190075Sobrien int i; 375250397Sobrien 375390075Sobrien for (i = 0; i < n; ++i) 375450397Sobrien { 375590075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 375690075Sobrien size += size_of_uleb128 (cs->action); 375750397Sobrien } 375890075Sobrien 375990075Sobrien return size; 376050397Sobrien} 376150397Sobrien 376290075Sobrienstatic int 376390075Sobriensjlj_size_of_call_site_table () 376490075Sobrien{ 376590075Sobrien int n = cfun->eh->call_site_data_used; 376690075Sobrien int size = 0; 376790075Sobrien int i; 376850397Sobrien 376990075Sobrien for (i = 0; i < n; ++i) 377090075Sobrien { 377190075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 377290075Sobrien size += size_of_uleb128 (INTVAL (cs->landing_pad)); 377390075Sobrien size += size_of_uleb128 (cs->action); 377490075Sobrien } 377590075Sobrien 377690075Sobrien return size; 377790075Sobrien} 377890075Sobrien#endif 377990075Sobrien 378090075Sobrienstatic void 378190075Sobriendw2_output_call_site_table () 378250397Sobrien{ 378390075Sobrien const char *const function_start_lab 378490075Sobrien = IDENTIFIER_POINTER (current_function_func_begin_label); 378590075Sobrien int n = cfun->eh->call_site_data_used; 378690075Sobrien int i; 378750397Sobrien 378890075Sobrien for (i = 0; i < n; ++i) 378950397Sobrien { 379090075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 379190075Sobrien char reg_start_lab[32]; 379290075Sobrien char reg_end_lab[32]; 379390075Sobrien char landing_pad_lab[32]; 379490075Sobrien 379590075Sobrien ASM_GENERATE_INTERNAL_LABEL (reg_start_lab, "LEHB", call_site_base + i); 379690075Sobrien ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i); 379790075Sobrien 379890075Sobrien if (cs->landing_pad) 379990075Sobrien ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L", 380090075Sobrien CODE_LABEL_NUMBER (cs->landing_pad)); 380190075Sobrien 380290075Sobrien /* ??? Perhaps use insn length scaling if the assembler supports 380390075Sobrien generic arithmetic. */ 380490075Sobrien /* ??? Perhaps use attr_length to choose data1 or data2 instead of 380590075Sobrien data4 if the function is small enough. */ 380690075Sobrien#ifdef HAVE_AS_LEB128 380790075Sobrien dw2_asm_output_delta_uleb128 (reg_start_lab, function_start_lab, 380890075Sobrien "region %d start", i); 380990075Sobrien dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab, 381090075Sobrien "length"); 381190075Sobrien if (cs->landing_pad) 381290075Sobrien dw2_asm_output_delta_uleb128 (landing_pad_lab, function_start_lab, 381390075Sobrien "landing pad"); 381490075Sobrien else 381590075Sobrien dw2_asm_output_data_uleb128 (0, "landing pad"); 381690075Sobrien#else 381790075Sobrien dw2_asm_output_delta (4, reg_start_lab, function_start_lab, 381890075Sobrien "region %d start", i); 381990075Sobrien dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length"); 382090075Sobrien if (cs->landing_pad) 382190075Sobrien dw2_asm_output_delta (4, landing_pad_lab, function_start_lab, 382290075Sobrien "landing pad"); 382390075Sobrien else 382490075Sobrien dw2_asm_output_data (4, 0, "landing pad"); 382590075Sobrien#endif 382690075Sobrien dw2_asm_output_data_uleb128 (cs->action, "action"); 382750397Sobrien } 382890075Sobrien 382990075Sobrien call_site_base += n; 383050397Sobrien} 383150397Sobrien 383290075Sobrienstatic void 383390075Sobriensjlj_output_call_site_table () 383490075Sobrien{ 383590075Sobrien int n = cfun->eh->call_site_data_used; 383690075Sobrien int i; 383750397Sobrien 383890075Sobrien for (i = 0; i < n; ++i) 383990075Sobrien { 384090075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 384190075Sobrien 384290075Sobrien dw2_asm_output_data_uleb128 (INTVAL (cs->landing_pad), 384390075Sobrien "region %d landing pad", i); 384490075Sobrien dw2_asm_output_data_uleb128 (cs->action, "action"); 384590075Sobrien } 384690075Sobrien 384790075Sobrien call_site_base += n; 384890075Sobrien} 384990075Sobrien 385090075Sobrienvoid 385190075Sobrienoutput_function_exception_table () 385250397Sobrien{ 385390075Sobrien int tt_format, cs_format, lp_format, i, n; 385490075Sobrien#ifdef HAVE_AS_LEB128 385590075Sobrien char ttype_label[32]; 385690075Sobrien char cs_after_size_label[32]; 385790075Sobrien char cs_end_label[32]; 385890075Sobrien#else 385990075Sobrien int call_site_len; 386090075Sobrien#endif 386190075Sobrien int have_tt_data; 386290075Sobrien int funcdef_number; 386390075Sobrien int tt_format_size = 0; 386450397Sobrien 386590075Sobrien /* Not all functions need anything. */ 386690075Sobrien if (! cfun->uses_eh_lsda) 386750397Sobrien return; 386850397Sobrien 386990075Sobrien funcdef_number = (USING_SJLJ_EXCEPTIONS 387090075Sobrien ? sjlj_funcdef_number 387190075Sobrien : current_funcdef_number); 387250397Sobrien 387390075Sobrien#ifdef IA64_UNWIND_INFO 387490075Sobrien fputs ("\t.personality\t", asm_out_file); 387590075Sobrien output_addr_const (asm_out_file, eh_personality_libfunc); 387690075Sobrien fputs ("\n\t.handlerdata\n", asm_out_file); 387790075Sobrien /* Note that varasm still thinks we're in the function's code section. 387890075Sobrien The ".endp" directive that will immediately follow will take us back. */ 387990075Sobrien#else 388090075Sobrien (*targetm.asm_out.exception_section) (); 388190075Sobrien#endif 388250397Sobrien 388390075Sobrien have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0 388490075Sobrien || VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0); 388550397Sobrien 388690075Sobrien /* Indicate the format of the @TType entries. */ 388790075Sobrien if (! have_tt_data) 388890075Sobrien tt_format = DW_EH_PE_omit; 388990075Sobrien else 389090075Sobrien { 389190075Sobrien tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1); 389290075Sobrien#ifdef HAVE_AS_LEB128 389390075Sobrien ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number); 389490075Sobrien#endif 389590075Sobrien tt_format_size = size_of_encoded_value (tt_format); 389650397Sobrien 389790075Sobrien assemble_align (tt_format_size * BITS_PER_UNIT); 389890075Sobrien } 389950397Sobrien 390090075Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number); 390150397Sobrien 390290075Sobrien /* The LSDA header. */ 390350397Sobrien 390490075Sobrien /* Indicate the format of the landing pad start pointer. An omitted 390590075Sobrien field implies @LPStart == @Start. */ 390690075Sobrien /* Currently we always put @LPStart == @Start. This field would 390790075Sobrien be most useful in moving the landing pads completely out of 390890075Sobrien line to another section, but it could also be used to minimize 390990075Sobrien the size of uleb128 landing pad offsets. */ 391090075Sobrien lp_format = DW_EH_PE_omit; 391190075Sobrien dw2_asm_output_data (1, lp_format, "@LPStart format (%s)", 391290075Sobrien eh_data_format_name (lp_format)); 391350397Sobrien 391490075Sobrien /* @LPStart pointer would go here. */ 391550397Sobrien 391690075Sobrien dw2_asm_output_data (1, tt_format, "@TType format (%s)", 391790075Sobrien eh_data_format_name (tt_format)); 391850397Sobrien 391990075Sobrien#ifndef HAVE_AS_LEB128 392090075Sobrien if (USING_SJLJ_EXCEPTIONS) 392190075Sobrien call_site_len = sjlj_size_of_call_site_table (); 392290075Sobrien else 392390075Sobrien call_site_len = dw2_size_of_call_site_table (); 392490075Sobrien#endif 392590075Sobrien 392690075Sobrien /* A pc-relative 4-byte displacement to the @TType data. */ 392790075Sobrien if (have_tt_data) 392890075Sobrien { 392990075Sobrien#ifdef HAVE_AS_LEB128 393090075Sobrien char ttype_after_disp_label[32]; 393190075Sobrien ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD", 393290075Sobrien funcdef_number); 393390075Sobrien dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label, 393490075Sobrien "@TType base offset"); 393590075Sobrien ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label); 393690075Sobrien#else 393790075Sobrien /* Ug. Alignment queers things. */ 393890075Sobrien unsigned int before_disp, after_disp, last_disp, disp; 393990075Sobrien 394090075Sobrien before_disp = 1 + 1; 394190075Sobrien after_disp = (1 + size_of_uleb128 (call_site_len) 394290075Sobrien + call_site_len 394390075Sobrien + VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) 394490075Sobrien + (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) 394590075Sobrien * tt_format_size)); 394690075Sobrien 394790075Sobrien disp = after_disp; 394890075Sobrien do 394990075Sobrien { 395090075Sobrien unsigned int disp_size, pad; 395190075Sobrien 395290075Sobrien last_disp = disp; 395390075Sobrien disp_size = size_of_uleb128 (disp); 395490075Sobrien pad = before_disp + disp_size + after_disp; 395590075Sobrien if (pad % tt_format_size) 395690075Sobrien pad = tt_format_size - (pad % tt_format_size); 395790075Sobrien else 395890075Sobrien pad = 0; 395990075Sobrien disp = after_disp + pad; 396090075Sobrien } 396190075Sobrien while (disp != last_disp); 396290075Sobrien 396390075Sobrien dw2_asm_output_data_uleb128 (disp, "@TType base offset"); 396490075Sobrien#endif 396590075Sobrien } 396690075Sobrien 396790075Sobrien /* Indicate the format of the call-site offsets. */ 396890075Sobrien#ifdef HAVE_AS_LEB128 396990075Sobrien cs_format = DW_EH_PE_uleb128; 397090075Sobrien#else 397190075Sobrien cs_format = DW_EH_PE_udata4; 397290075Sobrien#endif 397390075Sobrien dw2_asm_output_data (1, cs_format, "call-site format (%s)", 397490075Sobrien eh_data_format_name (cs_format)); 397590075Sobrien 397690075Sobrien#ifdef HAVE_AS_LEB128 397790075Sobrien ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB", 397890075Sobrien funcdef_number); 397990075Sobrien ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE", 398090075Sobrien funcdef_number); 398190075Sobrien dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label, 398290075Sobrien "Call-site table length"); 398390075Sobrien ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label); 398490075Sobrien if (USING_SJLJ_EXCEPTIONS) 398590075Sobrien sjlj_output_call_site_table (); 398690075Sobrien else 398790075Sobrien dw2_output_call_site_table (); 398890075Sobrien ASM_OUTPUT_LABEL (asm_out_file, cs_end_label); 398990075Sobrien#else 399090075Sobrien dw2_asm_output_data_uleb128 (call_site_len,"Call-site table length"); 399190075Sobrien if (USING_SJLJ_EXCEPTIONS) 399290075Sobrien sjlj_output_call_site_table (); 399390075Sobrien else 399490075Sobrien dw2_output_call_site_table (); 399590075Sobrien#endif 399690075Sobrien 399790075Sobrien /* ??? Decode and interpret the data for flag_debug_asm. */ 399890075Sobrien n = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data); 399990075Sobrien for (i = 0; i < n; ++i) 400090075Sobrien dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->action_record_data, i), 400190075Sobrien (i ? NULL : "Action record table")); 400290075Sobrien 400390075Sobrien if (have_tt_data) 400490075Sobrien assemble_align (tt_format_size * BITS_PER_UNIT); 400590075Sobrien 400690075Sobrien i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data); 400790075Sobrien while (i-- > 0) 400890075Sobrien { 400990075Sobrien tree type = VARRAY_TREE (cfun->eh->ttype_data, i); 401090075Sobrien rtx value; 401190075Sobrien 401290075Sobrien if (type == NULL_TREE) 401390075Sobrien type = integer_zero_node; 401490075Sobrien else 401590075Sobrien type = lookup_type_for_runtime (type); 401690075Sobrien 401790075Sobrien value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); 401890075Sobrien if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned) 401990075Sobrien assemble_integer (value, tt_format_size, 402090075Sobrien tt_format_size * BITS_PER_UNIT, 1); 402190075Sobrien else 402290075Sobrien dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL); 402390075Sobrien } 402490075Sobrien 402590075Sobrien#ifdef HAVE_AS_LEB128 402690075Sobrien if (have_tt_data) 402790075Sobrien ASM_OUTPUT_LABEL (asm_out_file, ttype_label); 402890075Sobrien#endif 402990075Sobrien 403090075Sobrien /* ??? Decode and interpret the data for flag_debug_asm. */ 403190075Sobrien n = VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data); 403290075Sobrien for (i = 0; i < n; ++i) 403390075Sobrien dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i), 403490075Sobrien (i ? NULL : "Exception specification table")); 403590075Sobrien 403690075Sobrien function_section (current_function_decl); 403790075Sobrien 403890075Sobrien if (USING_SJLJ_EXCEPTIONS) 403990075Sobrien sjlj_funcdef_number += 1; 404050397Sobrien} 4041