LEFT | RIGHT |
1 // Copyright 2013 The Go Authors. All rights reserved. | 1 // Copyright 2013 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #include "runtime.h" | 5 #include "runtime.h" |
6 #include "arch_GOARCH.h" | 6 #include "arch_GOARCH.h" |
7 #include "malloc.h" | 7 #include "malloc.h" |
8 #include "stack.h" | 8 #include "stack.h" |
9 #include "funcdata.h" | 9 #include "funcdata.h" |
10 #include "typekind.h" | 10 #include "typekind.h" |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 // Doing so would cause a deadlock (issue 1547). | 199 // Doing so would cause a deadlock (issue 1547). |
200 if(g != g->m->g0) | 200 if(g != g->m->g0) |
201 runtime·throw("stackalloc not on scheduler stack"); | 201 runtime·throw("stackalloc not on scheduler stack"); |
202 if((n & (n-1)) != 0) | 202 if((n & (n-1)) != 0) |
203 runtime·throw("stack size not a power of 2"); | 203 runtime·throw("stack size not a power of 2"); |
204 if(StackDebug >= 1) | 204 if(StackDebug >= 1) |
205 runtime·printf("stackalloc %d\n", n); | 205 runtime·printf("stackalloc %d\n", n); |
206 | 206 |
207 gp->stacksize += n; | 207 gp->stacksize += n; |
208 if(runtime·debug.efence || StackFromSystem) { | 208 if(runtime·debug.efence || StackFromSystem) { |
209 » » v = runtime·SysAlloc(ROUND(n, PageSize), &mstats.stacks_sys); | 209 » » v = runtime·sysAlloc(ROUND(n, PageSize), &mstats.stacks_sys); |
210 if(v == nil) | 210 if(v == nil) |
211 runtime·throw("out of memory (stackalloc)"); | 211 runtime·throw("out of memory (stackalloc)"); |
212 return v; | 212 return v; |
213 } | 213 } |
214 | 214 |
215 // Small stacks are allocated with a fixed-size free-list allocator. | 215 // Small stacks are allocated with a fixed-size free-list allocator. |
216 // If we need a stack of a bigger size, we fall back on allocating | 216 // If we need a stack of a bigger size, we fall back on allocating |
217 // a dedicated span. | 217 // a dedicated span. |
218 if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize)
{ | 218 if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize)
{ |
219 order = 0; | 219 order = 0; |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 { | 412 { |
413 CopyableInfo *cinfo; | 413 CopyableInfo *cinfo; |
414 Func *f; | 414 Func *f; |
415 StackMap *stackmap; | 415 StackMap *stackmap; |
416 | 416 |
417 cinfo = arg; | 417 cinfo = arg; |
418 f = frame->fn; | 418 f = frame->fn; |
419 if(StackDebug >= 2) | 419 if(StackDebug >= 2) |
420 runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", ru
ntime·funcname(f), frame->sp, frame->fp, cinfo->stk, cinfo->base); | 420 runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", ru
ntime·funcname(f), frame->sp, frame->fp, cinfo->stk, cinfo->base); |
421 // if we're not in the segment any more, return immediately. | 421 // if we're not in the segment any more, return immediately. |
422 » if(frame->varp < cinfo->stk || frame->varp >= cinfo->base) { | 422 » if((byte*)frame->varp < cinfo->stk || (byte*)frame->varp >= cinfo->base)
{ |
423 if(StackDebug >= 2) | 423 if(StackDebug >= 2) |
424 runtime·printf(" <next segment>\n"); | 424 runtime·printf(" <next segment>\n"); |
425 return false; // stop traceback | 425 return false; // stop traceback |
426 } | 426 } |
427 if(f->entry == (uintptr)runtime·main) { | 427 if(f->entry == (uintptr)runtime·main) { |
428 // A special routine at the TOS of the main routine. | 428 // A special routine at the TOS of the main routine. |
429 // We will allow it to be copied even though we don't | 429 // We will allow it to be copied even though we don't |
430 // have full GC info for it (because it is written in C). | 430 // have full GC info for it (because it is written in C). |
431 cinfo->frames++; | 431 cinfo->frames++; |
432 return false; // stop traceback | 432 return false; // stop traceback |
433 } | 433 } |
434 if(f->entry == (uintptr)runtime·switchtoM) { | 434 if(f->entry == (uintptr)runtime·switchtoM) { |
435 // A special routine at the bottom of stack of a goroutine that
does onM call. | 435 // A special routine at the bottom of stack of a goroutine that
does onM call. |
436 // We will allow it to be copied even though we don't | 436 // We will allow it to be copied even though we don't |
437 // have full GC info for it (because it is written in asm). | 437 // have full GC info for it (because it is written in asm). |
438 cinfo->frames++; | 438 cinfo->frames++; |
439 return true; | 439 return true; |
440 } | 440 } |
441 » if(frame->varp != (byte*)frame->sp) { // not in prologue (and has at lea
st one local or outarg) | 441 » if((byte*)frame->varp != (byte*)frame->sp) { // not in prologue (and has
at least one local or outarg) |
442 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); | 442 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); |
443 if(stackmap == nil) { | 443 if(stackmap == nil) { |
444 cinfo->frames = -1; | 444 cinfo->frames = -1; |
445 if(StackDebug >= 1) | 445 if(StackDebug >= 1) |
446 runtime·printf("copystack: no locals info for %s
\n", runtime·funcname(f)); | 446 runtime·printf("copystack: no locals info for %s
\n", runtime·funcname(f)); |
447 return false; | 447 return false; |
448 } | 448 } |
449 if(stackmap->n <= 0) { | 449 if(stackmap->n <= 0) { |
450 cinfo->frames = -1; | 450 cinfo->frames = -1; |
451 if(StackDebug >= 1) | 451 if(StackDebug >= 1) |
(...skipping 18 matching lines...) Expand all Loading... |
470 // frame, return -1. Otherwise return the number of frames | 470 // frame, return -1. Otherwise return the number of frames |
471 // in the top segment, all of which are copyable. | 471 // in the top segment, all of which are copyable. |
472 static int32 | 472 static int32 |
473 copyabletopsegment(G *gp) | 473 copyabletopsegment(G *gp) |
474 { | 474 { |
475 CopyableInfo cinfo; | 475 CopyableInfo cinfo; |
476 Defer *d; | 476 Defer *d; |
477 Func *f; | 477 Func *f; |
478 FuncVal *fn; | 478 FuncVal *fn; |
479 StackMap *stackmap; | 479 StackMap *stackmap; |
| 480 bool (*cb)(Stkframe*, void*); |
480 | 481 |
481 if(gp->stackbase == 0) | 482 if(gp->stackbase == 0) |
482 runtime·throw("stackbase == 0"); | 483 runtime·throw("stackbase == 0"); |
483 cinfo.stk = (byte*)gp->stackguard - StackGuard; | 484 cinfo.stk = (byte*)gp->stackguard - StackGuard; |
484 cinfo.base = (byte*)gp->stackbase + sizeof(Stktop); | 485 cinfo.base = (byte*)gp->stackbase + sizeof(Stktop); |
485 cinfo.frames = 0; | 486 cinfo.frames = 0; |
486 | 487 |
487 // Check that each frame is copyable. As a side effect, | 488 // Check that each frame is copyable. As a side effect, |
488 // count the frames. | 489 // count the frames. |
489 » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff
, checkframecopy, &cinfo, false); | 490 » cb = checkframecopy; |
| 491 » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff
, &cb, &cinfo, false); |
490 if(StackDebug >= 1 && cinfo.frames != -1) | 492 if(StackDebug >= 1 && cinfo.frames != -1) |
491 runtime·printf("copystack: %d copyable frames\n", cinfo.frames); | 493 runtime·printf("copystack: %d copyable frames\n", cinfo.frames); |
492 | 494 |
493 if(cinfo.frames == -1) | 495 if(cinfo.frames == -1) |
494 return -1; | 496 return -1; |
495 | 497 |
496 // Check to make sure all Defers are copyable | 498 // Check to make sure all Defers are copyable |
497 for(d = gp->defer; d != nil; d = d->link) { | 499 for(d = gp->defer; d != nil; d = d->link) { |
498 if(cinfo.stk <= (byte*)d && (byte*)d < cinfo.base) { | 500 if(cinfo.stk <= (byte*)d && (byte*)d < cinfo.base) { |
499 // Defer is on the stack. Its copyableness has | 501 // Defer is on the stack. Its copyableness has |
500 // been established during stack walking. | 502 // been established during stack walking. |
501 // For now, this only happens with the Defer in runtime.
main. | 503 // For now, this only happens with the Defer in runtime.
main. |
502 continue; | 504 continue; |
503 } | 505 } |
504 » » if(d->argp < cinfo.stk || cinfo.base <= d->argp) | 506 » » if((byte*)d->argp < cinfo.stk || cinfo.base <= (byte*)d->argp) |
505 break; // a defer for the next segment | 507 break; // a defer for the next segment |
506 fn = d->fn; | 508 fn = d->fn; |
507 if(fn == nil) // See issue 8047 | 509 if(fn == nil) // See issue 8047 |
508 continue; | 510 continue; |
509 f = runtime·findfunc((uintptr)fn->fn); | 511 f = runtime·findfunc((uintptr)fn->fn); |
510 if(f == nil) { | 512 if(f == nil) { |
511 if(StackDebug >= 1) | 513 if(StackDebug >= 1) |
512 runtime·printf("copystack: no func for deferred
pc %p\n", fn->fn); | 514 runtime·printf("copystack: no func for deferred
pc %p\n", fn->fn); |
513 return -1; | 515 return -1; |
514 } | 516 } |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
659 // Frame is dead. | 661 // Frame is dead. |
660 return true; | 662 return true; |
661 } | 663 } |
662 if(targetpc != f->entry) | 664 if(targetpc != f->entry) |
663 targetpc--; | 665 targetpc--; |
664 pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc); | 666 pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc); |
665 if(pcdata == -1) | 667 if(pcdata == -1) |
666 pcdata = 0; // in prologue | 668 pcdata = 0; // in prologue |
667 | 669 |
668 // adjust local pointers | 670 // adjust local pointers |
669 » if(frame->varp != (byte*)frame->sp) { | 671 » if((byte*)frame->varp != (byte*)frame->sp) { |
670 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); | 672 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); |
671 if(stackmap == nil) | 673 if(stackmap == nil) |
672 runtime·throw("no locals info"); | 674 runtime·throw("no locals info"); |
673 if(stackmap->n <= 0) | 675 if(stackmap->n <= 0) |
674 runtime·throw("locals size info only"); | 676 runtime·throw("locals size info only"); |
675 bv = runtime·stackmapdata(stackmap, pcdata); | 677 bv = runtime·stackmapdata(stackmap, pcdata); |
676 if(StackDebug >= 3) | 678 if(StackDebug >= 3) |
677 runtime·printf(" locals\n"); | 679 runtime·printf(" locals\n"); |
678 adjustpointers((byte**)frame->varp - bv.n / BitsPerPointer, &bv,
adjinfo, f); | 680 adjustpointers((byte**)frame->varp - bv.n / BitsPerPointer, &bv,
adjinfo, f); |
679 } | 681 } |
680 // adjust inargs and outargs | 682 // adjust inargs and outargs |
681 if(frame->arglen != 0) { | 683 if(frame->arglen != 0) { |
682 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); | 684 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); |
683 » » if(stackmap == nil) | 685 » » if(stackmap == nil) { |
| 686 » » » runtime·printf("size %d\n", (int32)frame->arglen); |
684 runtime·throw("no arg info"); | 687 runtime·throw("no arg info"); |
| 688 } |
685 bv = runtime·stackmapdata(stackmap, pcdata); | 689 bv = runtime·stackmapdata(stackmap, pcdata); |
686 if(StackDebug >= 3) | 690 if(StackDebug >= 3) |
687 runtime·printf(" args\n"); | 691 runtime·printf(" args\n"); |
688 adjustpointers((byte**)frame->argp, &bv, adjinfo, nil); | 692 adjustpointers((byte**)frame->argp, &bv, adjinfo, nil); |
689 } | 693 } |
690 return true; | 694 return true; |
691 } | 695 } |
692 | 696 |
693 static void | 697 static void |
694 adjustctxt(G *gp, AdjustInfo *adjinfo) | 698 adjustctxt(G *gp, AdjustInfo *adjinfo) |
(...skipping 13 matching lines...) Expand all Loading... |
708 | 712 |
709 for(dp = &gp->defer, d = *dp; d != nil; dp = &d->link, d = *dp) { | 713 for(dp = &gp->defer, d = *dp; d != nil; dp = &d->link, d = *dp) { |
710 if(adjinfo->oldstk <= (byte*)d && (byte*)d < adjinfo->oldbase) { | 714 if(adjinfo->oldstk <= (byte*)d && (byte*)d < adjinfo->oldbase) { |
711 // The Defer record is on the stack. Its fields will | 715 // The Defer record is on the stack. Its fields will |
712 // get adjusted appropriately. | 716 // get adjusted appropriately. |
713 // This only happens for runtime.main now, but a compile
r | 717 // This only happens for runtime.main now, but a compile
r |
714 // optimization could do more of this. | 718 // optimization could do more of this. |
715 *dp = (Defer*)((byte*)d + adjinfo->delta); | 719 *dp = (Defer*)((byte*)d + adjinfo->delta); |
716 continue; | 720 continue; |
717 } | 721 } |
718 » » if(d->argp < adjinfo->oldstk || adjinfo->oldbase <= d->argp) | 722 » » if((byte*)d->argp < adjinfo->oldstk || adjinfo->oldbase <= (byte
*)d->argp) |
719 break; // a defer for the next segment | 723 break; // a defer for the next segment |
720 fn = d->fn; | 724 fn = d->fn; |
721 if(fn == nil) { | 725 if(fn == nil) { |
722 // Defer of nil function. It will panic when run, and t
here | 726 // Defer of nil function. It will panic when run, and t
here |
723 // aren't any args to adjust. See issue 8047. | 727 // aren't any args to adjust. See issue 8047. |
724 d->argp += adjinfo->delta; | 728 d->argp += adjinfo->delta; |
725 continue; | 729 continue; |
726 } | 730 } |
727 f = runtime·findfunc((uintptr)fn->fn); | 731 f = runtime·findfunc((uintptr)fn->fn); |
728 if(f == nil) | 732 if(f == nil) |
(...skipping 24 matching lines...) Expand all Loading... |
753 { | 757 { |
754 SudoG *s; | 758 SudoG *s; |
755 byte *e; | 759 byte *e; |
756 | 760 |
757 // the data elements pointed to by a SudoG structure | 761 // the data elements pointed to by a SudoG structure |
758 // might be in the stack. | 762 // might be in the stack. |
759 for(s = gp->waiting; s != nil; s = s->waitlink) { | 763 for(s = gp->waiting; s != nil; s = s->waitlink) { |
760 e = s->elem; | 764 e = s->elem; |
761 if(adjinfo->oldstk <= e && e < adjinfo->oldbase) | 765 if(adjinfo->oldstk <= e && e < adjinfo->oldbase) |
762 s->elem = e + adjinfo->delta; | 766 s->elem = e + adjinfo->delta; |
| 767 e = (byte*)s->selectdone; |
| 768 if(adjinfo->oldstk <= e && e < adjinfo->oldbase) |
| 769 s->selectdone = (uint32*)(e + adjinfo->delta); |
763 } | 770 } |
764 } | 771 } |
765 | 772 |
766 // Copies the top stack segment of gp to a new stack segment of a | 773 // Copies the top stack segment of gp to a new stack segment of a |
767 // different size. The top segment must contain nframes frames. | 774 // different size. The top segment must contain nframes frames. |
768 static void | 775 static void |
769 copystack(G *gp, uintptr nframes, uintptr newsize) | 776 copystack(G *gp, uintptr nframes, uintptr newsize) |
770 { | 777 { |
771 byte *oldstk, *oldbase, *newstk, *newbase; | 778 byte *oldstk, *oldbase, *newstk, *newbase; |
772 uintptr oldsize, used; | 779 uintptr oldsize, used; |
773 AdjustInfo adjinfo; | 780 AdjustInfo adjinfo; |
774 Stktop *oldtop, *newtop; | 781 Stktop *oldtop, *newtop; |
775 uint32 oldstatus; | 782 uint32 oldstatus; |
| 783 bool (*cb)(Stkframe*, void*); |
776 | 784 |
777 if(gp->syscallstack != 0) | 785 if(gp->syscallstack != 0) |
778 runtime·throw("can't handle stack copy in syscall yet"); | 786 runtime·throw("can't handle stack copy in syscall yet"); |
779 oldstk = (byte*)gp->stackguard - StackGuard; | 787 oldstk = (byte*)gp->stackguard - StackGuard; |
780 if(gp->stackbase == 0) | 788 if(gp->stackbase == 0) |
781 runtime·throw("nil stackbase"); | 789 runtime·throw("nil stackbase"); |
782 oldbase = (byte*)gp->stackbase + sizeof(Stktop); | 790 oldbase = (byte*)gp->stackbase + sizeof(Stktop); |
783 oldsize = oldbase - oldstk; | 791 oldsize = oldbase - oldstk; |
784 used = oldbase - (byte*)gp->sched.sp; | 792 used = oldbase - (byte*)gp->sched.sp; |
785 oldtop = (Stktop*)gp->stackbase; | 793 oldtop = (Stktop*)gp->stackbase; |
786 | 794 |
787 // allocate new stack | 795 // allocate new stack |
788 newstk = runtime·stackalloc(gp, newsize); | 796 newstk = runtime·stackalloc(gp, newsize); |
789 newbase = newstk + newsize; | 797 newbase = newstk + newsize; |
790 newtop = (Stktop*)(newbase - sizeof(Stktop)); | 798 newtop = (Stktop*)(newbase - sizeof(Stktop)); |
791 | 799 |
792 if(StackDebug >= 1) | 800 if(StackDebug >= 1) |
793 runtime·printf("copystack gp=%p [%p %p]/%d -> [%p %p]/%d\n", gp,
oldstk, oldbase, (int32)oldsize, newstk, newbase, (int32)newsize); | 801 runtime·printf("copystack gp=%p [%p %p]/%d -> [%p %p]/%d\n", gp,
oldstk, oldbase, (int32)oldsize, newstk, newbase, (int32)newsize); |
794 USED(oldsize); | 802 USED(oldsize); |
795 ········ | 803 ········ |
796 // adjust pointers in the to-be-copied frames | 804 // adjust pointers in the to-be-copied frames |
797 adjinfo.oldstk = oldstk; | 805 adjinfo.oldstk = oldstk; |
798 adjinfo.oldbase = oldbase; | 806 adjinfo.oldbase = oldbase; |
799 adjinfo.delta = newbase - oldbase; | 807 adjinfo.delta = newbase - oldbase; |
800 » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, a
djustframe, &adjinfo, false); | 808 » cb = adjustframe; |
| 809 » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, &
cb, &adjinfo, false); |
801 ········ | 810 ········ |
802 // adjust other miscellaneous things that have pointers into stacks. | 811 // adjust other miscellaneous things that have pointers into stacks. |
803 adjustctxt(gp, &adjinfo); | 812 adjustctxt(gp, &adjinfo); |
804 adjustdefers(gp, &adjinfo); | 813 adjustdefers(gp, &adjinfo); |
805 adjustsudogs(gp, &adjinfo); | 814 adjustsudogs(gp, &adjinfo); |
806 ········ | 815 ········ |
807 // copy the stack (including Stktop) to the new location | 816 // copy the stack (including Stktop) to the new location |
808 runtime·memmove(newbase - used, oldbase - used, used); | 817 runtime·memmove(newbase - used, oldbase - used, used); |
809 oldstatus = runtime·readgstatus(gp); | 818 oldstatus = runtime·readgstatus(gp); |
810 oldstatus &= ~Gscan; | 819 oldstatus &= ~Gscan; |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1106 if(gp->m != nil && gp->m->libcallsp != 0) | 1115 if(gp->m != nil && gp->m->libcallsp != 0) |
1107 return; | 1116 return; |
1108 #endif | 1117 #endif |
1109 if(StackDebug > 0) | 1118 if(StackDebug > 0) |
1110 runtime·printf("shrinking stack %D->%D\n", (uint64)oldsize, (uin
t64)newsize); | 1119 runtime·printf("shrinking stack %D->%D\n", (uint64)oldsize, (uin
t64)newsize); |
1111 nframes = copyabletopsegment(gp); | 1120 nframes = copyabletopsegment(gp); |
1112 if(nframes == -1) | 1121 if(nframes == -1) |
1113 return; | 1122 return; |
1114 copystack(gp, nframes, newsize); | 1123 copystack(gp, nframes, newsize); |
1115 } | 1124 } |
LEFT | RIGHT |