Re: rework Ada EH Machine_Occurrence deallocation

2019-08-02 Thread Alexandre Oliva
On Jul 30, 2019, Alexandre Oliva  wrote:

> This was regstrapped on x86_64-linux-gnu, and tested internally on
> various other platforms.  I intend to install it after the corresponding
> GDB changes, that I'm about to post, are in.

https://sourceware.org/ml/gdb-patches/2019-07/msg00671.html is now in
the GDB master tree, so I pushed this to GCC trunk:

> for  gcc/ada/ChangeLog

>   * libgnat/a-exexpr.adb (Begin_Handler_v1, End_Handler_v1): New.
>   (Claimed_Cleanup): New.
>   (Begin_Handler, End_Handler): Document.
>   * gcc-interface/trans.c (gigi): Switch to exception handler
>   ABI #1.
>   (Exception_Handler_to_gnu_gcc): Save the original cleanup
>   returned by begin handler, pass it to end handler, and use
>   EH_ELSE_EXPR to pass a propagating exception to end handler.
>   (gnat_to_gnu): Leave the exception pointer alone for reraise.
>   (add_cleanup): Handle EH_ELSE_EXPR, require it by itself.

-- 
Alexandre Oliva, freedom fighter  he/him   https://FSFLA.org/blogs/lxo
Be the change, be Free! FSF Latin America board member
GNU Toolchain EngineerFree Software Evangelist
Hay que enGNUrecerse, pero sin perder la terGNUra jamás - Che GNUevara


rework Ada EH Machine_Occurrence deallocation

2019-07-30 Thread Alexandre Oliva
Introduce exception handler ABI #1 to ensure single release, no access
after release of reraised Machine_Occurrences, and no failure to
re-reraise a Machine_Occurrence.

Unlike Ada exceptions, foreign exceptions do not get a new
Machine_Occurrence upon reraise, but each handler would delete the
exception upon completion, normal or exceptional, save for the case of
a 'raise;' statement within the handler, that avoided the delete by
clearing the exception pointer that the cleanup would use to release
it.  The cleared exception pointer might then be used by a subsequent
reraise within the same handler.  Get_Current_Excep.all would also
expose the Machine_Occurrence to reuse by Reraise_Occurrence, even for
native exceptions.

Under ABI #1, Begin_Handler_v1 claims responsibility for releasing an
exception by saving its cleanup and setting it to Claimed_Cleanup.
End_Handler_v1 restores the cleanup and runs it, as long as it isn't
still Claimed_Cleanup (which indicates an enclosing handler has
already claimed responsibility for releasing it), and as long as the
same exception is not being propagated up (the next handler of the
propagating exception will then claim responsibility for releasing
it), so reraise no longer needs to clear the exception pointer, and it
can just propagate the exception, just like Reraise_Occurrence.

ABI #1 is fully interoperable with ABI #0, i.e., exception handlers
that call the #0 primitives can be linked together with ones that call
the #1 primitives, and they will not misbehave.  When a #1 handler
claims responsibility for releasing an exception, even #0 reraises
dynamically nested within it will refrain from releasing it.  However,
when a #0 handler is a handler of a foreign exception that would have
been responsible for releasing it with #1, a Reraise_Occurrence of
that foreign or other Machine_Occurrence-carrying exception may still
cause the exception to be released multiple times, and to be used
after it is first released, even if other handlers of the foreign
exception use #1.

This was regstrapped on x86_64-linux-gnu, and tested internally on
various other platforms.  I intend to install it after the corresponding
GDB changes, that I'm about to post, are in.


for  gcc/ada/ChangeLog

* libgnat/a-exexpr.adb (Begin_Handler_v1, End_Handler_v1): New.
(Claimed_Cleanup): New.
(Begin_Handler, End_Handler): Document.
* gcc-interface/trans.c (gigi): Switch to exception handler
ABI #1.
(Exception_Handler_to_gnu_gcc): Save the original cleanup
returned by begin handler, pass it to end handler, and use
EH_ELSE_EXPR to pass a propagating exception to end handler.
(gnat_to_gnu): Leave the exception pointer alone for reraise.
(add_cleanup): Handle EH_ELSE_EXPR, require it by itself.
---
 gcc/ada/gcc-interface/trans.c |  162 ++-
 gcc/ada/libgnat/a-exexpr.adb  |  188 -
 2 files changed, 303 insertions(+), 47 deletions(-)

diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 6cd37598d3962..b484bc78532a6 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -524,22 +524,27 @@ gigi (Node_Id gnat_root,
NULL_TREE, is_default, true, true, true, false, false, NULL, Empty);
 
   /* Hooks to call when entering/leaving an exception handler.  */
-  ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
-
+  ftype = build_function_type_list (ptr_type_node,
+   ptr_type_node, NULL_TREE);
   begin_handler_decl
-= create_subprog_decl (get_identifier ("__gnat_begin_handler"), NULL_TREE,
-  ftype, NULL_TREE,
+= create_subprog_decl (get_identifier ("__gnat_begin_handler_v1"),
+  NULL_TREE, ftype, NULL_TREE,
   is_default, true, true, true, false, false, NULL,
   Empty);
-  /* __gnat_begin_handler is a dummy procedure.  */
+  /* __gnat_begin_handler_v1 is not a dummy procedure, but we arrange
+ for it not to throw.  */
   TREE_NOTHROW (begin_handler_decl) = 1;
 
+  ftype = build_function_type_list (ptr_type_node,
+   ptr_type_node, ptr_type_node,
+   ptr_type_node, NULL_TREE);
   end_handler_decl
-= create_subprog_decl (get_identifier ("__gnat_end_handler"), NULL_TREE,
+= create_subprog_decl (get_identifier ("__gnat_end_handler_v1"), NULL_TREE,
   ftype, NULL_TREE,
   is_default, true, true, true, false, false, NULL,
   Empty);
 
+  ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
   unhandled_except_decl
 = create_subprog_decl (get_identifier ("__gnat_unhandled_except_handler"),
   NULL_TREE, ftype, NULL_TREE,
@@ -6201,37 +6206,55 @@