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.
9 #ifdef USING_SPLIT_STACK
11 extern void * __splitstack_find (void *, void *, size_t *, void **, void **,
14 extern void * __splitstack_find_context (void *context
[10], size_t *, void **,
19 bool runtime_usestackmaps
;
21 // Calling unwind_init in doscanstack only works if it does not do a
22 // tail call to doscanstack1.
23 #pragma GCC optimize ("-fno-optimize-sibling-calls")
25 extern void scanstackblock(uintptr addr
, uintptr size
, void *gcw
)
26 __asm__(GOSYM_PREFIX
"runtime.scanstackblock");
28 static bool doscanstack1(G
*, void*)
29 __attribute__ ((noinline
));
31 // Scan gp's stack, passing stack chunks to scanstackblock.
32 bool doscanstack(G
*gp
, void* gcw
) {
33 // Save registers on the stack, so that if we are scanning our
34 // own stack we will see them.
35 if (!runtime_usestackmaps
) {
36 __builtin_unwind_init();
37 flush_registers_to_secondary_stack();
40 return doscanstack1(gp
, gcw
);
43 // Scan gp's stack after saving registers.
44 static bool doscanstack1(G
*gp
, void *gcw
) {
45 #ifdef USING_SPLIT_STACK
54 if (runtime_usestackmaps
) {
55 // If stack map is enabled, we get here only when we can unwind
56 // the stack being scanned. That is, either we are scanning our
57 // own stack, or we are scanning through a signal handler.
58 __go_assert((_g_
== gp
) || ((_g_
== gp
->m
->gsignal
) && (gp
== gp
->m
->curg
)));
59 return scanstackwithmap(gcw
);
62 // Scanning our own stack.
63 // If we are on a signal stack, it can unwind through the signal
64 // handler and see the g stack, so just scan our own stack.
65 sp
= __splitstack_find(nil
, nil
, &spsize
, &next_segment
,
66 &next_sp
, &initial_sp
);
68 // Scanning another goroutine's stack.
69 // The goroutine is usually asleep (the world is stopped).
71 // The exception is that if the goroutine is about to enter or might
72 // have just exited a system call, it may be executing code such
73 // as schedlock and may have needed to start a new stack segment.
74 // Use the stack segment and stack pointer at the time of
75 // the system call instead, since that won't change underfoot.
76 if(gp
->gcstack
!= 0) {
77 sp
= (void*)(gp
->gcstack
);
78 spsize
= gp
->gcstacksize
;
79 next_segment
= (void*)(gp
->gcnextsegment
);
80 next_sp
= (void*)(gp
->gcnextsp
);
81 initial_sp
= (void*)(gp
->gcinitialsp
);
83 sp
= __splitstack_find_context((void**)(&gp
->stackcontext
[0]),
84 &spsize
, &next_segment
,
85 &next_sp
, &initial_sp
);
89 scanstackblock((uintptr
)(sp
), (uintptr
)(spsize
), gcw
);
90 while((sp
= __splitstack_find(next_segment
, next_sp
,
91 &spsize
, &next_segment
,
92 &next_sp
, &initial_sp
)) != nil
)
93 scanstackblock((uintptr
)(sp
), (uintptr
)(spsize
), gcw
);
101 if(gp
== runtime_g()) {
102 // Scanning our own stack.
104 nextsp2
= secondary_stack_pointer();
106 // Scanning another goroutine's stack.
107 // The goroutine is usually asleep (the world is stopped).
108 bottom
= (void*)gp
->gcnextsp
;
111 nextsp2
= (void*)gp
->gcnextsp2
;
113 top
= (byte
*)(void*)(gp
->gcinitialsp
) + gp
->gcstacksize
;
115 scanstackblock((uintptr
)(bottom
), (uintptr
)(top
- bottom
), gcw
);
117 scanstackblock((uintptr
)(top
), (uintptr
)(bottom
- top
), gcw
);
118 if (nextsp2
!= nil
) {
119 initialsp2
= (byte
*)(void*)(gp
->gcinitialsp2
);
120 if(initialsp2
> nextsp2
)
121 scanstackblock((uintptr
)(nextsp2
), (uintptr
)(initialsp2
- nextsp2
), gcw
);
123 scanstackblock((uintptr
)(initialsp2
), (uintptr
)(nextsp2
- initialsp2
), gcw
);
129 extern bool onCurrentStack(uintptr p
)
130 __asm__(GOSYM_PREFIX
"runtime.onCurrentStack");
132 bool onCurrentStack(uintptr p
)
134 #ifdef USING_SPLIT_STACK
142 sp
= __splitstack_find(nil
, nil
, &spsize
, &next_segment
, &next_sp
,
145 if (p
>= (uintptr
)(sp
) && p
< (uintptr
)(sp
) + spsize
) {
148 sp
= __splitstack_find(next_segment
, next_sp
, &spsize
,
149 &next_segment
, &next_sp
, &initial_sp
);
163 bottom
= (byte
*)(&p
);
164 top
= (byte
*)(void*)(gp
->gcinitialsp
) + gp
->gcstacksize
;
165 if ((uintptr
)(top
) < (uintptr
)(bottom
)) {
170 if (p
>= (uintptr
)(bottom
) && p
< (uintptr
)(top
)) {
174 nextsp2
= secondary_stack_pointer();
175 if (nextsp2
!= nil
) {
176 initialsp2
= (byte
*)(void*)(gp
->gcinitialsp2
);
177 if ((uintptr
)(initialsp2
) < (uintptr
)(nextsp2
)) {
179 initialsp2
= nextsp2
;
182 if (p
>= (uintptr
)(nextsp2
) && p
< (uintptr
)(initialsp2
)) {