This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/9] Gccgo port to s390[x] -- part I


This patch fixes bug 60406 in an architecture independent way.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60406

The key change in this patch is to use
_Unwind_FindEnclosingFunction() to identify the defering function.
However, this does not work on platforms that still use SJLJ
exceptions.

ChangeLog
2014-09-05  Dominik Vogt  <vogt@linux.vnet.ibm.com>

        * libgo/runtime/proc.c (runtime_main): Initialize new structure fields.
        * libgo/runtime/go-recover.c (__go_can_recover): Rewrite logic to detect
        recover by return address.
        * libgo/runtime/go-defer.c (__go_set_defer_retaddr): Removed.
        (__go_set_defering_fn): Replacement for __go_set_defer_retaddr.
        (__go_defer): Initialize new structure fields.
        * libgo/runtime/go-defer.h (struct __go_defer_stack): Replace __retaddr
        with __defering_fn.

gcc/go/ChangeLog
2014-09-05  Dominik Vogt  <vogt@linux.vnet.ibm.com>

        * gofrontend/statements.cc (build_thunk): The thunk uses the new
        libgo runtime runctions __go_set_defering_fn and no longer depends
        on the fake label and fake return value.
        * gofrontend/runtime.def: Replace SET_DEFER_RETADDR with
        SET_DEFERING_FN.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany
>From e6bbac3a00095f86535eceb5bdc87bca2ec406c9 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <vogt@linux.vnet.ibm.com>
Date: Fri, 5 Sep 2014 07:30:14 +0100
Subject: [PATCH 1/9] GO: Fix recover logic in libgo and gofrontend.

1) Fix recover logic in libgo.
2) Fix recover logic in gofrontend.
---
 gcc/go/gofrontend/runtime.def   |  5 ++---
 gcc/go/gofrontend/statements.cc | 25 +++++--------------------
 libgo/runtime/go-defer.c        | 17 ++++++++---------
 libgo/runtime/go-defer.h        | 11 ++++++-----
 libgo/runtime/go-recover.c      | 40 +++++++++++++++++++++-------------------
 libgo/runtime/proc.c            |  2 +-
 6 files changed, 43 insertions(+), 57 deletions(-)

diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index 8c6e82b..0cd045a 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -190,9 +190,8 @@ DEF_GO_RUNTIME(CAN_RECOVER, "__go_can_recover", P1(POINTER), R1(BOOL))
 // Get the return address of the function.
 DEF_GO_RUNTIME(RETURN_ADDRESS, "__go_return_address", P1(INT), R1(POINTER))
 
-// Set the return address for defer in a defer thunk.
-DEF_GO_RUNTIME(SET_DEFER_RETADDR, "__go_set_defer_retaddr", P1(POINTER),
-	       R1(BOOL))
+// Set the function address for defer in a defer thunk.
+DEF_GO_RUNTIME(SET_DEFERING_FN, "__go_set_defering_fn", P1(POINTER), R0())
 
 // Check for a deferred function in an exception handler.
 DEF_GO_RUNTIME(CHECK_DEFER, "__go_check_defer", P1(BOOLPTR), R0())
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 090c193..6f906fc 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -2348,25 +2348,14 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
   gogo->start_block(location);
 
   // For a defer statement, start with a call to
-  // __go_set_defer_retaddr.  */
-  Label* retaddr_label = NULL;
+  // __go_set_defering_fn.  */
   if (may_call_recover)
     {
-      retaddr_label = gogo->add_label_reference("retaddr", location, false);
-      Expression* arg = Expression::make_label_addr(retaddr_label, location);
-      Expression* call = Runtime::make_call(Runtime::SET_DEFER_RETADDR,
+      Expression* arg =
+	Expression::make_func_code_reference(function, location);
+      Expression* call = Runtime::make_call(Runtime::SET_DEFERING_FN,
 					    location, 1, arg);
-
-      // This is a hack to prevent the middle-end from deleting the
-      // label.
-      gogo->start_block(location);
-      gogo->add_statement(Statement::make_goto_statement(retaddr_label,
-							 location));
-      Block* then_block = gogo->finish_block(location);
-      then_block->determine_types();
-
-      Statement* s = Statement::make_if_statement(call, then_block, NULL,
-						  location);
+      Statement* s = Statement::make_statement(call, true);
       s->determine_types();
       gogo->add_statement(s);
     }
@@ -2455,12 +2444,8 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
 
   gogo->add_statement(call_statement);
 
-  // If this is a defer statement, the label comes immediately after
-  // the call.
   if (may_call_recover)
     {
-      gogo->add_label_definition("retaddr", location);
-
       Expression_list* vals = new Expression_list();
       vals->push_back(Expression::make_boolean(false, location));
       gogo->add_statement(Statement::make_return_statement(vals, location));
diff --git a/libgo/runtime/go-defer.c b/libgo/runtime/go-defer.c
index 5dd8c31..c0da2dc 100644
--- a/libgo/runtime/go-defer.c
+++ b/libgo/runtime/go-defer.c
@@ -26,7 +26,7 @@ __go_defer (_Bool *frame, void (*pfn) (void *), void *arg)
   n->__panic = g->panic;
   n->__pfn = pfn;
   n->__arg = arg;
-  n->__retaddr = NULL;
+  n->__defering_fn = NULL;
   n->__makefunc_can_recover = 0;
   n->__special = 0;
   g->defer = n;
@@ -69,17 +69,16 @@ __go_undefer (_Bool *frame)
     }
 }
 
-/* This function is called to record the address to which the deferred
-   function returns.  This may in turn be checked by __go_can_recover.
-   The frontend relies on this function returning false.  */
+/* This function is called to record the address of the function
+   to which the deferred function returns.  This may in turn be
+   checked by __go_can_recover.  */
 
-_Bool
-__go_set_defer_retaddr (void *retaddr)
+void
+__go_set_defering_fn (void *defering_fn)
 {
   G *g;
-
   g = runtime_g ();
   if (g->defer != NULL)
-    g->defer->__retaddr = retaddr;
-  return 0;
+    g->defer->__defering_fn = defering_fn;
+  return;
 }
diff --git a/libgo/runtime/go-defer.h b/libgo/runtime/go-defer.h
index acf2d40..c6d8b4a 100644
--- a/libgo/runtime/go-defer.h
+++ b/libgo/runtime/go-defer.h
@@ -30,14 +30,15 @@ struct __go_defer_stack
   /* The argument to pass to the function.  */
   void *__arg;
 
-  /* The return address that a recover thunk matches against.  This is
-     set by __go_set_defer_retaddr which is called by the thunks
-     created by defer statements.  */
-  const void *__retaddr;
+  /* The address of the function enclosing the return address that
+     a recover thunk matches against.  This is set by
+     __go_set_defering_fn which is called by the thunks created by
+     defer statements.  */
+  const void *__defering_fn;
 
   /* Set to true if a function created by reflect.MakeFunc is
      permitted to recover.  The return address of such a function
-     function will be somewhere in libffi, so __retaddr is not
+     function will be somewhere in libffi, so __defering_fn is not
      useful.  */
   _Bool __makefunc_can_recover;
 
diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c
index 2d3db55..85ebf52 100644
--- a/libgo/runtime/go-recover.c
+++ b/libgo/runtime/go-recover.c
@@ -8,6 +8,8 @@
 #include "interface.h"
 #include "go-panic.h"
 #include "go-defer.h"
+#include <stdint.h>
+#include "unwind-generic.h"
 
 /* This is called by a thunk to see if the real function should be
    permitted to recover a panic value.  Recovering a value is
@@ -20,8 +22,6 @@ __go_can_recover (const void *retaddr)
 {
   G *g;
   struct __go_defer_stack *d;
-  const char* ret;
-  const char* dret;
   Location loc;
   const byte *name;
 
@@ -38,24 +38,26 @@ __go_can_recover (const void *retaddr)
   if (d->__panic == g->panic)
     return 0;
 
-  /* D->__RETADDR is the address of a label immediately following the
-     call to the thunk.  We can recover a panic if that is the same as
-     the return address of the thunk.  We permit a bit of slack in
-     case there is any code between the function return and the label,
-     such as an instruction to adjust the stack pointer.  */
+  /* D->__DEFERING_FN is the address of the function that called
+     D->defer (or NULL if defer was not called).  We can recover a
+     D->panic if that is the same as the caller of the thunk.  */
 
-  ret = (const char *) retaddr;
-
-#ifdef __sparc__
-  /* On SPARC the address we get, from __builtin_return_address, is
-     the address of the call instruction.  Adjust forward, also
-     skipping the delayed instruction following the call.  */
-  ret += 8;
-#endif
-
-  dret = (const char *) d->__retaddr;
-  if (ret <= dret && ret + 16 >= dret)
-    return 1;
+  if (d->__defering_fn != NULL)
+    {
+      void *real_retaddr;
+
+      real_retaddr = __builtin_extract_return_addr ((void *)(uintptr_t)retaddr);
+      /* If the return address is before the defering function
+	 start skip the more expensive calculations.  */
+      if ((uintptr_t)real_retaddr >= (uintptr_t)d->__defering_fn)
+	{
+	  const void *caller;
+
+	  caller = _Unwind_FindEnclosingFunction (real_retaddr);
+	  if (caller == (const void *)d->__defering_fn)
+	    return 1;
+	}
+    }
 
   /* If the function calling recover was created by reflect.MakeFunc,
      then RETADDR will be somewhere in libffi.  Our caller is
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index 4195aff..6f656d8 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -561,7 +561,7 @@ runtime_main(void* dummy __attribute__((unused)))
 	d.__next = g->defer;
 	d.__arg = (void*)-1;
 	d.__panic = g->panic;
-	d.__retaddr = nil;
+	d.__defering_fn = nil;
 	d.__makefunc_can_recover = 0;
 	d.__frame = &frame;
 	d.__special = true;
-- 
1.8.4.2


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]