diff libgo/runtime/stack.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/stack.c	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Stack scanning code for the garbage collector.
+
+#include "runtime.h"
+
+#ifdef USING_SPLIT_STACK
+
+extern void * __splitstack_find (void *, void *, size_t *, void **, void **,
+				 void **);
+
+extern void * __splitstack_find_context (void *context[10], size_t *, void **,
+					 void **, void **);
+
+#endif
+
+// Calling unwind_init in doscanstack only works if it does not do a
+// tail call to doscanstack1.
+#pragma GCC optimize ("-fno-optimize-sibling-calls")
+
+extern void scanstackblock(void *addr, uintptr size, void *gcw)
+  __asm__("runtime.scanstackblock");
+
+void doscanstack(G*, void*)
+  __asm__("runtime.doscanstack");
+
+static void doscanstack1(G*, void*)
+  __attribute__ ((noinline));
+
+// Scan gp's stack, passing stack chunks to scanstackblock.
+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();
+
+	doscanstack1(gp, gcw);
+}
+
+// Scan gp's stack after saving registers.
+static void doscanstack1(G *gp, void *gcw) {
+#ifdef USING_SPLIT_STACK
+	void* sp;
+	size_t spsize;
+	void* next_segment;
+	void* next_sp;
+	void* initial_sp;
+
+	if (gp == runtime_g()) {
+		// Scanning our own stack.
+		sp = __splitstack_find(nil, nil, &spsize, &next_segment,
+				       &next_sp, &initial_sp);
+	} else {
+		// Scanning another goroutine's stack.
+		// The goroutine is usually asleep (the world is stopped).
+
+		// The exception is that if the goroutine is about to enter or might
+		// have just exited a system call, it may be executing code such
+		// as schedlock and may have needed to start a new stack segment.
+		// Use the stack segment and stack pointer at the time of
+		// the system call instead, since that won't change underfoot.
+		if(gp->gcstack != 0) {
+			sp = (void*)(gp->gcstack);
+			spsize = gp->gcstacksize;
+			next_segment = (void*)(gp->gcnextsegment);
+			next_sp = (void*)(gp->gcnextsp);
+			initial_sp = (void*)(gp->gcinitialsp);
+		} else {
+			sp = __splitstack_find_context((void**)(&gp->stackcontext[0]),
+						       &spsize, &next_segment,
+						       &next_sp, &initial_sp);
+		}
+	}
+	if(sp != nil) {
+		scanstackblock(sp, (uintptr)(spsize), gcw);
+		while((sp = __splitstack_find(next_segment, next_sp,
+					      &spsize, &next_segment,
+					      &next_sp, &initial_sp)) != nil)
+			scanstackblock(sp, (uintptr)(spsize), gcw);
+	}
+#else
+	byte* bottom;
+	byte* top;
+
+	if(gp == runtime_g()) {
+		// Scanning our own stack.
+		bottom = (byte*)&gp;
+	} else {
+		// Scanning another goroutine's stack.
+		// The goroutine is usually asleep (the world is stopped).
+		bottom = (void*)gp->gcnextsp;
+		if(bottom == nil)
+			return;
+	}
+	top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
+	if(top > bottom)
+		scanstackblock(bottom, (uintptr)(top - bottom), gcw);
+	else
+		scanstackblock(top, (uintptr)(bottom - top), gcw);
+#endif
+}