a partial merge.

From-SVN: r7668
This commit is contained in:
Mike Stump 1994-07-07 04:33:01 +00:00
parent 451c2f82ea
commit a3b49ccd5b
5 changed files with 200 additions and 18 deletions

View File

@ -1,3 +1,24 @@
Wed Jul 6 20:25:48 1994 Mike Stump (mrs@cygnus.com)
* except.c (init_exception_processing): Setup interim_eh_hook to
call lang_interim_eh.
* except.c (do_unwind): Propagate throw object value across
stack unwinding.
* except.c (saved_throw_value): Used to hold the value of the object
being thrown. It is always a reference to the real value.
* except.c (expand_start_catch_block): Add handling for the
value of the exception object.
* except.c (expand_start_catch_block): Add handler for the handler,
so that throws inside the handler go to the outer block.
* except.c (expand_end_catch_block): Ditto.
* parse.y (handler_args): Use parm instead, as the other doesn't yet
handle references correctly.
Wed Jul 6 17:55:32 1994 Per Bothner (bothner@kalessin.cygnus.com)
* decl2.c (mark_vtable_entries): If -ftable-thunks, set the
vtable entry properly to abort.
Fri Jul 1 09:35:51 1994 Jason Merrill (jason@deneb.cygnus.com)
* parse.y (init): ANSI C++ does not forbid { }.

View File

@ -2322,6 +2322,8 @@ mark_vtable_entries (decl)
if (DECL_ABSTRACT_VIRTUAL_P (fn))
{
extern tree abort_fndecl;
if (flag_vtable_thunks)
fnaddr = TREE_VALUE (entries);
TREE_OPERAND (fnaddr, 0) = abort_fndecl;
}
}

View File

@ -31,6 +31,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "obstack.h"
#include "expr.h"
extern void (*interim_eh_hook) PROTO((tree));
/* holds the fndecl for __builtin_return_address () */
tree builtin_return_address_fndecl;
@ -231,8 +233,10 @@ do_unwind (throw_label)
emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF,
Pmode,
throw_label), -8));
/* We use three values, PC, type, and value */
easy_expand_asm ("st %l0,[%fp]");
easy_expand_asm ("st %l1,[%fp+4]");
easy_expand_asm ("st %l2,[%fp+8]");
easy_expand_asm ("ret");
easy_expand_asm ("restore");
emit_barrier ();
@ -488,10 +492,12 @@ struct exceptStack {
========================================================================= */
/* holds the pc for doing "throw" */
/* Holds the pc for doing "throw" */
rtx saved_pc;
/* holds the type of the thing being thrown. */
/* Holds the type of the thing being thrown. */
rtx saved_throw_type;
/* Holds the value being thrown. */
rtx saved_throw_value;
rtx throw_label;
@ -749,6 +755,15 @@ new_except_stack (stack)
}
/* ========================================================================= */
void
lang_interim_eh (finalization)
tree finalization;
{
if (finalization)
end_protect (finalization);
else
start_protect ();
}
/* sets up all the global eh stuff that needs to be initialized at the
start of compilation.
@ -772,6 +787,8 @@ init_exception_processing ()
tree unwind_fndecl;
tree temp, PFV;
interim_eh_hook = lang_interim_eh;
/* void (*)() */
PFV = build_pointer_type (build_function_type (void_type_node, void_list_node));
@ -844,6 +861,7 @@ init_exception_processing ()
throw_label = gen_label_rtx ();
saved_pc = gen_rtx (REG, Pmode, 16);
saved_throw_type = gen_rtx (REG, Pmode, 17);
saved_throw_value = gen_rtx (REG, Pmode, 18);
new_eh_queue (&ehqueue);
new_eh_queue (&eh_table_output_queue);
@ -949,13 +967,17 @@ expand_start_all_catch ()
label = gen_label_rtx ();
/* The label for the exception handling block we will save. */
emit_label (label);
push_label_entry (&caught_return_label_stack, label);
/* Remember where we started. */
push_last_insn ();
emit_insn (gen_nop ());
/* Will this help us not stomp on it? */
emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
while (1)
{
@ -989,7 +1011,6 @@ expand_start_all_catch ()
pop_rtl_from_perm ();
emit_label (entry->end_label);
enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
/* After running the finalization, continue on out to the next
@ -997,6 +1018,7 @@ expand_start_all_catch ()
emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label));
/* Will this help us not stomp on it? */
emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
emit_jump (throw_label);
emit_label (entry->exception_handler_label);
expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
@ -1029,7 +1051,7 @@ expand_end_all_catch ()
push_except_stmts (&exceptstack, catchstart, catchend);
/* Here was fall through into the continuation code. */
/* Here we fall through into the continuation code. */
}
@ -1046,6 +1068,7 @@ expand_leftover_cleanups ()
/* Will this help us not stomp on it? */
emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
{
@ -1082,6 +1105,7 @@ expand_leftover_cleanups ()
emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label));
/* Will this help us not stomp on it? */
emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
emit_jump (throw_label);
emit_label (entry.exception_handler_label);
expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
@ -1099,16 +1123,40 @@ expand_start_catch_block (declspecs, declarator)
tree declspecs, declarator;
{
rtx false_label_rtx;
rtx protect_label_rtx;
tree type;
tree decl;
tree init;
if (! doing_eh (1))
return;
/* Create a binding level for the parm. */
expand_start_bindings (0);
if (declspecs)
{
decl = grokdeclarator (declarator, declspecs, PARM, 0, NULL_TREE);
tree init_type;
decl = grokdeclarator (declarator, declspecs, NORMAL, 1, NULL_TREE);
/* Figure out the type that the initializer is. */
init_type = TREE_TYPE (decl);
if (TREE_CODE (init_type) != REFERENCE_TYPE)
init_type = build_reference_type (init_type);
init = convert_from_reference (save_expr (make_tree (init_type, saved_throw_value)));
/* Do we need the below two lines? */
/* Let `finish_decl' know that this initializer is ok. */
DECL_INITIAL (decl) = init;
/* This needs to be preallocated under the try block,
in a union of all catch variables. */
pushdecl (decl);
type = TREE_TYPE (decl);
/* peel back references, so they match. */
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
}
else
type = NULL_TREE;
@ -1116,6 +1164,12 @@ expand_start_catch_block (declspecs, declarator)
false_label_rtx = gen_label_rtx ();
push_label_entry (&false_label_stack, false_label_rtx);
/* This is saved for the exception table. */
push_rtl_perm ();
protect_label_rtx = gen_label_rtx ();
pop_rtl_from_perm ();
push_label_entry (&false_label_stack, protect_label_rtx);
if (type)
{
tree params;
@ -1143,11 +1197,16 @@ expand_start_catch_block (declspecs, declarator)
/* if it returned FALSE, jump over the catch block, else fall into it */
emit_jump_insn (gen_bne (false_label_rtx));
finish_decl (decl, init, NULL_TREE, 0);
}
else
{
/* Fall into the catch all section. */
}
/* This is the starting of something to protect. */
emit_label (protect_label_rtx);
emit_line_note (input_filename, lineno);
}
@ -1159,11 +1218,45 @@ void expand_end_catch_block ()
{
if (doing_eh (1))
{
rtx start_protect_label_rtx;
rtx end_protect_label_rtx;
tree decls;
struct ehEntry entry;
/* label we jump to if we caught the exception */
emit_jump (top_label_entry (&caught_return_label_stack));
/* Code to throw out to outer context, if we get an throw from within
our catch handler. */
/* These are saved for the exception table. */
push_rtl_perm ();
entry.exception_handler_label = gen_label_rtx ();
pop_rtl_from_perm ();
emit_label (entry.exception_handler_label);
emit_move_insn (saved_pc, gen_rtx (LABEL_REF,
Pmode,
top_label_entry (&caught_return_label_stack)));
emit_jump (throw_label);
/* No associated finalization. */
entry.finalization = NULL_TREE;
/* Because we are reordered out of line, we have to protect this. */
/* label for the start of the protection region. */
start_protect_label_rtx = pop_label_entry (&false_label_stack);
/* Cleanup the EH paramater. */
expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0);
/* label we emit to jump to if this catch block didn't match. */
emit_label (pop_label_entry (&false_label_stack));
emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack));
/* Because we are reordered out of line, we have to protect this. */
entry.start_label = start_protect_label_rtx;
entry.end_label = end_protect_label_rtx;
/* These set up a call to throw the caught exception into the outer
context. */
enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
}
}
@ -1300,34 +1393,45 @@ void
expand_throw (exp)
tree exp;
{
tree raiseid = NULL_TREE;
rtx temp_size;
rtx label;
tree type;
if (! doing_eh (1))
return;
/* This is the label that represents where in the code we were, when
we got an exception. This needs to be updated when we rethrow an
exception, so that the matching routine knows to search out. */
label = gen_label_rtx ();
emit_label (label);
emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label));
if (exp)
{
/* throw variable */
/* throw expression */
/* First, decay it. */
exp = default_conversion (exp);
type = TREE_TYPE (exp);
{
char *typestring = build_overload_name (type, 1, 1);
tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring)));
rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
rtx throw_value_rtx;
emit_move_insn (saved_throw_type, throw_type_rtx);
exp = convert_to_reference (build_reference_type (build_type_variant (TREE_TYPE (exp), 1, 0)), exp, CONV_STATIC, LOOKUP_COMPLAIN, NULL_TREE);
if (exp == error_mark_node)
error (" in thrown expression");
throw_value_rtx = expand_expr (build_unary_op (ADDR_EXPR, exp, 0), NULL_RTX, VOIDmode, 0);
emit_move_insn (saved_throw_value, throw_value_rtx);
}
}
else
type = void_type_node;
{
char *typestring = build_overload_name (type, 1, 1);
tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring)));
rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
emit_move_insn (saved_throw_type, throw_type_rtx);
}
{
/* rethrow current exception */
/* This part is easy, as we dont' have to do anything else. */
}
emit_jump (throw_label);
}

View File

@ -1133,6 +1133,8 @@ This issue is currently under discussion in the core reflector
@node Exception Handling, Free Store, Copying Objects, Top
@section Exception Handling
Note, exception handling in g++ is still under development.
This section describes the mapping of C++ exceptions in the C++
front-end, into the back-end exception handling framework.
@ -1150,7 +1152,9 @@ building functions names. Int's are "i", const char * is PCc, etc...
Unfortunately, the standard allows standard type conversions on throw
parameters so they can match catch handlers. This means we need a
mechanism to handle type conversion at run time, ICK.
mechanism to handle type conversion at run time, ICK. I read this part
again, and it appears that we only have to be able to do a few of the
conversions at run time, so we should be ok.
In C++, all cleanups should be protected by exception regions. The
region starts just after the reason why the cleanup is created has
@ -1177,6 +1181,52 @@ hit before the section finishes normally, they examine the list for
actions to perform. I hope they add this logic into the back-end, as it
would be nice to get that alternative approach in C++.
On an rs6000, xlC stores exception objects on that stack, under the try
block. When is unwinds down into a handler, the frame pointer is
adjusted back to the normal value for the frame in which the handler
resides, and the stack pointer is left unchanged from the time at which
the object was throwed. This is so that there is always someplace for
the exception object, and nothing can overwrite it, once we start
throwing. The only bad part, is that the stack remains large.
Flaws in g++'s exception handling. The stack pointer is restored from
stack, we want to match rs6000, and propagate the stack pointer from
time of throw, down, to the catch place.
Only exact type matching of throw types works (references work also),
catch variables cannot be used. Only works on a Sun sparc running SunOS
4.1.x. Unwinding to outer catch clauses works. All temps and local
variables are cleaned up in all unwinded scopes. Completed parts of
partially constructed objects are not cleaned up. Don't expect
exception handling to work right if you optimize, in fact the compiler
will probably core dump. You can only have one source file worth of
exception handling code. If two EH regions are the exact same size, the
backend cannot tell which one is first. It punts by picking the last
one, if they tie. This is usually right. We really should stick in a
nop, if they are the same size.
If we fall off the end of a series of catch blocks, we return to the
flow of control in a normal fasion. But this is wrong, we should
rethrow.
When we invoke the copy constructor for an exception object because it
is passed by value, and if we take a hit (exception) inside the copy
constructor someplace, where do we go? I have tentatively choosen to
not catch throws by the outer block at the same unwind level, if one
exists, but rather to allow the frame to unwind into the next series of
handlers, if any. If this is the wrong way to do it, we will need to
protect the rest of the handler in some fashion. Maybe just changing
the handler's handler to protect the whole series of handlers is the
right way to go.
The EH object is copied like it should be, if it is passed by value,
otherwise we get a reference directly to it.
EH objects make it through unwinding, but are subject to being
overwritten as they are still past the top of stack.
Exceptions in catch handlers now go to outer block.
@node Free Store, Concept Index, Exception Handling, Top
@section Free Store

View File

@ -3369,6 +3369,7 @@ type_specifier_seq:
handler_args:
'(' ELLIPSIS ')'
{ expand_start_catch_block (NULL_TREE, NULL_TREE); }
/* This doesn't allow reference parameters, the below does.
| '(' type_specifier_seq absdcl ')'
{ expand_start_catch_block ($2, $3); }
| '(' type_specifier_seq ')'
@ -3377,6 +3378,10 @@ handler_args:
{ expand_start_catch_block ($2, $3); }
| '(' typed_typespecs after_type_declarator ')'
{ expand_start_catch_block ($2, $3); }
*/
| '(' parm ')'
{ expand_start_catch_block (TREE_PURPOSE ($2),
TREE_VALUE ($2)); }
;
label_colon: