]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.garbage] all: merge default (f38460037b72) into dev.garbage
authorRuss Cox <rsc@golang.org>
Fri, 14 Nov 2014 16:37:54 +0000 (11:37 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 14 Nov 2014 16:37:54 +0000 (11:37 -0500)
This is the revision that dev.cc is branched from.

LGTM=austin
R=austin
CC=golang-codereviews
https://golang.org/cl/169590043

13 files changed:
1  2 
lib/codereview/codereview.py
src/cmd/dist/build.c
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/asm_amd64p32.s
src/runtime/asm_arm.s
src/runtime/heapdump.c
src/runtime/malloc.go
src/runtime/mgc0.c
src/runtime/proc.c
src/runtime/runtime.h
src/runtime/stack.c
src/runtime/stubs.go

index 3aac8f43c97652c9d32ac8905b9e3584338b81ea,416702c634a895b48f164ff8ef9fabca438b3450..0c9b27a318ea9401bfd175f11abc46fc30da11a5
@@@ -1631,7 -1631,7 +1631,7 @@@ def clpatch_or_undo(ui, repo, clname, o
        try:
                cmd = subprocess.Popen(argv, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, close_fds=sys.platform != "win32")
        except:
-               return "hgapplydiff: " + ExceptionDetail() + "\nInstall hgapplydiff with:\n$ go get code.google.com/p/go.codereview/cmd/hgapplydiff\n"
+               return "hgapplydiff: " + ExceptionDetail() + "\nInstall hgapplydiff with:\n$ go get golang.org/x/codereview/cmd/hgapplydiff\n"
  
        out, err = cmd.communicate(patch)
        if cmd.returncode != 0 and not opts["ignore_hgapplydiff_failure"]:
@@@ -2024,13 -2024,13 +2024,13 @@@ def submit(ui, repo, *pats, **opts)
        # push to remote; if it fails for any reason, roll back
        try:
                new_heads = len(hg_heads(ui, repo).split())
 -              if old_heads != new_heads and not (old_heads == 0 and new_heads == 1):
 +              if cl.desc.find("create new branch") < 0 and old_heads != new_heads and not (old_heads == 0 and new_heads == 1):
                        # Created new head, so we weren't up to date.
                        need_sync()
  
                # Push changes to remote.  If it works, we're committed.  If not, roll back.
                try:
 -                      if hg_push(ui, repo):
 +                      if hg_push(ui, repo, new_branch=cl.desc.find("create new branch")>=0):
                                raise hg_util.Abort("push error")
                except hg_error.Abort, e:
                        if e.message.find("push creates new heads") >= 0:
@@@ -3451,6 -3451,7 +3451,7 @@@ class FakeMercurialUI(object)
        def __init__(self):
                self.quiet = True
                self.output = ''
+               self.debugflag = False
        
        def write(self, *args, **opts):
                self.output += ' '.join(args)
@@@ -3603,17 -3604,11 +3604,17 @@@ class MercurialVCS(VersionControlSystem
                        if use_hg_shell:
                                base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], silent_ok=True)
                        else:
 -                              base_content = str(self.repo[base_rev][oldrelpath].data())
 +                                try:
 +                                        base_content = str(self.repo[base_rev][oldrelpath].data())
 +                                except Exception:
 +                                        pass
                        is_binary = "\0" in base_content  # Mercurial's heuristic
                if status != "R":
 -                      new_content = open(relpath, "rb").read()
 -                      is_binary = is_binary or "\0" in new_content
 +                        try:
 +                                new_content = open(relpath, "rb").read()
 +                                is_binary = is_binary or "\0" in new_content
 +                        except Exception:
 +                                pass
                if is_binary and base_content and use_hg_shell:
                        # Fetch again without converting newlines
                        base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
diff --combined src/cmd/dist/build.c
index 8fd2e998a44d4a7990a2b2542f4c8c131dfd4d87,d638ae4ebedb407714307f3b5f4bc04225f7b42d..9c81dd8b22443f643a23fb873968af3dfe5dfdb4
@@@ -39,7 -39,7 +39,7 @@@ static void dopack(char*, char*, char**
  static char *findgoversion(void);
  
  // The known architecture letters.
 -static char *gochars = "5668";
 +static char *gochars = "566899";
  
  // The known architectures.
  static char *okgoarch[] = {
@@@ -48,8 -48,6 +48,8 @@@
        "amd64",
        "amd64p32",
        "386",
 +      "power64",
 +      "power64le",
  };
  
  // The known operating systems.
@@@ -346,7 -344,6 +346,7 @@@ static char *oldtool[] = 
        "5a", "5c", "5g", "5l",
        "6a", "6c", "6g", "6l",
        "8a", "8c", "8g", "8l",
 +      "9a", "9c", "9g", "9l",
        "6cov",
        "6nm",
        "6prof",
@@@ -524,7 -521,6 +524,7 @@@ static struct 
                "anames5.c",
                "anames6.c",
                "anames8.c",
 +              "anames9.c",
        }},
        {"cmd/cc", {
                "-pgen.c",
                "../cc/pswt.c",
                "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
        }},
 +      {"cmd/9c", {
 +              "../cc/pgen.c",
 +              "../cc/pswt.c",
 +              "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
 +      }},
        {"cmd/5g", {
                "../gc/cplx.c",
                "../gc/pgen.c",
                "../gc/popt.h",
                "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
        }},
 +      {"cmd/9g", {
 +              "../gc/cplx.c",
 +              "../gc/pgen.c",
 +              "../gc/plive.c",
 +              "../gc/popt.c",
 +              "../gc/popt.h",
 +              "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
 +      }},
        {"cmd/5l", {
                "../ld/*",
        }},
        {"cmd/8l", {
                "../ld/*",
        }},
 +      {"cmd/9l", {
 +              "../ld/*",
 +      }},
        {"cmd/go", {
                "zdefaultcc.go",
        }},
@@@ -638,7 -618,6 +638,7 @@@ static struct 
        {"anames5.c", mkanames},
        {"anames6.c", mkanames},
        {"anames8.c", mkanames},
 +      {"anames9.c", mkanames},
        {"zasm_", mkzasm},
        {"zdefaultcc.go", mkzdefaultcc},
        {"zsys_", mkzsys},
@@@ -691,13 -670,6 +691,6 @@@ install(char *dir
        bpathf(&final_path, "%s/src/%s", goroot_final, dir);
        name = lastelem(dir);
  
-       // For misc/prof, copy into the tool directory and we're done.
-       if(hasprefix(dir, "misc/")) {
-               copyfile(bpathf(&b, "%s/%s", tooldir, name),
-                       bpathf(&b1, "%s/misc/%s", goroot, name), 1);
-               goto out;
-       }
        // set up gcc command line on first run.
        if(gccargs.len == 0) {
                bprintf(&b, "%s %s", defaultcc, defaultcflags);
@@@ -1184,26 -1156,12 +1177,26 @@@ shouldbuild(char *file, char *dir
        
        // Check file name for GOOS or GOARCH.
        name = lastelem(file);
 -      for(i=0; i<nelem(okgoos); i++)
 -              if(contains(name, okgoos[i]) && !streq(okgoos[i], goos))
 +      for(i=0; i<nelem(okgoos); i++) {
 +              if(streq(okgoos[i], goos))
 +                      continue;
 +              p = xstrstr(name, okgoos[i]);
 +              if(p == nil)
 +                      continue;
 +              p += xstrlen(okgoos[i]);
 +              if(*p == '.' || *p == '_' || *p == '\0')
                        return 0;
 -      for(i=0; i<nelem(okgoarch); i++)
 -              if(contains(name, okgoarch[i]) && !streq(okgoarch[i], goarch))
 +      }
 +      for(i=0; i<nelem(okgoarch); i++) {
 +              if(streq(okgoarch[i], goarch))
 +                      continue;
 +              p = xstrstr(name, okgoarch[i]);
 +              if(p == nil)
 +                      continue;
 +              p += xstrlen(okgoarch[i]);
 +              if(*p == '.' || *p == '_' || *p == '\0')
                        return 0;
 +      }
  
        // Omit test files.
        if(contains(name, "_test"))
@@@ -1328,8 -1286,6 +1321,6 @@@ static char *buildorder[] = 
        "libbio",
        "liblink",
  
-       "misc/pprof",
        "cmd/cc",  // must be before c
        "cmd/gc",  // must be before g
        "cmd/%sl",  // must be before a, c, g
@@@ -1402,10 -1358,6 +1393,10 @@@ static char *cleantab[] = 
        "cmd/8c",
        "cmd/8g",
        "cmd/8l",
 +      "cmd/9a",
 +      "cmd/9c",
 +      "cmd/9g",
 +      "cmd/9l",
        "cmd/cc",
        "cmd/gc",
        "cmd/go",       
diff --combined src/runtime/asm_386.s
index d456e6bca4063a4409fface61ea8a5467fccc02a,b4b81d7397eb03f169aa527eab2d639cb6deb20a..501e64b094393e662251e5666744feb68fa500fd
@@@ -486,11 -486,11 +486,11 @@@ TEXT runtime·cas64(SB), NOSPLIT, $0-2
        MOVL    new_hi+16(FP), CX
        LOCK
        CMPXCHG8B       0(BP)
 -      JNZ     cas64_fail
 +      JNZ     fail
        MOVL    $1, AX
        MOVB    AX, ret+20(FP)
        RET
 -cas64_fail:
 +fail:
        MOVL    $0, AX
        MOVB    AX, ret+20(FP)
        RET
  //            return 1;
  //    }else
  //            return 0;
 -TEXT runtime·casp(SB), NOSPLIT, $0-13
 +TEXT runtime·casp1(SB), NOSPLIT, $0-13
        MOVL    ptr+0(FP), BX
        MOVL    old+4(FP), AX
        MOVL    new+8(FP), CX
@@@ -537,7 -537,7 +537,7 @@@ TEXT runtime·xchg(SB), NOSPLIT, $0-1
        MOVL    AX, ret+8(FP)
        RET
  
 -TEXT runtime·xchgp(SB), NOSPLIT, $0-12
 +TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
        MOVL    ptr+0(FP), BX
        MOVL    new+4(FP), AX
        XCHGL   AX, 0(BX)
@@@ -555,7 -555,7 +555,7 @@@ again
        JNZ     again
        RET
  
 -TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
 +TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
        MOVL    ptr+0(FP), BX
        MOVL    val+4(FP), AX
        XCHGL   AX, 0(BX)
@@@ -1356,29 -1356,29 +1356,29 @@@ TEXT strings·IndexByte(SB),NOSPLIT,$
  //   AX = 1/0/-1
  TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
        CMPL    SI, DI
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        CMPL    BX, DX
        MOVL    DX, BP
        CMOVLLT BX, BP // BP = min(alen, blen)
        CMPL    BP, $4
 -      JB      cmp_small
 +      JB      small
        TESTL   $0x4000000, runtime·cpuid_edx(SB) // check for sse2
 -      JE      cmp_mediumloop
 -cmp_largeloop:
 +      JE      mediumloop
 +largeloop:
        CMPL    BP, $16
 -      JB      cmp_mediumloop
 +      JB      mediumloop
        MOVOU   (SI), X0
        MOVOU   (DI), X1
        PCMPEQB X0, X1
        PMOVMSKB X1, AX
        XORL    $0xffff, AX     // convert EQ to NE
 -      JNE     cmp_diff16      // branch if at least one byte is not equal
 +      JNE     diff16  // branch if at least one byte is not equal
        ADDL    $16, SI
        ADDL    $16, DI
        SUBL    $16, BP
 -      JMP     cmp_largeloop
 +      JMP     largeloop
  
 -cmp_diff16:
 +diff16:
        BSFL    AX, BX  // index of first byte that differs
        XORL    AX, AX
        MOVB    (SI)(BX*1), CX
        LEAL    -1(AX*2), AX    // convert 1/0 to +1/-1
        RET
  
 -cmp_mediumloop:
 +mediumloop:
        CMPL    BP, $4
 -      JBE     cmp_0through4
 +      JBE     _0through4
        MOVL    (SI), AX
        MOVL    (DI), CX
        CMPL    AX, CX
 -      JNE     cmp_diff4
 +      JNE     diff4
        ADDL    $4, SI
        ADDL    $4, DI
        SUBL    $4, BP
 -      JMP     cmp_mediumloop
 +      JMP     mediumloop
  
 -cmp_0through4:
 +_0through4:
        MOVL    -4(SI)(BP*1), AX
        MOVL    -4(DI)(BP*1), CX
        CMPL    AX, CX
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
 -cmp_diff4:
 +diff4:
        BSWAPL  AX      // reverse order of bytes
        BSWAPL  CX
        XORL    AX, CX  // find bit differences
        RET
  
        // 0-3 bytes in common
 -cmp_small:
 +small:
        LEAL    (BP*8), CX
        NEGL    CX
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
        // load si
        CMPB    SI, $0xfc
 -      JA      cmp_si_high
 +      JA      si_high
        MOVL    (SI), SI
 -      JMP     cmp_si_finish
 -cmp_si_high:
 +      JMP     si_finish
 +si_high:
        MOVL    -4(SI)(BP*1), SI
        SHRL    CX, SI
 -cmp_si_finish:
 +si_finish:
        SHLL    CX, SI
  
        // same for di
        CMPB    DI, $0xfc
 -      JA      cmp_di_high
 +      JA      di_high
        MOVL    (DI), DI
 -      JMP     cmp_di_finish
 -cmp_di_high:
 +      JMP     di_finish
 +di_high:
        MOVL    -4(DI)(BP*1), DI
        SHRL    CX, DI
 -cmp_di_finish:
 +di_finish:
        SHLL    CX, DI
  
        BSWAPL  SI      // reverse order of bytes
        BSWAPL  DI
        XORL    SI, DI  // find bit differences
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        BSRL    DI, CX  // index of highest bit difference
        SHRL    CX, SI  // move a's bit to bottom
        ANDL    $1, SI  // mask bit
  
        // all the bytes in common are the same, so we just need
        // to compare the lengths.
 -cmp_allsame:
 +allsame:
        XORL    AX, AX
        XORL    CX, CX
        CMPL    BX, DX
@@@ -2284,3 -2284,9 +2284,9 @@@ TEXT _cgo_topofstack(SB),NOSPLIT,$
        MOVL    m_curg(AX), AX
        MOVL    (g_stack+stack_hi)(AX), AX
        RET
+ // The top-most function running on a goroutine
+ // returns to goexit+PCQuantum.
+ TEXT runtime·goexit(SB),NOSPLIT,$0-0
+       BYTE    $0x90   // NOP
+       CALL    runtime·goexit1(SB)    // does not return
diff --combined src/runtime/asm_amd64.s
index 5d176575c3a3f58c91f9aff2b8521fa2e841e86c,39d7c78f23346f9ed87259f324811d4c8b6538ba..1aa2d71a80c3615b839c8391822cb7ce35600712
@@@ -461,11 -461,11 +461,11 @@@ TEXT runtime·cas64(SB), NOSPLIT, $0-2
        MOVQ    new+16(FP), CX
        LOCK
        CMPXCHGQ        CX, 0(BX)
 -      JNZ     cas64_fail
 +      JNZ     fail
        MOVL    $1, AX
        MOVB    AX, ret+24(FP)
        RET
 -cas64_fail:
 +fail:
        MOVL    $0, AX
        MOVB    AX, ret+24(FP)
        RET
@@@ -489,7 -489,7 +489,7 @@@ TEXT runtime·atomicstoreuintptr(SB), N
  //            return 1;
  //    } else
  //            return 0;
 -TEXT runtime·casp(SB), NOSPLIT, $0-25
 +TEXT runtime·casp1(SB), NOSPLIT, $0-25
        MOVQ    ptr+0(FP), BX
        MOVQ    old+8(FP), AX
        MOVQ    new+16(FP), CX
@@@ -541,7 -541,7 +541,7 @@@ TEXT runtime·xchg64(SB), NOSPLIT, $0-2
        MOVQ    AX, ret+16(FP)
        RET
  
 -TEXT runtime·xchgp(SB), NOSPLIT, $0-24
 +TEXT runtime·xchgp1(SB), NOSPLIT, $0-24
        MOVQ    ptr+0(FP), BX
        MOVQ    new+8(FP), AX
        XCHGQ   AX, 0(BX)
@@@ -559,7 -559,7 +559,7 @@@ again
        JNZ     again
        RET
  
 -TEXT runtime·atomicstorep(SB), NOSPLIT, $0-16
 +TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
        MOVQ    ptr+0(FP), BX
        MOVQ    val+8(FP), AX
        XCHGQ   AX, 0(BX)
@@@ -890,24 -890,24 +890,24 @@@ TEXT runtime·aeshashbody(SB),NOSPLIT,$
        MOVO    runtime·aeskeysched+0(SB), X2
        MOVO    runtime·aeskeysched+16(SB), X3
        CMPQ    CX, $16
 -      JB      aessmall
 -aesloop:
 +      JB      small
 +loop:
        CMPQ    CX, $16
 -      JBE     aesloopend
 +      JBE     loopend
        MOVOU   (AX), X1
        AESENC  X2, X0
        AESENC  X1, X0
        SUBQ    $16, CX
        ADDQ    $16, AX
 -      JMP     aesloop
 +      JMP     loop
  // 1-16 bytes remaining
 -aesloopend:
 +loopend:
        // This load may overlap with the previous load above.
        // We'll hash some bytes twice, but that's ok.
        MOVOU   -16(AX)(CX*1), X1
        JMP     partial
  // 0-15 bytes
 -aessmall:
 +small:
        TESTQ   CX, CX
        JE      finalize        // 0 bytes
  
@@@ -1050,18 -1050,18 +1050,18 @@@ TEXT runtime·eqstring(SB),NOSPLIT,$0-3
        MOVQ    s1len+8(FP), AX
        MOVQ    s2len+24(FP), BX
        CMPQ    AX, BX
 -      JNE     different
 +      JNE     noteq
        MOVQ    s1str+0(FP), SI
        MOVQ    s2str+16(FP), DI
        CMPQ    SI, DI
 -      JEQ     same
 +      JEQ     eq
        CALL    runtime·memeqbody(SB)
        MOVB    AX, v+32(FP)
        RET
 -same:
 +eq:
        MOVB    $1, v+32(FP)
        RET
 -different:
 +noteq:
        MOVB    $0, v+32(FP)
        RET
  
@@@ -1184,29 -1184,29 +1184,29 @@@ TEXT runtime·cmpbytes(SB),NOSPLIT,$0-5
  //   AX = 1/0/-1
  TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
        CMPQ    SI, DI
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        CMPQ    BX, DX
        MOVQ    DX, BP
        CMOVQLT BX, BP // BP = min(alen, blen) = # of bytes to compare
        CMPQ    BP, $8
 -      JB      cmp_small
 +      JB      small
  
 -cmp_loop:
 +loop:
        CMPQ    BP, $16
 -      JBE     cmp_0through16
 +      JBE     _0through16
        MOVOU   (SI), X0
        MOVOU   (DI), X1
        PCMPEQB X0, X1
        PMOVMSKB X1, AX
        XORQ    $0xffff, AX     // convert EQ to NE
 -      JNE     cmp_diff16      // branch if at least one byte is not equal
 +      JNE     diff16  // branch if at least one byte is not equal
        ADDQ    $16, SI
        ADDQ    $16, DI
        SUBQ    $16, BP
 -      JMP     cmp_loop
 +      JMP     loop
        
        // AX = bit mask of differences
 -cmp_diff16:
 +diff16:
        BSFQ    AX, BX  // index of first byte that differs
        XORQ    AX, AX
        MOVB    (SI)(BX*1), CX
        RET
  
        // 0 through 16 bytes left, alen>=8, blen>=8
 -cmp_0through16:
 +_0through16:
        CMPQ    BP, $8
 -      JBE     cmp_0through8
 +      JBE     _0through8
        MOVQ    (SI), AX
        MOVQ    (DI), CX
        CMPQ    AX, CX
 -      JNE     cmp_diff8
 -cmp_0through8:
 +      JNE     diff8
 +_0through8:
        MOVQ    -8(SI)(BP*1), AX
        MOVQ    -8(DI)(BP*1), CX
        CMPQ    AX, CX
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
        // AX and CX contain parts of a and b that differ.
 -cmp_diff8:
 +diff8:
        BSWAPQ  AX      // reverse order of bytes
        BSWAPQ  CX
        XORQ    AX, CX
        RET
  
        // 0-7 bytes in common
 -cmp_small:
 +small:
        LEAQ    (BP*8), CX      // bytes left -> bits left
        NEGQ    CX              //  - bits lift (== 64 - bits left mod 64)
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
        // load bytes of a into high bytes of AX
        CMPB    SI, $0xf8
 -      JA      cmp_si_high
 +      JA      si_high
        MOVQ    (SI), SI
 -      JMP     cmp_si_finish
 -cmp_si_high:
 +      JMP     si_finish
 +si_high:
        MOVQ    -8(SI)(BP*1), SI
        SHRQ    CX, SI
 -cmp_si_finish:
 +si_finish:
        SHLQ    CX, SI
  
        // load bytes of b in to high bytes of BX
        CMPB    DI, $0xf8
 -      JA      cmp_di_high
 +      JA      di_high
        MOVQ    (DI), DI
 -      JMP     cmp_di_finish
 -cmp_di_high:
 +      JMP     di_finish
 +di_high:
        MOVQ    -8(DI)(BP*1), DI
        SHRQ    CX, DI
 -cmp_di_finish:
 +di_finish:
        SHLQ    CX, DI
  
        BSWAPQ  SI      // reverse order of bytes
        BSWAPQ  DI
        XORQ    SI, DI  // find bit differences
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        BSRQ    DI, CX  // index of highest bit difference
        SHRQ    CX, SI  // move a's bit to bottom
        ANDQ    $1, SI  // mask bit
        LEAQ    -1(SI*2), AX // 1/0 => +1/-1
        RET
  
 -cmp_allsame:
 +allsame:
        XORQ    AX, AX
        XORQ    CX, CX
        CMPQ    BX, DX
@@@ -1313,7 -1313,7 +1313,7 @@@ TEXT runtime·indexbytebody(SB),NOSPLIT
        MOVQ SI, DI
  
        CMPQ BX, $16
 -      JLT indexbyte_small
 +      JLT small
  
        // round up to first 16-byte boundary
        TESTQ $15, SI
@@@ -1371,7 -1371,7 +1371,7 @@@ failure
        RET
  
  // handle for lengths < 16
 -indexbyte_small:
 +small:
        MOVQ BX, CX
        REPN; SCASB
        JZ success
@@@ -2229,3 -2229,9 +2229,9 @@@ TEXT _cgo_topofstack(SB),NOSPLIT,$
        MOVQ    m_curg(AX), AX
        MOVQ    (g_stack+stack_hi)(AX), AX
        RET
+ // The top-most function running on a goroutine
+ // returns to goexit+PCQuantum.
+ TEXT runtime·goexit(SB),NOSPLIT,$0-0
+       BYTE    $0x90   // NOP
+       CALL    runtime·goexit1(SB)    // does not return
index 2b2155753e9a414b20ce6d3e5caae67ba3e2fca2,a1116b5d471ed35a44bd7a7a5c6d5c6d6816fc18..153564b14ea9eba97e74df106059099ed700f60e
@@@ -444,11 -444,11 +444,11 @@@ TEXT runtime·cas64(SB), NOSPLIT, $0-2
        MOVQ    new+16(FP), CX
        LOCK
        CMPXCHGQ        CX, 0(BX)
 -      JNZ     cas64_fail
 +      JNZ     fail
        MOVL    $1, AX
        MOVB    AX, ret+24(FP)
        RET
 -cas64_fail:
 +fail:
        MOVL    $0, AX
        MOVB    AX, ret+24(FP)
        RET
  //            return 1;
  //    } else
  //            return 0;
 -TEXT runtime·casp(SB), NOSPLIT, $0-17
 +TEXT runtime·casp1(SB), NOSPLIT, $0-17
        MOVL    ptr+0(FP), BX
        MOVL    old+4(FP), AX
        MOVL    new+8(FP), CX
@@@ -512,7 -512,7 +512,7 @@@ TEXT runtime·xchg64(SB), NOSPLIT, $0-2
        MOVQ    AX, ret+16(FP)
        RET
  
 -TEXT runtime·xchgp(SB), NOSPLIT, $0-12
 +TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
        MOVL    ptr+0(FP), BX
        MOVL    new+4(FP), AX
        XCHGL   AX, 0(BX)
@@@ -530,7 -530,7 +530,7 @@@ again
        JNZ     again
        RET
  
 -TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
 +TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
        MOVL    ptr+0(FP), BX
        MOVL    val+4(FP), AX
        XCHGL   AX, 0(BX)
@@@ -834,29 -834,29 +834,29 @@@ TEXT runtime·cmpbytes(SB),NOSPLIT,$0-2
  //   AX = 1/0/-1
  TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
        CMPQ    SI, DI
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        CMPQ    BX, DX
        MOVQ    DX, R8
        CMOVQLT BX, R8 // R8 = min(alen, blen) = # of bytes to compare
        CMPQ    R8, $8
 -      JB      cmp_small
 +      JB      small
  
 -cmp_loop:
 +loop:
        CMPQ    R8, $16
 -      JBE     cmp_0through16
 +      JBE     _0through16
        MOVOU   (SI), X0
        MOVOU   (DI), X1
        PCMPEQB X0, X1
        PMOVMSKB X1, AX
        XORQ    $0xffff, AX     // convert EQ to NE
 -      JNE     cmp_diff16      // branch if at least one byte is not equal
 +      JNE     diff16  // branch if at least one byte is not equal
        ADDQ    $16, SI
        ADDQ    $16, DI
        SUBQ    $16, R8
 -      JMP     cmp_loop
 +      JMP     loop
        
        // AX = bit mask of differences
 -cmp_diff16:
 +diff16:
        BSFQ    AX, BX  // index of first byte that differs
        XORQ    AX, AX
        ADDQ    BX, SI
        RET
  
        // 0 through 16 bytes left, alen>=8, blen>=8
 -cmp_0through16:
 +_0through16:
        CMPQ    R8, $8
 -      JBE     cmp_0through8
 +      JBE     _0through8
        MOVQ    (SI), AX
        MOVQ    (DI), CX
        CMPQ    AX, CX
 -      JNE     cmp_diff8
 -cmp_0through8:
 +      JNE     diff8
 +_0through8:
        ADDQ    R8, SI
        ADDQ    R8, DI
        MOVQ    -8(SI), AX
        MOVQ    -8(DI), CX
        CMPQ    AX, CX
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
        // AX and CX contain parts of a and b that differ.
 -cmp_diff8:
 +diff8:
        BSWAPQ  AX      // reverse order of bytes
        BSWAPQ  CX
        XORQ    AX, CX
        RET
  
        // 0-7 bytes in common
 -cmp_small:
 +small:
        LEAQ    (R8*8), CX      // bytes left -> bits left
        NEGQ    CX              //  - bits lift (== 64 - bits left mod 64)
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
        // load bytes of a into high bytes of AX
        CMPB    SI, $0xf8
 -      JA      cmp_si_high
 +      JA      si_high
        MOVQ    (SI), SI
 -      JMP     cmp_si_finish
 -cmp_si_high:
 +      JMP     si_finish
 +si_high:
        ADDQ    R8, SI
        MOVQ    -8(SI), SI
        SHRQ    CX, SI
 -cmp_si_finish:
 +si_finish:
        SHLQ    CX, SI
  
        // load bytes of b in to high bytes of BX
        CMPB    DI, $0xf8
 -      JA      cmp_di_high
 +      JA      di_high
        MOVQ    (DI), DI
 -      JMP     cmp_di_finish
 -cmp_di_high:
 +      JMP     di_finish
 +di_high:
        ADDQ    R8, DI
        MOVQ    -8(DI), DI
        SHRQ    CX, DI
 -cmp_di_finish:
 +di_finish:
        SHLQ    CX, DI
  
        BSWAPQ  SI      // reverse order of bytes
        BSWAPQ  DI
        XORQ    SI, DI  // find bit differences
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        BSRQ    DI, CX  // index of highest bit difference
        SHRQ    CX, SI  // move a's bit to bottom
        ANDQ    $1, SI  // mask bit
        LEAQ    -1(SI*2), AX // 1/0 => +1/-1
        RET
  
 -cmp_allsame:
 +allsame:
        XORQ    AX, AX
        XORQ    CX, CX
        CMPQ    BX, DX
@@@ -969,7 -969,7 +969,7 @@@ TEXT runtime·indexbytebody(SB),NOSPLIT
        MOVL SI, DI
  
        CMPL BX, $16
 -      JLT indexbyte_small
 +      JLT small
  
        // round up to first 16-byte boundary
        TESTL $15, SI
@@@ -1027,7 -1027,7 +1027,7 @@@ failure
        RET
  
  // handle for lengths < 16
 -indexbyte_small:
 +small:
        MOVL BX, CX
        REPN; SCASB
        JZ success
@@@ -1079,3 -1079,9 +1079,9 @@@ TEXT runtime·fastrand1(SB), NOSPLIT, $
  TEXT runtime·return0(SB), NOSPLIT, $0
        MOVL    $0, AX
        RET
+ // The top-most function running on a goroutine
+ // returns to goexit+PCQuantum.
+ TEXT runtime·goexit(SB),NOSPLIT,$0-0
+       BYTE    $0x90   // NOP
+       CALL    runtime·goexit1(SB)    // does not return
diff --combined src/runtime/asm_arm.s
index 9a58fdc51e25a1d4e9853c6d0a47f68fd6933cd1,0f3b5eeb8bd338d7087c4d969367443ea57a3670..58aebf3884e74baee3c44f309233309ca859b894
@@@ -492,7 -492,7 +492,7 @@@ TEXT asmcgocall<>(SB),NOSPLIT,$0-
        MOVW    g_m(g), R8
        MOVW    m_g0(R8), R3
        CMP     R3, g
 -      BEQ     asmcgocall_g0
 +      BEQ     g0
        BL      gosave<>(SB)
        MOVW    R0, R5
        MOVW    R3, R0
        MOVW    (g_sched+gobuf_sp)(g), R13
  
        // Now on a scheduling stack (a pthread-created stack).
 -asmcgocall_g0:
 +g0:
        SUB     $24, R13
        BIC     $0x7, R13       // alignment for gcc ABI
        MOVW    R4, 20(R13) // save old g
@@@ -751,13 -751,13 +751,13 @@@ TEXT runtime·memeq(SB),NOSPLIT,$-4-1
        ADD     R1, R3, R6
        MOVW    $1, R0
        MOVB    R0, ret+12(FP)
 -_next2:
 +loop:
        CMP     R1, R6
        RET.EQ
        MOVBU.P 1(R1), R4
        MOVBU.P 1(R2), R5
        CMP     R4, R5
 -      BEQ     _next2
 +      BEQ     loop
  
        MOVW    $0, R0
        MOVB    R0, ret+12(FP)
@@@ -780,13 -780,13 +780,13 @@@ TEXT runtime·eqstring(SB),NOSPLIT,$-4-
        CMP     R2, R3
        RET.EQ
        ADD     R2, R0, R6
 -_eqnext:
 +loop:
        CMP     R2, R6
        RET.EQ
        MOVBU.P 1(R2), R4
        MOVBU.P 1(R3), R5
        CMP     R4, R5
 -      BEQ     _eqnext
 +      BEQ     loop
        MOVB    R7, v+16(FP)
        RET
  
@@@ -801,26 -801,26 +801,26 @@@ TEXT bytes·Equal(SB),NOSPLIT,$
        MOVW    b_len+16(FP), R3
        
        CMP     R1, R3          // unequal lengths are not equal
 -      B.NE    _notequal
 +      B.NE    notequal
  
        MOVW    a+0(FP), R0
        MOVW    b+12(FP), R2
        ADD     R0, R1          // end
  
 -_byteseq_next:
 +loop:
        CMP     R0, R1
 -      B.EQ    _equal          // reached the end
 +      B.EQ    equal           // reached the end
        MOVBU.P 1(R0), R4
        MOVBU.P 1(R2), R5
        CMP     R4, R5
 -      B.EQ    _byteseq_next
 +      B.EQ    loop
  
 -_notequal:
 +notequal:
        MOVW    $0, R0
        MOVBU   R0, ret+24(FP)
        RET
  
 -_equal:
 +equal:
        MOVW    $1, R0
        MOVBU   R0, ret+24(FP)
        RET
@@@ -1320,3 -1320,9 +1320,9 @@@ TEXT _cgo_topofstack(SB),NOSPLIT,$
        MOVW    saveG-8(SP), g
        MOVW    saveR11-4(SP), R11
        RET
+ // The top-most function running on a goroutine
+ // returns to goexit+PCQuantum.
+ TEXT runtime·goexit(SB),NOSPLIT,$-4-0
+       MOVW    R0, R0  // NOP
+       BL      runtime·goexit1(SB)    // does not return
diff --combined src/runtime/heapdump.c
index 5ac37803bb5ccb55d3b64fbaeccdc6cdbfc78050,eddbc1d1c943bafe6b8283f9387e893135040ec8..da14f2d2416045dd90b12596ee096d3b6eeaf77a
@@@ -251,7 -251,9 +251,9 @@@ dumpbv(BitVector *bv, uintptr offset
        for(i = 0; i < bv->n; i += BitsPerPointer) {
                switch(bv->bytedata[i/8] >> i%8 & 3) {
                case BitsDead:
-                       return;
+                       // BitsDead has already been processed in makeheapobjbv.
+                       // We should only see it in stack maps, in which case we should continue processing.
+                       break;
                case BitsScalar:
                        break;
                case BitsPointer:
                        dumpint(offset + i / BitsPerPointer * PtrSize);
                        break;
                case BitsMultiWord:
 -                      switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
 -                      default:
 -                              runtime·throw("unexpected garbage collection bits");
 -                      case BitsIface:
 -                              dumpint(FieldKindIface);
 -                              dumpint(offset + i / BitsPerPointer * PtrSize);
 -                              i += BitsPerPointer;
 -                              break;
 -                      case BitsEface:
 -                              dumpint(FieldKindEface);
 -                              dumpint(offset + i / BitsPerPointer * PtrSize);
 -                              i += BitsPerPointer;
 -                              break;
 -                      }
 +                      runtime·throw("bumpbv unexpected garbage collection bits");
                }
        }
  }
@@@ -400,7 -415,7 +402,7 @@@ dumpgoroutine(G *gp
        child.sp = nil;
        child.depth = 0;
        fn = dumpframe;
-       runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, false);
+       runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, 0);
  
        // dump defer & panic records
        for(d = gp->defer; d != nil; d = d->link) {
diff --combined src/runtime/malloc.go
index a18e77421e886b0a243a30871624c8f0e9408797,8cf1c3d342664269703fe0fdc727851cddc308b0..fab8cf269579f423341b45a4c94f4f21e49e19a1
@@@ -4,7 -4,9 +4,7 @@@
  
  package runtime
  
 -import (
 -      "unsafe"
 -)
 +import "unsafe"
  
  const (
        debugMalloc = false
@@@ -41,7 -43,7 +41,7 @@@ var zerobase uintpt
  // Allocate an object of size bytes.
  // Small objects are allocated from the per-P cache's free lists.
  // Large objects (> 32 kB) are allocated straight from the heap.
- func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer {
+ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
        if size == 0 {
                return unsafe.Pointer(&zerobase)
        }
                        masksize = masksize * pointersPerByte / 8 // 4 bits per word
                        masksize++                                // unroll flag in the beginning
                        if masksize > maxGCMask && typ.gc[1] != 0 {
 +                              // write barriers have not been updated to deal with this case yet.
 +                              gothrow("maxGCMask too small for now")
                                // If the mask is too large, unroll the program directly
                                // into the GC bitmap. It's 7 times slower than copying
                                // from the pre-unrolled mask, but saves 1/16 of type size
                                goto marked
                        }
                        ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
 -                      // Check whether the program is already unrolled.
 -                      if uintptr(atomicloadp(unsafe.Pointer(ptrmask)))&0xff == 0 {
 +                      // Check whether the program is already unrolled
 +                      // by checking if the unroll flag byte is set
 +                      maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask)))
 +                      if *(*uint8)(unsafe.Pointer(&maskword)) == 0 {
                                mp := acquirem()
                                mp.ptrarg[0] = unsafe.Pointer(typ)
                                onM(unrollgcprog_m)
                }
        }
  marked:
 +
 +      // GCmarkterminate allocates black
 +      // All slots hold nil so no scanning is needed.
 +      // This may be racing with GC so do it atomically if there can be
 +      // a race marking the bit.
 +      if gcphase == _GCmarktermination {
 +              mp := acquirem()
 +              mp.ptrarg[0] = x
 +              onM(gcmarknewobject_m)
 +              releasem(mp)
 +      }
 +
        if raceenabled {
                racemalloc(x, size)
        }
        return x
  }
  
 +func loadPtrMask(typ *_type) []uint8 {
 +      var ptrmask *uint8
 +      nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize
 +      if typ.kind&kindGCProg != 0 {
 +              masksize := nptr
 +              if masksize%2 != 0 {
 +                      masksize *= 2 // repeated
 +              }
 +              masksize = masksize * pointersPerByte / 8 // 4 bits per word
 +              masksize++                                // unroll flag in the beginning
 +              if masksize > maxGCMask && typ.gc[1] != 0 {
 +                      // write barriers have not been updated to deal with this case yet.
 +                      gothrow("maxGCMask too small for now")
 +              }
 +              ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
 +              // Check whether the program is already unrolled
 +              // by checking if the unroll flag byte is set
 +              maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask)))
 +              if *(*uint8)(unsafe.Pointer(&maskword)) == 0 {
 +                      mp := acquirem()
 +                      mp.ptrarg[0] = unsafe.Pointer(typ)
 +                      onM(unrollgcprog_m)
 +                      releasem(mp)
 +              }
 +              ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
 +      } else {
 +              ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
 +      }
 +      return (*[1 << 30]byte)(unsafe.Pointer(ptrmask))[:(nptr+1)/2]
 +}
 +
  // implementation of new builtin
  func newobject(typ *_type) unsafe.Pointer {
-       flags := 0
+       flags := uint32(0)
        if typ.kind&kindNoPointers != 0 {
                flags |= flagNoScan
        }
  
  // implementation of make builtin for slices
  func newarray(typ *_type, n uintptr) unsafe.Pointer {
-       flags := 0
+       flags := uint32(0)
        if typ.kind&kindNoPointers != 0 {
                flags |= flagNoScan
        }
@@@ -483,20 -438,7 +483,20 @@@ func gogc(force int32) 
        mp = acquirem()
        mp.gcing = 1
        releasem(mp)
 +
        onM(stoptheworld)
 +      onM(finishsweep_m) // finish sweep before we start concurrent scan.
 +      if false {         // To turn on concurrent scan and mark set to true...
 +              onM(starttheworld)
 +              // Do a concurrent heap scan before we stop the world.
 +              onM(gcscan_m)
 +              onM(stoptheworld)
 +              onM(gcinstallmarkwb_m)
 +              onM(starttheworld)
 +              onM(gcmark_m)
 +              onM(stoptheworld)
 +              onM(gcinstalloffwb_m)
 +      }
        if mp != acquirem() {
                gothrow("gogc: rescheduled")
        }
                onM(gc_m)
        }
  
 +      onM(gccheckmark_m)
 +
        // all done
        mp.gcing = 0
        semrelease(&worldsema)
        }
  }
  
 +func GCcheckmarkenable() {
 +      onM(gccheckmarkenable_m)
 +}
 +
 +func GCcheckmarkdisable() {
 +      onM(gccheckmarkdisable_m)
 +}
 +
  // GC runs a garbage collection.
  func GC() {
        gogc(2)
diff --combined src/runtime/mgc0.c
index 214b9ebc2412368b5eece24d3af163dc241109ad,7754bad89d437ea27f5881a6a7d6214419ebe846..3248b0f49a006e7b4949ae0a23cd254a043c5a9f
@@@ -4,72 -4,22 +4,72 @@@
  
  // Garbage collector (GC).
  //
 -// GC is:
 -// - mark&sweep
 -// - mostly precise (with the exception of some C-allocated objects, assembly frames/arguments, etc)
 -// - parallel (up to MaxGcproc threads)
 -// - partially concurrent (mark is stop-the-world, while sweep is concurrent)
 -// - non-moving/non-compacting
 -// - full (non-partial)
 +// The GC runs concurrently with mutator threads, is type accurate (aka precise), allows multiple GC 
 +// thread to run in parallel. It is a concurrent mark and sweep that uses a write barrier. It is 
 +// non-generational and non-compacting. Allocation is done using size segregated per P allocation 
 +// areas to minimize fragmentation while eliminating locks in the common case. 
  //
 -// GC rate.
 -// Next GC is after we've allocated an extra amount of memory proportional to
 -// the amount already in use. The proportion is controlled by GOGC environment variable
 -// (100 by default). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M
 -// (this mark is tracked in next_gc variable). This keeps the GC cost in linear
 -// proportion to the allocation cost. Adjusting GOGC just changes the linear constant
 -// (and also the amount of extra memory used).
 +// The algorithm decomposes into several steps.
 +// This is a high level description of the algorithm being used. For an overview of GC a good
 +// place to start is Richard Jones' gchandbook.org.
 +// 
 +// The algorithm's intellectual heritage includes Dijkstra's on-the-fly algorithm, see
 +// Edsger W. Dijkstra, Leslie Lamport, A. J. Martin, C. S. Scholten, and E. F. M. Steffens. 1978. 
 +// On-the-fly garbage collection: an exercise in cooperation. Commun. ACM 21, 11 (November 1978), 966-975.
 +// For journal quality proofs that these steps are complete, correct, and terminate see
 +// Hudson, R., and Moss, J.E.B. Copying Garbage Collection without stopping the world. 
 +// Concurrency and Computation: Practice and Experience 15(3-5), 2003. 
  //
 +//  0. Set phase = GCscan from GCoff.
 +//  1. Wait for all P's to acknowledge phase change.
 +//         At this point all goroutines have passed through a GC safepoint and
 +//         know we are in the GCscan phase.
 +//  2. GC scans all goroutine stacks, mark and enqueues all encountered pointers
 +//       (marking avoids most duplicate enqueuing but races may produce duplication which is benign).
 +//       Preempted goroutines are scanned before P schedules next goroutine.
 +//  3. Set phase = GCmark.
 +//  4. Wait for all P's to acknowledge phase change.
 +//  5. Now write barrier marks and enqueues black, grey, or white to white pointers.
 +//       Malloc still allocates white (non-marked) objects.
 +//  6. Meanwhile GC transitively walks the heap marking reachable objects.
 +//  7. When GC finishes marking heap, it preempts P's one-by-one and
 +//       retakes partial wbufs (filled by write barrier or during a stack scan of the goroutine
 +//       currently scheduled on the P).
 +//  8. Once the GC has exhausted all available marking work it sets phase = marktermination.
 +//  9. Wait for all P's to acknowledge phase change.
 +// 10. Malloc now allocates black objects, so number of unmarked reachable objects
 +//        monotonically decreases.
 +// 11. GC preempts P's one-by-one taking partial wbufs and marks all unmarked yet reachable objects.
 +// 12. When GC completes a full cycle over P's and discovers no new grey
 +//         objects, (which means all reachable objects are marked) set phase = GCsweep.
 +// 13. Wait for all P's to acknowledge phase change.
 +// 14. Now malloc allocates white (but sweeps spans before use).
 +//         Write barrier becomes nop.
 +// 15. GC does background sweeping, see description below.
 +// 16. When sweeping is complete set phase to GCoff.
 +// 17. When sufficient allocation has taken place replay the sequence starting at 0 above, 
 +//         see discussion of GC rate below.
 +
 +// Changing phases.
 +// Phases are changed by setting the gcphase to the next phase and possibly calling ackgcphase.
 +// All phase action must be benign in the presence of a change.
 +// Starting with GCoff
 +// GCoff to GCscan
 +//     GSscan scans stacks and globals greying them and never marks an object black.
 +//     Once all the P's are aware of the new phase they will scan gs on preemption.
 +//     This means that the scanning of preempted gs can't start until all the Ps
 +//     have acknowledged.
 +// GCscan to GCmark
 +//     GCMark turns on the write barrier which also only greys objects. No scanning
 +//     of objects (making them black) can happen until all the Ps have acknowledged 
 +//     the phase change.
 +// GCmark to GCmarktermination
 +//     The only change here is that we start allocating black so the Ps must acknowledge
 +//     the change before we begin the termination algorithm
 +// GCmarktermination to GSsweep
 +//     Object currently on the freelist must be marked black for this to work. 
 +//     Are things on the free lists black or white? How does the sweep phase work?
 +
  // Concurrent sweep.
  // The sweep phase proceeds concurrently with normal program execution.
  // The heap is swept span-by-span both lazily (when a goroutine needs another span)
  // The finalizer goroutine is kicked off only when all spans are swept.
  // When the next GC starts, it sweeps all not-yet-swept spans (if any).
  
 +// GC rate.
 +// Next GC is after we've allocated an extra amount of memory proportional to
 +// the amount already in use. The proportion is controlled by GOGC environment variable
 +// (100 by default). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M
 +// (this mark is tracked in next_gc variable). This keeps the GC cost in linear 
 +// proportion to the allocation cost. Adjusting GOGC just changes the linear constant 
 +// (and also the amount of extra memory used).
 +
  #include "runtime.h"
  #include "arch_GOARCH.h"
  #include "malloc.h"
  
  enum {
        Debug           = 0,
 -      DebugPtrs       = 0, // if 1, print trace of every pointer load during GC
        ConcurrentSweep = 1,
  
 -      WorkbufSize     = 4*1024,
        FinBlockSize    = 4*1024,
        RootData        = 0,
        RootBss         = 1,
  // ptrmask for an allocation containing a single pointer.
  static byte oneptr[] = {BitsPointer};
  
 -// Initialized from $GOGC.  GOGC=off means no gc.
 +// Initialized from $GOGC.  GOGC=off means no GC.
  extern int32 runtime·gcpercent;
  
  // Holding worldsema grants an M the right to try to stop the world.
  //
  uint32 runtime·worldsema = 1;
  
 -typedef struct Workbuf Workbuf;
 -struct Workbuf
 -{
 -      LFNode  node; // must be first
 -      uintptr nobj;
 -      byte*   obj[(WorkbufSize-sizeof(LFNode)-sizeof(uintptr))/PtrSize];
 +// It is a bug if bits does not have bitBoundary set but
 +// there are still some cases where this happens related
 +// to stack spans.
 +typedef struct Markbits Markbits;
 +struct Markbits {
 +      byte *bitp; // pointer to the byte holding xbits
 +      byte shift; // bits xbits needs to be shifted to get bits
 +      byte xbits; // byte holding all the bits from *bitp
 +      byte bits;  // mark and boundary bits relevant to corresponding slot.
 +      byte tbits; // pointer||scalar bits relevant to corresponding slot.
  };
  
  extern byte runtime·data[];
@@@ -188,40 -128,26 +188,40 @@@ BitVector       runtime·gcbssmask
  
  Mutex runtime·gclock;
  
 -static        uintptr badblock[1024];
 -static        int32   nbadblock;
 -
 +static Workbuf* getpartialorempty(void);
 +static void   putpartial(Workbuf*);
  static Workbuf* getempty(Workbuf*);
  static Workbuf* getfull(Workbuf*);
  static void   putempty(Workbuf*);
 +static void   putfull(Workbuf*);
  static Workbuf* handoff(Workbuf*);
  static void   gchelperstart(void);
  static void   flushallmcaches(void);
 -static bool   scanframe(Stkframe *frame, void *unused);
 -static void   scanstack(G *gp);
 -static BitVector      unrollglobgcprog(byte *prog, uintptr size);
 +static bool   scanframe(Stkframe*, void*);
 +static void   scanstack(G*);
 +static BitVector      unrollglobgcprog(byte*, uintptr);
 +static void     scanblock(byte*, uintptr, byte*);
 +static byte*    objectstart(byte*, Markbits*);
 +static Workbuf*       greyobject(byte*, Markbits*, Workbuf*);
 +static bool     inheap(byte*);
 +static bool     shaded(byte*);
 +static void     shade(byte*);
 +static void   slottombits(byte*, Markbits*);
 +static void     atomicxor8(byte*, byte);
 +static bool     ischeckmarked(Markbits*);
 +static bool     ismarked(Markbits*);
 +static void     clearcheckmarkbits(void);
 +static void     clearcheckmarkbitsspan(MSpan*);
  
  void runtime·bgsweep(void);
 +void runtime·finishsweep_m(void);
  static FuncVal bgsweepv = {runtime·bgsweep};
  
  typedef struct WorkData WorkData;
  struct WorkData {
 -      uint64  full;  // lock-free list of full blocks
 -      uint64  empty; // lock-free list of empty blocks
 +      uint64  full;    // lock-free list of full blocks
 +      uint64  empty;   // lock-free list of empty blocks
 +      uint64  partial; // lock-free list of partially filled blocks
        byte    pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
        uint32  nproc;
        int64   tstart;
  };
  WorkData runtime·work;
  
 -// Is _cgo_allocate linked into the binary?
 +// To help debug the concurrent GC we remark with the world
 +// stopped ensuring that any object encountered has their normal
 +// mark bit set. To do this we use an orthogonal bit
 +// pattern to indicate the object is marked. The following pattern
 +// uses the upper two bits in the object's bounday nibble. 
 +// 01: scalar  not marked
 +// 10: pointer not marked
 +// 11: pointer     marked
 +// 00: scalar      marked
 +// Xoring with 01 will flip the pattern from marked to unmarked and vica versa.
 +// The higher bit is 1 for pointers and 0 for scalars, whether the object
 +// is marked or not.
 +// The first nibble no longer holds the bitsDead pattern indicating that the
 +// there are no more pointers in the object. This information is held
 +// in the second nibble.
 +
 +// When marking an object if the bool checkmark is true one uses the above 
 +// encoding, otherwise one uses the bitMarked bit in the lower two bits 
 +// of the nibble.
 +static bool checkmark = false;
 +static bool gccheckmarkenable = true;
 +
 +// Is address b in the known heap. If it doesn't have a valid gcmap
 +// returns false. For example pointers into stacks will return false.
  static bool
 -have_cgo_allocate(void)
 +inheap(byte *b)
  {
 -      extern  byte    go·weak·runtime·_cgo_allocate_internal[1];
 -      return go·weak·runtime·_cgo_allocate_internal != nil;
 +      MSpan *s;
 +      pageID k;
 +      uintptr x;
 +
 +      if(b == nil || b < runtime·mheap.arena_start || b >= runtime·mheap.arena_used)
 +              return false;
 +      // Not a beginning of a block, consult span table to find the block beginning.
 +      k = (uintptr)b>>PageShift;
 +      x = k;
 +      x -= (uintptr)runtime·mheap.arena_start>>PageShift;
 +      s = runtime·mheap.spans[x];
 +      if(s == nil || k < s->start || b >= s->limit || s->state != MSpanInUse)
 +              return false;
 +      return true;
  }
  
 -// scanblock scans a block of n bytes starting at pointer b for references
 -// to other objects, scanning any it finds recursively until there are no
 -// unscanned objects left.  Instead of using an explicit recursion, it keeps
 -// a work list in the Workbuf* structures and loops in the main function
 -// body.  Keeping an explicit work list is easier on the stack allocator and
 -// more efficient.
 +// Given an address in the heap return the relevant byte from the gcmap. This routine
 +// can be used on addresses to the start of an object or to the interior of the an object.
  static void
 -scanblock(byte *b, uintptr n, byte *ptrmask)
 +slottombits(byte *obj, Markbits *mbits)
  {
 -      byte *obj, *obj0, *p, *arena_start, *arena_used, **wp, *scanbuf[8], *ptrbitp, *bitp;
 -      uintptr i, j, nobj, size, idx, x, off, scanbufpos, bits, xbits, shift;
 -      Workbuf *wbuf;
 -      Iface *iface;
 -      Eface *eface;
 -      Type *typ;
 +      uintptr off;
 +
 +      off = (uintptr*)((uintptr)obj&~(PtrSize-1)) - (uintptr*)runtime·mheap.arena_start;
 +      mbits->bitp = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
 +      mbits->shift = (off % wordsPerBitmapByte) * gcBits;
 +      mbits->xbits = *mbits->bitp;
 +      mbits->bits = (mbits->xbits >> mbits->shift) & bitMask;
 +      mbits->tbits = ((mbits->xbits >> mbits->shift) & bitPtrMask) >> 2;
 +}
 +
 +// b is a pointer into the heap.
 +// Find the start of the object refered to by b.
 +// Set mbits to the associated bits from the bit map.
 +// If b is not a valid heap object return nil and
 +// undefined values in mbits.
 +static byte*
 +objectstart(byte *b, Markbits *mbits)
 +{
 +      byte *obj, *p;
        MSpan *s;
        pageID k;
 -      bool keepworking;
 +      uintptr x, size, idx;
  
 -      // Cache memory arena parameters in local vars.
 -      arena_start = runtime·mheap.arena_start;
 -      arena_used = runtime·mheap.arena_used;
 +      obj = (byte*)((uintptr)b&~(PtrSize-1));
 +      for(;;) {
 +              slottombits(obj, mbits);
 +              if((mbits->bits&bitBoundary) == bitBoundary)
 +                      break;
  
 -      wbuf = getempty(nil);
 -      nobj = wbuf->nobj;
 -      wp = &wbuf->obj[nobj];
 -      keepworking = b == nil;
 -      scanbufpos = 0;
 -      for(i = 0; i < nelem(scanbuf); i++)
 -              scanbuf[i] = nil;
 +              // Not a beginning of a block, consult span table to find the block beginning.
 +              k = (uintptr)obj>>PageShift;
 +              x = k;
 +              x -= (uintptr)runtime·mheap.arena_start>>PageShift;
 +              s = runtime·mheap.spans[x];
 +              if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse){
 +                      if(s != nil && s->state == MSpanStack) {
 +                              return nil; // This is legit.
 +                      }
 +
 +                      // The following ensures that we are rigorous about what data 
 +                      // structures hold valid pointers
 +                      if(0) {
 +                              // Still happens sometimes. We don't know why.
 +                              runtime·printf("runtime:objectstart Span weird: obj=%p, k=%p", obj, k);
 +                              if (s == nil)
 +                                      runtime·printf(" s=nil\n");
 +                              else
 +                                      runtime·printf(" s->start=%p s->limit=%p, s->state=%d\n", s->start*PageSize, s->limit, s->state);
 +                              runtime·throw("objectstart: bad pointer in unexpected span");
 +                      }
 +                      return nil;
 +              }
 +              p = (byte*)((uintptr)s->start<<PageShift);
 +              if(s->sizeclass != 0) {
 +                      size = s->elemsize;
 +                      idx = ((byte*)obj - p)/size;
 +                      p = p+idx*size;
 +              }
 +              if(p == obj) {
 +                      runtime·printf("runtime: failed to find block beginning for %p s=%p s->limit=%p\n",
 +                                     p, s->start*PageSize, s->limit);
 +                      runtime·throw("failed to find block beginning");
 +              }
 +              obj = p;
 +      }
 +      // if size(obj.firstfield) < PtrSize, the &obj.secondfield could map to the boundary bit
 +      // Clear any low bits to get to the start of the object.
 +      // greyobject depends on this.
 +      return obj;
 +}
 +
 +// Slow for now as we serialize this, since this is on a debug path 
 +// speed is not critical at this point.
 +static Mutex andlock;
 +static void
 +atomicand8(byte *src, byte val)
 +{
 +      runtime·lock(&andlock);
 +      *src = *src&val;
 +      runtime·unlock(&andlock);
 +}
 +
 +// Mark using the checkmark scheme.
 +void
 +docheckmark(Markbits *mbits)
 +{
 +      // xor 01 moves 01(scalar unmarked) to 00(scalar marked) 
 +      // and 10(pointer unmarked) to 11(pointer marked)
 +      if(mbits->tbits == BitsScalar)
 +              atomicand8(mbits->bitp, ~(byte)(BitsCheckMarkXor<<mbits->shift<<2));
 +      else if(mbits->tbits == BitsPointer)
 +              runtime·atomicor8(mbits->bitp, BitsCheckMarkXor<<mbits->shift<<2);
 +
 +      // reload bits for ischeckmarked
 +      mbits->xbits = *mbits->bitp;
 +      mbits->bits = (mbits->xbits >> mbits->shift) & bitMask;
 +      mbits->tbits = ((mbits->xbits >> mbits->shift) & bitPtrMask) >> 2;
 +
 +      return;
 +}
 +
 +// In the default scheme does mbits refer to a marked object.
 +static bool
 +ismarked(Markbits *mbits)
 +{
 +      if((mbits->bits&bitBoundary) != bitBoundary)
 +              runtime·throw("ismarked: bits should have boundary bit set");
 +      return (mbits->bits&bitMarked) == bitMarked;
 +}
 +
 +// In the checkmark scheme does mbits refer to a marked object.
 +static bool
 +ischeckmarked(Markbits *mbits)
 +{
 +      if((mbits->bits&bitBoundary) != bitBoundary)
 +              runtime·printf("runtime:ischeckmarked: bits should have boundary bit set\n");
 +      return mbits->tbits==BitsScalarMarked || mbits->tbits==BitsPointerMarked;
 +}
 +
 +// When in GCmarkterminate phase we allocate black.
 +void
 +runtime·gcmarknewobject_m(void)
 +{
 +      Markbits mbits;
 +      byte *obj;
 +
 +      if(runtime·gcphase != GCmarktermination)
 +              runtime·throw("marking new object while not in mark termination phase");
 +      if(checkmark) // The world should be stopped so this should not happen.
 +              runtime·throw("gcmarknewobject called while doing checkmark");
 +
 +      obj = g->m->ptrarg[0];  
 +      slottombits((byte*)((uintptr)obj & (PtrSize-1)), &mbits);
 +
 +      if((mbits.bits&bitMarked) != 0)
 +              return;
 +      
 +      // Each byte of GC bitmap holds info for two words.
 +      // If the current object is larger than two words, or if the object is one word
 +      // but the object it shares the byte with is already marked,
 +      // then all the possible concurrent updates are trying to set the same bit,
 +      // so we can use a non-atomic update.
 +      if((mbits.xbits&(bitMask|(bitMask<<gcBits))) != (bitBoundary|(bitBoundary<<gcBits)) || runtime·work.nproc == 1)
 +              *mbits.bitp = mbits.xbits | (bitMarked<<mbits.shift);
 +      else
 +              runtime·atomicor8(mbits.bitp, bitMarked<<mbits.shift);
 +      return; 
 +}
 +
 +// obj is the start of an object with mark mbits.
 +// If it isn't already marked, mark it and enqueue into workbuf.
 +// Return possibly new workbuf to use.
 +static Workbuf*
 +greyobject(byte *obj, Markbits *mbits, Workbuf *wbuf) 
 +{
 +      // obj should be start of allocation, and so must be at least pointer-aligned.
 +      if(((uintptr)obj & (PtrSize-1)) != 0)
 +              runtime·throw("greyobject: obj not pointer-aligned");
 +
 +      if(checkmark) {
 +              if(!ismarked(mbits)) {
 +                      MSpan *s;
 +                      pageID k;
 +                      uintptr x, i;
 +
 +                      runtime·printf("runtime:greyobject: checkmarks finds unexpected unmarked object obj=%p, mbits->bits=%x, *mbits->bitp=%x\n", obj, mbits->bits, *mbits->bitp);
 +
 +                      k = (uintptr)obj>>PageShift;
 +                      x = k;
 +                      x -= (uintptr)runtime·mheap.arena_start>>PageShift;
 +                      s = runtime·mheap.spans[x];
 +                      runtime·printf("runtime:greyobject Span: obj=%p, k=%p", obj, k);
 +                      if (s == nil) {
 +                              runtime·printf(" s=nil\n");
 +                      } else {
 +                              runtime·printf(" s->start=%p s->limit=%p, s->state=%d, s->sizeclass=%d, s->elemsize=%D \n", s->start*PageSize, s->limit, s->state, s->sizeclass, s->elemsize);
 +                              for(i=0; i<s->sizeclass; i++) {
 +                                      runtime·printf(" ((uintptr*)obj)[%D]=%p\n", i, ((uintptr*)obj)[i]);
 +                              }
 +                      }
 +                      runtime·throw("checkmark found unmarked object");
 +              }
 +              if(ischeckmarked(mbits))
 +                      return wbuf;
 +              docheckmark(mbits);
 +              if(!ischeckmarked(mbits)) {
 +                      runtime·printf("mbits xbits=%x bits=%x tbits=%x shift=%d\n", mbits->xbits, mbits->bits, mbits->tbits, mbits->shift);
 +                      runtime·throw("docheckmark and ischeckmarked disagree");
 +              }
 +      } else {
 +              // If marked we have nothing to do.
 +              if((mbits->bits&bitMarked) != 0)
 +                      return wbuf;
 +
 +              // Each byte of GC bitmap holds info for two words.
 +              // If the current object is larger than two words, or if the object is one word
 +              // but the object it shares the byte with is already marked,
 +              // then all the possible concurrent updates are trying to set the same bit,
 +              // so we can use a non-atomic update.
 +              if((mbits->xbits&(bitMask|(bitMask<<gcBits))) != (bitBoundary|(bitBoundary<<gcBits)) || runtime·work.nproc == 1)
 +                      *mbits->bitp = mbits->xbits | (bitMarked<<mbits->shift);
 +              else
 +                      runtime·atomicor8(mbits->bitp, bitMarked<<mbits->shift);
 +      }
 +
 +      if (!checkmark && (((mbits->xbits>>(mbits->shift+2))&BitsMask) == BitsDead))
 +              return wbuf;  // noscan object
 +
 +      // Queue the obj for scanning. The PREFETCH(obj) logic has been removed but
 +      // seems like a nice optimization that can be added back in.
 +      // There needs to be time between the PREFETCH and the use.
 +      // Previously we put the obj in an 8 element buffer that is drained at a rate
 +      // to give the PREFETCH time to do its work.
 +      // Use of PREFETCHNTA might be more appropriate than PREFETCH
 +
 +      // If workbuf is full, obtain an empty one.
 +      if(wbuf->nobj >= nelem(wbuf->obj)) {
 +              wbuf = getempty(wbuf);
 +      }
 +
 +      wbuf->obj[wbuf->nobj] = obj;
 +      wbuf->nobj++;
 +      return wbuf;                    
 +}
 +
 +// Scan the object b of size n, adding pointers to wbuf.
 +// Return possibly new wbuf to use.
 +// If ptrmask != nil, it specifies where pointers are in b.
 +// If ptrmask == nil, the GC bitmap should be consulted.
 +// In this case, n may be an overestimate of the size; the GC bitmap
 +// must also be used to make sure the scan stops at the end of b.
 +static Workbuf*
 +scanobject(byte *b, uintptr n, byte *ptrmask, Workbuf *wbuf)
 +{
 +      byte *obj, *arena_start, *arena_used, *ptrbitp;
 +      uintptr i, j;
 +      int32 bits;
 +      Markbits mbits;
  
 +      arena_start = (byte*)runtime·mheap.arena_start;
 +      arena_used = runtime·mheap.arena_used;
        ptrbitp = nil;
  
 +      // Find bits of the beginning of the object.
 +      if(ptrmask == nil) {
 +              b = objectstart(b, &mbits);
 +              if(b == nil)
 +                      return wbuf;
 +              ptrbitp = mbits.bitp; //arena_start - off/wordsPerBitmapByte - 1;
 +      }
 +      for(i = 0; i < n; i += PtrSize) {
 +              // Find bits for this word.
 +              if(ptrmask != nil) {
 +                      // dense mask (stack or data)
 +                      bits = (ptrmask[(i/PtrSize)/4]>>(((i/PtrSize)%4)*BitsPerPointer))&BitsMask;
 +              } else {
 +                      // Check if we have reached end of span.
 +                      // n is an overestimate of the size of the object.
 +                      if((((uintptr)b+i)%PageSize) == 0 &&
 +                              runtime·mheap.spans[(b-arena_start)>>PageShift] != runtime·mheap.spans[(b+i-arena_start)>>PageShift])
 +                              break;
 +                      // Consult GC bitmap.
 +                      bits = *ptrbitp;
 +                      if(wordsPerBitmapByte != 2)
 +                              runtime·throw("alg doesn't work for wordsPerBitmapByte != 2");
 +                      j = ((uintptr)b+i)/PtrSize & 1; // j indicates upper nibble or lower nibble
 +                      bits >>= gcBits*j;
 +                      if(i == 0)
 +                              bits &= ~bitBoundary;
 +                      ptrbitp -= j;
 +              
 +                      if((bits&bitBoundary) != 0 && i != 0)
 +                              break; // reached beginning of the next object
 +                      bits = (bits&bitPtrMask)>>2; // bits refer to the type bits.
 +                      
 +                      if(i != 0 && bits == BitsDead) // BitsDead in first nibble not valid during checkmark
 +                              break; // reached no-scan part of the object
 +              }
 +
 +              if(bits <= BitsScalar) // Bits Scalar ||
 +                                     // BitsDead    ||       // default encoding 
 +                                     // BitsScalarMarked     // checkmark encoding
 +                              continue;
 +
 +              if((bits&BitsPointer) != BitsPointer) {
 +                      runtime·printf("gc checkmark=%d, b=%p ptrmask=%p, mbits.bitp=%p, mbits.xbits=%x, bits=%x\n", checkmark, b, ptrmask, mbits.bitp, mbits.xbits, bits);
 +                      runtime·throw("unexpected garbage collection bits");
 +              }
 +
 +              obj = *(byte**)(b+i);
 +              // At this point we have extracted the next potential pointer.
 +              // Check if it points into heap.
 +              if(obj == nil || obj < arena_start || obj >= arena_used)
 +                      continue;
 +              // Mark the object. return some important bits.
 +              // We we combine the following two rotines we don't have to pass mbits or obj around.
 +              obj = objectstart(obj, &mbits);
 +              // In the case of the span being MSpan_Stack mbits is useless and will not have 
 +              // the boundary bit set. It does not need to be greyed since it will be
 +              // scanned using the scan stack mechanism.
 +              if(obj == nil)
 +                      continue;
 +              wbuf = greyobject(obj, &mbits, wbuf);
 +      }
 +      return wbuf;
 +}
 +
 +// scanblock starts by scanning b as scanobject would.
 +// If the gcphase is GCscan, that's all scanblock does.
 +// Otherwise it traverses some fraction of the pointers it found in b, recursively.
 +// As a special case, scanblock(nil, 0, nil) means to scan previously queued work,
 +// stopping only when no work is left in the system.
 +static void
 +scanblock(byte *b, uintptr n, byte *ptrmask)
 +{
 +      Workbuf *wbuf;
 +      bool keepworking;
 +
 +      wbuf = getpartialorempty();
 +      if(b != nil) {
 +              wbuf = scanobject(b, n, ptrmask, wbuf);
 +              if(runtime·gcphase == GCscan) {
 +                      if(inheap(b) && !ptrmask)
 +                              // b is in heap, we are in GCscan so there should be a ptrmask.
 +                              runtime·throw("scanblock: In GCscan phase and inheap is true.");
 +                      // GCscan only goes one level deep since mark wb not turned on.
 +                      putpartial(wbuf);
 +                      return;
 +              }
 +      }
 +      if(runtime·gcphase == GCscan) {
 +              runtime·throw("scanblock: In GCscan phase but no b passed in.");
 +      }
 +      
 +      keepworking = b == nil;
 +
        // ptrmask can have 2 possible values:
        // 1. nil - obtain pointer mask from GC bitmap.
        // 2. pointer to a compact mask (for stacks and data).
 -      if(b != nil)
 -              goto scanobj;
        for(;;) {
 -              if(nobj == 0) {
 -                      // Out of work in workbuf.
 -                      // First, see is there is any work in scanbuf.
 -                      for(i = 0; i < nelem(scanbuf); i++) {
 -                              b = scanbuf[scanbufpos];
 -                              scanbuf[scanbufpos++] = nil;
 -                              scanbufpos %= nelem(scanbuf);
 -                              if(b != nil) {
 -                                      n = arena_used - b; // scan until bitBoundary or BitsDead
 -                                      ptrmask = nil; // use GC bitmap for pointer info
 -                                      goto scanobj;
 -                              }
 -                      }
 +              if(wbuf->nobj == 0) {
                        if(!keepworking) {
                                putempty(wbuf);
                                return;
                        }
                        // Refill workbuf from global queue.
                        wbuf = getfull(wbuf);
 -                      if(wbuf == nil)
 +                      if(wbuf == nil) // nil means out of work barrier reached
                                return;
 -                      nobj = wbuf->nobj;
 -                      wp = &wbuf->obj[nobj];
 +
 +                      if(wbuf->nobj<=0) {
 +                              runtime·throw("runtime:scanblock getfull returns empty buffer");
 +                      }
 +
                }
  
                // If another proc wants a pointer, give it some.
 -              if(runtime·work.nwait > 0 && nobj > 4 && runtime·work.full == 0) {
 -                      wbuf->nobj = nobj;
 +              if(runtime·work.nwait > 0 && wbuf->nobj > 4 && runtime·work.full == 0) {
                        wbuf = handoff(wbuf);
 -                      nobj = wbuf->nobj;
 -                      wp = &wbuf->obj[nobj];
                }
  
 -              wp--;
 -              nobj--;
 -              b = *wp;
 -              n = arena_used - b; // scan until next bitBoundary or BitsDead
 -              ptrmask = nil; // use GC bitmap for pointer info
 -
 -      scanobj:
 -              if(DebugPtrs)
 -                      runtime·printf("scanblock %p +%p %p\n", b, n, ptrmask);
 -              // Find bits of the beginning of the object.
 -              if(ptrmask == nil) {
 -                      off = (uintptr*)b - (uintptr*)arena_start;
 -                      ptrbitp = arena_start - off/wordsPerBitmapByte - 1;
 -              }
 -              for(i = 0; i < n; i += PtrSize) {
 -                      obj = nil;
 -                      // Find bits for this word.
 -                      if(ptrmask == nil) {
 -                              // Check is we have reached end of span.
 -                              if((((uintptr)b+i)%PageSize) == 0 &&
 -                                      runtime·mheap.spans[(b-arena_start)>>PageShift] != runtime·mheap.spans[(b+i-arena_start)>>PageShift])
 -                                      break;
 -                              // Consult GC bitmap.
 -                              bits = *ptrbitp;
 -
 -                              if(wordsPerBitmapByte != 2)
 -                                      runtime·throw("alg doesn't work for wordsPerBitmapByte != 2");
 -                              j = ((uintptr)b+i)/PtrSize & 1;
 -                              ptrbitp -= j;
 -                              bits >>= gcBits*j;
 -
 -                              if((bits&bitBoundary) != 0 && i != 0)
 -                                      break; // reached beginning of the next object
 -                              bits = (bits>>2)&BitsMask;
 -                              if(bits == BitsDead)
 -                                      break; // reached no-scan part of the object
 -                      } else // dense mask (stack or data)
 -                              bits = (ptrmask[(i/PtrSize)/4]>>(((i/PtrSize)%4)*BitsPerPointer))&BitsMask;
 -
 -                      if(bits <= BitsScalar) // BitsScalar || BitsDead
 -                              continue;
 -                      if(bits == BitsPointer) {
 -                              obj = *(byte**)(b+i);
 -                              obj0 = obj;
 -                              goto markobj;
 -                      }
 -
 -                      // With those three out of the way, must be multi-word.
 -                      if(Debug && bits != BitsMultiWord)
 -                              runtime·throw("unexpected garbage collection bits");
 -                      // Find the next pair of bits.
 -                      if(ptrmask == nil) {
 -                              bits = *ptrbitp;
 -                              j = ((uintptr)b+i+PtrSize)/PtrSize & 1;
 -                              ptrbitp -= j;
 -                              bits >>= gcBits*j;
 -                              bits = (bits>>2)&BitsMask;
 -                      } else
 -                              bits = (ptrmask[((i+PtrSize)/PtrSize)/4]>>((((i+PtrSize)/PtrSize)%4)*BitsPerPointer))&BitsMask;
 -
 -                      if(Debug && bits != BitsIface && bits != BitsEface)
 -                              runtime·throw("unexpected garbage collection bits");
 -
 -                      if(bits == BitsIface) {
 -                              iface = (Iface*)(b+i);
 -                              if(iface->tab != nil) {
 -                                      typ = iface->tab->type;
 -                                      if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
 -                                              obj = iface->data;
 -                              }
 -                      } else {
 -                              eface = (Eface*)(b+i);
 -                              typ = eface->type;
 -                              if(typ != nil) {
 -                                      if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
 -                                              obj = eface->data;
 -                              }
 -                      }
 -
 -                      i += PtrSize;
 -
 -                      obj0 = obj;
 -              markobj:
 -                      // At this point we have extracted the next potential pointer.
 -                      // Check if it points into heap.
 -                      if(obj == nil)
 -                              continue;
 -                      if(obj < arena_start || obj >= arena_used) {
 -                              if((uintptr)obj < PhysPageSize && runtime·invalidptr) {
 -                                      s = nil;
 -                                      goto badobj;
 -                              }
 -                              continue;
 -                      }
 -                      // Mark the object.
 -                      obj = (byte*)((uintptr)obj & ~(PtrSize-1));
 -                      off = (uintptr*)obj - (uintptr*)arena_start;
 -                      bitp = arena_start - off/wordsPerBitmapByte - 1;
 -                      shift = (off % wordsPerBitmapByte) * gcBits;
 -                      xbits = *bitp;
 -                      bits = (xbits >> shift) & bitMask;
 -                      if((bits&bitBoundary) == 0) {
 -                              // Not a beginning of a block, consult span table to find the block beginning.
 -                              k = (uintptr)obj>>PageShift;
 -                              x = k;
 -                              x -= (uintptr)arena_start>>PageShift;
 -                              s = runtime·mheap.spans[x];
 -                              if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse) {
 -                                      // Stack pointers lie within the arena bounds but are not part of the GC heap.
 -                                      // Ignore them.
 -                                      if(s != nil && s->state == MSpanStack)
 -                                              continue;
 -                              
 -                              badobj:
 -                                      // If cgo_allocate is linked into the binary, it can allocate
 -                                      // memory as []unsafe.Pointer that may not contain actual
 -                                      // pointers and must be scanned conservatively.
 -                                      // In this case alone, allow the bad pointer.
 -                                      if(have_cgo_allocate() && ptrmask == nil)
 -                                              continue;
 -
 -                                      // Anything else indicates a bug somewhere.
 -                                      // If we're in the middle of chasing down a different bad pointer,
 -                                      // don't confuse the trace by printing about this one.
 -                                      if(nbadblock > 0)
 -                                              continue;
 -
 -                                      runtime·printf("runtime: garbage collector found invalid heap pointer *(%p+%p)=%p", b, i, obj);
 -                                      if(s == nil)
 -                                              runtime·printf(" s=nil\n");
 -                                      else
 -                                              runtime·printf(" span=%p-%p-%p state=%d\n", (uintptr)s->start<<PageShift, s->limit, (uintptr)(s->start+s->npages)<<PageShift, s->state);
 -                                      if(ptrmask != nil)
 -                                              runtime·throw("invalid heap pointer");
 -                                      // Add to badblock list, which will cause the garbage collection
 -                                      // to keep repeating until it has traced the chain of pointers
 -                                      // leading to obj all the way back to a root.
 -                                      if(nbadblock == 0)
 -                                              badblock[nbadblock++] = (uintptr)b;
 -                                      continue;
 -                              }
 -                              p = (byte*)((uintptr)s->start<<PageShift);
 -                              if(s->sizeclass != 0) {
 -                                      size = s->elemsize;
 -                                      idx = ((byte*)obj - p)/size;
 -                                      p = p+idx*size;
 -                              }
 -                              if(p == obj) {
 -                                      runtime·printf("runtime: failed to find block beginning for %p s=%p s->limit=%p\n",
 -                                              p, s->start*PageSize, s->limit);
 -                                      runtime·throw("failed to find block beginning");
 -                              }
 -                              obj = p;
 -                              goto markobj;
 -                      }
 -                      if(DebugPtrs)
 -                              runtime·printf("scan *%p = %p => base %p\n", b+i, obj0, obj);
 -
 -                      if(nbadblock > 0 && (uintptr)obj == badblock[nbadblock-1]) {
 -                              // Running garbage collection again because
 -                              // we want to find the path from a root to a bad pointer.
 -                              // Found possible next step; extend or finish path.
 -                              for(j=0; j<nbadblock; j++)
 -                                      if(badblock[j] == (uintptr)b)
 -                                              goto AlreadyBad;
 -                              runtime·printf("runtime: found *(%p+%p) = %p+%p\n", b, i, obj0, (uintptr)(obj-obj0));
 -                              if(ptrmask != nil)
 -                                      runtime·throw("bad pointer");
 -                              if(nbadblock >= nelem(badblock))
 -                                      runtime·throw("badblock trace too long");
 -                              badblock[nbadblock++] = (uintptr)b;
 -                      AlreadyBad:;
 -                      }
 -
 -                      // Now we have bits, bitp, and shift correct for
 -                      // obj pointing at the base of the object.
 -                      // Only care about not marked objects.
 -                      if((bits&bitMarked) != 0)
 -                              continue;
 -                      // If obj size is greater than 8, then each byte of GC bitmap
 -                      // contains info for at most one object. In such case we use
 -                      // non-atomic byte store to mark the object. This can lead
 -                      // to double enqueue of the object for scanning, but scanning
 -                      // is an idempotent operation, so it is OK. This cannot lead
 -                      // to bitmap corruption because the single marked bit is the
 -                      // only thing that can change in the byte.
 -                      // For 8-byte objects we use non-atomic store, if the other
 -                      // quadruple is already marked. Otherwise we resort to CAS
 -                      // loop for marking.
 -                      if((xbits&(bitMask|(bitMask<<gcBits))) != (bitBoundary|(bitBoundary<<gcBits)) ||
 -                              runtime·work.nproc == 1)
 -                              *bitp = xbits | (bitMarked<<shift);
 -                      else
 -                              runtime·atomicor8(bitp, bitMarked<<shift);
 -
 -                      if(((xbits>>(shift+2))&BitsMask) == BitsDead)
 -                              continue;  // noscan object
 -
 -                      // Queue the obj for scanning.
 -                      PREFETCH(obj);
 -                      p = scanbuf[scanbufpos];
 -                      scanbuf[scanbufpos++] = obj;
 -                      scanbufpos %= nelem(scanbuf);
 -                      if(p == nil)
 -                              continue;
 -
 -                      // If workbuf is full, obtain an empty one.
 -                      if(nobj >= nelem(wbuf->obj)) {
 -                              wbuf->nobj = nobj;
 -                              wbuf = getempty(wbuf);
 -                              nobj = wbuf->nobj;
 -                              wp = &wbuf->obj[nobj];
 -                      }
 -                      *wp = p;
 -                      wp++;
 -                      nobj++;
 -              }
 -              if(DebugPtrs)
 -                      runtime·printf("end scanblock %p +%p %p\n", b, n, ptrmask);
 -
 -              if(Debug && ptrmask == nil) {
 -                      // For heap objects ensure that we did not overscan.
 -                      n = 0;
 -                      p = nil;
 -                      if(!runtime·mlookup(b, &p, &n, nil) || b != p || i > n) {
 -                              runtime·printf("runtime: scanned (%p,%p), heap object (%p,%p)\n", b, i, p, n);
 -                              runtime·throw("scanblock: scanned invalid object");
 -                      }
 -              }
 +              // This might be a good place to add prefetch code...
 +              // if(wbuf->nobj > 4) {
 +              //         PREFETCH(wbuf->obj[wbuf->nobj - 3];
 +              //  }
 +              --wbuf->nobj;
 +              b = wbuf->obj[wbuf->nobj];
 +              wbuf = scanobject(b, runtime·mheap.arena_used - b, nil, wbuf);
        }
  }
  
@@@ -665,7 -484,7 +665,7 @@@ markroot(ParFor *desc, uint32 i
        void *p;
        uint32 status;
        bool restart;
 -
 + 
        USED(&desc);
        // Note: if you add a case here, please also update heapdump.c:dumproots.
        switch(i) {
                        s = runtime·work.spans[spanidx];
                        if(s->state != MSpanInUse)
                                continue;
 -                      if(s->sweepgen != sg) {
 +                      if(!checkmark && s->sweepgen != sg) { 
 +                              // sweepgen was updated (+2) during non-checkmark GC pass
                                runtime·printf("sweep %d %d\n", s->sweepgen, sg);
                                runtime·throw("gc: unswept span");
                        }
                                spf = (SpecialFinalizer*)sp;
                                // A finalizer can be set for an inner byte of an object, find object beginning.
                                p = (void*)((s->start << PageShift) + spf->special.offset/s->elemsize*s->elemsize);
 -                              scanblock(p, s->elemsize, nil);
 +                              if(runtime·gcphase != GCscan)
 +                                      scanblock(p, s->elemsize, nil); // Scanned during mark phase
                                scanblock((void*)&spf->fn, PtrSize, oneptr);
                        }
                }
                break;
  
        case RootFlushCaches:
 -              flushallmcaches();
 +              if (runtime·gcphase != GCscan) // Do not flush mcaches during GCscan phase.
 +                      flushallmcaches();
                break;
  
        default:
                gp = runtime·allg[i - RootCount];
                // remember when we've first observed the G blocked
                // needed only to output in traceback
 -              status = runtime·readgstatus(gp);
 +              status = runtime·readgstatus(gp); // We are not in a scan state
                if((status == Gwaiting || status == Gsyscall) && gp->waitsince == 0)
                        gp->waitsince = runtime·work.tstart;
 -              // Shrink a stack if not much of it is being used.
 -              runtime·shrinkstack(gp);
 -              if(runtime·readgstatus(gp) == Gdead) 
 +              // Shrink a stack if not much of it is being used but not in the scan phase.
 +              if (runtime·gcphase != GCscan) // Do not shrink during GCscan phase.
 +                      runtime·shrinkstack(gp);
 +              if(runtime·readgstatus(gp) == Gdead)
                        gp->gcworkdone = true;
                else 
                        gp->gcworkdone = false; 
                restart = runtime·stopg(gp);
 -              scanstack(gp);
 +
 +              // goroutine will scan its own stack when it stops running.
 +              // Wait until it has.
 +              while(runtime·readgstatus(gp) == Grunning && !gp->gcworkdone) {
 +              }
 +
 +              // scanstack(gp) is done as part of gcphasework
 +              // But to make sure we finished we need to make sure that
 +              // the stack traps have all responded so drop into
 +              // this while loop until they respond.
 +              while(!gp->gcworkdone){
 +                      status = runtime·readgstatus(gp);
 +                      if(status == Gdead) {
 +                              gp->gcworkdone = true; // scan is a noop
 +                              break;
 +                              //do nothing, scan not needed. 
 +                      }
 +                      if(status == Gwaiting || status == Grunnable)
 +                              restart = runtime·stopg(gp);
 +              }
                if(restart)
                        runtime·restartg(gp);
                break;
  static Workbuf*
  getempty(Workbuf *b)
  {
 -      MCache *c;
 -
 -      if(b != nil)
 -              runtime·lfstackpush(&runtime·work.full, &b->node);
 -      b = nil;
 -      c = g->m->mcache;
 -      if(c->gcworkbuf != nil) {
 -              b = c->gcworkbuf;
 -              c->gcworkbuf = nil;
 +      if(b != nil) {
 +              putfull(b);
 +              b = nil;
        }
 -      if(b == nil)
 +      if(runtime·work.empty)
                b = (Workbuf*)runtime·lfstackpop(&runtime·work.empty);
 -      if(b == nil)
 +
 +      if(b && b->nobj != 0) {
 +              runtime·printf("m%d: getempty: popped b=%p with non-zero b->nobj=%d\n", g->m->id, b, (uint32)b->nobj);
 +              runtime·throw("getempty: workbuffer not empty, b->nobj not 0");
 +      }
 +      if(b == nil) {
                b = runtime·persistentalloc(sizeof(*b), CacheLineSize, &mstats.gc_sys);
 -      b->nobj = 0;
 +              b->nobj = 0;
 +      }
        return b;
  }
  
  static void
  putempty(Workbuf *b)
  {
 -      MCache *c;
 -
 -      c = g->m->mcache;
 -      if(c->gcworkbuf == nil) {
 -              c->gcworkbuf = b;
 -              return;
 +      if(b->nobj != 0) {
 +              runtime·throw("putempty: b->nobj not 0\n");
        }
        runtime·lfstackpush(&runtime·work.empty, &b->node);
  }
  
 -void
 -runtime·gcworkbuffree(void *b)
 +// Put a full or partially full workbuf on the full list.
 +static void
 +putfull(Workbuf *b)
  {
 -      if(b != nil)
 -              putempty(b);
 +      if(b->nobj <= 0) {
 +              runtime·throw("putfull: b->nobj <= 0\n");
 +      }
 +      runtime·lfstackpush(&runtime·work.full, &b->node);
  }
  
 -// Get a full work buffer off the work.full list, or return nil.
 +// Get an partially empty work buffer
 +// if none are available get an empty one.
 +static Workbuf*
 +getpartialorempty(void)
 +{
 +      Workbuf *b;
 +
 +      b = (Workbuf*)runtime·lfstackpop(&runtime·work.partial);
 +      if(b == nil)
 +              b = getempty(nil);
 +      return b;
 +}
 +
 +static void
 +putpartial(Workbuf *b)
 +{
 +
 +      if(b->nobj == 0)
 +              runtime·lfstackpush(&runtime·work.empty, &b->node);
 +      else if (b->nobj < nelem(b->obj))
 +              runtime·lfstackpush(&runtime·work.partial, &b->node);
 +      else if (b->nobj == nelem(b->obj))
 +              runtime·lfstackpush(&runtime·work.full, &b->node);
 +      else {
 +              runtime·printf("b=%p, b->nobj=%d, nelem(b->obj)=%d\n", b, (uint32)b->nobj, (uint32)nelem(b->obj));
 +              runtime·throw("putpartial: bad Workbuf b->nobj");
 +      }
 +}
 +
 +// Get a full work buffer off the work.full or a partially
 +// filled one off the work.partial list. If nothing is available
 +// wait until all the other gc helpers have finished and then
 +// return nil.
 +// getfull acts as a barrier for work.nproc helpers. As long as one
 +// gchelper is actively marking objects it
 +// may create a workbuffer that the other helpers can work on.
 +// The for loop either exits when a work buffer is found
 +// or when _all_ of the work.nproc GC helpers are in the loop 
 +// looking for work and thus not capable of creating new work.
 +// This is in fact the termination condition for the STW mark 
 +// phase.
  static Workbuf*
  getfull(Workbuf *b)
  {
        int32 i;
  
        if(b != nil)
 -              runtime·lfstackpush(&runtime·work.empty, &b->node);
 +              putempty(b);
 +
        b = (Workbuf*)runtime·lfstackpop(&runtime·work.full);
 +      if(b==nil)
 +              b = (Workbuf*)runtime·lfstackpop(&runtime·work.partial);
        if(b != nil || runtime·work.nproc == 1)
                return b;
  
                if(runtime·work.full != 0) {
                        runtime·xadd(&runtime·work.nwait, -1);
                        b = (Workbuf*)runtime·lfstackpop(&runtime·work.full);
 -                      if(b != nil)
 +                      if(b==nil)
 +                              b = (Workbuf*)runtime·lfstackpop(&runtime·work.partial);
 +                      if(b != nil) 
                                return b;
                        runtime·xadd(&runtime·work.nwait, +1);
                }
@@@ -985,7 -737,7 +985,7 @@@ scanframe(Stkframe *frame, void *unused
                        }
                        bv = runtime·stackmapdata(stackmap, pcdata);
                }
 -              scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata);
 +              scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata);
        }
        return true;
  }
@@@ -1008,7 -760,8 +1008,7 @@@ scanstack(G *gp
        case Gdead:
                return;
        case Grunning:
 -              runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
 -              runtime·throw("mark - world not stopped");
 +              runtime·throw("scanstack: - goroutine not stopped");
        case Grunnable:
        case Gsyscall:
        case Gwaiting:
                runtime·throw("can't scan gchelper stack");
  
        fn = scanframe;
-       runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, false);
+       runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, 0);
        runtime·tracebackdefers(gp, &fn, nil);
  }
  
 -// The gp has been moved to a gc safepoint. If there is gcphase specific
 -// work it is done here. 
 +// If the slot is grey or black return true, if white return false.
 +// If the slot is not in the known heap and thus does not have a valid GC bitmap then
 +// it is considered grey. Globals and stacks can hold such slots.
 +// The slot is grey if its mark bit is set and it is enqueued to be scanned.
 +// The slot is black if it has already been scanned.
 +// It is white if it has a valid mark bit and the bit is not set. 
 +static bool
 +shaded(byte *slot)
 +{
 +      Markbits mbits;
 +      byte *valid;
 +
 +      if(!inheap(slot)) // non-heap slots considered grey
 +              return true;
 +
 +      valid = objectstart(slot, &mbits);
 +      if(valid == nil)
 +              return true;
 +
 +      if(checkmark)
 +              return ischeckmarked(&mbits);
 +
 +      return (mbits.bits&bitMarked) != 0;
 +}
 +
 +// Shade the object if it isn't already.
 +// The object is not nil and known to be in the heap.
 +static void
 +shade(byte *b)
 +{
 +      byte *obj;
 +      Workbuf *wbuf;
 +      Markbits mbits;
 +      
 +      if(!inheap(b))
 +              runtime·throw("shade: passed an address not in the heap");
 +      
 +      wbuf = getpartialorempty();
 +      // Mark the object, return some important bits.
 +      // If we combine the following two rotines we don't have to pass mbits or obj around.
 +      obj = objectstart(b, &mbits);
 +      if(obj != nil)
 +              wbuf = greyobject(obj, &mbits, wbuf); // augments the wbuf
 +
 +      putpartial(wbuf);
 +      return;
 +}
 +
 +// This is the Dijkstra barrier coarsened to always shade the ptr (dst) object.
 +// The original Dijkstra barrier only shaded ptrs being placed in black slots.
 +//
 +// Shade indicates that it has seen a white pointer by adding the referent
 +// to wbuf as well as marking it.
 +//
 +// slot is the destination (dst) in go code
 +// ptr is the value that goes into the slot (src) in the go code
 +//
 +// Dijkstra pointed out that maintaining the no black to white
 +// pointers means that white to white pointers not need 
 +// to be noted by the write barrier. Furthermore if either 
 +// white object dies before it is reached by the 
 +// GC then the object can be collected during this GC cycle 
 +// instead of waiting for the next cycle. Unfortunately the cost of 
 +// ensure that the object holding the slot doesn't concurrently
 +// change to black without the mutator noticing seems prohibitive.
 +//
 +// Consider the following example where the mutator writes into 
 +// a slot and then loads the slot's mark bit while the GC thread 
 +// writes to the slot's mark bit and then as part of scanning reads 
 +// the slot.
 +// 
 +// Initially both [slot] and [slotmark] are 0 (nil)
 +// Mutator thread          GC thread
 +// st [slot], ptr          st [slotmark], 1
 +// 
 +// ld r1, [slotmark]       ld r2, [slot]
 +//
 +// This is a classic example of independent reads of independent writes,
 +// aka IRIW. The question is if r1==r2==0 is allowed and for most HW the 
 +// answer is yes without inserting a memory barriers between the st and the ld. 
 +// These barriers are expensive so we have decided that we will 
 +// always grey the ptr object regardless of the slot's color.
 +// 
 +void
 +runtime·gcmarkwb_m()
 +{
 +      byte *ptr;
 +      ptr = (byte*)g->m->scalararg[1];
 +
 +      switch(runtime·gcphase) {
 +      default:
 +              runtime·throw("gcphasework in bad gcphase");
 +      case GCoff:
 +      case GCquiesce:
 +      case GCstw:
 +      case GCsweep:
 +      case GCscan:
 +              break;
 +      case GCmark:
 +              if(ptr != nil && inheap(ptr))
 +                      shade(ptr);
 +              break;
 +      case GCmarktermination:
 +              if(ptr != nil && inheap(ptr))
 +                      shade(ptr);
 +              break;
 +      }
 +}
 +
 +// The gp has been moved to a GC safepoint. GC phase specific
 +// work is done here. 
  void
  runtime·gcphasework(G *gp)
  {
        case GCquiesce:
        case GCstw:
        case GCsweep:
 -              // No work for now.
 +              // No work.
 +              break;
 +      case GCscan:
 +              // scan the stack, mark the objects, put pointers in work buffers
 +              // hanging off the P where this is being run.
 +              scanstack(gp);
                break;
        case GCmark:
 -              // Disabled until concurrent GC is implemented
 -              // but indicate the scan has been done. 
 -              // scanstack(gp);
 +              break;
 +      case GCmarktermination:
 +              scanstack(gp);
 +              // All available mark work will be emptied before returning.
                break;
        }
        gp->gcworkdone = true;
@@@ -1247,7 -885,6 +1247,7 @@@ runtime·iterate_finq(void (*callback)(
        }
  }
  
 +// Returns only when span s has been swept.
  void
  runtime·MSpan_EnsureSwept(MSpan *s)
  {
        sg = runtime·mheap.sweepgen;
        if(runtime·atomicload(&s->sweepgen) == sg)
                return;
 +      // The caller must be sure that the span is a MSpanInUse span.
        if(runtime·cas(&s->sweepgen, sg-2, sg-1)) {
                runtime·MSpan_Sweep(s, false);
                return;
@@@ -1290,9 -926,6 +1290,9 @@@ runtime·MSpan_Sweep(MSpan *s, bool pre
        Special *special, **specialp, *y;
        bool res, sweepgenset;
  
 +      if(checkmark)
 +              runtime·throw("MSpan_Sweep: checkmark only runs in STW and after the sweep.");
 +
        // It's critical that we enter this function with preemption disabled,
        // GC must not start while we are in the middle of this function.
        if(g->m->locks == 0 && g->m->mallocing == 0 && g != g->m->g0)
@@@ -1540,7 -1173,6 +1540,7 @@@ runtime·gosweepdone(void
        return runtime·mheap.sweepdone;
  }
  
 +
  void
  runtime·gchelper(void)
  {
        g->m->traceback = 2;
        gchelperstart();
  
 -      // parallel mark for over gc roots
 +      // parallel mark for over GC roots
        runtime·parfordo(runtime·work.markfor);
 -
 -      // help other threads scan secondary blocks
 -      scanblock(nil, 0, nil);
 -
 -      nproc = runtime·work.nproc;  // runtime·work.nproc can change right after we increment runtime·work.ndone
 +      if(runtime·gcphase != GCscan) 
 +              scanblock(nil, 0, nil); // blocks in getfull
 +      nproc = runtime·work.nproc;  // work.nproc can change right after we increment work.ndone
        if(runtime·xadd(&runtime·work.ndone, +1) == nproc-1)
                runtime·notewakeup(&runtime·work.alldone);
        g->m->traceback = 0;
@@@ -1719,7 -1353,6 +1719,7 @@@ runtime·gcinit(void
        runtime·gcbssmask = unrollglobgcprog(runtime·gcbss, runtime·ebss - runtime·bss);
  }
  
 +// Called from malloc.go using onM, stopping and starting the world handled in caller.
  void
  runtime·gc_m(void)
  {
        a.start_time = (uint64)(g->m->scalararg[0]) | ((uint64)(g->m->scalararg[1]) << 32);
        a.eagersweep = g->m->scalararg[2];
        gc(&a);
 +      runtime·casgstatus(gp, Gwaiting, Grunning);
 +}
 +
 +// Similar to clearcheckmarkbits but works on a single span. 
 +// It preforms two tasks. 
 +// 1. When used before the checkmark phase it converts BitsDead (00) to bitsScalar (01)
 +//    for nibbles with the BoundaryBit set.
 +// 2. When used after the checkmark phase it converts BitsPointerMark (11) to BitsPointer 10 and 
 +//    BitsScalarMark (00) to BitsScalar (01), thus clearing the checkmark mark encoding.
 +// For the second case it is possible to restore the BitsDead pattern but since
 +// clearmark is a debug tool performance has a lower priority than simplicity.
 +// The span is MSpanInUse and the world is stopped.
 +static void
 +clearcheckmarkbitsspan(MSpan *s)
 +{
 +      int32 cl, n, npages, i;
 +      uintptr size, off, step;
 +      byte *p, *bitp, *arena_start, b;
 +
 +      if(s->state != MSpanInUse) {
 +              runtime·printf("runtime:clearcheckmarkbitsspan: state=%d\n",
 +                      s->state);
 +              runtime·throw("clearcheckmarkbitsspan: bad span state");
 +      }
 +      arena_start = runtime·mheap.arena_start;
 +      cl = s->sizeclass;
 +      size = s->elemsize;
 +      if(cl == 0) {
 +              n = 1;
 +      } else {
 +              // Chunk full of small blocks.
 +              npages = runtime·class_to_allocnpages[cl];
 +              n = (npages << PageShift) / size;
 +      }
  
 -      if(nbadblock > 0) {
 -              // Work out path from root to bad block.
 -              for(;;) {
 -                      gc(&a);
 -                      if(nbadblock >= nelem(badblock))
 -                              runtime·throw("cannot find path to bad pointer");
 +      // MSpan_Sweep has similar code but instead of overloading and 
 +      // complicating that routine we do a simpler walk here.
 +      // Sweep through n objects of given size starting at p.
 +      // This thread owns the span now, so it can manipulate
 +      // the block bitmap without atomic operations.
 +      p = (byte*)(s->start << PageShift);
 +      // Find bits for the beginning of the span.
 +      off = (uintptr*)p - (uintptr*)arena_start;
 +      bitp = arena_start - off/wordsPerBitmapByte - 1;
 +      step = size/(PtrSize*wordsPerBitmapByte);
 +
 +      // The type bit values are:
 +      //      00 - BitsDead, for us BitsScalarMarked
 +      //      01 - BitsScalar
 +      //      10 - BitsPointer
 +      //      11 - unused, for us BitsPointerMarked
 +      //
 +      // When called to prepare for the checkmark phase (checkmark==1),
 +      // we change BitsDead to BitsScalar, so that there are no BitsScalarMarked
 +      // type bits anywhere.
 +      //
 +      // The checkmark phase marks by changing BitsScalar to BitsScalarMarked
 +      // and BitsPointer to BitsPointerMarked.
 +      //
 +      // When called to clean up after the checkmark phase (checkmark==0),
 +      // we unmark by changing BitsScalarMarked back to BitsScalar and
 +      // BitsPointerMarked back to BitsPointer.
 +      //
 +      // There are two problems with the scheme as just described.
 +      // First, the setup rewrites BitsDead to BitsScalar, but the type bits
 +      // following a BitsDead are uninitialized and must not be used.
 +      // Second, objects that are free are expected to have their type
 +      // bits zeroed (BitsDead), so in the cleanup we need to restore
 +      // any BitsDeads that were there originally.
 +      //
 +      // In a one-word object (8-byte allocation on 64-bit system),
 +      // there is no difference between BitsScalar and BitsDead, because
 +      // neither is a pointer and there are no more words in the object,
 +      // so using BitsScalar during the checkmark is safe and mapping
 +      // both back to BitsDead during cleanup is also safe.
 +      //
 +      // In a larger object, we need to be more careful. During setup,
 +      // if the type of the first word is BitsDead, we change it to BitsScalar
 +      // (as we must) but also initialize the type of the second
 +      // word to BitsDead, so that a scan during the checkmark phase
 +      // will still stop before seeing the uninitialized type bits in the
 +      // rest of the object. The sequence 'BitsScalar BitsDead' never
 +      // happens in real type bitmaps - BitsDead is always as early
 +      // as possible, so immediately after the last BitsPointer.
 +      // During cleanup, if we see a BitsScalar, we can check to see if it
 +      // is followed by BitsDead. If so, it was originally BitsDead and
 +      // we can change it back.
 +
 +      if(step == 0) {
 +              // updating top and bottom nibbles, all boundaries
 +              for(i=0; i<n/2; i++, bitp--) {
 +                      if((*bitp & bitBoundary) != bitBoundary)
 +                              runtime·throw("missing bitBoundary");      
 +                      b = (*bitp & bitPtrMask)>>2;
 +                      if(!checkmark && (b == BitsScalar || b == BitsScalarMarked))
 +                              *bitp &= ~0x0c; // convert to BitsDead
 +                      else if(b == BitsScalarMarked || b == BitsPointerMarked)
 +                              *bitp ^= BitsCheckMarkXor<<2;
 +                      
 +                      if(((*bitp>>gcBits) & bitBoundary) != bitBoundary)
 +                              runtime·throw("missing bitBoundary");            
 +                      b = ((*bitp>>gcBits) & bitPtrMask)>>2;
 +                      if(!checkmark && (b == BitsScalar || b == BitsScalarMarked))
 +                              *bitp &= ~0xc0; // convert to BitsDead
 +                      else if(b == BitsScalarMarked || b == BitsPointerMarked)
 +                              *bitp ^= BitsCheckMarkXor<<(2+gcBits);
 +              }
 +      } else {
 +              // updating bottom nibble for first word of each object
 +              for(i=0; i<n; i++, bitp -= step) {
 +                      if((*bitp & bitBoundary) != bitBoundary)
 +                              runtime·throw("missing bitBoundary");            
 +                      b = (*bitp & bitPtrMask)>>2;
 +                      
 +                      if(checkmark && b == BitsDead) {
 +                              // move BitsDead into second word.
 +                              // set bits to BitsScalar in preparation for checkmark phase.
 +                              *bitp &= ~0xc0;
 +                              *bitp |= BitsScalar<<2;
 +                      } else if(!checkmark && (b == BitsScalar || b == BitsScalarMarked) && (*bitp & 0xc0) == 0) {
 +                              // Cleaning up after checkmark phase.
 +                              // First word is scalar or dead (we forgot)
 +                              // and second word is dead.
 +                              // First word might as well be dead too.
 +                              *bitp &= ~0x0c;
 +                      } else if(b == BitsScalarMarked || b == BitsPointerMarked)
 +                              *bitp ^= BitsCheckMarkXor<<2;
                }
        }
 +}
  
 -      runtime·casgstatus(gp, Gwaiting, Grunning);
 +// clearcheckmarkbits preforms two tasks.
 +// 1. When used before the checkmark phase it converts BitsDead (00) to bitsScalar (01)
 +//    for nibbles with the BoundaryBit set.
 +// 2. When used after the checkmark phase it converts BitsPointerMark (11) to BitsPointer 10 and 
 +//    BitsScalarMark (00) to BitsScalar (01), thus clearing the checkmark mark encoding.
 +// This is a bit expensive but preserves the BitsDead encoding during the normal marking.
 +// BitsDead remains valid for every nibble except the ones with BitsBoundary set.
 +static void
 +clearcheckmarkbits(void)
 +{
 +      uint32 idx;
 +      MSpan *s;
 +      for(idx=0; idx<runtime·work.nspan; idx++) {
 +              s = runtime·work.spans[idx];
 +              if(s->state == MSpanInUse) {
 +                      clearcheckmarkbitsspan(s);
 +              }
 +      }
 +}
 +
 +// Called from malloc.go using onM. 
 +// The world is stopped. Rerun the scan and mark phases
 +// using the bitMarkedCheck bit instead of the
 +// bitMarked bit. If the marking encounters an
 +// bitMarked bit that is not set then we throw.
 +void
 +runtime·gccheckmark_m(void)
 +{
 +      if(!gccheckmarkenable)
 +              return;
 +
 +      if(checkmark)
 +              runtime·throw("gccheckmark_m, entered with checkmark already true.");
 +
 +      checkmark = true;
 +      clearcheckmarkbits(); // Converts BitsDead to BitsScalar.
 +      runtime·gc_m(); // turns off checkmark
 +      // Work done, fixed up the GC bitmap to remove the checkmark bits.
 +      clearcheckmarkbits();
 +}
 +
 +// checkmarkenable is initially false
 +void
 +runtime·gccheckmarkenable_m(void)
 +{
 +      gccheckmarkenable = true;
 +}
 +
 +void
 +runtime·gccheckmarkdisable_m(void)
 +{
 +      gccheckmarkenable = false;
 +}
 +
 +void
 +runtime·finishsweep_m(void)
 +{
 +      uint32 i, sg;
 +      MSpan *s;
 +
 +      // The world is stopped so we should be able to complete the sweeps 
 +      // quickly. 
 +      while(runtime·sweepone() != -1)
 +              runtime·sweep.npausesweep++;
 +
 +      // There may be some other spans being swept concurrently that 
 +      // we need to wait for. If finishsweep_m is done with the world stopped
 +      // this code is not required.
 +      sg = runtime·mheap.sweepgen;
 +      for(i=0; i<runtime·work.nspan; i++) {
 +              s = runtime·work.spans[i];
 +              if(s->sweepgen == sg) {
 +                      continue;
 +              }
 +              if(s->state != MSpanInUse) // Span is not part of the GCed heap so no need to ensure it is swept.
 +                      continue;
 +              runtime·MSpan_EnsureSwept(s);
 +      }       
 +}
 +
 +// Scan all of the stacks, greying (or graying if in America) the referents
 +// but not blackening them since the mark write barrier isn't installed.
 +void
 +runtime·gcscan_m(void)
 +{
 +      uint32 i, allglen, oldphase;
 +      G *gp, *mastergp, **allg;
 +
 +      // Grab the g that called us and potentially allow rescheduling.
 +      // This allows it to be scanned like other goroutines.
 +      mastergp = g->m->curg;
 +
 +      runtime·casgstatus(mastergp, Grunning, Gwaiting);
 +      mastergp->waitreason = runtime·gostringnocopy((byte*)"garbage collection scan");
 +
 +      // Span sweeping has been done by finishsweep_m.
 +      // Long term we will want to make this goroutine runnable 
 +      // by placing it onto a scanenqueue state and then calling 
 +      // runtime·restartg(mastergp) to make it Grunnable.  
 +      // At the bottom we will want to return this p back to the scheduler.
 +
 +      oldphase = runtime·gcphase;
 +
 +      runtime·lock(&runtime·allglock);
 +      allglen = runtime·allglen;
 +      allg = runtime·allg;
 +      // Prepare flag indicating that the scan has not been completed.
 +      for(i = 0; i < allglen; i++) {
 +              gp = allg[i];
 +              gp->gcworkdone = false;  // set to true in gcphasework
 +      }
 +      runtime·unlock(&runtime·allglock);
 +
 +      runtime·work.nwait = 0;
 +      runtime·work.ndone = 0;
 +      runtime·work.nproc = 1; // For now do not do this in parallel.
 +      runtime·gcphase = GCscan;
 +      //      ackgcphase is not needed since we are not scanning running goroutines.
 +      runtime·parforsetup(runtime·work.markfor, runtime·work.nproc, RootCount + allglen, nil, false, markroot);
 +      runtime·parfordo(runtime·work.markfor);
 +      
 +      runtime·lock(&runtime·allglock);      
 +
 +      allg = runtime·allg;
 +      // Check that gc work is done. 
 +      for(i = 0; i < allglen; i++) {
 +              gp = allg[i];
 +              if(!gp->gcworkdone) {
 +                      runtime·throw("scan missed a g");
 +              }
 +      }
 +      runtime·unlock(&runtime·allglock);
 +
 +      runtime·gcphase = oldphase;
 +      runtime·casgstatus(mastergp, Gwaiting, Grunning);
 +      // Let the g that called us continue to run.
 +}
 +
 +// Mark all objects that are known about.
 +void
 +runtime·gcmark_m(void)
 +{
 +      scanblock(nil, 0, nil);
 +}
 +
 +// For now this must be bracketed with a stoptheworld and a starttheworld to ensure
 +// all go routines see the new barrier.
 +void
 +runtime·gcinstallmarkwb_m(void)
 +{
 +      runtime·gcphase = GCmark;
 +}
 +
 +// For now this must be bracketed with a stoptheworld and a starttheworld to ensure
 +// all go routines see the new barrier.
 +void
 +runtime·gcinstalloffwb_m(void)
 +{
 +      runtime·gcphase = GCoff;
  }
  
  static void
@@@ -2031,9 -1385,9 +2031,9 @@@ gc(struct gc_args *args
        int64 t0, t1, t2, t3, t4;
        uint64 heap0, heap1, obj;
        GCStats stats;
 -
 -      if(DebugPtrs)
 -              runtime·printf("GC start\n");
 +      uint32 oldphase;
 +      uint32 i;
 +      G *gp;
  
        if(runtime·debug.allocfreetrace)
                runtime·tracegc();
        if(runtime·debug.gctrace)
                t1 = runtime·nanotime();
  
 -      // Sweep what is not sweeped by bgsweep.
 -      while(runtime·sweepone() != -1)
 -              runtime·sweep.npausesweep++;
 +      if(!checkmark)
 +              runtime·finishsweep_m(); // skip during checkmark debug phase.
  
 -      // Cache runtime.mheap.allspans in work.spans to avoid conflicts with
 +      // Cache runtime·mheap.allspans in work.spans to avoid conflicts with
        // resizing/freeing allspans.
        // New spans can be created while GC progresses, but they are not garbage for
        // this round:
        runtime·work.spans = runtime·mheap.allspans;
        runtime·work.nspan = runtime·mheap.nspan;
        runtime·unlock(&runtime·mheap.lock);
 +      oldphase = runtime·gcphase;
  
        runtime·work.nwait = 0;
        runtime·work.ndone = 0;
 -      runtime·work.nproc = runtime·gcprocs();
 +      runtime·work.nproc = runtime·gcprocs(); 
 +      runtime·gcphase = GCmarktermination;
 +
 +      // World is stopped so allglen will not change.
 +      for(i = 0; i < runtime·allglen; i++) {
 +              gp = runtime·allg[i];
 +              gp->gcworkdone = false;  // set to true in gcphasework
 +      }
 +
        runtime·parforsetup(runtime·work.markfor, runtime·work.nproc, RootCount + runtime·allglen, nil, false, markroot);
        if(runtime·work.nproc > 1) {
                runtime·noteclear(&runtime·work.alldone);
  
        gchelperstart();
        runtime·parfordo(runtime·work.markfor);
 +
        scanblock(nil, 0, nil);
  
 +      if(runtime·work.full)
 +              runtime·throw("runtime·work.full != nil");
 +      if(runtime·work.partial)
 +              runtime·throw("runtime·work.partial != nil");
 +
 +      runtime·gcphase = oldphase;
        t3 = 0;
        if(runtime·debug.gctrace)
                t3 = runtime·nanotime();
        // Free the old cached mark array if necessary.
        if(runtime·work.spans != nil && runtime·work.spans != runtime·mheap.allspans)
                runtime·SysFree(runtime·work.spans, runtime·work.nspan*sizeof(runtime·work.spans[0]), &mstats.other_sys);
 +      
 +      if(gccheckmarkenable) {
 +              if(!checkmark) {
 +                      // first half of two-pass; don't set up sweep
 +                      runtime·unlock(&runtime·mheap.lock);
 +                      return;
 +              }
 +              checkmark = false; // done checking marks
 +      }
 +
        // Cache the current array for sweeping.
        runtime·mheap.gcspans = runtime·mheap.allspans;
        runtime·mheap.sweepgen += 2;
        runtime·sweep.spanidx = 0;
        runtime·unlock(&runtime·mheap.lock);
  
 +
        if(ConcurrentSweep && !args->eagersweep) {
                runtime·lock(&runtime·gclock);
                if(runtime·sweep.g == nil)
  
        runtime·mProf_GC();
        g->m->traceback = 0;
 -
 -      if(DebugPtrs)
 -              runtime·printf("GC end\n");
  }
  
  extern uintptr runtime·sizeof_C_MStats;
@@@ -2453,7 -1784,7 +2453,7 @@@ runtime·unrollgcprog_m(void
        Type *typ;
        byte *mask, *prog;
        uintptr pos;
 -      uint32 x;
 +      uintptr x;
  
        typ = g->m->ptrarg[0];
        g->m->ptrarg[0] = nil;
                        prog = (byte*)typ->gc[1];
                        unrollgcprog1(mask, prog, &pos, false, true);
                }
 +
                // atomic way to say mask[0] = 1
 -              x = ((uint32*)mask)[0];
 -              runtime·atomicstore((uint32*)mask, x|1);
 +              x = *(uintptr*)mask;
 +              ((byte*)&x)[0] = 1;
 +              runtime·atomicstorep((void**)mask, (void*)x);
        }
        runtime·unlock(&lock);
  }
@@@ -2635,7 -1964,7 +2635,7 @@@ runtime·getgcmask(byte *p, Type *t, by
        frame.fn = nil;
        frame.sp = (uintptr)p;
        cb = getgcmaskcb;
-       runtime·gentraceback(g->m->curg->sched.pc, g->m->curg->sched.sp, 0, g->m->curg, 0, nil, 1000, &cb, &frame, false);
+       runtime·gentraceback(g->m->curg->sched.pc, g->m->curg->sched.sp, 0, g->m->curg, 0, nil, 1000, &cb, &frame, 0);
        if(frame.fn != nil) {
                Func *f;
                StackMap *stackmap;
diff --combined src/runtime/proc.c
index c1df40d02ff741490f8fe338a474839dae2c476b,91e3fe16d69ce1fb1b7c2efb7d8c70a4b20be8da..ce39db4abb40c63c233fe3af8c3c082ae75e9e5b
@@@ -423,7 -423,13 +423,7 @@@ runtime·casgstatus(G *gp, uint32 oldva
        // loop if gp->atomicstatus is in a scan state giving
        // GC time to finish and change the state to oldval.
        while(!runtime·cas(&gp->atomicstatus, oldval, newval)) {
 -              // Help GC if needed. 
 -              if(gp->preemptscan && !gp->gcworkdone && (oldval == Grunning || oldval == Gsyscall)) {
 -                      gp->preemptscan = false;
 -                      g->m->ptrarg[0] = gp;
 -                      fn = helpcasgstatus;
 -                      runtime·onM(&fn);
 -              }
 +
        }       
  }
  
@@@ -498,13 -504,6 +498,13 @@@ runtime·stopg(G *gp
                        return false;
  
                case Grunning:
 +                      if(runtime·gcphase == GCscan) {
 +                              gp->gcworkdone = true;
 +                              return false;
 +                              // Running routines not scanned during
 +                              // GCscan phase, we only scan non-running routines.
 +                      }
 +                              
                        // Claim goroutine, so we aren't racing with a status
                        // transition away from Grunning.
                        if(!runtime·castogscanstatus(gp, Grunning, Gscanrunning))
@@@ -582,10 -581,9 +582,10 @@@ mquiesce(G *gpmaster
        uint32 status;
        uint32 activeglen;
  
 -      activeglen = runtime·allglen;
        // enqueue the calling goroutine.
        runtime·restartg(gpmaster);
 +
 +      activeglen = runtime·allglen;
        for(i = 0; i < activeglen; i++) {
                gp = runtime·allg[i];
                if(runtime·readgstatus(gp) == Gdead) 
@@@ -876,9 -874,7 +876,9 @@@ runtime·allocm(P *p
                mp->g0 = runtime·malg(-1);
        else
                mp->g0 = runtime·malg(8192);
 +      runtime·writebarrierptr_nostore(&mp->g0, mp->g0);
        mp->g0->m = mp;
 +      runtime·writebarrierptr_nostore(&mp->g0->m, mp->g0->m);
  
        if(p == g->m->p)
                releasep();
@@@ -994,7 -990,7 +994,7 @@@ runtime·newextram(void
        // the goroutine stack ends.
        mp = runtime·allocm(nil);
        gp = runtime·malg(4096);
-       gp->sched.pc = (uintptr)runtime·goexit;
+       gp->sched.pc = (uintptr)runtime·goexit + PCQuantum;
        gp->sched.sp = gp->stack.hi;
        gp->sched.sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
        gp->sched.lr = 0;
@@@ -1062,7 -1058,7 +1062,7 @@@ runtime·dropm(void
        unlockextra(mp);
  }
  
 -#define MLOCKED ((M*)1)
 +#define MLOCKED 1
  
  // lockextra locks the extra list and returns the list head.
  // The caller must unlock the list by storing a new list head
  static M*
  lockextra(bool nilokay)
  {
 -      M *mp;
 +      uintptr mpx;
        void (*yield)(void);
  
        for(;;) {
 -              mp = runtime·atomicloadp(&runtime·extram);
 -              if(mp == MLOCKED) {
 +              mpx = runtime·atomicloaduintptr((uintptr*)&runtime·extram);
 +              if(mpx == MLOCKED) {
                        yield = runtime·osyield;
                        yield();
                        continue;
                }
 -              if(mp == nil && !nilokay) {
 +              if(mpx == 0 && !nilokay) {
                        runtime·usleep(1);
                        continue;
                }
 -              if(!runtime·casp(&runtime·extram, mp, MLOCKED)) {
 +              if(!runtime·casuintptr((uintptr*)&runtime·extram, mpx, MLOCKED)) {
                        yield = runtime·osyield;
                        yield();
                        continue;
                }
                break;
        }
 -      return mp;
 +      return (M*)mpx;
  }
  
  #pragma textflag NOSPLIT
@@@ -1647,12 -1643,10 +1647,10 @@@ runtime·gosched_m(G *gp
  }
  
  // Finishes execution of the current goroutine.
- // Need to mark it as nosplit, because it runs with sp > stackbase.
- // Since it does not return it does not matter.  But if it is preempted
- // at the split stack check, GC will complain about inconsistent sp.
+ // Must be NOSPLIT because it is called from Go.
  #pragma textflag NOSPLIT
  void
- runtime·goexit(void)
+ runtime·goexit1(void)
  {
        void (*fn)(G*);
  
@@@ -1921,7 -1915,6 +1919,7 @@@ exitsyscallfast(void
  
        // Freezetheworld sets stopwait but does not retake P's.
        if(runtime·sched.stopwait) {
 +              g->m->mcache = nil; 
                g->m->p = nil;
                return false;
        }
                return true;
        }
        // Try to get any other idle P.
 +      g->m->mcache = nil;
        g->m->p = nil;
        if(runtime·sched.pidle) {
                fn = exitsyscallfast_pidle;
@@@ -2130,7 -2122,7 +2128,7 @@@ runtime·newproc(int32 siz, FuncVal* fn
        byte *argp;
        void (*mfn)(void);
  
 -      if(thechar == '5')
 +      if(thechar == '5' || thechar == '9')
                argp = (byte*)(&fn+2);  // skip caller's saved LR
        else
                argp = (byte*)(&fn+1);
@@@ -2190,7 -2182,7 +2188,7 @@@ runtime·newproc1(FuncVal *fn, byte *ar
        sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
        sp -= siz;
        runtime·memmove(sp, argp, narg);
 -      if(thechar == '5') {
 +      if(thechar == '5' || thechar == '9') {
                // caller's LR
                sp -= sizeof(void*);
                *(void**)sp = nil;
  
        runtime·memclr((byte*)&newg->sched, sizeof newg->sched);
        newg->sched.sp = (uintptr)sp;
-       newg->sched.pc = (uintptr)runtime·goexit;
+       newg->sched.pc = (uintptr)runtime·goexit + PCQuantum; // +PCQuantum so that previous instruction is in same function
        newg->sched.g = newg;
        runtime·gostartcallfn(&newg->sched, fn);
        newg->gopc = (uintptr)callerpc;
@@@ -2432,9 -2424,10 +2430,10 @@@ static struct ProfState 
        int32 hz;
  } prof;
  
- static void System(void) {}
- static void ExternalCode(void) {}
- static void GC(void) {}
+ static void System(void) { System(); }
+ static void ExternalCode(void) { ExternalCode(); }
+ static void GC(void) { GC(); }
  extern void runtime·cpuproftick(uintptr*, int32);
  extern byte runtime·etext[];
  
@@@ -2538,7 -2531,7 +2537,7 @@@ runtime·sigprof(uint8 *pc, uint8 *sp, 
  
        n = 0;
        if(traceback)
-               n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, false);
+               n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, TraceTrap);
        if(!traceback || n <= 0) {
                // Normal traceback is impossible or has failed.
                // See if it falls into several common cases.
                        // Cgo, we can't unwind and symbolize arbitrary C code,
                        // so instead collect Go stack that leads to the cgo call.
                        // This is especially important on windows, since all syscalls are cgo calls.
-                       n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, stk, nelem(stk), nil, nil, false);
+                       n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, stk, nelem(stk), nil, nil, 0);
                }
  #ifdef GOOS_windows
                if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
                        // Libcall, i.e. runtime syscall on windows.
                        // Collect Go stack that leads to the call.
-                       n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, stk, nelem(stk), nil, nil, false);
+                       n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, stk, nelem(stk), nil, nil, 0);
                }
  #endif
                if(n == 0) {
@@@ -2622,8 -2615,6 +2621,8 @@@ runtime·setcpuprofilerate_m(void
  P *runtime·newP(void);
  
  // Change number of processors.  The world is stopped, sched is locked.
 +// gcworkbufs are not being modified by either the GC or 
 +// the write barrier code.
  static void
  procresize(int32 new)
  {
diff --combined src/runtime/runtime.h
index fec224390c9bd2a5d6492568d1b7f0cb5c28c4d6,977c4547dfbacf55f2627968e9c4d3fd39c72016..330ed429b9e5f9c8a41f171c8143e21ff9bad50a
@@@ -94,7 -94,6 +94,7 @@@ typedef       struct  PollDesc        PollDesc
  typedef       struct  DebugVars       DebugVars;
  typedef       struct  ForceGCState    ForceGCState;
  typedef       struct  Stack           Stack;
 +typedef struct  Workbuf         Workbuf;
  
  /*
   * Per-CPU declaration.
@@@ -305,7 -304,7 +305,7 @@@ struct     
        bool    paniconfault;   // panic (instead of crash) on unexpected fault address
        bool    preemptscan;    // preempted g does scan for GC
        bool    gcworkdone;     // debug: cleared at begining of gc work phase cycle, set by gcphasework, tested at end of cycle
 -      bool    throwsplit; // must not split stack
 +      bool    throwsplit;     // must not split stack
        int8    raceignore;     // ignore race detection events
        M*      m;              // for debuggers, but offset not hard-coded
        M*      lockedm;
@@@ -345,8 -344,6 +345,8 @@@ struct     
        int32   helpgc;
        bool    spinning;       // M is out of work and is actively looking for work
        bool    blocked;        // M is blocked on a Note
 +      bool    inwb;           // M is executing a write barrier
 +      int8    printlock;
        uint32  fastrand;
        uint64  ncgocall;       // number of cgo calls in total
        int32   ncgo;           // number of cgo calls currently in progress
@@@ -573,10 -570,9 +573,10 @@@ enum 
  #endif
  
  // Lock-free stack node.
 +// Also known to export_test.go.
  struct LFNode
  {
 -      LFNode  *next;
 +      uint64  next;
        uintptr pushcnt;
  };
  
@@@ -602,16 -598,6 +602,16 @@@ struct ParFo
        uint64 nsleep;
  };
  
 +enum {
 +      WorkbufSize     = 4*1024,
 +};
 +struct Workbuf
 +{
 +      LFNode  node; // must be first
 +      uintptr nobj;
 +      byte*   obj[(WorkbufSize-sizeof(LFNode)-sizeof(uintptr))/PtrSize];
 +};
 +
  // Track memory allocated by code not written in Go during a cgo call,
  // so that the garbage collector can see them.
  struct CgoMal
@@@ -634,14 -620,12 +634,14 @@@ struct DebugVar
  
  // Indicates to write barrier and sychronization task to preform.
  enum
 -{                   // Synchronization            Write barrier
 -      GCoff,      // stop and start             nop
 -      GCquiesce,  // stop and start             nop
 -      GCstw,      // stop the ps                nop
 -      GCmark,     // scan the stacks and start  no white to black
 -      GCsweep,    // stop and start             nop
 +{                               // Action               WB installation
 +      GCoff = 0,              // stop and start       no wb
 +      GCquiesce,              // stop and start       no wb
 +      GCstw,                  // stop the ps          nop
 +      GCscan,                 // scan the stacks prior to marking
 +      GCmark,                 // mark use wbufs from GCscan and globals, scan the stacks, then go to GCtermination
 +      GCmarktermination,      // mark termination detection. Allocate black, Ps help out GC
 +      GCsweep,                // stop and start       nop
  };
  
  struct ForceGCState
  };
  
  extern uint32 runtime·gcphase;
 +extern Mutex runtime·allglock;
  
  /*
   * defined macros
@@@ -683,7 -666,6 +683,7 @@@ enum 
  
  uint32  runtime·readgstatus(G*);
  void    runtime·casgstatus(G*, uint32, uint32);
 +bool    runtime·castogscanstatus(G*, uint32, uint32);
  void    runtime·quiesce(G*);
  bool    runtime·stopg(G*);
  void    runtime·restartg(G*);
@@@ -737,9 -719,15 +737,15 @@@ struct Stkfram
        BitVector*      argmap; // force use of this argmap
  };
  
- intgo runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, bool);
+ enum
+ {
+       TraceRuntimeFrames = 1<<0, // include frames for internal runtime functions.
+       TraceTrap = 1<<1, // the initial PC, SP are from a trap, not a return PC from a call
+ };
+ intgo runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, uintgo);
  void  runtime·tracebackdefers(G*, bool(**)(Stkframe*, void*), void*);
  void  runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
+ void  runtime·tracebacktrap(uintptr pc, uintptr sp, uintptr lr, G* gp);
  void  runtime·tracebackothers(G*);
  bool  runtime·haszeroargs(uintptr pc);
  bool  runtime·topofstack(Func*);
@@@ -894,7 -882,6 +900,7 @@@ int32      runtime·round2(int32 x); // roun
  bool  runtime·cas(uint32*, uint32, uint32);
  bool  runtime·cas64(uint64*, uint64, uint64);
  bool  runtime·casp(void**, void*, void*);
 +bool  runtime·casuintptr(uintptr*, uintptr, uintptr);
  // Don't confuse with XADD x86 instruction,
  // this one is actually 'addx', that is, add-and-fetch.
  uint32        runtime·xadd(uint32 volatile*, int32);
@@@ -1121,8 -1108,6 +1127,8 @@@ void    runtime·osyield(void)
  void  runtime·lockOSThread(void);
  void  runtime·unlockOSThread(void);
  
 +void  runtime·writebarrierptr_nostore(void*, void*);
 +
  bool  runtime·showframe(Func*, G*);
  void  runtime·printcreatedby(G*);
  
diff --combined src/runtime/stack.c
index a4947a53b3ec557bf690fc3a6a435ac6d401bb55,072bc242bc2a5d3cad6bd004a2d2011b17fd5f92..ffae73a2ab35a5452958cec473896ee269b0daae
@@@ -382,6 -382,8 +382,6 @@@ adjustpointers(byte **scanp, BitVector 
        uintptr delta;
        int32 num, i;
        byte *p, *minp, *maxp;
 -      Type *t;
 -      Itab *tab;
        
        minp = (byte*)adjinfo->old.lo;
        maxp = (byte*)adjinfo->old.hi;
                        }
                        break;
                case BitsMultiWord:
 -                      switch(bv->bytedata[(i+1) / (8 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 7) & 3) {
 -                      default:
 -                              runtime·throw("unexpected garbage collection bits");
 -                      case BitsEface:
 -                              t = (Type*)scanp[i];
 -                              if(t != nil && ((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0)) {
 -                                      p = scanp[i+1];
 -                                      if(minp <= p && p < maxp) {
 -                                              if(StackDebug >= 3)
 -                                                      runtime·printf("adjust eface %p\n", p);
 -                                              if(t->size > PtrSize) // currently we always allocate such objects on the heap
 -                                                      runtime·throw("large interface value found on stack");
 -                                              scanp[i+1] = p + delta;
 -                                      }
 -                              }
 -                              i++;
 -                              break;
 -                      case BitsIface:
 -                              tab = (Itab*)scanp[i];
 -                              if(tab != nil) {
 -                                      t = tab->type;
 -                                      //runtime·printf("          type=%p\n", t);
 -                                      if((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0) {
 -                                              p = scanp[i+1];
 -                                              if(minp <= p && p < maxp) {
 -                                                      if(StackDebug >= 3)
 -                                                              runtime·printf("adjust iface %p\n", p);
 -                                                      if(t->size > PtrSize) // currently we always allocate such objects on the heap
 -                                                              runtime·throw("large interface value found on stack");
 -                                                      scanp[i+1] = p + delta;
 -                                              }
 -                                      }
 -                              }
 -                              i++;
 -                              break;
 -                      }
 -                      break;
 +                      runtime·throw("adjustpointers: unexpected garbage collection bits");
                }
        }
  }
@@@ -549,13 -587,13 +549,13 @@@ adjustsudogs(G *gp, AdjustInfo *adjinfo
  }
  
  // Copies gp's stack to a new stack of a different size.
 +// Caller must have changed gp status to Gcopystack.
  static void
  copystack(G *gp, uintptr newsize)
  {
        Stack old, new;
        uintptr used;
        AdjustInfo adjinfo;
 -      uint32 oldstatus;
        bool (*cb)(Stkframe*, void*);
        byte *p, *ep;
  
        adjinfo.old = old;
        adjinfo.delta = new.hi - old.hi;
        cb = adjustframe;
-       runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, false);
+       runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, 0);
        
        // adjust other miscellaneous things that have pointers into stacks.
        adjustctxt(gp, &adjinfo);
        }
        runtime·memmove((byte*)new.hi - used, (byte*)old.hi - used, used);
  
 -      oldstatus = runtime·readgstatus(gp);
 -      oldstatus &= ~Gscan;
 -      if(oldstatus == Gwaiting || oldstatus == Grunnable)
 -              runtime·casgstatus(gp, oldstatus, Gcopystack); // oldstatus is Gwaiting or Grunnable
 -      else
 -              runtime·throw("copystack: bad status, not Gwaiting or Grunnable");
 -
        // Swap out old stack for new one
        gp->stack = new;
        gp->stackguard0 = new.lo + StackGuard; // NOTE: might clobber a preempt request
        gp->sched.sp = new.hi - used;
  
 -      runtime·casgstatus(gp, Gcopystack, oldstatus); // oldstatus is Gwaiting or Grunnable
 -
        // free old stack
        if(StackPoisonCopy) {
                p = (byte*)old.lo;
@@@ -653,7 -700,6 +653,7 @@@ voi
  runtime·newstack(void)
  {
        int32 oldsize, newsize;
 +      uint32 oldstatus;
        uintptr sp;
        G *gp;
        Gobuf morebuf;
                runtime·printf("runtime: split stack overflow: %p < %p\n", sp, gp->stack.lo);
                runtime·throw("runtime: split stack overflow");
        }
 +      
 +      if(gp->sched.ctxt != nil) {
 +              // morestack wrote sched.ctxt on its way in here,
 +              // without a write barrier. Run the write barrier now.
 +              // It is not possible to be preempted between then
 +              // and now, so it's okay.
 +              runtime·writebarrierptr_nostore(&gp->sched.ctxt, gp->sched.ctxt);
 +      }
  
        if(gp->stackguard0 == (uintptr)StackPreempt) {
                if(gp == g->m->g0)
                runtime·throw("stack overflow");
        }
  
 -      // Note that the concurrent GC might be scanning the stack as we try to replace it.
 -      // copystack takes care of the appropriate coordination with the stack scanner.
 +      oldstatus = runtime·readgstatus(gp);
 +      oldstatus &= ~Gscan;
 +      runtime·casgstatus(gp, oldstatus, Gcopystack); // oldstatus is Gwaiting or Grunnable
 +      // The concurrent GC will not scan the stack while we are doing the copy since
 +      // the gp is in a Gcopystack status.
        copystack(gp, newsize);
        if(StackDebug >= 1)
                runtime·printf("stack grow done\n");
 -      runtime·casgstatus(gp, Gwaiting, Grunning);
 +      runtime·casgstatus(gp, Gcopystack, Grunning);
        runtime·gogo(&gp->sched);
  }
  
@@@ -790,7 -825,6 +790,7 @@@ voi
  runtime·shrinkstack(G *gp)
  {
        uintptr used, oldsize, newsize;
 +      uint32 oldstatus;
  
        if(runtime·readgstatus(gp) == Gdead) {
                if(gp->stack.lo != 0) {
  #endif
        if(StackDebug > 0)
                runtime·printf("shrinking stack %D->%D\n", (uint64)oldsize, (uint64)newsize);
 +      // This is being done in a Gscan state and was initiated by the GC so no need to move to
 +      // the Gcopystate.
 +      // The world is stopped, so the goroutine must be Gwaiting or Grunnable,
 +      // and what it is is not changing underfoot.
 +
 +      oldstatus = runtime·readgstatus(gp);
 +      oldstatus &= ~Gscan;
 +      if(oldstatus != Gwaiting && oldstatus != Grunnable)
 +              runtime·throw("status is not Gwaiting or Grunnable");
 +      runtime·casgstatus(gp, oldstatus, Gcopystack);
        copystack(gp, newsize);
 -}
 +      runtime·casgstatus(gp, Gcopystack, oldstatus);
 + }
  
  // Do any delayed stack freeing that was queued up during GC.
  void
diff --combined src/runtime/stubs.go
index 421ab04e507aa5b9b51253c0344cd05fde167ff6,fe8f9c9222aba574260cd9f132515aba18fee49e..9889567d6100b88d99c0e25d39442a039bc9b2c6
@@@ -106,16 -106,6 +106,16 @@@ func recovery_m(*g
  func mcacheRefill_m()
  func largeAlloc_m()
  func gc_m()
 +func gcscan_m()
 +func gcmark_m()
 +func gccheckmark_m()
 +func gccheckmarkenable_m()
 +func gccheckmarkdisable_m()
 +func gcinstallmarkwb_m()
 +func gcinstalloffwb_m()
 +func gcmarknewobject_m()
 +func gcmarkwb_m()
 +func finishsweep_m()
  func scavenge_m()
  func setFinalizer_m()
  func removeFinalizer_m()
@@@ -213,6 -203,9 +213,6 @@@ func write(fd uintptr, p unsafe.Pointer
  //go:noescape
  func cas(ptr *uint32, old, new uint32) bool
  
 -//go:noescape
 -func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
 -
  //go:noescape
  func casuintptr(ptr *uintptr, old, new uintptr) bool
  
@@@ -228,6 -221,34 +228,34 @@@ func atomicloaduint(ptr *uint) uin
  //go:noescape
  func setcallerpc(argp unsafe.Pointer, pc uintptr)
  
+ // getcallerpc returns the program counter (PC) of its caller's caller.
+ // getcallersp returns the stack pointer (SP) of its caller's caller.
+ // For both, the argp must be a pointer to the caller's first function argument.
+ // The implementation may or may not use argp, depending on
+ // the architecture.
+ //
+ // For example:
+ //
+ //    func f(arg1, arg2, arg3 int) {
+ //            pc := getcallerpc(unsafe.Pointer(&arg1))
+ //            sp := getcallerpc(unsafe.Pointer(&arg2))
+ //    }
+ //
+ // These two lines find the PC and SP immediately following
+ // the call to f (where f will return).
+ //
+ // The call to getcallerpc and getcallersp must be done in the
+ // frame being asked about. It would not be correct for f to pass &arg1
+ // to another function g and let g call getcallerpc/getcallersp.
+ // The call inside g might return information about g's caller or
+ // information about f's caller or complete garbage.
+ //
+ // The result of getcallersp is correct at the time of the return,
+ // but it may be invalidated by any subsequent call to a function
+ // that might relocate the stack in order to grow or shrink it.
+ // A general rule is that the result of getcallersp should be used
+ // immediately and can only be passed to nosplit functions.
  //go:noescape
  func getcallerpc(argp unsafe.Pointer) uintptr