Source file
src/runtime/stack.go
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/cpu"
10 "internal/goarch"
11 "internal/goexperiment"
12 "internal/goos"
13 "internal/runtime/atomic"
14 "internal/runtime/gc"
15 "internal/runtime/sys"
16 "math/bits"
17 "unsafe"
18 )
19
20
69
70 const (
71
72
73
74
75 stackSystem = goos.IsWindows*4096 + goos.IsPlan9*512 + goos.IsIos*goarch.IsArm64*1024
76
77
78 stackMin = 2048
79
80
81
82 fixedStack0 = stackMin + stackSystem
83 fixedStack1 = fixedStack0 - 1
84 fixedStack2 = fixedStack1 | (fixedStack1 >> 1)
85 fixedStack3 = fixedStack2 | (fixedStack2 >> 2)
86 fixedStack4 = fixedStack3 | (fixedStack3 >> 4)
87 fixedStack5 = fixedStack4 | (fixedStack4 >> 8)
88 fixedStack6 = fixedStack5 | (fixedStack5 >> 16)
89 fixedStack = fixedStack6 + 1
90
91
92
93
94 stackNosplit = abi.StackNosplitBase * sys.StackGuardMultiplier
95
96
97
98
99
100
101
102 stackGuard = stackNosplit + stackSystem + abi.StackSmall
103 )
104
105 const (
106
107
108
109
110
111 stackDebug = 0
112 stackFromSystem = 0
113 stackFaultOnFree = 0
114 stackNoCache = 0
115
116
117 debugCheckBP = false
118 )
119
120 var (
121 stackPoisonCopy = 0
122 )
123
124 const (
125 uintptrMask = 1<<(8*goarch.PtrSize) - 1
126
127
128
129
130
131
132
133 stackPreempt = uintptrMask & -1314
134
135
136
137 stackFork = uintptrMask & -1234
138
139
140
141 stackForceMove = uintptrMask & -275
142
143
144 stackPoisonMin = uintptrMask & -4096
145 )
146
147
148
149
150
151
152
153 var stackpool [_NumStackOrders]struct {
154 item stackpoolItem
155 _ [(cpu.CacheLinePadSize - unsafe.Sizeof(stackpoolItem{})%cpu.CacheLinePadSize) % cpu.CacheLinePadSize]byte
156 }
157
158 type stackpoolItem struct {
159 _ sys.NotInHeap
160 mu mutex
161 span mSpanList
162 }
163
164
165 var stackLarge struct {
166 lock mutex
167 free [heapAddrBits - gc.PageShift]mSpanList
168 }
169
170 func stackinit() {
171 if _StackCacheSize&pageMask != 0 {
172 throw("cache size must be a multiple of page size")
173 }
174 for i := range stackpool {
175 stackpool[i].item.span.init()
176 lockInit(&stackpool[i].item.mu, lockRankStackpool)
177 }
178 for i := range stackLarge.free {
179 stackLarge.free[i].init()
180 lockInit(&stackLarge.lock, lockRankStackLarge)
181 }
182 }
183
184
185 func stacklog2(n uintptr) int {
186 if n == 0 {
187 return 0
188 }
189 return bits.Len64(uint64(n))
190 }
191
192
193
194 func stackpoolalloc(order uint8) gclinkptr {
195 list := &stackpool[order].item.span
196 s := list.first
197 lockWithRankMayAcquire(&mheap_.lock, lockRankMheap)
198 if s == nil {
199
200 s = mheap_.allocManual(_StackCacheSize>>gc.PageShift, spanAllocStack)
201 if s == nil {
202 throw("out of memory")
203 }
204 if s.allocCount != 0 {
205 throw("bad allocCount")
206 }
207 if s.manualFreeList.ptr() != nil {
208 throw("bad manualFreeList")
209 }
210 osStackAlloc(s)
211 s.elemsize = fixedStack << order
212 for i := uintptr(0); i < _StackCacheSize; i += s.elemsize {
213 x := gclinkptr(s.base() + i)
214 if valgrindenabled {
215
216
217
218
219 valgrindMalloc(unsafe.Pointer(x.ptr()), unsafe.Sizeof(x.ptr()))
220 }
221 x.ptr().next = s.manualFreeList
222 s.manualFreeList = x
223 }
224 list.insert(s)
225 }
226 x := s.manualFreeList
227 if x.ptr() == nil {
228 throw("span has no free stacks")
229 }
230 s.manualFreeList = x.ptr().next
231 s.allocCount++
232 if s.manualFreeList.ptr() == nil {
233
234 list.remove(s)
235 }
236 return x
237 }
238
239
240 func stackpoolfree(x gclinkptr, order uint8) {
241 s := spanOfUnchecked(uintptr(x))
242 if s.state.get() != mSpanManual {
243 throw("freeing stack not in a stack span")
244 }
245 if s.manualFreeList.ptr() == nil {
246
247 stackpool[order].item.span.insert(s)
248 }
249 x.ptr().next = s.manualFreeList
250 s.manualFreeList = x
251 s.allocCount--
252 if gcphase == _GCoff && s.allocCount == 0 {
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268 stackpool[order].item.span.remove(s)
269 s.manualFreeList = 0
270 osStackFree(s)
271 mheap_.freeManual(s, spanAllocStack)
272 }
273 }
274
275
276
277
278
279 func stackcacherefill(c *mcache, order uint8) {
280 if stackDebug >= 1 {
281 print("stackcacherefill order=", order, "\n")
282 }
283
284
285
286 var list gclinkptr
287 var size uintptr
288 lock(&stackpool[order].item.mu)
289 for size < _StackCacheSize/2 {
290 x := stackpoolalloc(order)
291 x.ptr().next = list
292 list = x
293 size += fixedStack << order
294 }
295 unlock(&stackpool[order].item.mu)
296 c.stackcache[order].list = list
297 c.stackcache[order].size = size
298 }
299
300
301 func stackcacherelease(c *mcache, order uint8) {
302 if stackDebug >= 1 {
303 print("stackcacherelease order=", order, "\n")
304 }
305 x := c.stackcache[order].list
306 size := c.stackcache[order].size
307 lock(&stackpool[order].item.mu)
308 for size > _StackCacheSize/2 {
309 y := x.ptr().next
310 stackpoolfree(x, order)
311 x = y
312 size -= fixedStack << order
313 }
314 unlock(&stackpool[order].item.mu)
315 c.stackcache[order].list = x
316 c.stackcache[order].size = size
317 }
318
319
320 func stackcache_clear(c *mcache) {
321 if stackDebug >= 1 {
322 print("stackcache clear\n")
323 }
324 for order := uint8(0); order < _NumStackOrders; order++ {
325 lock(&stackpool[order].item.mu)
326 x := c.stackcache[order].list
327 for x.ptr() != nil {
328 y := x.ptr().next
329 stackpoolfree(x, order)
330 x = y
331 }
332 c.stackcache[order].list = 0
333 c.stackcache[order].size = 0
334 unlock(&stackpool[order].item.mu)
335 }
336 }
337
338
339
340
341
342
343
344 func stackalloc(n uint32) stack {
345
346
347
348 thisg := getg()
349 if thisg != thisg.m.g0 {
350 throw("stackalloc not on scheduler stack")
351 }
352 if n&(n-1) != 0 {
353 throw("stack size not a power of 2")
354 }
355 if stackDebug >= 1 {
356 print("stackalloc ", n, "\n")
357 }
358
359 if debug.efence != 0 || stackFromSystem != 0 {
360 n = uint32(alignUp(uintptr(n), physPageSize))
361 v := sysAlloc(uintptr(n), &memstats.stacks_sys, "goroutine stack (system)")
362 if v == nil {
363 throw("out of memory (stackalloc)")
364 }
365 return stack{uintptr(v), uintptr(v) + uintptr(n)}
366 }
367
368
369
370
371 var v unsafe.Pointer
372 if n < fixedStack<<_NumStackOrders && n < _StackCacheSize {
373 order := uint8(0)
374 n2 := n
375 for n2 > fixedStack {
376 order++
377 n2 >>= 1
378 }
379 var x gclinkptr
380 if stackNoCache != 0 || thisg.m.p == 0 || thisg.m.preemptoff != "" {
381
382
383
384
385 lock(&stackpool[order].item.mu)
386 x = stackpoolalloc(order)
387 unlock(&stackpool[order].item.mu)
388 } else {
389 c := thisg.m.p.ptr().mcache
390 x = c.stackcache[order].list
391 if x.ptr() == nil {
392 stackcacherefill(c, order)
393 x = c.stackcache[order].list
394 }
395 c.stackcache[order].list = x.ptr().next
396 c.stackcache[order].size -= uintptr(n)
397 }
398 if valgrindenabled {
399
400
401
402 valgrindFree(unsafe.Pointer(x.ptr()))
403 }
404 v = unsafe.Pointer(x)
405 } else {
406 var s *mspan
407 npage := uintptr(n) >> gc.PageShift
408 log2npage := stacklog2(npage)
409
410
411 lock(&stackLarge.lock)
412 if !stackLarge.free[log2npage].isEmpty() {
413 s = stackLarge.free[log2npage].first
414 stackLarge.free[log2npage].remove(s)
415 }
416 unlock(&stackLarge.lock)
417
418 lockWithRankMayAcquire(&mheap_.lock, lockRankMheap)
419
420 if s == nil {
421
422 s = mheap_.allocManual(npage, spanAllocStack)
423 if s == nil {
424 throw("out of memory")
425 }
426 osStackAlloc(s)
427 s.elemsize = uintptr(n)
428 }
429 v = unsafe.Pointer(s.base())
430 }
431
432 if traceAllocFreeEnabled() {
433 trace := traceAcquire()
434 if trace.ok() {
435 trace.GoroutineStackAlloc(uintptr(v), uintptr(n))
436 traceRelease(trace)
437 }
438 }
439 if raceenabled {
440 racemalloc(v, uintptr(n))
441 }
442 if msanenabled {
443 msanmalloc(v, uintptr(n))
444 }
445 if asanenabled {
446 asanunpoison(v, uintptr(n))
447 }
448 if valgrindenabled {
449 valgrindMalloc(v, uintptr(n))
450 }
451 if stackDebug >= 1 {
452 print(" allocated ", v, "\n")
453 }
454 return stack{uintptr(v), uintptr(v) + uintptr(n)}
455 }
456
457
458
459
460
461
462
463 func stackfree(stk stack) {
464 gp := getg()
465 v := unsafe.Pointer(stk.lo)
466 n := stk.hi - stk.lo
467 if n&(n-1) != 0 {
468 throw("stack not a power of 2")
469 }
470 if stk.lo+n < stk.hi {
471 throw("bad stack size")
472 }
473 if stackDebug >= 1 {
474 println("stackfree", v, n)
475 memclrNoHeapPointers(v, n)
476 }
477 if debug.efence != 0 || stackFromSystem != 0 {
478 if debug.efence != 0 || stackFaultOnFree != 0 {
479 sysFault(v, n)
480 } else {
481 sysFree(v, n, &memstats.stacks_sys)
482 }
483 return
484 }
485 if traceAllocFreeEnabled() {
486 trace := traceAcquire()
487 if trace.ok() {
488 trace.GoroutineStackFree(uintptr(v))
489 traceRelease(trace)
490 }
491 }
492 if msanenabled {
493 msanfree(v, n)
494 }
495 if asanenabled {
496 asanpoison(v, n)
497 }
498 if valgrindenabled {
499 valgrindFree(v)
500 }
501 if n < fixedStack<<_NumStackOrders && n < _StackCacheSize {
502 order := uint8(0)
503 n2 := n
504 for n2 > fixedStack {
505 order++
506 n2 >>= 1
507 }
508 x := gclinkptr(v)
509 if stackNoCache != 0 || gp.m.p == 0 || gp.m.preemptoff != "" {
510 lock(&stackpool[order].item.mu)
511 if valgrindenabled {
512
513
514 valgrindMalloc(unsafe.Pointer(x.ptr()), unsafe.Sizeof(x.ptr()))
515 }
516 stackpoolfree(x, order)
517 unlock(&stackpool[order].item.mu)
518 } else {
519 c := gp.m.p.ptr().mcache
520 if c.stackcache[order].size >= _StackCacheSize {
521 stackcacherelease(c, order)
522 }
523 if valgrindenabled {
524
525
526
527 valgrindMalloc(unsafe.Pointer(x.ptr()), unsafe.Sizeof(x.ptr()))
528 }
529 x.ptr().next = c.stackcache[order].list
530 c.stackcache[order].list = x
531 c.stackcache[order].size += n
532 }
533 } else {
534 s := spanOfUnchecked(uintptr(v))
535 if s.state.get() != mSpanManual {
536 println(hex(s.base()), v)
537 throw("bad span state")
538 }
539 if gcphase == _GCoff {
540
541
542 osStackFree(s)
543 mheap_.freeManual(s, spanAllocStack)
544 } else {
545
546
547
548
549
550 log2npage := stacklog2(s.npages)
551 lock(&stackLarge.lock)
552 stackLarge.free[log2npage].insert(s)
553 unlock(&stackLarge.lock)
554 }
555 }
556 }
557
558 var maxstacksize uintptr = 1 << 20
559
560 var maxstackceiling = maxstacksize
561
562 var ptrnames = []string{
563 0: "scalar",
564 1: "ptr",
565 }
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600 type adjustinfo struct {
601 old stack
602 delta uintptr
603
604
605 sghi uintptr
606 }
607
608
609
610 func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
611 pp := (*uintptr)(vpp)
612 p := *pp
613 if stackDebug >= 4 {
614 print(" ", pp, ":", hex(p), "\n")
615 }
616 if valgrindenabled {
617
618
619
620
621
622
623
624 valgrindMakeMemDefined(unsafe.Pointer(&p), unsafe.Sizeof(&p))
625 }
626 if adjinfo.old.lo <= p && p < adjinfo.old.hi {
627 *pp = p + adjinfo.delta
628 if stackDebug >= 3 {
629 print(" adjust ptr ", pp, ":", hex(p), " -> ", hex(*pp), "\n")
630 }
631 }
632 }
633
634
635
636 type bitvector struct {
637 n int32
638 bytedata *uint8
639 }
640
641
642
643
644
645 func (bv *bitvector) ptrbit(i uintptr) uint8 {
646 b := *(addb(bv.bytedata, i/8))
647 return (b >> (i % 8)) & 1
648 }
649
650
651
652 func adjustpointers(scanp unsafe.Pointer, bv *bitvector, adjinfo *adjustinfo, f funcInfo) {
653 minp := adjinfo.old.lo
654 maxp := adjinfo.old.hi
655 delta := adjinfo.delta
656 num := uintptr(bv.n)
657
658
659
660
661
662 useCAS := uintptr(scanp) < adjinfo.sghi
663 for i := uintptr(0); i < num; i += 8 {
664 if stackDebug >= 4 {
665 for j := uintptr(0); j < 8; j++ {
666 print(" ", add(scanp, (i+j)*goarch.PtrSize), ":", ptrnames[bv.ptrbit(i+j)], ":", hex(*(*uintptr)(add(scanp, (i+j)*goarch.PtrSize))), " # ", i, " ", *addb(bv.bytedata, i/8), "\n")
667 }
668 }
669 b := *(addb(bv.bytedata, i/8))
670 for b != 0 {
671 j := uintptr(sys.TrailingZeros8(b))
672 b &= b - 1
673 pp := (*uintptr)(add(scanp, (i+j)*goarch.PtrSize))
674 retry:
675 p := *pp
676 if f.valid() && 0 < p && p < minLegalPointer && debug.invalidptr != 0 {
677
678
679 getg().m.traceback = 2
680 print("runtime: bad pointer in frame ", funcname(f), " at ", pp, ": ", hex(p), "\n")
681 throw("invalid pointer found on stack")
682 }
683 if minp <= p && p < maxp {
684 if stackDebug >= 3 {
685 print("adjust ptr ", hex(p), " ", funcname(f), "\n")
686 }
687 if useCAS {
688 ppu := (*unsafe.Pointer)(unsafe.Pointer(pp))
689 if !atomic.Casp1(ppu, unsafe.Pointer(p), unsafe.Pointer(p+delta)) {
690 goto retry
691 }
692 } else {
693 *pp = p + delta
694 }
695 }
696 }
697 }
698 }
699
700
701 func adjustframe(frame *stkframe, adjinfo *adjustinfo) {
702
703 if (goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.ARM64) && frame.argp-frame.varp == 2*goarch.PtrSize {
704 if stackDebug >= 3 {
705 print(" saved bp\n")
706 }
707 if debugCheckBP {
708
709
710 bp := *(*uintptr)(unsafe.Pointer(frame.varp))
711 if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) {
712 println("runtime: found invalid frame pointer")
713 print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n")
714 throw("bad frame pointer")
715 }
716 }
717
718
719
720
721 adjustpointer(adjinfo, unsafe.Pointer(frame.varp))
722 }
723 if goarch.ArchFamily == goarch.ARM64 && isInjectedCall(frame.fn.funcID) {
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748 adjustpointer(adjinfo, unsafe.Pointer(frame.fp+goarch.PtrSize))
749 }
750
751 if frame.continpc == 0 {
752
753
754
755 return
756 }
757 f := frame.fn
758 if stackDebug >= 2 {
759 print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
760 }
761
762 locals, args, objs := frame.getStackMap(true)
763
764
765 if locals.n > 0 {
766 size := uintptr(locals.n) * goarch.PtrSize
767 adjustpointers(unsafe.Pointer(frame.varp-size), &locals, adjinfo, f)
768 }
769
770
771 if args.n > 0 {
772 if stackDebug >= 3 {
773 print(" args\n")
774 }
775 adjustpointers(unsafe.Pointer(frame.argp), &args, adjinfo, funcInfo{})
776 }
777
778
779
780 if frame.varp != 0 {
781 for i := range objs {
782 obj := &objs[i]
783 off := obj.off
784 base := frame.varp
785 if off >= 0 {
786 base = frame.argp
787 }
788 p := base + uintptr(off)
789 if p < frame.sp {
790
791
792
793 continue
794 }
795 ptrBytes, gcData := obj.gcdata()
796 for i := uintptr(0); i < ptrBytes; i += goarch.PtrSize {
797 if *addb(gcData, i/(8*goarch.PtrSize))>>(i/goarch.PtrSize&7)&1 != 0 {
798 adjustpointer(adjinfo, unsafe.Pointer(p+i))
799 }
800 }
801 }
802 }
803 }
804
805 func adjustctxt(gp *g, adjinfo *adjustinfo) {
806 adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.ctxt))
807 if !framepointer_enabled {
808 return
809 }
810 if debugCheckBP {
811 bp := gp.sched.bp
812 if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) {
813 println("runtime: found invalid top frame pointer")
814 print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n")
815 throw("bad top frame pointer")
816 }
817 }
818 oldfp := gp.sched.bp
819 adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.bp))
820 if GOARCH == "arm64" {
821
822
823
824 if oldfp == gp.sched.sp-goarch.PtrSize {
825 memmove(unsafe.Pointer(gp.sched.bp), unsafe.Pointer(oldfp), goarch.PtrSize)
826 adjustpointer(adjinfo, unsafe.Pointer(gp.sched.bp))
827 }
828 }
829 }
830
831 func adjustdefers(gp *g, adjinfo *adjustinfo) {
832
833
834
835 adjustpointer(adjinfo, unsafe.Pointer(&gp._defer))
836 for d := gp._defer; d != nil; d = d.link {
837 adjustpointer(adjinfo, unsafe.Pointer(&d.fn))
838 adjustpointer(adjinfo, unsafe.Pointer(&d.sp))
839 adjustpointer(adjinfo, unsafe.Pointer(&d.link))
840 }
841 }
842
843 func adjustpanics(gp *g, adjinfo *adjustinfo) {
844
845
846 adjustpointer(adjinfo, unsafe.Pointer(&gp._panic))
847 }
848
849 func adjustsudogs(gp *g, adjinfo *adjustinfo) {
850
851
852 for s := gp.waiting; s != nil; s = s.waitlink {
853 adjustpointer(adjinfo, unsafe.Pointer(&s.elem.vu))
854 adjustpointer(adjinfo, unsafe.Pointer(&s.elem.vp))
855 }
856 }
857
858 func fillstack(stk stack, b byte) {
859 for p := stk.lo; p < stk.hi; p++ {
860 *(*byte)(unsafe.Pointer(p)) = b
861 }
862 }
863
864 func findsghi(gp *g, stk stack) uintptr {
865 var sghi uintptr
866 for sg := gp.waiting; sg != nil; sg = sg.waitlink {
867 p := sg.elem.uintptr() + uintptr(sg.c.get().elemsize)
868 if stk.lo <= p && p < stk.hi && p > sghi {
869 sghi = p
870 }
871 }
872 return sghi
873 }
874
875
876
877
878 func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr {
879 if gp.waiting == nil {
880 return 0
881 }
882
883
884 var lastc *hchan
885 for sg := gp.waiting; sg != nil; sg = sg.waitlink {
886 if sg.c.get() != lastc {
887
888
889
890
891
892
893
894
895
896 lockWithRank(&sg.c.get().lock, lockRankHchanLeaf)
897 }
898 lastc = sg.c.get()
899 }
900
901
902 adjustsudogs(gp, adjinfo)
903
904
905
906
907 var sgsize uintptr
908 if adjinfo.sghi != 0 {
909 oldBot := adjinfo.old.hi - used
910 newBot := oldBot + adjinfo.delta
911 sgsize = adjinfo.sghi - oldBot
912 memmove(unsafe.Pointer(newBot), unsafe.Pointer(oldBot), sgsize)
913 }
914
915
916 lastc = nil
917 for sg := gp.waiting; sg != nil; sg = sg.waitlink {
918 if sg.c.get() != lastc {
919 unlock(&sg.c.get().lock)
920 }
921 lastc = sg.c.get()
922 }
923
924 return sgsize
925 }
926
927
928
929 func copystack(gp *g, newsize uintptr) {
930 if gp.syscallsp != 0 {
931 throw("stack growth not allowed in system call")
932 }
933 old := gp.stack
934 if old.lo == 0 {
935 throw("nil stackbase")
936 }
937 used := old.hi - gp.sched.sp
938
939
940
941
942 gcController.addScannableStack(getg().m.p.ptr(), int64(newsize)-int64(old.hi-old.lo))
943
944
945 new := stackalloc(uint32(newsize))
946 if stackPoisonCopy != 0 {
947 fillstack(new, 0xfd)
948 }
949 if stackDebug >= 1 {
950 print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]", " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n")
951 }
952
953
954 var adjinfo adjustinfo
955 adjinfo.old = old
956 adjinfo.delta = new.hi - old.hi
957
958
959 ncopy := used
960 if !gp.activeStackChans {
961 if newsize < old.hi-old.lo && gp.parkingOnChan.Load() {
962
963
964
965
966 throw("racy sudog adjustment due to parking on channel")
967 }
968 adjustsudogs(gp, &adjinfo)
969 } else {
970
971
972
973
974
975
976
977 adjinfo.sghi = findsghi(gp, old)
978
979
980
981 ncopy -= syncadjustsudogs(gp, used, &adjinfo)
982 }
983
984
985 memmove(unsafe.Pointer(new.hi-ncopy), unsafe.Pointer(old.hi-ncopy), ncopy)
986
987
988
989
990 adjustctxt(gp, &adjinfo)
991 adjustdefers(gp, &adjinfo)
992 adjustpanics(gp, &adjinfo)
993 if adjinfo.sghi != 0 {
994 adjinfo.sghi += adjinfo.delta
995 }
996
997
998 gp.stack = new
999 gp.stackguard0 = new.lo + stackGuard
1000 gp.sched.sp = new.hi - used
1001 gp.stktopsp += adjinfo.delta
1002
1003
1004 var u unwinder
1005 for u.init(gp, 0); u.valid(); u.next() {
1006 adjustframe(&u.frame, &adjinfo)
1007 }
1008
1009 if valgrindenabled {
1010 if gp.valgrindStackID == 0 {
1011 gp.valgrindStackID = valgrindRegisterStack(unsafe.Pointer(new.lo), unsafe.Pointer(new.hi))
1012 } else {
1013 valgrindChangeStack(gp.valgrindStackID, unsafe.Pointer(new.lo), unsafe.Pointer(new.hi))
1014 }
1015 }
1016
1017
1018 if goexperiment.RuntimeSecret && gp.secret > 0 {
1019
1020
1021
1022
1023
1024 memclrNoHeapPointers(unsafe.Pointer(old.lo), old.hi-old.lo)
1025
1026 secretEraseRegisters()
1027 }
1028 if stackPoisonCopy != 0 {
1029 fillstack(old, 0xfc)
1030 }
1031 stackfree(old)
1032 }
1033
1034
1035 func round2(x int32) int32 {
1036 s := uint(0)
1037 for 1<<s < x {
1038 s++
1039 }
1040 return 1 << s
1041 }
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055 func newstack() {
1056 thisg := getg()
1057
1058 if thisg.m.morebuf.g.ptr().stackguard0 == stackFork {
1059 throw("stack growth after fork")
1060 }
1061 if thisg.m.morebuf.g.ptr() != thisg.m.curg {
1062 print("runtime: newstack called from g=", hex(thisg.m.morebuf.g), "\n"+"\tm=", thisg.m, " m->curg=", thisg.m.curg, " m->g0=", thisg.m.g0, " m->gsignal=", thisg.m.gsignal, "\n")
1063 morebuf := thisg.m.morebuf
1064 traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g.ptr())
1065 throw("runtime: wrong goroutine in newstack")
1066 }
1067
1068 gp := thisg.m.curg
1069 if goexperiment.RuntimeSecret && gp.secret > 0 {
1070
1071
1072
1073
1074
1075 secretEraseRegisters()
1076 }
1077
1078 if thisg.m.curg.throwsplit {
1079
1080 morebuf := thisg.m.morebuf
1081 gp.syscallsp = morebuf.sp
1082 gp.syscallpc = morebuf.pc
1083 pcname, pcoff := "(unknown)", uintptr(0)
1084 f := findfunc(gp.sched.pc)
1085 if f.valid() {
1086 pcname = funcname(f)
1087 pcoff = gp.sched.pc - f.entry()
1088 }
1089 print("runtime: newstack at ", pcname, "+", hex(pcoff),
1090 " sp=", hex(gp.sched.sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n",
1091 "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n",
1092 "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n")
1093
1094 thisg.m.traceback = 2
1095 traceback(morebuf.pc, morebuf.sp, morebuf.lr, gp)
1096 throw("runtime: stack split at bad time")
1097 }
1098
1099 morebuf := thisg.m.morebuf
1100 thisg.m.morebuf.pc = 0
1101 thisg.m.morebuf.lr = 0
1102 thisg.m.morebuf.sp = 0
1103 thisg.m.morebuf.g = 0
1104
1105
1106
1107
1108 stackguard0 := atomic.Loaduintptr(&gp.stackguard0)
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122 preempt := stackguard0 == stackPreempt
1123 if preempt {
1124 if !canPreemptM(thisg.m) {
1125
1126
1127 gp.stackguard0 = gp.stack.lo + stackGuard
1128 gogo(&gp.sched)
1129 }
1130 }
1131
1132 if gp.stack.lo == 0 {
1133 throw("missing stack in newstack")
1134 }
1135 sp := gp.sched.sp
1136 if goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.I386 || goarch.ArchFamily == goarch.WASM {
1137
1138 sp -= goarch.PtrSize
1139 }
1140 if stackDebug >= 1 || sp < gp.stack.lo {
1141 print("runtime: newstack sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n",
1142 "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n",
1143 "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n")
1144 }
1145 if sp < gp.stack.lo {
1146 print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->status=", hex(readgstatus(gp)), "\n ")
1147 print("runtime: split stack overflow: ", hex(sp), " < ", hex(gp.stack.lo), "\n")
1148 throw("runtime: split stack overflow")
1149 }
1150
1151 if preempt {
1152 if gp == thisg.m.g0 {
1153 throw("runtime: preempt g0")
1154 }
1155 if thisg.m.p == 0 && thisg.m.locks == 0 {
1156 throw("runtime: g is running but p is not")
1157 }
1158
1159 if gp.preemptShrink {
1160
1161
1162 gp.preemptShrink = false
1163 shrinkstack(gp)
1164 }
1165
1166
1167 gp.syncSafePoint = true
1168
1169 if gp.preemptStop {
1170 preemptPark(gp)
1171 }
1172
1173
1174 gopreempt_m(gp)
1175 }
1176
1177
1178 oldsize := gp.stack.hi - gp.stack.lo
1179 newsize := oldsize * 2
1180
1181
1182
1183
1184 if f := findfunc(gp.sched.pc); f.valid() {
1185 max := uintptr(funcMaxSPDelta(f))
1186 needed := max + stackGuard
1187 used := gp.stack.hi - gp.sched.sp
1188 for newsize-used < needed {
1189 newsize *= 2
1190 }
1191 }
1192
1193 if stackguard0 == stackForceMove {
1194
1195
1196
1197 newsize = oldsize
1198 }
1199
1200 if newsize > maxstacksize || newsize > maxstackceiling {
1201 if maxstacksize < maxstackceiling {
1202 print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n")
1203 } else {
1204 print("runtime: goroutine stack exceeds ", maxstackceiling, "-byte limit\n")
1205 }
1206 print("runtime: sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n")
1207 throw("stack overflow")
1208 }
1209
1210
1211
1212 casgstatus(gp, _Grunning, _Gcopystack)
1213
1214
1215
1216 copystack(gp, newsize)
1217 if stackDebug >= 1 {
1218 print("stack grow done\n")
1219 }
1220 casgstatus(gp, _Gcopystack, _Grunning)
1221 gogo(&gp.sched)
1222 }
1223
1224
1225 func nilfunc() {
1226 *(*uint8)(nil) = 0
1227 }
1228
1229
1230
1231 func gostartcallfn(gobuf *gobuf, fv *funcval) {
1232 var fn unsafe.Pointer
1233 if fv != nil {
1234 fn = unsafe.Pointer(fv.fn)
1235 } else {
1236 fn = unsafe.Pointer(abi.FuncPCABIInternal(nilfunc))
1237 }
1238 gostartcall(gobuf, fn, unsafe.Pointer(fv))
1239 }
1240
1241
1242
1243
1244
1245 func isShrinkStackSafe(gp *g) bool {
1246
1247
1248
1249
1250 if gp.syscallsp != 0 {
1251 return false
1252 }
1253
1254
1255
1256 if gp.asyncSafePoint {
1257 return false
1258 }
1259
1260
1261
1262 if gp.parkingOnChan.Load() {
1263 return false
1264 }
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276 if readgstatus(gp)&^_Gscan == _Gwaiting && gp.waitreason.isWaitingForSuspendG() {
1277 return false
1278 }
1279 return true
1280 }
1281
1282
1283
1284
1285
1286 func shrinkstack(gp *g) {
1287 if gp.stack.lo == 0 {
1288 throw("missing stack in shrinkstack")
1289 }
1290 if s := readgstatus(gp); s&_Gscan == 0 {
1291
1292
1293
1294 if !(gp == getg().m.curg && getg() != getg().m.curg && s == _Grunning) {
1295
1296 throw("bad status in shrinkstack")
1297 }
1298 }
1299 if !isShrinkStackSafe(gp) {
1300 throw("shrinkstack at bad time")
1301 }
1302
1303
1304
1305 if gp == getg().m.curg && gp.m.libcallsp != 0 {
1306 throw("shrinking stack in libcall")
1307 }
1308
1309 if debug.gcshrinkstackoff > 0 {
1310 return
1311 }
1312
1313 oldsize := gp.stack.hi - gp.stack.lo
1314 newsize := oldsize / 2
1315
1316
1317 if newsize < fixedStack {
1318 return
1319 }
1320
1321
1322
1323
1324
1325 avail := gp.stack.hi - gp.stack.lo
1326 if used := gp.stack.hi - gp.sched.sp + stackNosplit; used >= avail/4 {
1327 return
1328 }
1329
1330 if stackDebug > 0 {
1331 print("shrinking stack ", oldsize, "->", newsize, "\n")
1332 }
1333
1334 copystack(gp, newsize)
1335 }
1336
1337
1338 func freeStackSpans() {
1339
1340 for order := range stackpool {
1341 lock(&stackpool[order].item.mu)
1342 list := &stackpool[order].item.span
1343 for s := list.first; s != nil; {
1344 next := s.next
1345 if s.allocCount == 0 {
1346 list.remove(s)
1347 s.manualFreeList = 0
1348 osStackFree(s)
1349 mheap_.freeManual(s, spanAllocStack)
1350 }
1351 s = next
1352 }
1353 unlock(&stackpool[order].item.mu)
1354 }
1355
1356
1357 lock(&stackLarge.lock)
1358 for i := range stackLarge.free {
1359 for s := stackLarge.free[i].first; s != nil; {
1360 next := s.next
1361 stackLarge.free[i].remove(s)
1362 osStackFree(s)
1363 mheap_.freeManual(s, spanAllocStack)
1364 s = next
1365 }
1366 }
1367 unlock(&stackLarge.lock)
1368 }
1369
1370
1371
1372 type stackObjectRecord struct {
1373
1374
1375
1376 off int32
1377 size int32
1378 ptrBytes int32
1379 gcdataoff uint32
1380 }
1381
1382
1383
1384
1385 func (r *stackObjectRecord) gcdata() (uintptr, *byte) {
1386 ptr := uintptr(unsafe.Pointer(r))
1387 var mod *moduledata
1388 for datap := &firstmoduledata; datap != nil; datap = datap.next {
1389
1390 if datap.gofunc <= ptr && ptr < datap.epclntab {
1391 mod = datap
1392 break
1393 }
1394
1395 if datap.noptrbss <= ptr && ptr < datap.enoptrbss {
1396 mod = datap
1397 break
1398 }
1399 }
1400
1401
1402
1403 res := mod.rodata + uintptr(r.gcdataoff)
1404 return uintptr(r.ptrBytes), (*byte)(unsafe.Pointer(res))
1405 }
1406
1407
1408
1409
1410
1411 func morestackc() {
1412 throw("attempt to execute system stack code on user stack")
1413 }
1414
1415
1416
1417
1418
1419 var startingStackSize uint32 = fixedStack
1420
1421 func gcComputeStartingStackSize() {
1422 if debug.adaptivestackstart == 0 {
1423 return
1424 }
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435 var scannedStackSize uint64
1436 var scannedStacks uint64
1437 for _, p := range allp {
1438 scannedStackSize += p.scannedStackSize
1439 scannedStacks += p.scannedStacks
1440
1441 p.scannedStackSize = 0
1442 p.scannedStacks = 0
1443 }
1444 if scannedStacks == 0 {
1445 startingStackSize = fixedStack
1446 return
1447 }
1448 avg := scannedStackSize/scannedStacks + stackGuard
1449
1450
1451 if avg > uint64(maxstacksize) {
1452 avg = uint64(maxstacksize)
1453 }
1454 if avg < fixedStack {
1455 avg = fixedStack
1456 }
1457
1458 startingStackSize = uint32(round2(int32(avg)))
1459 }
1460
View as plain text