First cut of changes to utilize the new exception handling model

From-SVN: r19746
This commit is contained in:
Andrew MacLeod 1998-05-14 13:39:15 +00:00 committed by Andrew Macleod
parent 2129b0816f
commit 9a0d1e1b11
14 changed files with 960 additions and 213 deletions

View File

@ -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

View File

@ -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.

View File

@ -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 ();
}

View File

@ -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;

View File

@ -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);
}
;

View File

@ -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. */

133
gcc/eh-common.h Normal file
View File

@ -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 */

View File

@ -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;

View File

@ -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. */

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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