]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/mstkbar.go
runtime: break out system-specific constants into package sys
[gostls13.git] / src / runtime / mstkbar.go
1 // Copyright 2015 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.
4
5 // Garbage collector: stack barriers
6 //
7 // Stack barriers enable the garbage collector to determine how much
8 // of a gorountine stack has changed between when a stack is scanned
9 // during the concurrent scan phase and when it is re-scanned during
10 // the stop-the-world mark termination phase. Mark termination only
11 // needs to re-scan the changed part, so for deep stacks this can
12 // significantly reduce GC pause time compared to the alternative of
13 // re-scanning whole stacks. The deeper the stacks, the more stack
14 // barriers help.
15 //
16 // When stacks are scanned during the concurrent scan phase, the stack
17 // scan installs stack barriers by selecting stack frames and
18 // overwriting the saved return PCs (or link registers) of these
19 // frames with the PC of a "stack barrier trampoline". Later, when a
20 // selected frame returns, it "returns" to this trampoline instead of
21 // returning to its actual caller. The trampoline records that the
22 // stack has unwound past this frame and jumps to the original return
23 // PC recorded when the stack barrier was installed. Mark termination
24 // re-scans only as far as the first frame that hasn't hit a stack
25 // barrier and then removes and un-hit stack barriers.
26 //
27 // This scheme is very lightweight. No special code is required in the
28 // mutator to record stack unwinding and the trampoline is only a few
29 // assembly instructions.
30 //
31 // Book-keeping
32 // ------------
33 //
34 // The primary cost of stack barriers is book-keeping: the runtime has
35 // to record the locations of all stack barriers and the original
36 // return PCs in order to return to the correct caller when a stack
37 // barrier is hit and so it can remove un-hit stack barriers. In order
38 // to minimize this cost, the Go runtime places stack barriers in
39 // exponentially-spaced frames, starting 1K past the current frame.
40 // The book-keeping structure hence grows logarithmically with the
41 // size of the stack and mark termination re-scans at most twice as
42 // much stack as necessary.
43 //
44 // The runtime reserves space for this book-keeping structure at the
45 // top of the stack allocation itself (just above the outermost
46 // frame). This is necessary because the regular memory allocator can
47 // itself grow the stack, and hence can't be used when allocating
48 // stack-related structures.
49 //
50 // For debugging, the runtime also supports installing stack barriers
51 // at every frame. However, this requires significantly more
52 // book-keeping space.
53 //
54 // Correctness
55 // -----------
56 //
57 // The runtime and the compiler cooperate to ensure that all objects
58 // reachable from the stack as of mark termination are marked.
59 // Anything unchanged since the concurrent scan phase will be marked
60 // because it is marked by the concurrent scan. After the concurrent
61 // scan, there are three possible classes of stack modifications that
62 // must be tracked:
63 //
64 // 1) Mutator writes below the lowest un-hit stack barrier. This
65 // includes all writes performed by an executing function to its own
66 // stack frame. This part of the stack will be re-scanned by mark
67 // termination, which will mark any objects made reachable from
68 // modifications to this part of the stack.
69 //
70 // 2) Mutator writes above the lowest un-hit stack barrier. It's
71 // possible for a mutator to modify the stack above the lowest un-hit
72 // stack barrier if a higher frame has passed down a pointer to a
73 // stack variable in its frame. This is called an "up-pointer". The
74 // compiler ensures that writes through up-pointers have an
75 // accompanying write barrier (it simply doesn't distinguish between
76 // writes through up-pointers and writes through heap pointers). This
77 // write barrier marks any object made reachable from modifications to
78 // this part of the stack.
79 //
80 // 3) Runtime writes to the stack. Various runtime operations such as
81 // sends to unbuffered channels can write to arbitrary parts of the
82 // stack, including above the lowest un-hit stack barrier. We solve
83 // this in two ways. In many cases, the runtime can perform an
84 // explicit write barrier operation like in case 2. However, in the
85 // case of bulk memory move (typedmemmove), the runtime doesn't
86 // necessary have ready access to a pointer bitmap for the memory
87 // being copied, so it simply unwinds any stack barriers below the
88 // destination.
89 //
90 // Gotchas
91 // -------
92 //
93 // Anything that inspects or manipulates the stack potentially needs
94 // to understand stack barriers. The most obvious case is that
95 // gentraceback needs to use the original return PC when it encounters
96 // the stack barrier trampoline. Anything that unwinds the stack such
97 // as panic/recover must unwind stack barriers in tandem with
98 // unwinding the stack.
99 //
100 // Stack barriers require that any goroutine whose stack has been
101 // scanned must execute write barriers. Go solves this by simply
102 // enabling write barriers globally during the concurrent scan phase.
103 // However, traditionally, write barriers are not enabled during this
104 // phase.
105
106 package runtime
107
108 import (
109         "runtime/internal/sys"
110         "unsafe"
111 )
112
113 const debugStackBarrier = false
114
115 // firstStackBarrierOffset is the approximate byte offset at
116 // which to place the first stack barrier from the current SP.
117 // This is a lower bound on how much stack will have to be
118 // re-scanned during mark termination. Subsequent barriers are
119 // placed at firstStackBarrierOffset * 2^n offsets.
120 //
121 // For debugging, this can be set to 0, which will install a
122 // stack barrier at every frame. If you do this, you may also
123 // have to raise _StackMin, since the stack barrier
124 // bookkeeping will use a large amount of each stack.
125 var firstStackBarrierOffset = 1024
126
127 // gcMaxStackBarriers returns the maximum number of stack barriers
128 // that can be installed in a stack of stackSize bytes.
129 func gcMaxStackBarriers(stackSize int) (n int) {
130         if firstStackBarrierOffset == 0 {
131                 // Special debugging case for inserting stack barriers
132                 // at every frame. Steal half of the stack for the
133                 // []stkbar. Technically, if the stack were to consist
134                 // solely of return PCs we would need two thirds of
135                 // the stack, but stealing that much breaks things and
136                 // this doesn't happen in practice.
137                 return stackSize / 2 / int(unsafe.Sizeof(stkbar{}))
138         }
139
140         offset := firstStackBarrierOffset
141         for offset < stackSize {
142                 n++
143                 offset *= 2
144         }
145         return n + 1
146 }
147
148 // gcInstallStackBarrier installs a stack barrier over the return PC of frame.
149 //go:nowritebarrier
150 func gcInstallStackBarrier(gp *g, frame *stkframe) bool {
151         if frame.lr == 0 {
152                 if debugStackBarrier {
153                         print("not installing stack barrier with no LR, goid=", gp.goid, "\n")
154                 }
155                 return false
156         }
157
158         if frame.fn.entry == cgocallback_gofuncPC {
159                 // cgocallback_gofunc doesn't return to its LR;
160                 // instead, its return path puts LR in g.sched.pc and
161                 // switches back to the system stack on which
162                 // cgocallback_gofunc was originally called. We can't
163                 // have a stack barrier in g.sched.pc, so don't
164                 // install one in this frame.
165                 if debugStackBarrier {
166                         print("not installing stack barrier over LR of cgocallback_gofunc, goid=", gp.goid, "\n")
167                 }
168                 return false
169         }
170
171         // Save the return PC and overwrite it with stackBarrier.
172         var lrUintptr uintptr
173         if usesLR {
174                 lrUintptr = frame.sp
175         } else {
176                 lrUintptr = frame.fp - sys.RegSize
177         }
178         lrPtr := (*sys.Uintreg)(unsafe.Pointer(lrUintptr))
179         if debugStackBarrier {
180                 print("install stack barrier at ", hex(lrUintptr), " over ", hex(*lrPtr), ", goid=", gp.goid, "\n")
181                 if uintptr(*lrPtr) != frame.lr {
182                         print("frame.lr=", hex(frame.lr))
183                         throw("frame.lr differs from stack LR")
184                 }
185         }
186
187         gp.stkbar = gp.stkbar[:len(gp.stkbar)+1]
188         stkbar := &gp.stkbar[len(gp.stkbar)-1]
189         stkbar.savedLRPtr = lrUintptr
190         stkbar.savedLRVal = uintptr(*lrPtr)
191         *lrPtr = sys.Uintreg(stackBarrierPC)
192         return true
193 }
194
195 // gcRemoveStackBarriers removes all stack barriers installed in gp's stack.
196 //go:nowritebarrier
197 func gcRemoveStackBarriers(gp *g) {
198         if debugStackBarrier && gp.stkbarPos != 0 {
199                 print("hit ", gp.stkbarPos, " stack barriers, goid=", gp.goid, "\n")
200         }
201
202         // Remove stack barriers that we didn't hit.
203         for _, stkbar := range gp.stkbar[gp.stkbarPos:] {
204                 gcRemoveStackBarrier(gp, stkbar)
205         }
206
207         // Clear recorded stack barriers so copystack doesn't try to
208         // adjust them.
209         gp.stkbarPos = 0
210         gp.stkbar = gp.stkbar[:0]
211 }
212
213 // gcRemoveStackBarrier removes a single stack barrier. It is the
214 // inverse operation of gcInstallStackBarrier.
215 //
216 // This is nosplit to ensure gp's stack does not move.
217 //
218 //go:nowritebarrier
219 //go:nosplit
220 func gcRemoveStackBarrier(gp *g, stkbar stkbar) {
221         if debugStackBarrier {
222                 print("remove stack barrier at ", hex(stkbar.savedLRPtr), " with ", hex(stkbar.savedLRVal), ", goid=", gp.goid, "\n")
223         }
224         lrPtr := (*sys.Uintreg)(unsafe.Pointer(stkbar.savedLRPtr))
225         if val := *lrPtr; val != sys.Uintreg(stackBarrierPC) {
226                 printlock()
227                 print("at *", hex(stkbar.savedLRPtr), " expected stack barrier PC ", hex(stackBarrierPC), ", found ", hex(val), ", goid=", gp.goid, "\n")
228                 print("gp.stkbar=")
229                 gcPrintStkbars(gp.stkbar)
230                 print(", gp.stkbarPos=", gp.stkbarPos, ", gp.stack=[", hex(gp.stack.lo), ",", hex(gp.stack.hi), ")\n")
231                 throw("stack barrier lost")
232         }
233         *lrPtr = sys.Uintreg(stkbar.savedLRVal)
234 }
235
236 // gcPrintStkbars prints a []stkbar for debugging.
237 func gcPrintStkbars(stkbar []stkbar) {
238         print("[")
239         for i, s := range stkbar {
240                 if i > 0 {
241                         print(" ")
242                 }
243                 print("*", hex(s.savedLRPtr), "=", hex(s.savedLRVal))
244         }
245         print("]")
246 }
247
248 // gcUnwindBarriers marks all stack barriers up the frame containing
249 // sp as hit and removes them. This is used during stack unwinding for
250 // panic/recover and by heapBitsBulkBarrier to force stack re-scanning
251 // when its destination is on the stack.
252 //
253 // This is nosplit to ensure gp's stack does not move.
254 //
255 //go:nosplit
256 func gcUnwindBarriers(gp *g, sp uintptr) {
257         // On LR machines, if there is a stack barrier on the return
258         // from the frame containing sp, this will mark it as hit even
259         // though it isn't, but it's okay to be conservative.
260         before := gp.stkbarPos
261         for int(gp.stkbarPos) < len(gp.stkbar) && gp.stkbar[gp.stkbarPos].savedLRPtr < sp {
262                 gcRemoveStackBarrier(gp, gp.stkbar[gp.stkbarPos])
263                 gp.stkbarPos++
264         }
265         if debugStackBarrier && gp.stkbarPos != before {
266                 print("skip barriers below ", hex(sp), " in goid=", gp.goid, ": ")
267                 gcPrintStkbars(gp.stkbar[before:gp.stkbarPos])
268                 print("\n")
269         }
270 }
271
272 // nextBarrierPC returns the original return PC of the next stack barrier.
273 // Used by getcallerpc, so it must be nosplit.
274 //go:nosplit
275 func nextBarrierPC() uintptr {
276         gp := getg()
277         return gp.stkbar[gp.stkbarPos].savedLRVal
278 }
279
280 // setNextBarrierPC sets the return PC of the next stack barrier.
281 // Used by setcallerpc, so it must be nosplit.
282 //go:nosplit
283 func setNextBarrierPC(pc uintptr) {
284         gp := getg()
285         gp.stkbar[gp.stkbarPos].savedLRVal = pc
286 }