aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2018-02-02 00:16:43 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-02-02 00:16:43 +0000
commit38f08ec0bd9bd39c578c2e9283a9aa00dc6bda15 (patch)
tree13c1ddb95c4048060b536abd200b8e24d0b2d066
parent2e30f1ee86b087497fb5178a23a09ea6e22b1af4 (diff)
downloadgcc-38f08ec0bd9bd39c578c2e9283a9aa00dc6bda15.zip
gcc-38f08ec0bd9bd39c578c2e9283a9aa00dc6bda15.tar.gz
gcc-38f08ec0bd9bd39c578c2e9283a9aa00dc6bda15.tar.bz2
runtime: scan register backing store on ia64
On ia64, a separate stack is used for saving/restoring register frames, occupying the other end of the stack mapping. This must also be scanned for pointers into the heap. Reviewed-on: https://go-review.googlesource.com/85276 From-SVN: r257323
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--libgo/go/runtime/runtime2.go4
-rw-r--r--libgo/runtime/proc.c10
-rw-r--r--libgo/runtime/runtime.h17
-rw-r--r--libgo/runtime/stack.c12
5 files changed, 44 insertions, 1 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index cc64fad..46bdc3c 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-e148068360699f24118950b728f23a5c98e1f85e
+5e8a91bf239c253d7b5c84bd2c1dd3ecb18980e9
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go
index 543086d..0299d5a 100644
--- a/libgo/go/runtime/runtime2.go
+++ b/libgo/go/runtime/runtime2.go
@@ -409,11 +409,15 @@ type g struct {
// gcnextsegment: unused
// gcnextsp: current SP while executing a syscall
// gcinitialsp: g0: top of stack; others: start of stack memory
+ // gcnextsp2: current secondary stack pointer (if present)
+ // gcinitialsp2: start of secondary stack (if present)
gcstack uintptr
gcstacksize uintptr
gcnextsegment uintptr
gcnextsp uintptr
gcinitialsp unsafe.Pointer
+ gcnextsp2 uintptr
+ gcinitialsp2 unsafe.Pointer
// gcregs holds the register values while executing a syscall.
// This is set by getcontext and scanned by the garbage collector.
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index 556d86f..12c055d 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -308,6 +308,7 @@ runtime_mcall(FuncVal *fv)
// Ensure that all registers are on the stack for the garbage
// collector.
__builtin_unwind_init();
+ flush_registers_to_secondary_stack();
gp = g;
mp = gp->m;
@@ -322,6 +323,7 @@ runtime_mcall(FuncVal *fv)
// We have to point to an address on the stack that is
// below the saved registers.
gp->gcnextsp = (uintptr)(&afterregs);
+ gp->gcnextsp2 = (uintptr)(secondary_stack_pointer());
#endif
gp->fromgogo = false;
getcontext(ucontext_arg(&gp->context[0]));
@@ -500,6 +502,8 @@ runtime_mstart(void *arg)
// is the top of the stack, not the bottom.
gp->gcstacksize = 0;
gp->gcnextsp = (uintptr)(&arg);
+ gp->gcinitialsp2 = secondary_stack_pointer();
+ gp->gcnextsp2 = (uintptr)(gp->gcinitialsp2);
#endif
// Save the currently active context. This will return
@@ -576,6 +580,8 @@ setGContext(void)
gp->gcstack = 0;
gp->gcstacksize = 0;
gp->gcnextsp = (uintptr)(&val);
+ gp->gcinitialsp2 = secondary_stack_pointer();
+ gp->gcnextsp2 = (uintptr)(gp->gcinitialsp2);
#endif
getcontext(ucontext_arg(&gp->context[0]));
@@ -654,6 +660,7 @@ doentersyscall(uintptr pc, uintptr sp)
void *v;
g->gcnextsp = (uintptr)(&v);
+ g->gcnextsp2 = (uintptr)(secondary_stack_pointer());
}
#endif
@@ -694,6 +701,7 @@ doentersyscallblock(uintptr pc, uintptr sp)
void *v;
g->gcnextsp = (uintptr)(&v);
+ g->gcnextsp2 = (uintptr)(secondary_stack_pointer());
}
#endif
@@ -756,6 +764,7 @@ runtime_malg(bool allocatestack, bool signalstack, byte** ret_stack, uintptr* re
*ret_stacksize = (uintptr)stacksize;
newg->gcinitialsp = *ret_stack;
newg->gcstacksize = (uintptr)stacksize;
+ newg->gcinitialsp2 = initial_secondary_stack_pointer(*ret_stack);
#endif
}
return newg;
@@ -807,6 +816,7 @@ resetNewG(G *newg, void **sp, uintptr *spsize)
if(*spsize == 0)
runtime_throw("bad spsize in resetNewG");
newg->gcnextsp = (uintptr)(*sp);
+ newg->gcnextsp2 = (uintptr)(newg->gcinitialsp2);
#endif
}
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index 28d550d..0fafe82 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -437,6 +437,23 @@ void runtime_check(void)
// the stacks are allocated by the splitstack library.
extern uintptr runtime_stacks_sys;
+/*
+ * ia64's register file is spilled to a separate stack, the register backing
+ * store, on window overflow, and must also be scanned. This occupies the other
+ * end of the normal stack allocation, growing upwards.
+ * We also need to ensure all register windows are flushed to the backing
+ * store, as unlike SPARC, __builtin_unwind_init doesn't do this on ia64.
+ */
+#ifdef __ia64__
+# define secondary_stack_pointer() __builtin_ia64_bsp()
+# define initial_secondary_stack_pointer(stack_alloc) (stack_alloc)
+# define flush_registers_to_secondary_stack() __builtin_ia64_flushrs()
+#else
+# define secondary_stack_pointer() nil
+# define initial_secondary_stack_pointer(stack_alloc) nil
+# define flush_registers_to_secondary_stack()
+#endif
+
struct backtrace_state;
extern struct backtrace_state *__go_get_backtrace_state(void);
extern _Bool __go_file_line(uintptr, int, String*, String*, intgo *);
diff --git a/libgo/runtime/stack.c b/libgo/runtime/stack.c
index 900ca64..a971e8f 100644
--- a/libgo/runtime/stack.c
+++ b/libgo/runtime/stack.c
@@ -34,6 +34,7 @@ void doscanstack(G *gp, void* gcw) {
// Save registers on the stack, so that if we are scanning our
// own stack we will see them.
__builtin_unwind_init();
+ flush_registers_to_secondary_stack();
doscanstack1(gp, gcw);
}
@@ -82,21 +83,32 @@ static void doscanstack1(G *gp, void *gcw) {
#else
byte* bottom;
byte* top;
+ byte* nextsp2;
+ byte* initialsp2;
if(gp == runtime_g()) {
// Scanning our own stack.
bottom = (byte*)&gp;
+ nextsp2 = secondary_stack_pointer();
} else {
// Scanning another goroutine's stack.
// The goroutine is usually asleep (the world is stopped).
bottom = (void*)gp->gcnextsp;
if(bottom == nil)
return;
+ nextsp2 = (void*)gp->gcnextsp2;
}
top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
if(top > bottom)
scanstackblock(bottom, (uintptr)(top - bottom), gcw);
else
scanstackblock(top, (uintptr)(bottom - top), gcw);
+ if (nextsp2 != nil) {
+ initialsp2 = (byte*)(void*)(gp->gcinitialsp2);
+ if(initialsp2 > nextsp2)
+ scanstackblock(nextsp2, (uintptr)(initialsp2 - nextsp2), gcw);
+ else
+ scanstackblock(initialsp2, (uintptr)(nextsp2 - initialsp2), gcw);
+ }
#endif
}