2017-09-13 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libgo / runtime / stack.c
blob900ca64b7f7d3f8b99faea92b3446c79b56ae2fc
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Stack scanning code for the garbage collector.
7 #include "runtime.h"
9 #ifdef USING_SPLIT_STACK
11 extern void * __splitstack_find (void *, void *, size_t *, void **, void **,
12 void **);
14 extern void * __splitstack_find_context (void *context[10], size_t *, void **,
15 void **, void **);
17 #endif
19 // Calling unwind_init in doscanstack only works if it does not do a
20 // tail call to doscanstack1.
21 #pragma GCC optimize ("-fno-optimize-sibling-calls")
23 extern void scanstackblock(void *addr, uintptr size, void *gcw)
24 __asm__("runtime.scanstackblock");
26 void doscanstack(G*, void*)
27 __asm__("runtime.doscanstack");
29 static void doscanstack1(G*, void*)
30 __attribute__ ((noinline));
32 // Scan gp's stack, passing stack chunks to scanstackblock.
33 void doscanstack(G *gp, void* gcw) {
34 // Save registers on the stack, so that if we are scanning our
35 // own stack we will see them.
36 __builtin_unwind_init();
38 doscanstack1(gp, gcw);
41 // Scan gp's stack after saving registers.
42 static void doscanstack1(G *gp, void *gcw) {
43 #ifdef USING_SPLIT_STACK
44 void* sp;
45 size_t spsize;
46 void* next_segment;
47 void* next_sp;
48 void* initial_sp;
50 if (gp == runtime_g()) {
51 // Scanning our own stack.
52 sp = __splitstack_find(nil, nil, &spsize, &next_segment,
53 &next_sp, &initial_sp);
54 } else {
55 // Scanning another goroutine's stack.
56 // The goroutine is usually asleep (the world is stopped).
58 // The exception is that if the goroutine is about to enter or might
59 // have just exited a system call, it may be executing code such
60 // as schedlock and may have needed to start a new stack segment.
61 // Use the stack segment and stack pointer at the time of
62 // the system call instead, since that won't change underfoot.
63 if(gp->gcstack != 0) {
64 sp = (void*)(gp->gcstack);
65 spsize = gp->gcstacksize;
66 next_segment = (void*)(gp->gcnextsegment);
67 next_sp = (void*)(gp->gcnextsp);
68 initial_sp = (void*)(gp->gcinitialsp);
69 } else {
70 sp = __splitstack_find_context((void**)(&gp->stackcontext[0]),
71 &spsize, &next_segment,
72 &next_sp, &initial_sp);
75 if(sp != nil) {
76 scanstackblock(sp, (uintptr)(spsize), gcw);
77 while((sp = __splitstack_find(next_segment, next_sp,
78 &spsize, &next_segment,
79 &next_sp, &initial_sp)) != nil)
80 scanstackblock(sp, (uintptr)(spsize), gcw);
82 #else
83 byte* bottom;
84 byte* top;
86 if(gp == runtime_g()) {
87 // Scanning our own stack.
88 bottom = (byte*)&gp;
89 } else {
90 // Scanning another goroutine's stack.
91 // The goroutine is usually asleep (the world is stopped).
92 bottom = (void*)gp->gcnextsp;
93 if(bottom == nil)
94 return;
96 top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
97 if(top > bottom)
98 scanstackblock(bottom, (uintptr)(top - bottom), gcw);
99 else
100 scanstackblock(top, (uintptr)(bottom - top), gcw);
101 #endif