if fn.Func.Pragma&Nosplit != 0 {
                s.f.NoSplit = true
        }
-       defer func() {
-               if s.f.WBPos.IsKnown() {
-                       fn.Func.WBPos = s.f.WBPos
-               }
-       }()
        s.exitCode = fn.Func.Exit
        s.panics = map[funcLine]*ssa.Block{}
 
        return Debug_checknil != 0
 }
 
-func (e *ssafn) Debug_wb() bool {
-       return Debug_wb != 0
-}
-
 func (e *ssafn) UseWriteBarrier() bool {
        return use_writebarrier
 }
        return nil
 }
 
+func (e *ssafn) SetWBPos(pos src.XPos) {
+       e.curfn.Func.setWBPos(pos)
+}
+
 func (n *Node) Typ() *types.Type {
        return n.Type
 }
 
        Label int32 // largest auto-generated label in this function
 
        Endlineno src.XPos
-       WBPos     src.XPos // position of first write barrier
+       WBPos     src.XPos // position of first write barrier; see SetWBPos
 
        Pragma syntax.Pragma // go:xxx function annotations
 
 func (f *Func) SetNilCheckDisabled(b bool)    { f.flags.set(funcNilCheckDisabled, b) }
 func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, b) }
 
+func (f *Func) setWBPos(pos src.XPos) {
+       if Debug_wb != 0 {
+               Warnl(pos, "write barrier")
+       }
+       if !f.WBPos.IsKnown() {
+               f.WBPos = pos
+       }
+}
+
 type Op uint8
 
 // Node ops.
 
                nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
                nptr1.Etype = 1
                nptr2 := l2
+               Curfn.Func.setWBPos(n.Pos)
                fn := syslook("typedslicecopy")
                fn = substArgTypes(fn, l1.Type, l2.Type)
                var ln Nodes
 //
 func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
        if types.Haspointers(n.Left.Type.Elem()) {
+               Curfn.Func.setWBPos(n.Pos)
                fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
                return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right)
        }
 
 
        // Forwards the Debug flags from gc
        Debug_checknil() bool
-       Debug_wb() bool
 }
 
 type Frontend interface {
 
        // UseWriteBarrier returns whether write barrier is enabled
        UseWriteBarrier() bool
+
+       // SetWBPos indicates that a write barrier has been inserted
+       // in this function at position pos.
+       SetWBPos(pos src.XPos)
 }
 
 // interface used to hold a *gc.Node (a stack variable).
 
 func (DummyFrontend) UseWriteBarrier() bool {
        return true // only writebarrier_test cares
 }
+func (DummyFrontend) SetWBPos(pos src.XPos) {
+}
 
 func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
 func (d DummyFrontend) Log() bool                            { return true }
 func (d DummyFrontend) Fatalf(_ src.XPos, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
 func (d DummyFrontend) Warnl(_ src.XPos, msg string, args ...interface{})  { d.t.Logf(msg, args...) }
 func (d DummyFrontend) Debug_checknil() bool                               { return false }
-func (d DummyFrontend) Debug_wb() bool                                     { return false }
 
 var dummyTypes Types
 
 
        scheduled bool // Values in Blocks are in final order
        NoSplit   bool // true if function is marked as nosplit.  Used by schedule check pass.
 
-       WBPos src.XPos // line number of first write barrier
-
        // when register allocation is done, maps value ids to locations
        RegAlloc []Location
 
 
 
                        if fn != nil {
                                // Note that we set up a writebarrier function call.
-                               if !f.WBPos.IsKnown() {
-                                       f.WBPos = pos
-                               }
-                               if f.fe.Debug_wb() {
-                                       f.Warnl(pos, "write barrier")
-                               }
+                               f.fe.SetWBPos(pos)
                        }
                }