This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 1/9] Gccgo port to s390[x] -- part I
- From: Dominik Vogt <vogt at linux dot vnet dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: gofrontend-dev at googlegroups dot com
- Date: Tue, 9 Sep 2014 13:48:26 +0100
- Subject: [PATCH 1/9] Gccgo port to s390[x] -- part I
- Authentication-results: sourceware.org; auth=none
- References: <20140909124446 dot GA25290 at linux dot vnet dot ibm dot com>
- Reply-to: vogt at linux dot vnet dot ibm dot com
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