First cut of changes to utilize the new exception handling model
From-SVN: r19746
This commit is contained in:
parent
2129b0816f
commit
9a0d1e1b11
|
@ -1,3 +1,65 @@
|
|||
Thu May 14 16:30:47 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
|
||||
|
||||
* eh-common.h: New file for basic EH data structures.
|
||||
* except.h: Various prototypes and structures for NEW_EH_MODEL
|
||||
* function.h (struct function): Add a struct eh_stack for the catch
|
||||
clause stack.
|
||||
* except.c (gen_exception_label): New function to generate an
|
||||
exception label.
|
||||
(push_eh_entry): Use gen_exception_label() and init 'label_used' field.
|
||||
(push_entry): New function to push an existing entry onto a stack.
|
||||
(receive_exception_label): New function to emit the code required
|
||||
at the start of all catch blocks.
|
||||
(struct func_eh_entry): New structure for maintaining handlers
|
||||
associated with EH regions.
|
||||
(new_eh_region_entry): New function to register an EH region.
|
||||
(add_new_handler): New function to register a handler with a region.
|
||||
(get_new_handler): Creates anew handler entry for registering.
|
||||
(find_func_region): New function to convert a NOTE eh region number
|
||||
to an Eh region index.
|
||||
(get_first_handler): New function to get the first handler in a region.
|
||||
(clear_function_eh_region): New function to release memory.
|
||||
(duplicate_handlers): New function to duplicate a list of handlers.
|
||||
(expand_eh_region_end): Create a new region entry node as well.
|
||||
(expand_leftover_cleanups): Call receive_exception_label() and
|
||||
register the cleanup as a handler to the current region.
|
||||
(expand_start_catch): New function to start a catch clause.
|
||||
(expand_end_catch): New function to end a catch clause.
|
||||
(expand_start_all_catch): restructure to not do the equivilent of
|
||||
what expand_start_catch() does now. Push the exception region being
|
||||
handled onto the catch stack.
|
||||
(output_exception_table_entry): Issue an entry for each handler
|
||||
associated with a region.
|
||||
(set_exception_lang_code): New function for setting the language code.
|
||||
(set_exception_version_code): New function to set the version number.
|
||||
(output_exception_table): Output version and language codes.
|
||||
(find_exception_handler_labels): Find handler labels using new scheme.
|
||||
(is_exception_handler_label): New function, returns 1 if label is
|
||||
present as a handler in some exception region.
|
||||
(check_exception_handler_labels): Use the new scheme.
|
||||
(init_eh_for_function): Initialize the catch stack.
|
||||
(save_eh_status): Save the catch stack.
|
||||
(restore_eh_status): Restore the catch stack.
|
||||
(scan_region): Don't remove unreferenced handler label. Flow does it.
|
||||
(get_reg_for_handler): New function to get the eh_context pointer
|
||||
passed by __throw.
|
||||
(expand_builtin_eh_stub): Changes required for NEW_EH_MODEL only.
|
||||
* final.c (final_scan_insn): With NEW_EH_MODEL, add EH table
|
||||
entry when processing END region rather that START region.
|
||||
* flow.c (find_basic_blocks_1): Find all potential handler regions
|
||||
now that we don't automatically know what the labels might be.
|
||||
Let scan_region() remove unreferenced EH BEGIN/END labels.
|
||||
* integrate.c (get_label_from_map): Put inlined labels onto the
|
||||
permanent obstack since we dont know which ones might be exception
|
||||
labels.
|
||||
(save_for_inline_copying): Make new copies of all the handlers.
|
||||
(expand_inline_function): Make new copies of all the handlers.
|
||||
* libgcc2.c: Remove local struct decls, and include eh-common.h.
|
||||
(find_exception_handler): With NEW_EH_MODEL the first matching
|
||||
region we find is the right one. Add eh_info as a new parameter.
|
||||
(__throw): Pass eh_info to find_exception_handler. Set handler
|
||||
and pass use different regs under NEW_EH_MODEL.
|
||||
|
||||
Thu May 14 12:58:21 1998 Jim Wilson <wilson@cygnus.com>
|
||||
|
||||
* i960.h (hard_regno_mode_ok): Changed to function from array of
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
Thu May 14 16:30:47 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
|
||||
|
||||
* exception.cc: Include eh-common.h.
|
||||
(struct cp_eh_info): add eh_info struct with NEW_EH_MODEL.
|
||||
(__cplus_type_matcher): First stab at new C++ runtime type matcher.
|
||||
(__cp_push_exception): Initialize eh_info struct as well.
|
||||
* except.c: Remove local structs and include eh-common.h.
|
||||
(init_exception_processing): Set language and version codes.
|
||||
(call_eh_info): add presence of eh_info to runtime description of
|
||||
struct cp_eh_info.
|
||||
(expand_end_eh_spec): call start_catch_block() and end_catch_block().
|
||||
* semantics.c (finish_try_block): call start_catch_block() and
|
||||
end_catch_block().
|
||||
* parse.y (function_try_block): call start_catch_block() and
|
||||
end_catch_block().
|
||||
|
||||
Thu May 14 12:27:34 1998 Brendan Kehoe <brendan@cygnus.com>
|
||||
|
||||
* typeck.c (original_type): New function.
|
||||
|
|
|
@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA. */
|
|||
#include "function.h"
|
||||
#include "defaults.h"
|
||||
#include "toplev.h"
|
||||
#include "eh-common.h"
|
||||
|
||||
rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
|
||||
|
||||
|
@ -65,14 +66,6 @@ static tree do_pop_exception PROTO((void));
|
|||
#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
|
||||
#endif
|
||||
|
||||
#ifdef EXCEPT_SECTION_ASM_OP
|
||||
typedef struct {
|
||||
void *start_region;
|
||||
void *end_region;
|
||||
void *exception_handler;
|
||||
} exception_table;
|
||||
#endif /* EXCEPT_SECTION_ASM_OP */
|
||||
|
||||
#ifdef EXCEPT_SECTION_ASM_OP
|
||||
|
||||
/* on machines which support it, the exception table lives in another section,
|
||||
|
@ -227,6 +220,11 @@ init_exception_processing ()
|
|||
|
||||
push_lang_context (lang_name_c);
|
||||
|
||||
#ifdef NEW_EH_MODEL
|
||||
set_exception_lang_code (EH_LANG_C_plus_plus);
|
||||
set_exception_version_code (1);
|
||||
#endif
|
||||
|
||||
CatchMatch
|
||||
= builtin_function (flag_rtti
|
||||
? "__throw_type_match_rtti"
|
||||
|
@ -269,7 +267,8 @@ call_eh_info ()
|
|||
fn = IDENTIFIER_GLOBAL_VALUE (fn);
|
||||
else
|
||||
{
|
||||
tree t, fields[6];
|
||||
tree t1,t, fields[7];
|
||||
int fo = 0;
|
||||
|
||||
/* Declare cp_eh_info * __cp_exception_info (void),
|
||||
as defined in exception.cc. */
|
||||
|
@ -278,25 +277,56 @@ call_eh_info ()
|
|||
|
||||
/* struct cp_eh_info. This must match exception.cc. Note that this
|
||||
type is not pushed anywhere. */
|
||||
#ifdef NEW_EH_MODEL
|
||||
t1= make_lang_type (RECORD_TYPE);
|
||||
fields[0] = build_lang_field_decl (FIELD_DECL,
|
||||
get_identifier ("handler_label"), ptr_type_node);
|
||||
fields[1] = build_lang_field_decl (FIELD_DECL,
|
||||
get_identifier ("dynamic_handler_chain"), ptr_type_node);
|
||||
fields[2] = build_lang_field_decl (FIELD_DECL,
|
||||
get_identifier ("info"), ptr_type_node);
|
||||
/* N.B.: The fourth field LEN is expected to be
|
||||
the number of fields - 1, not the total number of fields. */
|
||||
finish_builtin_type (t1, "eh_context", fields, 2, ptr_type_node);
|
||||
t1 = build_pointer_type (t1);
|
||||
|
||||
t1= make_lang_type (RECORD_TYPE);
|
||||
fields[0] = build_lang_field_decl (FIELD_DECL,
|
||||
get_identifier ("match_function"), ptr_type_node);
|
||||
fields[1] = build_lang_field_decl (FIELD_DECL,
|
||||
get_identifier ("coerced_value"), ptr_type_node);
|
||||
fields[2] = build_lang_field_decl (FIELD_DECL,
|
||||
get_identifier ("language"), short_integer_type_node);
|
||||
fields[3] = build_lang_field_decl (FIELD_DECL,
|
||||
get_identifier ("version"), short_integer_type_node);
|
||||
/* N.B.: The fourth field LEN is expected to be
|
||||
the number of fields - 1, not the total number of fields. */
|
||||
finish_builtin_type (t1, "__eh_info", fields, 3, ptr_type_node);
|
||||
fo = 1;
|
||||
#endif
|
||||
t = make_lang_type (RECORD_TYPE);
|
||||
fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
|
||||
#ifdef NEW_EH_MODEL
|
||||
fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("eh_info"),
|
||||
t1);
|
||||
#endif
|
||||
fields[0+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
|
||||
ptr_type_node);
|
||||
fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
|
||||
fields[1+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
|
||||
ptr_type_node);
|
||||
fields[2] = build_lang_field_decl
|
||||
fields[2+fo] = build_lang_field_decl
|
||||
(FIELD_DECL, get_identifier ("cleanup"),
|
||||
build_pointer_type (build_function_type
|
||||
(ptr_type_node, tree_cons
|
||||
(NULL_TREE, ptr_type_node, void_list_node))));
|
||||
fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
|
||||
fields[3+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
|
||||
boolean_type_node);
|
||||
fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
|
||||
fields[4+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
|
||||
build_pointer_type (t));
|
||||
fields[5] = build_lang_field_decl
|
||||
fields[5+fo] = build_lang_field_decl
|
||||
(FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
|
||||
/* N.B.: The fourth field LEN is expected to be
|
||||
the number of fields - 1, not the total number of fields. */
|
||||
finish_builtin_type (t, "cp_eh_info", fields, 5, ptr_type_node);
|
||||
finish_builtin_type (t, "cp_eh_info", fields, 5+fo, ptr_type_node);
|
||||
t = build_pointer_type (t);
|
||||
|
||||
/* And now the function. */
|
||||
|
@ -681,6 +711,7 @@ expand_end_eh_spec (raises)
|
|||
int count = 0;
|
||||
|
||||
expand_start_all_catch ();
|
||||
expand_start_catch (NULL);
|
||||
expand_start_catch_block (NULL_TREE, NULL_TREE);
|
||||
|
||||
/* Build up an array of type_infos. */
|
||||
|
@ -733,6 +764,7 @@ expand_end_eh_spec (raises)
|
|||
expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
||||
|
||||
expand_end_catch_block ();
|
||||
expand_end_catch ();
|
||||
expand_end_all_catch ();
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "typeinfo"
|
||||
#include "exception"
|
||||
#include <stddef.h>
|
||||
#include "eh-common.h"
|
||||
|
||||
/* Define terminate, unexpected, set_terminate, set_unexpected as
|
||||
well as the default terminate func and default unexpected func. */
|
||||
|
@ -85,6 +86,9 @@ std::unexpected ()
|
|||
|
||||
struct cp_eh_info
|
||||
{
|
||||
#ifdef NEW_EH_MODEL
|
||||
__eh_info eh_info;
|
||||
#endif
|
||||
void *value;
|
||||
void *type;
|
||||
void (*cleanup)(void *, int);
|
||||
|
@ -133,6 +137,29 @@ __eh_free (void *p)
|
|||
free (p);
|
||||
}
|
||||
|
||||
|
||||
#ifdef NEW_EH_MODEL
|
||||
|
||||
typedef void * (* rtimetype) (void);
|
||||
|
||||
extern "C" void *
|
||||
__cplus_type_matcher (cp_eh_info *info, exception_table *matching_info,
|
||||
exception_descriptor *exception_table)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (exception_table->lang.language != EH_LANG_C_plus_plus)
|
||||
return NULL;
|
||||
|
||||
/* we don't worry about version info yet, there is only one version! */
|
||||
|
||||
void *match_type = ((rtimetype) (matching_info->match_info)) ();
|
||||
ret = __throw_type_match_rtti (match_type, info->type, info->value);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Compiler hook to push a new exception onto the stack.
|
||||
Used by expand_throw(). */
|
||||
|
||||
|
@ -147,6 +174,13 @@ __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
|
|||
p->handlers = 0;
|
||||
p->caught = false;
|
||||
|
||||
#ifdef NEW_EH_MODEL
|
||||
p->eh_info.match_function = __cplus_type_matcher;
|
||||
p->eh_info.language = EH_LANG_C_plus_plus;
|
||||
p->eh_info.version = 1;
|
||||
p->eh_info.coerced_value = NULL;
|
||||
#endif
|
||||
|
||||
cp_eh_info **q = __get_eh_info ();
|
||||
|
||||
p->next = *q;
|
||||
|
|
|
@ -3222,12 +3222,16 @@ function_try_block:
|
|||
expand_start_early_try_stmts ();
|
||||
}
|
||||
ctor_initializer_opt compstmt
|
||||
{ expand_start_all_catch (); }
|
||||
{
|
||||
expand_start_all_catch ();
|
||||
expand_start_catch (NULL);
|
||||
}
|
||||
handler_seq
|
||||
{
|
||||
int nested = (hack_decl_function_context
|
||||
(current_function_decl) != NULL_TREE);
|
||||
expand_end_all_catch ();
|
||||
expand_end_catch ();
|
||||
finish_function (lineno, (int)$3, nested);
|
||||
}
|
||||
;
|
||||
|
|
|
@ -587,7 +587,10 @@ finish_try_block (try_block)
|
|||
if (processing_template_decl)
|
||||
RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block));
|
||||
else
|
||||
expand_start_all_catch ();
|
||||
{
|
||||
expand_start_all_catch ();
|
||||
expand_start_catch (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Finish a handler-sequence for a try-block, which may be given by
|
||||
|
@ -600,7 +603,10 @@ finish_handler_sequence (try_block)
|
|||
if (processing_template_decl)
|
||||
RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
|
||||
else
|
||||
expand_end_all_catch ();
|
||||
{
|
||||
expand_end_catch ();
|
||||
expand_end_all_catch ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin a handler. Returns a HANDLER if appropriate. */
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of GNU CC. */
|
||||
|
||||
/* This file contains the structures required for the language
|
||||
independant exception handling model. Both the static compiler and
|
||||
the runtime library share this file. */
|
||||
|
||||
/* The compiler flag NEW_EH_MODEL is used to determine whether the
|
||||
compiler supports the new runtime typechecking mechanism or not. Under
|
||||
the new model, runtime info is contained in the exception table, and
|
||||
the __throw() library routine determines which handler to call based
|
||||
on the results of a call to a matching function provided by the expcetion
|
||||
thrower. Otherwise the old scheme of calling any handler which matches
|
||||
an exception range is used, and the handler is responsible for all
|
||||
checking of runtime conditions. If the handler wasn't suppose to
|
||||
get the exception, it performs a re-throw. */
|
||||
|
||||
#include "gansidecl.h"
|
||||
|
||||
|
||||
#ifndef NEW_EH_MODEL
|
||||
|
||||
struct eh_context
|
||||
{
|
||||
void **dynamic_handler_chain;
|
||||
/* This is language dependent part of the eh context. */
|
||||
void *info;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
/* The handler_label field MUST be the first field in this structure. The
|
||||
__throw() library routine expects uses __eh_stub() from except.c, which
|
||||
simply dereferences the context pointer to get the handler */
|
||||
|
||||
struct eh_context
|
||||
{
|
||||
void *handler_label;
|
||||
void **dynamic_handler_chain;
|
||||
/* This is language dependent part of the eh context. */
|
||||
void *info;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef EH_TABLE_LOOKUP
|
||||
|
||||
#ifndef NEW_EH_MODEL
|
||||
|
||||
typedef struct exception_table
|
||||
{
|
||||
void *start_region;
|
||||
void *end_region;
|
||||
void *exception_handler;
|
||||
} exception_table;
|
||||
|
||||
typedef exception_table exception_descriptor;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct exception_table
|
||||
{
|
||||
void *start_region;
|
||||
void *end_region;
|
||||
void *exception_handler;
|
||||
void *match_info; /* runtime type info */
|
||||
} exception_table;
|
||||
|
||||
|
||||
/* The language identifying portion of an exception table */
|
||||
|
||||
typedef struct exception_lang_info
|
||||
{
|
||||
short language;
|
||||
short version;
|
||||
} exception_lang_info;
|
||||
|
||||
/* Each function has an exception_descriptor which contains the
|
||||
language info, and a table of exception ranges and handlers */
|
||||
|
||||
typedef struct exception_descriptor
|
||||
{
|
||||
exception_lang_info lang;
|
||||
exception_table table[1];
|
||||
} exception_descriptor;
|
||||
|
||||
|
||||
/* A pointer to a matching function is initialized at runtime by the
|
||||
specific language if run-time exceptions are supported.
|
||||
The function takes 3 parameters
|
||||
1 - runtime exception that has been thrown info. (__eh_info *)
|
||||
2 - Match info pointer from the region being considered (void *)
|
||||
3 - exception table region is in (exception descriptor *)
|
||||
*/
|
||||
|
||||
typedef void * (*__eh_matcher) PROTO ((void *, void *, void *));
|
||||
|
||||
/* This is the runtime exception information. This forms the minimum required
|
||||
information for an exception info pointer in an eh_context structure. */
|
||||
|
||||
typedef struct __eh_info
|
||||
{
|
||||
__eh_matcher match_function;
|
||||
void *coerced_value;
|
||||
short language;
|
||||
short version;
|
||||
} __eh_info;
|
||||
|
||||
/* Convienient language codes for ID the originating language. Similar
|
||||
to the codes in dwarf2.h. */
|
||||
|
||||
enum exception_source_language
|
||||
{
|
||||
EH_LANG_C89 = 0x0001,
|
||||
EH_LANG_C = 0x0002,
|
||||
EH_LANG_Ada83 = 0x0003,
|
||||
EH_LANG_C_plus_plus = 0x0004,
|
||||
EH_LANG_Cobol74 = 0x0005,
|
||||
EH_LANG_Cobol85 = 0x0006,
|
||||
EH_LANG_Fortran77 = 0x0007,
|
||||
EH_LANG_Fortran90 = 0x0008,
|
||||
EH_LANG_Pascal83 = 0x0009,
|
||||
EH_LANG_Modula2 = 0x000a,
|
||||
EH_LANG_Java = 0x000b,
|
||||
EH_LANG_Mips_Assembler = 0x8001
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* EH_TABLE_LOOKUP */
|
||||
|
||||
|
562
gcc/except.c
562
gcc/except.c
|
@ -390,6 +390,7 @@ Boston, MA 02111-1307, USA. */
|
|||
|
||||
#include "config.h"
|
||||
#include "defaults.h"
|
||||
#include "eh-common.h"
|
||||
#include "system.h"
|
||||
#include "rtl.h"
|
||||
#include "tree.h"
|
||||
|
@ -442,6 +443,12 @@ rtx current_function_ehc;
|
|||
|
||||
static struct eh_stack ehstack;
|
||||
|
||||
|
||||
/* This stack is used to represent what the current eh region is
|
||||
for the catch blocks beings processed */
|
||||
|
||||
static struct eh_stack catchstack;
|
||||
|
||||
/* A queue used for tracking which exception regions have closed but
|
||||
whose handlers have not yet been expanded. Regions are emitted in
|
||||
groups in an attempt to improve paging performance.
|
||||
|
@ -553,6 +560,20 @@ top_label_entry (stack)
|
|||
return (*stack)->u.tlabel;
|
||||
}
|
||||
|
||||
/* get an exception label. These must be on the permanent obstack */
|
||||
|
||||
rtx
|
||||
gen_exception_label ()
|
||||
{
|
||||
rtx lab;
|
||||
|
||||
push_obstacks_nochange ();
|
||||
end_temporary_allocation ();
|
||||
lab = gen_label_rtx ();
|
||||
pop_obstacks ();
|
||||
return lab;
|
||||
}
|
||||
|
||||
/* Push a new eh_node entry onto STACK. */
|
||||
|
||||
static void
|
||||
|
@ -563,14 +584,27 @@ push_eh_entry (stack)
|
|||
struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
|
||||
|
||||
entry->outer_context = gen_label_rtx ();
|
||||
entry->exception_handler_label = gen_label_rtx ();
|
||||
entry->finalization = NULL_TREE;
|
||||
entry->label_used = 0;
|
||||
entry->exception_handler_label = gen_exception_label ();
|
||||
|
||||
node->entry = entry;
|
||||
node->chain = stack->top;
|
||||
stack->top = node;
|
||||
}
|
||||
|
||||
/* push an existing entry onto a stack. */
|
||||
static void
|
||||
push_entry (stack, entry)
|
||||
struct eh_stack *stack;
|
||||
struct eh_entry *entry;
|
||||
{
|
||||
struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
|
||||
node->entry = entry;
|
||||
node->chain = stack->top;
|
||||
stack->top = node;
|
||||
}
|
||||
|
||||
/* Pop an entry from the given STACK. */
|
||||
|
||||
static struct eh_entry *
|
||||
|
@ -631,6 +665,185 @@ dequeue_eh_entry (queue)
|
|||
|
||||
return tempentry;
|
||||
}
|
||||
|
||||
static void
|
||||
receive_exception_label (handler_label)
|
||||
rtx handler_label;
|
||||
{
|
||||
emit_label (handler_label);
|
||||
|
||||
#ifdef HAVE_exception_receiver
|
||||
if (! exceptions_via_longjmp)
|
||||
if (HAVE_exception_receiver)
|
||||
emit_insn (gen_exception_receiver ());
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_nonlocal_goto_receiver
|
||||
if (! exceptions_via_longjmp)
|
||||
if (HAVE_nonlocal_goto_receiver)
|
||||
emit_insn (gen_nonlocal_goto_receiver ());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
struct func_eh_entry
|
||||
{
|
||||
int range_number; /* EH region number from EH NOTE insn's */
|
||||
struct handler_info *handlers;
|
||||
};
|
||||
|
||||
|
||||
/* table of function eh regions */
|
||||
static struct func_eh_entry *function_eh_regions = NULL;
|
||||
static int num_func_eh_entries = 0;
|
||||
static int current_func_eh_entry = 0;
|
||||
|
||||
#define SIZE_FUNC_EH(X) (sizeof (struct func_eh_entry) * X)
|
||||
|
||||
/* Add a new eh_entry for this function, and base it off of the information
|
||||
in the EH_ENTRY parameter. A NULL parameter is invalid. The number
|
||||
returned is an number which uniquely identifies this exception range. */
|
||||
|
||||
int
|
||||
new_eh_region_entry (note_eh_region)
|
||||
int note_eh_region;
|
||||
{
|
||||
if (current_func_eh_entry == num_func_eh_entries)
|
||||
{
|
||||
if (num_func_eh_entries == 0)
|
||||
{
|
||||
function_eh_regions =
|
||||
(struct func_eh_entry *) malloc (SIZE_FUNC_EH (50));
|
||||
num_func_eh_entries = 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
num_func_eh_entries = num_func_eh_entries * 3 / 2;
|
||||
function_eh_regions = (struct func_eh_entry *)
|
||||
realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
|
||||
}
|
||||
}
|
||||
function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
|
||||
function_eh_regions[current_func_eh_entry].handlers = NULL;
|
||||
|
||||
return current_func_eh_entry++;
|
||||
}
|
||||
|
||||
/* Add new handler information to an exception range. The first parameter
|
||||
specifies the range number (returned from new_eh_entry()). The second
|
||||
parameter specifies the handler. By default the handler is inserted at
|
||||
the end of the list. A handler list may contain only ONE NULL_TREE
|
||||
typeinfo entry. Regardless where it is positioned, a NULL_TREE entry
|
||||
is always output as the LAST handler in the exception table for a region. */
|
||||
|
||||
void
|
||||
add_new_handler (region, newhandler)
|
||||
int region;
|
||||
struct handler_info *newhandler;
|
||||
{
|
||||
struct handler_info *last;
|
||||
|
||||
newhandler->next = NULL;
|
||||
last = function_eh_regions[region].handlers;
|
||||
if (last == NULL)
|
||||
function_eh_regions[region].handlers = newhandler;
|
||||
else
|
||||
{
|
||||
for ( ; last->next != NULL; last = last->next)
|
||||
last->next = newhandler;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a new handler structure initialized with the handler label and
|
||||
typeinfo fields passed in. */
|
||||
|
||||
struct handler_info *
|
||||
get_new_handler (handler, typeinfo)
|
||||
rtx handler;
|
||||
void *typeinfo;
|
||||
{
|
||||
struct handler_info* ptr;
|
||||
ptr = (struct handler_info *) malloc (sizeof (struct handler_info));
|
||||
ptr->handler_label = handler;
|
||||
ptr->type_info = typeinfo;
|
||||
ptr->next = NULL;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Find the index in function_eh_regions associated with a NOTE region. If
|
||||
the region cannot be found, a -1 is returned. This should never happen! */
|
||||
|
||||
int
|
||||
find_func_region (insn_region)
|
||||
int insn_region;
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < current_func_eh_entry; x++)
|
||||
if (function_eh_regions[x].range_number == insn_region)
|
||||
return x;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get a pointer to the first handler in an exception region's list. */
|
||||
|
||||
struct handler_info *
|
||||
get_first_handler (region)
|
||||
int region;
|
||||
{
|
||||
return function_eh_regions[find_func_region (region)].handlers;
|
||||
}
|
||||
|
||||
/* Clean out the function_eh_region table and free all memory */
|
||||
|
||||
static void
|
||||
clear_function_eh_region ()
|
||||
{
|
||||
int x;
|
||||
struct handler_info *ptr, *next;
|
||||
for (x = 0; x < current_func_eh_entry; x++)
|
||||
for (ptr = function_eh_regions[x].handlers; ptr != NULL; ptr = next)
|
||||
{
|
||||
next = ptr->next;
|
||||
free (ptr);
|
||||
}
|
||||
free (function_eh_regions);
|
||||
num_func_eh_entries = 0;
|
||||
current_func_eh_entry = 0;
|
||||
}
|
||||
|
||||
/* Make a duplicate of an exception region by copying all the handlers
|
||||
for an exception region. Return the new handler index. */
|
||||
|
||||
int
|
||||
duplicate_handlers (old_note_eh_region, new_note_eh_region)
|
||||
int old_note_eh_region, new_note_eh_region;
|
||||
{
|
||||
struct handler_info *ptr, *new_ptr;
|
||||
int new_region, region;
|
||||
|
||||
region = find_func_region (old_note_eh_region);
|
||||
if (region == -1)
|
||||
error ("Cannot duplicate non-existant exception region.");
|
||||
|
||||
if (find_func_region (new_note_eh_region) != -1)
|
||||
error ("Cannot duplicate EH region because new note region already exists");
|
||||
|
||||
new_region = new_eh_region_entry (new_note_eh_region);
|
||||
ptr = function_eh_regions[region].handlers;
|
||||
|
||||
for ( ; ptr; ptr = ptr->next)
|
||||
{
|
||||
new_ptr = get_new_handler (ptr->handler_label, ptr->type_info);
|
||||
add_new_handler (new_region, new_ptr);
|
||||
}
|
||||
|
||||
return new_region;
|
||||
}
|
||||
|
||||
|
||||
/* Routine to see if exception handling is turned on.
|
||||
DO_WARN is non-zero if we want to inform the user that exception
|
||||
|
@ -1118,6 +1331,9 @@ expand_eh_region_end (handler)
|
|||
|
||||
entry->finalization = handler;
|
||||
|
||||
/* create region entry in final exception table */
|
||||
new_eh_region_entry (NOTE_BLOCK_NUMBER (note));
|
||||
|
||||
enqueue_eh_entry (&ehqueue, entry);
|
||||
|
||||
/* If we have already started ending the bindings, don't recurse.
|
||||
|
@ -1232,19 +1448,13 @@ expand_leftover_cleanups ()
|
|||
abort ();
|
||||
|
||||
/* Output the label for the start of the exception handler. */
|
||||
emit_label (entry->exception_handler_label);
|
||||
|
||||
#ifdef HAVE_exception_receiver
|
||||
if (! exceptions_via_longjmp)
|
||||
if (HAVE_exception_receiver)
|
||||
emit_insn (gen_exception_receiver ());
|
||||
#endif
|
||||
receive_exception_label (entry->exception_handler_label);
|
||||
|
||||
#ifdef HAVE_nonlocal_goto_receiver
|
||||
if (! exceptions_via_longjmp)
|
||||
if (HAVE_nonlocal_goto_receiver)
|
||||
emit_insn (gen_nonlocal_goto_receiver ());
|
||||
#endif
|
||||
/* register a handler for this cleanup region */
|
||||
add_new_handler (
|
||||
find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)),
|
||||
get_new_handler (entry->exception_handler_label, NULL));
|
||||
|
||||
/* And now generate the insns for the handler. */
|
||||
expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
|
||||
|
@ -1270,6 +1480,37 @@ expand_start_try_stmts ()
|
|||
expand_eh_region_start ();
|
||||
}
|
||||
|
||||
/* Called to begin a catch clause. The parameter is the object which
|
||||
will be passed to the runtime type check routine. */
|
||||
void
|
||||
expand_start_catch (rtime)
|
||||
tree rtime;
|
||||
{
|
||||
rtx handler_label = catchstack.top->entry->exception_handler_label;
|
||||
int insn_region_num = CODE_LABEL_NUMBER (handler_label);
|
||||
int eh_region_entry = find_func_region (insn_region_num);
|
||||
|
||||
/* If we've already issued this label, pick a new one */
|
||||
if (catchstack.top->entry->label_used == 0)
|
||||
handler_label = gen_exception_label ();
|
||||
else
|
||||
catchstack.top->entry->label_used = 1;
|
||||
|
||||
receive_exception_label (handler_label);
|
||||
|
||||
add_new_handler (eh_region_entry, get_new_handler (handler_label, rtime));
|
||||
}
|
||||
|
||||
/* End a catch clause by dequeuing the current region */
|
||||
|
||||
void
|
||||
expand_end_catch ()
|
||||
{
|
||||
struct eh_entry *entry;
|
||||
entry = pop_eh_entry (&catchstack);
|
||||
free (entry);
|
||||
}
|
||||
|
||||
/* Generate RTL for the start of a group of catch clauses.
|
||||
|
||||
It is responsible for starting a new instruction sequence for the
|
||||
|
@ -1308,12 +1549,13 @@ expand_start_all_catch ()
|
|||
the handlers in this handler-seq. */
|
||||
start_sequence ();
|
||||
|
||||
while (1)
|
||||
entry = dequeue_eh_entry (&ehqueue);
|
||||
for ( ; entry->finalization != integer_zero_node;
|
||||
entry = dequeue_eh_entry (&ehqueue))
|
||||
{
|
||||
rtx prev;
|
||||
|
||||
entry = dequeue_eh_entry (&ehqueue);
|
||||
/* Emit the label for the exception handler for this region, and
|
||||
/* Emit the label for the cleanup handler for this region, and
|
||||
expand the code for the handler.
|
||||
|
||||
Note that a catch region is handled as a side-effect here;
|
||||
|
@ -1322,29 +1564,15 @@ expand_start_all_catch ()
|
|||
expand_expr call below. But, the label for the handler will
|
||||
still be emitted, so any code emitted after this point will
|
||||
end up being the handler. */
|
||||
emit_label (entry->exception_handler_label);
|
||||
|
||||
receive_exception_label (entry->exception_handler_label);
|
||||
|
||||
#ifdef HAVE_exception_receiver
|
||||
if (! exceptions_via_longjmp)
|
||||
if (HAVE_exception_receiver)
|
||||
emit_insn (gen_exception_receiver ());
|
||||
#endif
|
||||
/* register a handler for this cleanup region */
|
||||
add_new_handler (
|
||||
find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)),
|
||||
get_new_handler (entry->exception_handler_label, NULL));
|
||||
|
||||
#ifdef HAVE_nonlocal_goto_receiver
|
||||
if (! exceptions_via_longjmp)
|
||||
if (HAVE_nonlocal_goto_receiver)
|
||||
emit_insn (gen_nonlocal_goto_receiver ());
|
||||
#endif
|
||||
|
||||
/* When we get down to the matching entry for this try block, stop. */
|
||||
if (entry->finalization == integer_zero_node)
|
||||
{
|
||||
/* Don't forget to free this entry. */
|
||||
free (entry);
|
||||
break;
|
||||
}
|
||||
|
||||
/* And now generate the insns for the handler. */
|
||||
/* And now generate the insns for the cleanup handler. */
|
||||
expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
|
||||
|
||||
prev = get_last_insn ();
|
||||
|
@ -1358,6 +1586,12 @@ expand_start_all_catch ()
|
|||
free (entry);
|
||||
}
|
||||
|
||||
/* At this point, all the cleanups are done, and the ehqueue now has
|
||||
the current exception region at its head. We dequeue it, and put it
|
||||
on the catch stack. */
|
||||
|
||||
push_entry (&catchstack, entry);
|
||||
|
||||
/* If we are not doing setjmp/longjmp EH, because we are reordered
|
||||
out of line, we arrange to rethrow in the outer context. We need to
|
||||
do this because we are not physically within the region, if any, that
|
||||
|
@ -1496,15 +1730,16 @@ protect_with_terminate (e)
|
|||
handler for the region. This is added by add_eh_table_entry and
|
||||
used by output_exception_table_entry. */
|
||||
|
||||
static int *eh_table;
|
||||
static int eh_table_size;
|
||||
static int eh_table_max_size;
|
||||
static int *eh_table = NULL;
|
||||
static int eh_table_size = 0;
|
||||
static int eh_table_max_size = 0;
|
||||
|
||||
/* Note the need for an exception table entry for region N. If we
|
||||
don't need to output an explicit exception table, avoid all of the
|
||||
extra work.
|
||||
|
||||
Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen.
|
||||
(Or NOTE_INSN_EH_REGION_END sometimes)
|
||||
N is the NOTE_BLOCK_NUMBER of the note, which comes from the code
|
||||
label number of the exception handler for the region. */
|
||||
|
||||
|
@ -1562,24 +1797,60 @@ output_exception_table_entry (file, n)
|
|||
{
|
||||
char buf[256];
|
||||
rtx sym;
|
||||
int eh_entry;
|
||||
struct handler_info *handler;
|
||||
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
|
||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
handler = get_first_handler (n);
|
||||
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
|
||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
for ( ; handler != NULL; handler = handler->next)
|
||||
{
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
|
||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "L", n);
|
||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
|
||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
|
||||
assemble_integer (handler->handler_label,
|
||||
POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
|
||||
putc ('\n', file); /* blank line */
|
||||
#ifdef NEW_EH_MODEL
|
||||
/* for now make sure the sizes match */
|
||||
if (handler->type_info == NULL)
|
||||
assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
else
|
||||
output_constant ((tree)(handler->type_info),
|
||||
POINTER_SIZE / BITS_PER_UNIT);
|
||||
#endif
|
||||
|
||||
putc ('\n', file); /* blank line */
|
||||
}
|
||||
}
|
||||
|
||||
/* Output the exception table if we have and need one. */
|
||||
|
||||
#ifdef NEW_EH_MODEL
|
||||
|
||||
static short language_code = 0;
|
||||
static short version_code = 0;
|
||||
|
||||
/* This routine will set the language code for exceptions. */
|
||||
void set_exception_lang_code (code)
|
||||
short code;
|
||||
{
|
||||
language_code = code;
|
||||
}
|
||||
|
||||
/* This routine will set the language version code for exceptions. */
|
||||
void set_exception_version_code (code)
|
||||
short code;
|
||||
{
|
||||
version_code = code;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
output_exception_table ()
|
||||
{
|
||||
|
@ -1595,15 +1866,31 @@ output_exception_table ()
|
|||
assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
|
||||
assemble_label ("__EXCEPTION_TABLE__");
|
||||
|
||||
#ifdef NEW_EH_MODEL
|
||||
assemble_integer (GEN_INT (language_code), 2 , 1);
|
||||
assemble_integer (GEN_INT (version_code), 2 , 1);
|
||||
|
||||
/* Add enough padding to make sure table aligns on a pointer boundry. */
|
||||
i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
|
||||
for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
|
||||
;
|
||||
if (i != 0)
|
||||
assemble_integer (const0_rtx, i , 1);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < eh_table_size; ++i)
|
||||
output_exception_table_entry (asm_out_file, eh_table[i]);
|
||||
|
||||
free (eh_table);
|
||||
clear_function_eh_region ();
|
||||
|
||||
/* Ending marker for table. */
|
||||
assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
#ifndef NEW_EH_MODEL
|
||||
/* for binary compatability, the old __throw checked the second
|
||||
position for a -1, so we should output at least 2 -1's */
|
||||
assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
#endif
|
||||
putc ('\n', asm_out_file); /* blank line */
|
||||
}
|
||||
|
||||
|
@ -1662,9 +1949,6 @@ void
|
|||
find_exception_handler_labels ()
|
||||
{
|
||||
rtx insn;
|
||||
int max_labelno = max_label_num ();
|
||||
int min_labelno = get_first_label_num ();
|
||||
rtx *labels;
|
||||
|
||||
exception_handler_labels = NULL_RTX;
|
||||
|
||||
|
@ -1672,53 +1956,42 @@ find_exception_handler_labels ()
|
|||
if (! doing_eh (0))
|
||||
return;
|
||||
|
||||
/* Generate a handy reference to each label. */
|
||||
|
||||
/* We call xmalloc here instead of alloca; we did the latter in the past,
|
||||
but found that it can sometimes end up being asked to allocate space
|
||||
for more than 1 million labels. */
|
||||
labels = (rtx *) xmalloc ((max_labelno - min_labelno) * sizeof (rtx));
|
||||
bzero ((char *) labels, (max_labelno - min_labelno) * sizeof (rtx));
|
||||
|
||||
/* Arrange for labels to be indexed directly by CODE_LABEL_NUMBER. */
|
||||
labels -= min_labelno;
|
||||
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
{
|
||||
if (GET_CODE (insn) == CODE_LABEL)
|
||||
if (CODE_LABEL_NUMBER (insn) >= min_labelno
|
||||
&& CODE_LABEL_NUMBER (insn) < max_labelno)
|
||||
labels[CODE_LABEL_NUMBER (insn)] = insn;
|
||||
}
|
||||
|
||||
/* For each start of a region, add its label to the list. */
|
||||
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
{
|
||||
struct handler_info* ptr;
|
||||
if (GET_CODE (insn) == NOTE
|
||||
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
|
||||
{
|
||||
rtx label = NULL_RTX;
|
||||
|
||||
if (NOTE_BLOCK_NUMBER (insn) >= min_labelno
|
||||
&& NOTE_BLOCK_NUMBER (insn) < max_labelno)
|
||||
{
|
||||
label = labels[NOTE_BLOCK_NUMBER (insn)];
|
||||
|
||||
if (label)
|
||||
exception_handler_labels
|
||||
= gen_rtx_EXPR_LIST (VOIDmode,
|
||||
label, exception_handler_labels);
|
||||
else
|
||||
warning ("didn't find handler for EH region %d",
|
||||
NOTE_BLOCK_NUMBER (insn));
|
||||
}
|
||||
else
|
||||
warning ("mismatched EH region %d", NOTE_BLOCK_NUMBER (insn));
|
||||
ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn));
|
||||
for ( ; ptr; ptr = ptr->next)
|
||||
{
|
||||
/* make sure label isn't in the list already */
|
||||
rtx x;
|
||||
for (x = exception_handler_labels; x; x = XEXP (x, 1))
|
||||
if (XEXP (x, 0) == ptr->handler_label)
|
||||
break;
|
||||
if (! x)
|
||||
exception_handler_labels = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
ptr->handler_label, exception_handler_labels);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free (labels + min_labelno);
|
||||
/* Return a value of 1 if the parameter label number is an exception handler
|
||||
label. Return 0 otherwise. */
|
||||
|
||||
int
|
||||
is_exception_handler_label (lab)
|
||||
int lab;
|
||||
{
|
||||
rtx x;
|
||||
for (x = exception_handler_labels ; x ; x = XEXP (x, 1))
|
||||
if (lab == CODE_LABEL_NUMBER (XEXP (x, 0)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Perform sanity checking on the exception_handler_labels list.
|
||||
|
@ -1730,60 +2003,24 @@ find_exception_handler_labels ()
|
|||
void
|
||||
check_exception_handler_labels ()
|
||||
{
|
||||
rtx insn, handler;
|
||||
rtx insn, insn2;
|
||||
|
||||
/* If we aren't doing exception handling, there isn't much to check. */
|
||||
if (! doing_eh (0))
|
||||
return;
|
||||
|
||||
/* Ensure that the CODE_LABEL_NUMBER for the CODE_LABEL entry point
|
||||
in each handler corresponds to the CODE_LABEL_NUMBER of the
|
||||
handler. */
|
||||
|
||||
for (handler = exception_handler_labels;
|
||||
handler;
|
||||
handler = XEXP (handler, 1))
|
||||
/* Make sure there is no more than 1 copy of a label */
|
||||
for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
|
||||
{
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
{
|
||||
if (GET_CODE (insn) == CODE_LABEL)
|
||||
{
|
||||
if (CODE_LABEL_NUMBER (insn)
|
||||
== CODE_LABEL_NUMBER (XEXP (handler, 0)))
|
||||
{
|
||||
if (insn != XEXP (handler, 0))
|
||||
warning ("mismatched handler %d",
|
||||
CODE_LABEL_NUMBER (insn));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (insn == NULL_RTX)
|
||||
warning ("handler not found %d",
|
||||
CODE_LABEL_NUMBER (XEXP (handler, 0)));
|
||||
int count = 0;
|
||||
for (insn2 = exception_handler_labels; insn2; insn2 = XEXP (insn2, 1))
|
||||
if (XEXP (insn, 0) == XEXP (insn2, 0))
|
||||
count++;
|
||||
if (count != 1)
|
||||
warning ("Counted %d copies of EH region %d in list.\n", count,
|
||||
CODE_LABEL_NUMBER (insn));
|
||||
}
|
||||
|
||||
/* Now go through and make sure that for each region there is a
|
||||
corresponding label. */
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
{
|
||||
if (GET_CODE (insn) == NOTE
|
||||
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
|
||||
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
|
||||
{
|
||||
for (handler = exception_handler_labels;
|
||||
handler;
|
||||
handler = XEXP (handler, 1))
|
||||
{
|
||||
if (CODE_LABEL_NUMBER (XEXP (handler, 0))
|
||||
== NOTE_BLOCK_NUMBER (insn))
|
||||
break;
|
||||
}
|
||||
if (handler == NULL_RTX && !flag_syntax_only)
|
||||
warning ("region exists, no handler %d",
|
||||
NOTE_BLOCK_NUMBER (insn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This group of functions initializes the exception handling data
|
||||
|
@ -1805,6 +2042,7 @@ void
|
|||
init_eh_for_function ()
|
||||
{
|
||||
ehstack.top = 0;
|
||||
catchstack.top = 0;
|
||||
ehqueue.head = ehqueue.tail = 0;
|
||||
catch_clauses = NULL_RTX;
|
||||
false_label_stack = 0;
|
||||
|
@ -1826,6 +2064,7 @@ save_eh_status (p)
|
|||
abort ();
|
||||
|
||||
p->ehstack = ehstack;
|
||||
p->catchstack = catchstack;
|
||||
p->ehqueue = ehqueue;
|
||||
p->catch_clauses = catch_clauses;
|
||||
p->false_label_stack = false_label_stack;
|
||||
|
@ -1853,6 +2092,7 @@ restore_eh_status (p)
|
|||
catch_clauses = p->catch_clauses;
|
||||
ehqueue = p->ehqueue;
|
||||
ehstack = p->ehstack;
|
||||
catchstack = p->catchstack;
|
||||
current_function_ehc = p->ehc;
|
||||
}
|
||||
|
||||
|
@ -1951,6 +2191,10 @@ scan_region (insn, n, delete_outer)
|
|||
delete_insn (start);
|
||||
delete_insn (insn);
|
||||
|
||||
/* We no longer removed labels here, since flow will now remove any
|
||||
handler which cannot be called any more. */
|
||||
|
||||
#if 0
|
||||
/* Only do this part if we have built the exception handler
|
||||
labels. */
|
||||
if (exception_handler_labels)
|
||||
|
@ -1984,6 +2228,7 @@ scan_region (insn, n, delete_outer)
|
|||
prev = &XEXP (x, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return insn;
|
||||
}
|
||||
|
@ -2133,6 +2378,20 @@ eh_regs (r1, r2, outgoing)
|
|||
*r2 = reg2;
|
||||
}
|
||||
|
||||
|
||||
/* Retrieve the register which contains the pointer to the eh_context
|
||||
structure set the __throw. */
|
||||
|
||||
rtx
|
||||
get_reg_for_handler ()
|
||||
{
|
||||
rtx reg1;
|
||||
reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node),
|
||||
current_function_decl);
|
||||
return reg1;
|
||||
}
|
||||
|
||||
|
||||
/* Emit inside of __throw a stub which adjusts the stack pointer and jumps
|
||||
to the exception handler. __throw will set up the necessary values
|
||||
and then return to the stub. */
|
||||
|
@ -2150,8 +2409,28 @@ expand_builtin_eh_stub ()
|
|||
eh_regs (&handler, &offset, 0);
|
||||
|
||||
adjust_stack (offset);
|
||||
#ifdef NEW_EH_MODEL
|
||||
|
||||
/* Handler is in fact a pointer to the _eh_context structure, we need
|
||||
to pick out the handler field (first element), and jump to there,
|
||||
leaving the pointer to _eh_conext in the same hardware register. */
|
||||
{
|
||||
rtx jump_to, temp;
|
||||
|
||||
temp = gen_rtx_MEM (Pmode, handler);
|
||||
MEM_IN_STRUCT_P (temp) = 1;
|
||||
RTX_UNCHANGING_P (temp) = 1;
|
||||
emit_insn (gen_rtx_SET (Pmode, offset, temp));
|
||||
emit_insn (gen_rtx_USE (Pmode, handler));
|
||||
|
||||
emit_indirect_jump (offset);
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
emit_indirect_jump (handler);
|
||||
|
||||
#endif
|
||||
emit_label (after_stub);
|
||||
return gen_rtx_LABEL_REF (Pmode, stub_start);
|
||||
}
|
||||
|
@ -2213,7 +2492,8 @@ set_insn_eh_region (first, region_num)
|
|||
|
||||
/* Free the insn table, an make sure it cannot be used again. */
|
||||
|
||||
void free_insn_eh_region ()
|
||||
void
|
||||
free_insn_eh_region ()
|
||||
{
|
||||
if (!doing_eh (0))
|
||||
return;
|
||||
|
@ -2229,7 +2509,8 @@ void free_insn_eh_region ()
|
|||
this routine. If it is unavailable, passing a value of 0 will
|
||||
cause this routine to calculate it as well. */
|
||||
|
||||
void init_insn_eh_region (first, max_uid)
|
||||
void
|
||||
init_insn_eh_region (first, max_uid)
|
||||
rtx first;
|
||||
int max_uid;
|
||||
{
|
||||
|
@ -2255,8 +2536,9 @@ void init_insn_eh_region (first, max_uid)
|
|||
|
||||
/* Check whether 2 instructions are within the same region. */
|
||||
|
||||
int in_same_eh_region(insn1, insn2)
|
||||
rtx insn1,insn2;
|
||||
int
|
||||
in_same_eh_region (insn1, insn2)
|
||||
rtx insn1, insn2;
|
||||
{
|
||||
int ret, uid1, uid2;
|
||||
|
||||
|
|
82
gcc/except.h
82
gcc/except.h
|
@ -43,6 +43,10 @@ struct label_node {
|
|||
EXCEPTION_HANDLER_LABEL is the label corresponding to the handler
|
||||
for this region.
|
||||
|
||||
LABEL_USED indicates whether a CATCH block has already used this
|
||||
label or not. New ones are needed for additional catch blocks if
|
||||
it has.
|
||||
|
||||
FINALIZATION is the tree codes for the handler, or is NULL_TREE if
|
||||
one hasn't been generated yet, or is integer_zero_node to mark the
|
||||
end of a group of try blocks. */
|
||||
|
@ -50,8 +54,8 @@ struct label_node {
|
|||
struct eh_entry {
|
||||
rtx outer_context;
|
||||
rtx exception_handler_label;
|
||||
|
||||
tree finalization;
|
||||
int label_used;
|
||||
};
|
||||
|
||||
/* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next
|
||||
|
@ -145,17 +149,89 @@ extern int doing_eh PROTO ((int));
|
|||
|
||||
/* Toplevel initialization for EH. */
|
||||
|
||||
#ifdef NEW_EH_MODEL
|
||||
|
||||
void set_exception_lang_code PROTO((short));
|
||||
void set_exception_version_code PROTO((short));
|
||||
|
||||
#endif
|
||||
|
||||
/* A list of handlers asocciated with an exception region. HANDLER_LABEL
|
||||
is the the label that control should be transfered to if the data
|
||||
in TYPE_INFO matches an exception. a value of NULL_TREE for TYPE_INFO
|
||||
means This is a cleanup, and must always be called. A value of
|
||||
CATCH_ALL_TYPE works like a cleanup, but a call to the runtime matcher
|
||||
is still performed to avoid being caught by a different language
|
||||
exception. NEXT is a pointer to the next handler for this region.
|
||||
NULL means there are no more. */
|
||||
|
||||
#define CATCH_ALL_TYPE (tree *) -1
|
||||
|
||||
typedef struct handler_info
|
||||
{
|
||||
rtx handler_label;
|
||||
void *type_info;
|
||||
struct handler_info *next;
|
||||
} handler_info;
|
||||
|
||||
|
||||
/* Add a new eh_entry for this function, The parameter specifies what
|
||||
exception region number NOTE insns use to delimit this range.
|
||||
The integer returned is uniquely identifies this exception range
|
||||
within an internal table. */
|
||||
|
||||
int new_eh_region_entry PROTO((int));
|
||||
|
||||
/* Add new handler information to an exception range. The first parameter
|
||||
specifies the range number (returned from new_eh_entry()). The second
|
||||
parameter specifies the handler. By default the handler is inserted at
|
||||
the end of the list. A handler list may contain only ONE NULL_TREE
|
||||
typeinfo entry. Regardless where it is positioned, a NULL_TREE entry
|
||||
is always output as the LAST handler in the exception table for a region. */
|
||||
|
||||
void add_new_handler PROTO((int, struct handler_info *));
|
||||
|
||||
/* Create a new handler structure initialized with the handler label and
|
||||
typeinfo fields passed in. */
|
||||
|
||||
struct handler_info *get_new_handler PROTO((rtx, void *));
|
||||
|
||||
/* Make a duplicate of an exception region by copying all the handlers
|
||||
for an exception region. Return the new handler index. */
|
||||
|
||||
int duplicate_handlers PROTO((int, int));
|
||||
|
||||
|
||||
/* Get a pointer to the first handler in an exception region's list. */
|
||||
|
||||
struct handler_info *get_first_handler PROTO((int));
|
||||
|
||||
|
||||
extern void init_eh PROTO((void));
|
||||
|
||||
/* Initialization for the per-function EH data. */
|
||||
|
||||
extern void init_eh_for_function PROTO((void));
|
||||
|
||||
/* Generate an exception label. Use instead of gen_label_rtx */
|
||||
|
||||
extern rtx gen_exception_label PROTO((void));
|
||||
|
||||
/* Adds an EH table entry for EH entry number N. Called from
|
||||
final_scan_insn for NOTE_INSN_EH_REGION_BEG. */
|
||||
|
||||
extern void add_eh_table_entry PROTO((int n));
|
||||
|
||||
/* Start a catch clause, triggered by runtime value paramter. */
|
||||
|
||||
#ifdef TREE_CODE
|
||||
extern void expand_start_catch PROTO((tree));
|
||||
#endif
|
||||
|
||||
/* End a catch clause. */
|
||||
|
||||
extern void expand_end_catch PROTO((void));
|
||||
|
||||
/* Returns a non-zero value if we need to output an exception table. */
|
||||
|
||||
extern int exception_table_p PROTO((void));
|
||||
|
@ -225,6 +301,10 @@ extern void end_eh_unwinder PROTO((void));
|
|||
|
||||
extern void find_exception_handler_labels PROTO((void));
|
||||
|
||||
/* Determine if an arbitrary label is an exception label */
|
||||
|
||||
extern int is_exception_handler_label PROTO((int));
|
||||
|
||||
/* Performs sanity checking on the check_exception_handler_labels
|
||||
list. */
|
||||
|
||||
|
|
|
@ -1988,7 +1988,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
|
|||
&& ! exceptions_via_longjmp)
|
||||
{
|
||||
ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn));
|
||||
#ifndef NEW_EH_MODEL
|
||||
add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
|
||||
#endif
|
||||
#ifdef ASM_OUTPUT_EH_REGION_BEG
|
||||
ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn));
|
||||
#endif
|
||||
|
@ -1999,6 +2001,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
|
|||
&& ! exceptions_via_longjmp)
|
||||
{
|
||||
ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn));
|
||||
#ifdef NEW_EH_MODEL
|
||||
add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
|
||||
#endif
|
||||
#ifdef ASM_OUTPUT_EH_REGION_END
|
||||
ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn));
|
||||
#endif
|
||||
|
|
55
gcc/flow.c
55
gcc/flow.c
|
@ -396,7 +396,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
|||
register char *block_marked = (char *) alloca (n_basic_blocks);
|
||||
/* An array of CODE_LABELs, indexed by UID for the start of the active
|
||||
EH handler for each insn in F. */
|
||||
rtx *active_eh_handler;
|
||||
int *active_eh_region;
|
||||
int *nested_eh_region;
|
||||
/* List of label_refs to all labels whose addresses are taken
|
||||
and used as data. */
|
||||
rtx label_value_list;
|
||||
|
@ -406,7 +407,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
|||
int in_libcall_block = 0;
|
||||
|
||||
pass = 1;
|
||||
active_eh_handler = (rtx *) alloca ((max_uid_for_flow + 1) * sizeof (rtx));
|
||||
active_eh_region = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int));
|
||||
nested_eh_region = (int *) alloca ((max_label_num () + 1) * sizeof (int));
|
||||
restart:
|
||||
|
||||
label_value_list = 0;
|
||||
|
@ -414,7 +416,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
|||
bzero (block_live, n_basic_blocks);
|
||||
bzero (block_marked, n_basic_blocks);
|
||||
bzero (basic_block_computed_jump_target, n_basic_blocks);
|
||||
bzero ((char *) active_eh_handler, (max_uid_for_flow + 1) * sizeof (rtx));
|
||||
bzero ((char *) active_eh_region, (max_uid_for_flow + 1) * sizeof (int));
|
||||
bzero ((char *) nested_eh_region, (max_label_num () + 1) * sizeof (int));
|
||||
current_function_has_computed_jump = 0;
|
||||
|
||||
/* Initialize with just block 0 reachable and no blocks marked. */
|
||||
|
@ -482,20 +485,18 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
|||
label_value_list);
|
||||
}
|
||||
|
||||
/* Keep a lifo list of the currently active exception handlers. */
|
||||
/* Keep a lifo list of the currently active exception notes. */
|
||||
if (GET_CODE (insn) == NOTE)
|
||||
{
|
||||
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
|
||||
{
|
||||
for (x = exception_handler_labels; x; x = XEXP (x, 1))
|
||||
if (CODE_LABEL_NUMBER (XEXP (x, 0)) == NOTE_BLOCK_NUMBER (insn))
|
||||
{
|
||||
eh_note = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
XEXP (x, 0), eh_note);
|
||||
break;
|
||||
}
|
||||
if (x == NULL_RTX)
|
||||
abort ();
|
||||
if (eh_note)
|
||||
nested_eh_region [NOTE_BLOCK_NUMBER (insn)] =
|
||||
NOTE_BLOCK_NUMBER (XEXP (eh_note, 0));
|
||||
else
|
||||
nested_eh_region [NOTE_BLOCK_NUMBER (insn)] = 0;
|
||||
eh_note = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
insn, eh_note);
|
||||
}
|
||||
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
|
||||
eh_note = XEXP (eh_note, 1);
|
||||
|
@ -509,8 +510,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
|||
&& (asynchronous_exceptions
|
||||
|| (GET_CODE (insn) == CALL_INSN
|
||||
&& ! in_libcall_block)))
|
||||
active_eh_handler[INSN_UID (insn)] = XEXP (eh_note, 0);
|
||||
|
||||
active_eh_region[INSN_UID (insn)] =
|
||||
NOTE_BLOCK_NUMBER (XEXP (eh_note, 0));
|
||||
BLOCK_NUM (insn) = i;
|
||||
|
||||
if (code != NOTE)
|
||||
|
@ -655,11 +656,20 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
|||
&& ! find_reg_note (insn, REG_RETVAL,
|
||||
NULL_RTX)))
|
||||
{
|
||||
if (active_eh_handler[INSN_UID (insn)])
|
||||
mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
|
||||
active_eh_handler[INSN_UID (insn)]),
|
||||
insn, 0);
|
||||
|
||||
if (active_eh_region[INSN_UID (insn)])
|
||||
{
|
||||
int region;
|
||||
handler_info *ptr;
|
||||
region = active_eh_region[INSN_UID (insn)];
|
||||
for ( ; region;
|
||||
region = nested_eh_region[region])
|
||||
{
|
||||
ptr = get_first_handler (region);
|
||||
for ( ; ptr ; ptr = ptr->next)
|
||||
mark_label_ref (gen_rtx_LABEL_REF
|
||||
(VOIDmode, ptr->handler_label), insn, 0);
|
||||
}
|
||||
}
|
||||
if (!asynchronous_exceptions)
|
||||
{
|
||||
for (x = nonlocal_label_list;
|
||||
|
@ -764,6 +774,10 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
|||
/* Now we have to find the EH_BEG and EH_END notes
|
||||
associated with this label and remove them. */
|
||||
|
||||
#if 0
|
||||
/* Handlers and labels no longer needs to have the same values.
|
||||
If there are no references, scan_region will remove any region
|
||||
labels which are of no use. */
|
||||
for (x = get_insns (); x; x = NEXT_INSN (x))
|
||||
{
|
||||
if (GET_CODE (x) == NOTE
|
||||
|
@ -778,6 +792,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
|||
NOTE_SOURCE_FILE (x) = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
prev = &XEXP (x, 1);
|
||||
|
|
|
@ -133,6 +133,7 @@ struct function
|
|||
|
||||
/* For exception handling information. */
|
||||
struct eh_stack ehstack;
|
||||
struct eh_stack catchstack;
|
||||
struct eh_queue ehqueue;
|
||||
rtx catch_clauses;
|
||||
struct label_node *false_label_stack;
|
||||
|
|
|
@ -95,7 +95,12 @@ get_label_from_map (map, i)
|
|||
rtx x = map->label_map[i];
|
||||
|
||||
if (x == NULL_RTX)
|
||||
x = map->label_map[i] = gen_label_rtx();
|
||||
{
|
||||
push_obstacks_nochange ();
|
||||
end_temporary_allocation ();
|
||||
x = map->label_map[i] = gen_label_rtx();
|
||||
pop_obstacks ();
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
@ -658,10 +663,28 @@ save_for_inline_copying (fndecl)
|
|||
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
|
||||
|| NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END)
|
||||
{
|
||||
int new_region = CODE_LABEL_NUMBER
|
||||
(label_map[NOTE_BLOCK_NUMBER (copy)]);
|
||||
|
||||
/* we have to duplicate the handlers for the original */
|
||||
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
|
||||
{
|
||||
handler_info *ptr, *temp;
|
||||
int nr;
|
||||
nr = new_eh_region_entry (new_region);
|
||||
ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
|
||||
for ( ; ptr; ptr = ptr->next)
|
||||
{
|
||||
temp = get_new_handler (
|
||||
label_map[CODE_LABEL_NUMBER (ptr->handler_label)],
|
||||
ptr->type_info);
|
||||
add_new_handler (nr, temp);
|
||||
}
|
||||
}
|
||||
|
||||
/* We have to forward these both to match the new exception
|
||||
region. */
|
||||
NOTE_BLOCK_NUMBER (copy)
|
||||
= CODE_LABEL_NUMBER (label_map[NOTE_BLOCK_NUMBER (copy)]);
|
||||
NOTE_BLOCK_NUMBER (copy) = new_region;
|
||||
|
||||
}
|
||||
RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);
|
||||
|
@ -2038,6 +2061,22 @@ expand_inline_function (fndecl, parms, target, ignore, type,
|
|||
rtx label
|
||||
= get_label_from_map (map, NOTE_BLOCK_NUMBER (copy));
|
||||
|
||||
/* we have to duplicate the handlers for the original */
|
||||
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
|
||||
{
|
||||
handler_info *ptr, *temp;
|
||||
int nr;
|
||||
nr = new_eh_region_entry (CODE_LABEL_NUMBER (label));
|
||||
ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
|
||||
for ( ; ptr; ptr = ptr->next)
|
||||
{
|
||||
temp = get_new_handler ( get_label_from_map (map,
|
||||
CODE_LABEL_NUMBER (ptr->handler_label)),
|
||||
ptr->type_info);
|
||||
add_new_handler (nr, temp);
|
||||
}
|
||||
}
|
||||
|
||||
/* We have to forward these both to match the new exception
|
||||
region. */
|
||||
NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label);
|
||||
|
|
|
@ -3046,14 +3046,10 @@ __empty ()
|
|||
{
|
||||
}
|
||||
|
||||
/* EH context structure. */
|
||||
|
||||
struct eh_context
|
||||
{
|
||||
void **dynamic_handler_chain;
|
||||
/* This is language dependent part of the eh context. */
|
||||
void *info;
|
||||
};
|
||||
/* Include definitions of EH context and table layout */
|
||||
|
||||
#include "eh-common.h"
|
||||
|
||||
/* This is a safeguard for dynamic handler chain. */
|
||||
|
||||
|
@ -3361,11 +3357,6 @@ EH_TABLE_LOOKUP
|
|||
#else
|
||||
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
typedef struct exception_table {
|
||||
void *start;
|
||||
void *end;
|
||||
void *exception_handler;
|
||||
} exception_table;
|
||||
|
||||
/* This routine takes a PC and a pointer to the exception region TABLE for
|
||||
its translation unit, and returns the address of the exception handler
|
||||
|
@ -3376,31 +3367,68 @@ typedef struct exception_table {
|
|||
an inner block. */
|
||||
|
||||
static void *
|
||||
find_exception_handler (void *pc, exception_table *table)
|
||||
find_exception_handler (void *pc, exception_descriptor *table, void *eh_info)
|
||||
{
|
||||
if (table)
|
||||
{
|
||||
#ifdef NEW_EH_MODEL
|
||||
/* The new model assumed the table is sorted inner-most out so the
|
||||
first region we find which matches is the correct one */
|
||||
|
||||
int pos;
|
||||
void *ret;
|
||||
exception_table *tab = &(table->table[0]);
|
||||
|
||||
/* Subtract 1 from the PC to avoid hitting the next region */
|
||||
pc--;
|
||||
|
||||
/* We can't do a binary search because the table is in inner-most
|
||||
to outermost address ranges within functions */
|
||||
for (pos = 0; tab[pos].start_region != (void *) -1; pos++)
|
||||
{
|
||||
if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
|
||||
{
|
||||
if (tab[pos].match_info)
|
||||
{
|
||||
__eh_matcher matcher = ((__eh_info *)eh_info)->match_function;
|
||||
/* match info but no matcher is NOT a match */
|
||||
if (matcher)
|
||||
{
|
||||
ret = (*matcher)(eh_info, tab[pos].match_info, table);
|
||||
if (ret)
|
||||
{
|
||||
((__eh_info *)eh_info)->coerced_value = ret;
|
||||
return tab[pos].exception_handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return tab[pos].exception_handler;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int pos;
|
||||
int best = -1;
|
||||
|
||||
/* We can't do a binary search because the table isn't guaranteed
|
||||
to be sorted from function to function. */
|
||||
for (pos = 0; table[pos].exception_handler != (void *) -1; ++pos)
|
||||
{
|
||||
if (table[pos].start <= pc && table[pos].end > pc)
|
||||
{
|
||||
/* This can apply. Make sure it is at least as small as
|
||||
the previous best. */
|
||||
if (best == -1 || (table[pos].end <= table[best].end
|
||||
&& table[pos].start >= table[best].start))
|
||||
best = pos;
|
||||
}
|
||||
/* But it is sorted by starting PC within a function. */
|
||||
else if (best >= 0 && table[pos].start > pc)
|
||||
break;
|
||||
}
|
||||
to be sorted from function to function. */
|
||||
for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
|
||||
{
|
||||
if (table[pos].start_region <= pc && table[pos].end_region > pc)
|
||||
{
|
||||
/* This can apply. Make sure it is at least as small as
|
||||
the previous best. */
|
||||
if (best == -1 || (table[pos].end_region <= table[best].end_region
|
||||
&& table[pos].start_region >= table[best].start_region))
|
||||
best = pos;
|
||||
}
|
||||
/* But it is sorted by starting PC within a function. */
|
||||
else if (best >= 0 && table[pos].start_region > pc)
|
||||
break;
|
||||
}
|
||||
if (best != -1)
|
||||
return table[best].exception_handler;
|
||||
return table[best].exception_handler;
|
||||
#endif
|
||||
}
|
||||
|
||||
return (void *) 0;
|
||||
|
@ -3583,7 +3611,7 @@ label:
|
|||
if (! udata)
|
||||
break;
|
||||
|
||||
handler = find_exception_handler (pc, udata->eh_ptr);
|
||||
handler = find_exception_handler (pc, udata->eh_ptr, eh->info);
|
||||
|
||||
/* If we found one, we can stop searching. */
|
||||
if (handler)
|
||||
|
@ -3602,6 +3630,10 @@ label:
|
|||
if (! handler)
|
||||
__terminate ();
|
||||
|
||||
#ifdef NEW_EH_MODEL
|
||||
eh->handler_label = handler;
|
||||
#endif
|
||||
|
||||
if (pc == saved_pc)
|
||||
/* We found a handler in the throw context, no need to unwind. */
|
||||
udata = my_udata;
|
||||
|
@ -3669,7 +3701,13 @@ label:
|
|||
|
||||
/* Set up the registers we use to communicate with the stub.
|
||||
We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack. */
|
||||
|
||||
#ifdef NEW_EH_MODEL
|
||||
__builtin_set_eh_regs ((void *)eh,
|
||||
#else
|
||||
__builtin_set_eh_regs (handler,
|
||||
#endif
|
||||
|
||||
#ifdef STACK_GROWS_DOWNWARD
|
||||
udata->cfa - my_udata->cfa
|
||||
#else
|
||||
|
|
Loading…
Reference in New Issue