fn.SetWrapper(true)
fn.Nname.SetType(types.NewSignature(types.LocalPkg, nil, nil, nil, nil))
fn.Body = []ir.Node{call}
+ if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC {
+ // If the callee is a named function, link to the original callee.
+ x := call.X
+ if x.Op() == ir.ONAME && x.(*ir.Name).Class == ir.PFUNC {
+ fn.WrappedFunc = call.X.(*ir.Name).Func
+ } else if x.Op() == ir.OMETHEXPR && ir.MethodExprFunc(x).Nname != nil {
+ fn.WrappedFunc = ir.MethodExprName(x).Func
+ }
+ }
clo := fn.OClosure
if n.Op() == ir.OGO {
objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
x.Set(obj.AttrStatic, true)
}
+ if x := fn.WrapInfo; x != nil && !x.OnList() {
+ objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
+ x.Set(obj.AttrStatic, true)
+ }
}
}
// function for go:nowritebarrierrec analysis. Only filled in
// if nowritebarrierrecCheck != nil.
NWBRCalls *[]SymAndPos
+
+ // For wrapper functions, WrappedFunc point to the original Func.
+ // Currently only used for go/defer wrappers.
+ WrappedFunc *Func
}
func NewFunc(pos src.XPos) *Func {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Func{}, 192, 328},
+ {Func{}, 196, 336},
{Name{}, 112, 200},
}
return x
}
+// for wrapper, emit info of wrapped function.
+func emitWrappedFuncInfo(e *ssafn, pp *objw.Progs) {
+ if base.Ctxt.Flag_linkshared {
+ // Relative reference (SymPtrOff) to another shared object doesn't work.
+ // Unfortunate.
+ return
+ }
+
+ wfn := e.curfn.WrappedFunc
+ if wfn == nil {
+ return
+ }
+
+ wsym := wfn.Linksym()
+ x := base.Ctxt.LookupInit(fmt.Sprintf("%s.wrapinfo", wsym.Name), func(x *obj.LSym) {
+ objw.SymPtrOff(x, 0, wsym)
+ x.Set(obj.AttrContentAddressable, true)
+ })
+ e.curfn.LSym.Func().WrapInfo = x
+
+ // Emit a funcdata pointing at the wrap info data.
+ p := pp.Prog(obj.AFUNCDATA)
+ p.From.SetConst(objabi.FUNCDATA_WrapInfo)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = x
+}
+
// genssa appends entries to pp for each instruction in f.
func genssa(f *ssa.Func, pp *objw.Progs) {
var s State
p.To.Sym = openDeferInfo
}
+ emitWrappedFuncInfo(e, pp)
+
// Remember where each block starts.
s.bstart = make([]*obj.Prog, f.NumBlocks())
s.pp = pp
OpenCodedDeferInfo *LSym
ArgInfo *LSym // argument info for traceback
ArgLiveInfo *LSym // argument liveness info for traceback
+ WrapInfo *LSym // for wrapper, info of wrapped function
FuncInfoSym *LSym
}
strings.HasSuffix(name, ".arginfo0") ||
strings.HasSuffix(name, ".arginfo1") ||
strings.HasSuffix(name, ".argliveinfo") ||
+ strings.HasSuffix(name, ".wrapinfo") ||
strings.HasSuffix(name, ".args_stackmap") ||
strings.HasSuffix(name, ".stkobj") {
return 'F' // go.func.* or go.funcrel.*
FUNCDATA_OpenCodedDeferInfo = 4
FUNCDATA_ArgInfo = 5
FUNCDATA_ArgLiveInfo = 6
+ FUNCDATA_WrapInfo = 7
// ArgsSizeUnknown is set in Func.argsize to mark all functions
// whose argument size is unknown (C vararg functions, and
strings.HasSuffix(name, ".arginfo0"),
strings.HasSuffix(name, ".arginfo1"),
strings.HasSuffix(name, ".argliveinfo"),
+ strings.HasSuffix(name, ".wrapinfo"),
strings.HasSuffix(name, ".args_stackmap"),
strings.HasSuffix(name, ".stkobj"):
ldr.SetAttrNotInSymbolTable(s, true)
#define FUNCDATA_OpenCodedDeferInfo 4 /* info for func with open-coded defers */
#define FUNCDATA_ArgInfo 5
#define FUNCDATA_ArgLiveInfo 6
+#define FUNCDATA_WrapInfo 7
// Pseudo-assembly statements.
_FUNCDATA_OpenCodedDeferInfo = 4
_FUNCDATA_ArgInfo = 5
_FUNCDATA_ArgLiveInfo = 6
+ _FUNCDATA_WrapInfo = 7
_ArgsSizeUnknown = -0x80000000
)
gp.traceseq = 0
gp.tracelastp = getg().m.p
// +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum.
- id := trace.stackTab.put([]uintptr{gp.startpc + sys.PCQuantum})
+ id := trace.stackTab.put([]uintptr{startPCforTrace(gp.startpc) + sys.PCQuantum})
traceEvent(traceEvGoCreate, -1, uint64(gp.goid), uint64(id), stackID)
}
if status == _Gwaiting {
newg.traceseq = 0
newg.tracelastp = getg().m.p
// +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum.
- id := trace.stackTab.put([]uintptr{pc + sys.PCQuantum})
+ id := trace.stackTab.put([]uintptr{startPCforTrace(pc) + sys.PCQuantum})
traceEvent(traceEvGoCreate, 2, uint64(newg.goid), uint64(id))
}
traceReleaseBuffer(pid)
}
+
+// the start PC of a goroutine for tracing purposes. If pc is a wrapper,
+// it returns the PC of the wrapped function. Otherwise it returns pc.
+func startPCforTrace(pc uintptr) uintptr {
+ f := findfunc(pc)
+ if !f.valid() {
+ return pc // should not happen, but don't care
+ }
+ w := funcdata(f, _FUNCDATA_WrapInfo)
+ if w == nil {
+ return pc // not a wrapper
+ }
+ return f.datap.textAddr(*(*uint32)(w))
+}