diff mbox series

libgo patch committed: scan register backing store on ia64

Message ID CAOyqgcXyg9BiQGk0m5mOpTK4zJCtNhQS3mbS_kRwn_8XXqcM3Q@mail.gmail.com
State New
Headers show
Series libgo patch committed: scan register backing store on ia64 | expand

Commit Message

Ian Lance Taylor Feb. 2, 2018, 12:16 a.m. UTC
This libgo patch by James Clarke scans the register backing store on
ia64 when doing a Go garbage collection.  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.  Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.
Committed to mainline.

Ian
diff mbox series

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 257319)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -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.
Index: libgo/go/runtime/runtime2.go
===================================================================
--- libgo/go/runtime/runtime2.go	(revision 257312)
+++ libgo/go/runtime/runtime2.go	(working copy)
@@ -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.
Index: libgo/runtime/proc.c
===================================================================
--- libgo/runtime/proc.c	(revision 257312)
+++ libgo/runtime/proc.c	(working copy)
@@ -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
 		void *v;
 
 		g->gcnextsp = (uintptr)(&v);
+		g->gcnextsp2 = (uintptr)(secondary_stack_pointer());
 	}
 #endif
 
@@ -756,6 +764,7 @@  runtime_malg(bool allocatestack, bool si
 		*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 *s
   if(*spsize == 0)
     runtime_throw("bad spsize in resetNewG");
   newg->gcnextsp = (uintptr)(*sp);
+  newg->gcnextsp2 = (uintptr)(newg->gcinitialsp2);
 #endif
 }
 
Index: libgo/runtime/runtime.h
===================================================================
--- libgo/runtime/runtime.h	(revision 257312)
+++ libgo/runtime/runtime.h	(working copy)
@@ -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 *);
Index: libgo/runtime/stack.c
===================================================================
--- libgo/runtime/stack.c	(revision 257312)
+++ libgo/runtime/stack.c	(working copy)
@@ -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 *gc
 #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
 }