From a3b49ccd5b72453a4c87944bbf827b7748a6d74d Mon Sep 17 00:00:00 2001 From: Mike Stump Date: Thu, 7 Jul 1994 04:33:01 +0000 Subject: [PATCH] a partial merge. From-SVN: r7668 --- gcc/cp/ChangeLog | 21 +++++++ gcc/cp/decl2.c | 2 + gcc/cp/except.c | 138 +++++++++++++++++++++++++++++++++++++++------ gcc/cp/gxxint.texi | 52 ++++++++++++++++- gcc/cp/parse.y | 5 ++ 5 files changed, 200 insertions(+), 18 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 78aef9fb59c0..d0f869cd7800 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 { }. diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index d04cf51a0e84..80bb62aee5cb 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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; } } diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 160a10b19b34..dc91b9d3b1f0 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -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); } diff --git a/gcc/cp/gxxint.texi b/gcc/cp/gxxint.texi index 426417acdad9..00ff72e8a1be 100644 --- a/gcc/cp/gxxint.texi +++ b/gcc/cp/gxxint.texi @@ -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 diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y index 44ea9ea0affd..d30e511bbfb4 100644 --- a/gcc/cp/parse.y +++ b/gcc/cp/parse.y @@ -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: -- 2.47.2