gp.waitsince = work.tstart
                }
 
-               // Shrink a stack if not much of it is being used but not in the scan phase.
-               if gcphase == _GCmarktermination {
-                       // Shrink during STW GCmarktermination phase thus avoiding
-                       // complications introduced by shrinking during
-                       // non-STW phases.
+               if gcphase == _GCmarktermination && status == _Gdead {
+                       // Free gp's stack if necessary. Only do this
+                       // during mark termination because otherwise
+                       // _Gdead may be transient.
                        shrinkstack(gp)
                }
 
                throw("can't scan gchelper stack")
        }
 
+       // Shrink the stack if not much of it is being used. During
+       // concurrent GC, we can do this during concurrent mark.
+       if !work.markrootDone {
+               shrinkstack(gp)
+       }
+
+       // Prepare for stack barrier insertion/removal.
        var sp, barrierOffset, nextBarrier uintptr
        if gp.syscallsp != 0 {
                sp = gp.syscallsp
                throw("scanstack in wrong phase")
        }
 
+       // Scan the stack.
        var cache pcvalueCache
        gcw := &getg().m.p.ptr().gcw
        n := 0
 
 // Called at garbage collection time.
 // gp must be stopped, but the world need not be.
 func shrinkstack(gp *g) {
-       if readgstatus(gp) == _Gdead {
+       gstatus := readgstatus(gp)
+       if gstatus&^_Gscan == _Gdead {
                if gp.stack.lo != 0 {
                        // Free whole stack - it will get reallocated
                        // if G is used again.
        if gp.stack.lo == 0 {
                throw("missing stack in shrinkstack")
        }
+       if gstatus&_Gscan == 0 {
+               throw("bad status in shrinkstack")
+       }
 
        if debug.gcshrinkstackoff > 0 {
                return
                print("shrinking stack ", oldsize, "->", newsize, "\n")
        }
 
-       oldstatus := casgcopystack(gp)
        copystack(gp, newsize, false)
-       casgstatus(gp, _Gcopystack, oldstatus)
 }
 
 // freeStackSpans frees unused stack spans at the end of GC.