mirror of
https://github.com/golang/go
synced 2024-11-11 19:51:37 -07:00
[dev.regabi] cmd/compile: split out package reflectdata [generated]
[git-generate] cd src/cmd/compile/internal/gc rf ' ex { import "cmd/compile/internal/base" thearch.LinkArch.Name -> base.Ctxt.Arch.Name } # Move out of reflect.go a few functions that should stay. mv addsignats obj.go mv deferstruct ssa.go # Export reflectdata API. mv zerosize ZeroSize mv hmap MapType mv bmap MapBucketType mv hiter MapIterType mv addsignat NeedRuntimeType mv typename TypePtr mv typenamesym TypeSym mv typesymprefix TypeSymPrefix mv itabsym ITabSym mv tracksym TrackSym mv zeroaddr ZeroAddr mv itabname ITabAddr mv ifaceMethodOffset InterfaceMethodOffset mv peekitabs CompileITabs mv addptabs CollectPTabs mv algtype AlgType mv dtypesym WriteType mv dumpbasictypes WriteBasicTypes mv dumpimportstrings WriteImportStrings mv dumpsignats WriteRuntimeTypes mv dumptabs WriteTabs mv eqinterface EqInterface mv eqstring EqString mv GCProg gcProg mv EqCanPanic eqCanPanic mv IsRegularMemory isRegularMemory mv Sig typeSig mv hashmem alg.go mv CollectPTabs genwrapper ZeroSize reflect.go mv alg.go reflect.go cmd/compile/internal/reflectdata ' Change-Id: Iaae9da9e9fad5f772f5216004823ccff2ea8f139 Reviewed-on: https://go-review.googlesource.com/c/go/+/279475 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
4dfb5d91a8
commit
de65151e50
@ -7,6 +7,7 @@ package gc
|
||||
import (
|
||||
"bufio"
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
@ -38,10 +39,10 @@ func TestMain(m *testing.M) {
|
||||
types.PtrSize = thearch.LinkArch.PtrSize
|
||||
types.RegSize = thearch.LinkArch.RegSize
|
||||
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
|
||||
return typenamesym(t).Linksym()
|
||||
return reflectdata.TypeSym(t).Linksym()
|
||||
}
|
||||
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
|
||||
return typenamesym(t).Linksym()
|
||||
return reflectdata.TypeSym(t).Linksym()
|
||||
}
|
||||
typecheck.Init()
|
||||
os.Exit(m.Run())
|
||||
|
@ -12,8 +12,6 @@ import (
|
||||
|
||||
var pragcgobuf [][]string
|
||||
|
||||
var zerosize int64
|
||||
|
||||
// interface to back end
|
||||
|
||||
type Arch struct {
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/logopt"
|
||||
"cmd/compile/internal/noder"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/ssa"
|
||||
"cmd/compile/internal/staticdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
@ -190,19 +191,19 @@ func Main(archInit func(*Arch)) {
|
||||
types.RegSize = thearch.LinkArch.RegSize
|
||||
types.MaxWidth = thearch.MAXWIDTH
|
||||
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
|
||||
return typenamesym(t).Linksym()
|
||||
return reflectdata.TypeSym(t).Linksym()
|
||||
}
|
||||
|
||||
typecheck.Target = new(ir.Package)
|
||||
|
||||
typecheck.NeedFuncSym = staticdata.NeedFuncSym
|
||||
typecheck.NeedITab = func(t, iface *types.Type) { itabname(t, iface) }
|
||||
typecheck.NeedRuntimeType = addsignat // TODO(rsc): typenamesym for lock?
|
||||
typecheck.NeedITab = func(t, iface *types.Type) { reflectdata.ITabAddr(t, iface) }
|
||||
typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): typenamesym for lock?
|
||||
|
||||
base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
|
||||
|
||||
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
|
||||
return typenamesym(t).Linksym()
|
||||
return reflectdata.TypeSym(t).Linksym()
|
||||
}
|
||||
typecheck.Init()
|
||||
|
||||
@ -282,7 +283,7 @@ func Main(archInit func(*Arch)) {
|
||||
// the right side of OCONVIFACE so that methods
|
||||
// can be de-virtualized during compilation.
|
||||
ir.CurFunc = nil
|
||||
peekitabs()
|
||||
reflectdata.CompileITabs()
|
||||
|
||||
// Compile top level functions.
|
||||
// Don't use range--walk can add functions to Target.Decls.
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/objw"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/staticdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
@ -112,14 +113,14 @@ func dumpdata() {
|
||||
|
||||
dumpglobls(typecheck.Target.Externs)
|
||||
staticdata.WriteFuncSyms()
|
||||
addptabs()
|
||||
reflectdata.CollectPTabs()
|
||||
numExports := len(typecheck.Target.Exports)
|
||||
addsignats(typecheck.Target.Externs)
|
||||
dumpsignats()
|
||||
dumptabs()
|
||||
numPTabs, numITabs := CountTabs()
|
||||
dumpimportstrings()
|
||||
dumpbasictypes()
|
||||
reflectdata.WriteRuntimeTypes()
|
||||
reflectdata.WriteTabs()
|
||||
numPTabs, numITabs := reflectdata.CountTabs()
|
||||
reflectdata.WriteImportStrings()
|
||||
reflectdata.WriteBasicTypes()
|
||||
dumpembeds()
|
||||
|
||||
// Calls to dumpsignats can generate functions,
|
||||
@ -138,7 +139,7 @@ func dumpdata() {
|
||||
}
|
||||
numDecls = len(typecheck.Target.Decls)
|
||||
compileFunctions()
|
||||
dumpsignats()
|
||||
reflectdata.WriteRuntimeTypes()
|
||||
if numDecls == len(typecheck.Target.Decls) {
|
||||
break
|
||||
}
|
||||
@ -147,9 +148,9 @@ func dumpdata() {
|
||||
// Dump extra globals.
|
||||
dumpglobls(typecheck.Target.Externs[numExterns:])
|
||||
|
||||
if zerosize > 0 {
|
||||
if reflectdata.ZeroSize > 0 {
|
||||
zero := ir.Pkgs.Map.Lookup("zero")
|
||||
objw.Global(zero.Linksym(), int32(zerosize), obj.DUPOK|obj.RODATA)
|
||||
objw.Global(zero.Linksym(), int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
|
||||
}
|
||||
|
||||
addGCLocals()
|
||||
@ -157,7 +158,7 @@ func dumpdata() {
|
||||
if numExports != len(typecheck.Target.Exports) {
|
||||
base.Fatalf("Target.Exports changed after compile functions loop")
|
||||
}
|
||||
newNumPTabs, newNumITabs := CountTabs()
|
||||
newNumPTabs, newNumITabs := reflectdata.CountTabs()
|
||||
if newNumPTabs != numPTabs {
|
||||
base.Fatalf("ptabs changed after compile functions loop")
|
||||
}
|
||||
@ -184,36 +185,6 @@ func dumpLinkerObj(bout *bio.Writer) {
|
||||
obj.WriteObjFile(base.Ctxt, bout)
|
||||
}
|
||||
|
||||
func addptabs() {
|
||||
if !base.Ctxt.Flag_dynlink || types.LocalPkg.Name != "main" {
|
||||
return
|
||||
}
|
||||
for _, exportn := range typecheck.Target.Exports {
|
||||
s := exportn.Sym()
|
||||
nn := ir.AsNode(s.Def)
|
||||
if nn == nil {
|
||||
continue
|
||||
}
|
||||
if nn.Op() != ir.ONAME {
|
||||
continue
|
||||
}
|
||||
n := nn.(*ir.Name)
|
||||
if !types.IsExported(s.Name) {
|
||||
continue
|
||||
}
|
||||
if s.Pkg.Name != "main" {
|
||||
continue
|
||||
}
|
||||
if n.Type().Kind() == types.TFUNC && n.Class_ == ir.PFUNC {
|
||||
// function
|
||||
ptabs = append(ptabs, ptabEntry{s: s, t: s.Def.Type()})
|
||||
} else {
|
||||
// variable
|
||||
ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(s.Def.Type())})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpGlobal(n *ir.Name) {
|
||||
if n.Type() == nil {
|
||||
base.Fatalf("external %v nil type\n", n)
|
||||
@ -373,3 +344,12 @@ func dumpembeds() {
|
||||
staticdata.WriteEmbed(v)
|
||||
}
|
||||
}
|
||||
|
||||
func addsignats(dcls []ir.Node) {
|
||||
// copy types from dcl list to signatset
|
||||
for _, n := range dcls {
|
||||
if n.Op() == ir.OTYPE {
|
||||
reflectdata.NeedRuntimeType(n.Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/escape"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/src"
|
||||
@ -882,7 +883,7 @@ func (o *Order) stmt(n ir.Node) {
|
||||
|
||||
// n.Prealloc is the temp for the iterator.
|
||||
// hiter contains pointers and needs to be zeroed.
|
||||
n.Prealloc = o.newTemp(hiter(n.Type()), true)
|
||||
n.Prealloc = o.newTemp(reflectdata.MapIterType(n.Type()), true)
|
||||
}
|
||||
o.exprListInPlace(n.Vars)
|
||||
if orderBody {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/liveness"
|
||||
"cmd/compile/internal/objw"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/ssa"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
@ -225,7 +226,7 @@ func compile(fn *ir.Func) {
|
||||
switch n.Class_ {
|
||||
case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO:
|
||||
if liveness.ShouldTrack(n) && n.Addrtaken() {
|
||||
dtypesym(n.Type())
|
||||
reflectdata.WriteType(n.Type())
|
||||
// Also make sure we allocate a linker symbol
|
||||
// for the stack object data, for the same reason.
|
||||
if fn.LSym.Func().StackObjects == nil {
|
||||
|
@ -7,6 +7,7 @@ package gc
|
||||
import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/sys"
|
||||
@ -180,7 +181,7 @@ func walkrange(nrange *ir.RangeStmt) ir.Node {
|
||||
fn := typecheck.LookupRuntime("mapiterinit")
|
||||
|
||||
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), th)
|
||||
init = append(init, mkcall1(fn, nil, nil, typename(t), ha, typecheck.NodAddr(hit)))
|
||||
init = append(init, mkcall1(fn, nil, nil, reflectdata.TypePtr(t), ha, typecheck.NodAddr(hit)))
|
||||
nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), typecheck.NodNil())
|
||||
|
||||
fn = typecheck.LookupRuntime("mapiternext")
|
||||
@ -383,7 +384,7 @@ func mapClear(m ir.Node) ir.Node {
|
||||
// instantiate mapclear(typ *type, hmap map[any]any)
|
||||
fn := typecheck.LookupRuntime("mapclear")
|
||||
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
|
||||
n := mkcall1(fn, nil, nil, typename(t), m)
|
||||
n := mkcall1(fn, nil, nil, reflectdata.TypePtr(t), m)
|
||||
return walkstmt(typecheck.Stmt(n))
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ package gc
|
||||
import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/staticdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
@ -314,9 +315,9 @@ func (s *InitSchedule) staticassign(l *ir.Name, loff int64, r ir.Node, typ *type
|
||||
|
||||
var itab *ir.AddrExpr
|
||||
if typ.IsEmptyInterface() {
|
||||
itab = typename(val.Type())
|
||||
itab = reflectdata.TypePtr(val.Type())
|
||||
} else {
|
||||
itab = itabname(val.Type(), typ)
|
||||
itab = reflectdata.ITabAddr(val.Type(), typ)
|
||||
}
|
||||
|
||||
// Create a copy of l to modify while we emit data.
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/liveness"
|
||||
"cmd/compile/internal/objw"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/ssa"
|
||||
"cmd/compile/internal/staticdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
@ -89,7 +90,7 @@ func initssaconfig() {
|
||||
_ = types.NewPtr(types.Types[types.TINT64]) // *int64
|
||||
_ = types.NewPtr(types.ErrorType) // *error
|
||||
types.NewPtrCacheEnabled = false
|
||||
ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, base.Ctxt, base.Flag.N == 0)
|
||||
ssaConfig = ssa.NewConfig(base.Ctxt.Arch.Name, *types_, base.Ctxt, base.Flag.N == 0)
|
||||
ssaConfig.SoftFloat = thearch.SoftFloat
|
||||
ssaConfig.Race = base.Flag.Race
|
||||
ssaCaches = make([]ssa.Cache, base.Flag.LowerC)
|
||||
@ -134,7 +135,7 @@ func initssaconfig() {
|
||||
ir.Syms.Zerobase = typecheck.LookupRuntimeVar("zerobase")
|
||||
|
||||
// asm funcs with special ABI
|
||||
if thearch.LinkArch.Name == "amd64" {
|
||||
if base.Ctxt.Arch.Name == "amd64" {
|
||||
GCWriteBarrierReg = map[int16]*obj.LSym{
|
||||
x86.REG_AX: typecheck.LookupRuntimeFunc("gcWriteBarrier"),
|
||||
x86.REG_CX: typecheck.LookupRuntimeFunc("gcWriteBarrierCX"),
|
||||
@ -389,7 +390,7 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
|
||||
|
||||
s.hasOpenDefers = base.Flag.N == 0 && s.hasdefer && !s.curfn.OpenCodedDeferDisallowed()
|
||||
switch {
|
||||
case s.hasOpenDefers && (base.Ctxt.Flag_shared || base.Ctxt.Flag_dynlink) && thearch.LinkArch.Name == "386":
|
||||
case s.hasOpenDefers && (base.Ctxt.Flag_shared || base.Ctxt.Flag_dynlink) && base.Ctxt.Arch.Name == "386":
|
||||
// Don't support open-coded defers for 386 ONLY when using shared
|
||||
// libraries, because there is extra code (added by rewriteToUseGot())
|
||||
// preceding the deferreturn/ret code that is generated by gencallret()
|
||||
@ -6427,7 +6428,7 @@ func emitStackObjects(e *ssafn, pp *objw.Progs) {
|
||||
if !types.TypeSym(v.Type()).Siggen() {
|
||||
e.Fatalf(v.Pos(), "stack object's type symbol not generated for type %s", v.Type())
|
||||
}
|
||||
off = objw.SymPtr(x, off, dtypesym(v.Type()), 0)
|
||||
off = objw.SymPtr(x, off, reflectdata.WriteType(v.Type()), 0)
|
||||
}
|
||||
|
||||
// Emit a funcdata pointing at the stack object data.
|
||||
@ -7247,7 +7248,7 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
|
||||
}
|
||||
|
||||
func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
|
||||
return itabsym(it, offset)
|
||||
return reflectdata.ITabSym(it, offset)
|
||||
}
|
||||
|
||||
// SplitSlot returns a slot representing the data of parent starting at offset.
|
||||
@ -7411,3 +7412,44 @@ func max8(a, b int8) int8 {
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// deferstruct makes a runtime._defer structure, with additional space for
|
||||
// stksize bytes of args.
|
||||
func deferstruct(stksize int64) *types.Type {
|
||||
makefield := func(name string, typ *types.Type) *types.Field {
|
||||
// Unlike the global makefield function, this one needs to set Pkg
|
||||
// because these types might be compared (in SSA CSE sorting).
|
||||
// TODO: unify this makefield and the global one above.
|
||||
sym := &types.Sym{Name: name, Pkg: types.LocalPkg}
|
||||
return types.NewField(src.NoXPos, sym, typ)
|
||||
}
|
||||
argtype := types.NewArray(types.Types[types.TUINT8], stksize)
|
||||
argtype.Width = stksize
|
||||
argtype.Align = 1
|
||||
// These fields must match the ones in runtime/runtime2.go:_defer and
|
||||
// cmd/compile/internal/gc/ssa.go:(*state).call.
|
||||
fields := []*types.Field{
|
||||
makefield("siz", types.Types[types.TUINT32]),
|
||||
makefield("started", types.Types[types.TBOOL]),
|
||||
makefield("heap", types.Types[types.TBOOL]),
|
||||
makefield("openDefer", types.Types[types.TBOOL]),
|
||||
makefield("sp", types.Types[types.TUINTPTR]),
|
||||
makefield("pc", types.Types[types.TUINTPTR]),
|
||||
// Note: the types here don't really matter. Defer structures
|
||||
// are always scanned explicitly during stack copying and GC,
|
||||
// so we make them uintptr type even though they are real pointers.
|
||||
makefield("fn", types.Types[types.TUINTPTR]),
|
||||
makefield("_panic", types.Types[types.TUINTPTR]),
|
||||
makefield("link", types.Types[types.TUINTPTR]),
|
||||
makefield("framepc", types.Types[types.TUINTPTR]),
|
||||
makefield("varp", types.Types[types.TUINTPTR]),
|
||||
makefield("fd", types.Types[types.TUINTPTR]),
|
||||
makefield("args", argtype),
|
||||
}
|
||||
|
||||
// build struct holding the above fields
|
||||
s := types.NewStruct(types.NoPkg, fields)
|
||||
s.SetNoalg(true)
|
||||
types.CalcStructSize(s)
|
||||
return s
|
||||
}
|
||||
|
@ -6,9 +6,8 @@ package gc
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/escape"
|
||||
"cmd/compile/internal/inline"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/src"
|
||||
@ -319,144 +318,9 @@ func cheapexpr(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
return copyexpr(n, n.Type(), init)
|
||||
}
|
||||
|
||||
// Generate a wrapper function to convert from
|
||||
// a receiver of type T to a receiver of type U.
|
||||
// That is,
|
||||
//
|
||||
// func (t T) M() {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// already exists; this function generates
|
||||
//
|
||||
// func (u U) M() {
|
||||
// u.M()
|
||||
// }
|
||||
//
|
||||
// where the types T and U are such that u.M() is valid
|
||||
// and calls the T.M method.
|
||||
// The resulting function is for use in method tables.
|
||||
//
|
||||
// rcvr - U
|
||||
// method - M func (t T)(), a TFIELD type struct
|
||||
// newnam - the eventual mangled name of this function
|
||||
func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
||||
if false && base.Flag.LowerR != 0 {
|
||||
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
|
||||
}
|
||||
|
||||
// Only generate (*T).M wrappers for T.M in T's own package.
|
||||
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
|
||||
rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg {
|
||||
return
|
||||
}
|
||||
|
||||
// Only generate I.M wrappers for I in I's own package
|
||||
// but keep doing it for error.Error (was issue #29304).
|
||||
if rcvr.IsInterface() && rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && rcvr != types.ErrorType {
|
||||
return
|
||||
}
|
||||
|
||||
base.Pos = base.AutogeneratedPos
|
||||
typecheck.DeclContext = ir.PEXTERN
|
||||
|
||||
tfn := ir.NewFuncType(base.Pos,
|
||||
ir.NewField(base.Pos, typecheck.Lookup(".this"), nil, rcvr),
|
||||
typecheck.NewFuncParams(method.Type.Params(), true),
|
||||
typecheck.NewFuncParams(method.Type.Results(), false))
|
||||
|
||||
fn := typecheck.DeclFunc(newnam, tfn)
|
||||
fn.SetDupok(true)
|
||||
|
||||
nthis := ir.AsNode(tfn.Type().Recv().Nname)
|
||||
|
||||
methodrcvr := method.Type.Recv().Type
|
||||
|
||||
// generate nil pointer check for better error
|
||||
if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
|
||||
// generating wrapper from *T to T.
|
||||
n := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
||||
n.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, nthis, typecheck.NodNil())
|
||||
call := ir.NewCallExpr(base.Pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)
|
||||
n.Body = []ir.Node{call}
|
||||
fn.Body.Append(n)
|
||||
}
|
||||
|
||||
dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
|
||||
|
||||
// generate call
|
||||
// It's not possible to use a tail call when dynamic linking on ppc64le. The
|
||||
// bad scenario is when a local call is made to the wrapper: the wrapper will
|
||||
// call the implementation, which might be in a different module and so set
|
||||
// the TOC to the appropriate value for that module. But if it returns
|
||||
// directly to the wrapper's caller, nothing will reset it to the correct
|
||||
// value for that function.
|
||||
if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(thearch.LinkArch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) {
|
||||
// generate tail call: adjust pointer receiver and jump to embedded method.
|
||||
left := dot.X // skip final .M
|
||||
if !left.Type().IsPtr() {
|
||||
left = typecheck.NodAddr(left)
|
||||
}
|
||||
as := ir.NewAssignStmt(base.Pos, nthis, typecheck.ConvNop(left, rcvr))
|
||||
fn.Body.Append(as)
|
||||
fn.Body.Append(ir.NewBranchStmt(base.Pos, ir.ORETJMP, ir.MethodSym(methodrcvr, method.Sym)))
|
||||
} else {
|
||||
fn.SetWrapper(true) // ignore frame for panic+recover matching
|
||||
call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
|
||||
call.Args.Set(ir.ParamNames(tfn.Type()))
|
||||
call.IsDDD = tfn.Type().IsVariadic()
|
||||
if method.Type.NumResults() > 0 {
|
||||
ret := ir.NewReturnStmt(base.Pos, nil)
|
||||
ret.Results = []ir.Node{call}
|
||||
fn.Body.Append(ret)
|
||||
} else {
|
||||
fn.Body.Append(call)
|
||||
}
|
||||
}
|
||||
|
||||
if false && base.Flag.LowerR != 0 {
|
||||
ir.DumpList("genwrapper body", fn.Body)
|
||||
}
|
||||
|
||||
typecheck.FinishFuncBody()
|
||||
if base.Debug.DclStack != 0 {
|
||||
types.CheckDclstack()
|
||||
}
|
||||
|
||||
typecheck.Func(fn)
|
||||
ir.CurFunc = fn
|
||||
typecheck.Stmts(fn.Body)
|
||||
|
||||
// Inline calls within (*T).M wrappers. This is safe because we only
|
||||
// generate those wrappers within the same compilation unit as (T).M.
|
||||
// TODO(mdempsky): Investigate why we can't enable this more generally.
|
||||
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym() != nil {
|
||||
inline.InlineCalls(fn)
|
||||
}
|
||||
escape.Batch([]*ir.Func{fn}, false)
|
||||
|
||||
ir.CurFunc = nil
|
||||
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
|
||||
}
|
||||
|
||||
func hashmem(t *types.Type) ir.Node {
|
||||
sym := ir.Pkgs.Runtime.Lookup("memhash")
|
||||
|
||||
n := typecheck.NewName(sym)
|
||||
ir.MarkFunc(n)
|
||||
n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
}, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
}))
|
||||
return n
|
||||
}
|
||||
|
||||
func ngotype(n ir.Node) *types.Sym {
|
||||
if n.Type() != nil {
|
||||
return typenamesym(n.Type())
|
||||
return reflectdata.TypeSym(n.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/escape"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/staticdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
@ -594,12 +595,12 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
n := n.(*ir.TypeAssertExpr)
|
||||
n.X = walkexpr(n.X, init)
|
||||
// Set up interface type addresses for back end.
|
||||
n.Ntype = typename(n.Type())
|
||||
n.Ntype = reflectdata.TypePtr(n.Type())
|
||||
if n.Op() == ir.ODOTTYPE {
|
||||
n.Ntype.(*ir.AddrExpr).Alloc = typename(n.X.Type())
|
||||
n.Ntype.(*ir.AddrExpr).Alloc = reflectdata.TypePtr(n.X.Type())
|
||||
}
|
||||
if !n.Type().IsInterface() && !n.X.Type().IsEmptyInterface() {
|
||||
n.Itab = []ir.Node{itabname(n.Type(), n.X.Type())}
|
||||
n.Itab = []ir.Node{reflectdata.ITabAddr(n.Type(), n.X.Type())}
|
||||
}
|
||||
return n
|
||||
|
||||
@ -781,7 +782,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
// Left in place for back end.
|
||||
// Do not add a new write barrier.
|
||||
// Set up address of type for back end.
|
||||
r.(*ir.CallExpr).X = typename(r.Type().Elem())
|
||||
r.(*ir.CallExpr).X = reflectdata.TypePtr(r.Type().Elem())
|
||||
return as
|
||||
}
|
||||
// Otherwise, lowered for race detector.
|
||||
@ -870,11 +871,11 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
var call *ir.CallExpr
|
||||
if w := t.Elem().Width; w <= zeroValSize {
|
||||
fn := mapfn(mapaccess2[fast], t)
|
||||
call = mkcall1(fn, fn.Type().Results(), init, typename(t), r.X, key)
|
||||
call = mkcall1(fn, fn.Type().Results(), init, reflectdata.TypePtr(t), r.X, key)
|
||||
} else {
|
||||
fn := mapfn("mapaccess2_fat", t)
|
||||
z := zeroaddr(w)
|
||||
call = mkcall1(fn, fn.Type().Results(), init, typename(t), r.X, key, z)
|
||||
z := reflectdata.ZeroAddr(w)
|
||||
call = mkcall1(fn, fn.Type().Results(), init, reflectdata.TypePtr(t), r.X, key, z)
|
||||
}
|
||||
|
||||
// mapaccess2* returns a typed bool, but due to spec changes,
|
||||
@ -915,7 +916,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
// order.stmt made sure key is addressable.
|
||||
key = typecheck.NodAddr(key)
|
||||
}
|
||||
return mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key)
|
||||
return mkcall1(mapfndel(mapdelete[fast], t), nil, init, reflectdata.TypePtr(t), map_, key)
|
||||
|
||||
case ir.OAS2DOTTYPE:
|
||||
n := n.(*ir.AssignListStmt)
|
||||
@ -937,9 +938,9 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
// typeword generates the type word of the interface value.
|
||||
typeword := func() ir.Node {
|
||||
if toType.IsEmptyInterface() {
|
||||
return typename(fromType)
|
||||
return reflectdata.TypePtr(fromType)
|
||||
}
|
||||
return itabname(fromType, toType)
|
||||
return reflectdata.ITabAddr(fromType, toType)
|
||||
}
|
||||
|
||||
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
|
||||
@ -1048,7 +1049,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
var tab ir.Node
|
||||
if fromType.IsInterface() {
|
||||
// convI2I
|
||||
tab = typename(toType)
|
||||
tab = reflectdata.TypePtr(toType)
|
||||
} else {
|
||||
// convT2x
|
||||
tab = typeword()
|
||||
@ -1218,7 +1219,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
// order.expr made sure key is addressable.
|
||||
key = typecheck.NodAddr(key)
|
||||
}
|
||||
call = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key)
|
||||
call = mkcall1(mapfn(mapassign[fast], t), nil, init, reflectdata.TypePtr(t), map_, key)
|
||||
} else {
|
||||
// m[k] is not the target of an assignment.
|
||||
fast := mapfast(t)
|
||||
@ -1229,10 +1230,10 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
}
|
||||
|
||||
if w := t.Elem().Width; w <= zeroValSize {
|
||||
call = mkcall1(mapfn(mapaccess1[fast], t), types.NewPtr(t.Elem()), init, typename(t), map_, key)
|
||||
call = mkcall1(mapfn(mapaccess1[fast], t), types.NewPtr(t.Elem()), init, reflectdata.TypePtr(t), map_, key)
|
||||
} else {
|
||||
z := zeroaddr(w)
|
||||
call = mkcall1(mapfn("mapaccess1_fat", t), types.NewPtr(t.Elem()), init, typename(t), map_, key, z)
|
||||
z := reflectdata.ZeroAddr(w)
|
||||
call = mkcall1(mapfn("mapaccess1_fat", t), types.NewPtr(t.Elem()), init, reflectdata.TypePtr(t), map_, key, z)
|
||||
}
|
||||
}
|
||||
call.SetType(types.NewPtr(t.Elem()))
|
||||
@ -1340,12 +1341,12 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
argtype = types.Types[types.TINT]
|
||||
}
|
||||
|
||||
return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, typename(n.Type()), typecheck.Conv(size, argtype))
|
||||
return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, reflectdata.TypePtr(n.Type()), typecheck.Conv(size, argtype))
|
||||
|
||||
case ir.OMAKEMAP:
|
||||
n := n.(*ir.MakeExpr)
|
||||
t := n.Type()
|
||||
hmapType := hmap(t)
|
||||
hmapType := reflectdata.MapType(t)
|
||||
hint := n.Len
|
||||
|
||||
// var h *hmap
|
||||
@ -1365,7 +1366,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
// Maximum key and elem size is 128 bytes, larger objects
|
||||
// are stored with an indirection. So max bucket size is 2048+eps.
|
||||
if !ir.IsConst(hint, constant.Int) ||
|
||||
constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(BUCKETSIZE)) {
|
||||
constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(reflectdata.BUCKETSIZE)) {
|
||||
|
||||
// In case hint is larger than BUCKETSIZE runtime.makemap
|
||||
// will allocate the buckets on the heap, see #20184
|
||||
@ -1376,11 +1377,11 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
// h.buckets = b
|
||||
// }
|
||||
|
||||
nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLE, hint, ir.NewInt(BUCKETSIZE)), nil, nil)
|
||||
nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLE, hint, ir.NewInt(reflectdata.BUCKETSIZE)), nil, nil)
|
||||
nif.Likely = true
|
||||
|
||||
// var bv bmap
|
||||
bv := typecheck.Temp(bmap(t))
|
||||
bv := typecheck.Temp(reflectdata.MapBucketType(t))
|
||||
nif.Body.Append(ir.NewAssignStmt(base.Pos, bv, nil))
|
||||
|
||||
// b = &bv
|
||||
@ -1394,7 +1395,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
}
|
||||
}
|
||||
|
||||
if ir.IsConst(hint, constant.Int) && constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(BUCKETSIZE)) {
|
||||
if ir.IsConst(hint, constant.Int) && constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(reflectdata.BUCKETSIZE)) {
|
||||
// Handling make(map[any]any) and
|
||||
// make(map[any]any, hint) where hint <= BUCKETSIZE
|
||||
// special allows for faster map initialization and
|
||||
@ -1442,7 +1443,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
|
||||
fn := typecheck.LookupRuntime(fnname)
|
||||
fn = typecheck.SubstArgTypes(fn, hmapType, t.Key(), t.Elem())
|
||||
return mkcall1(fn, n.Type(), init, typename(n.Type()), typecheck.Conv(hint, argtype), h)
|
||||
return mkcall1(fn, n.Type(), init, reflectdata.TypePtr(n.Type()), typecheck.Conv(hint, argtype), h)
|
||||
|
||||
case ir.OMAKESLICE:
|
||||
n := n.(*ir.MakeExpr)
|
||||
@ -1511,7 +1512,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
m.SetType(t)
|
||||
|
||||
fn := typecheck.LookupRuntime(fnname)
|
||||
m.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), typecheck.Conv(len, argtype), typecheck.Conv(cap, argtype))
|
||||
m.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(len, argtype), typecheck.Conv(cap, argtype))
|
||||
m.Ptr.MarkNonNil()
|
||||
m.LenCap = []ir.Node{typecheck.Conv(len, types.Types[types.TINT]), typecheck.Conv(cap, types.Types[types.TINT])}
|
||||
return walkexpr(typecheck.Expr(m), init)
|
||||
@ -1565,7 +1566,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
// instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
|
||||
fn := typecheck.LookupRuntime("makeslicecopy")
|
||||
s := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
|
||||
s.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), length, copylen, typecheck.Conv(copyptr, types.Types[types.TUNSAFEPTR]))
|
||||
s.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.TypePtr(t.Elem()), length, copylen, typecheck.Conv(copyptr, types.Types[types.TUNSAFEPTR]))
|
||||
s.Ptr.MarkNonNil()
|
||||
s.LenCap = []ir.Node{length, length}
|
||||
s.SetType(t)
|
||||
@ -1709,7 +1710,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
// markTypeUsedInInterface marks that type t is converted to an interface.
|
||||
// This information is used in the linker in dead method elimination.
|
||||
func markTypeUsedInInterface(t *types.Type, from *obj.LSym) {
|
||||
tsym := typenamesym(t).Linksym()
|
||||
tsym := reflectdata.TypeSym(t).Linksym()
|
||||
// Emit a marker relocation. The linker will know the type is converted
|
||||
// to an interface if "from" is reachable.
|
||||
r := obj.Addrel(from)
|
||||
@ -1722,13 +1723,13 @@ func markTypeUsedInInterface(t *types.Type, from *obj.LSym) {
|
||||
func markUsedIfaceMethod(n *ir.CallExpr) {
|
||||
dot := n.X.(*ir.SelectorExpr)
|
||||
ityp := dot.X.Type()
|
||||
tsym := typenamesym(ityp).Linksym()
|
||||
tsym := reflectdata.TypeSym(ityp).Linksym()
|
||||
r := obj.Addrel(ir.CurFunc.LSym)
|
||||
r.Sym = tsym
|
||||
// dot.Xoffset is the method index * Widthptr (the offset of code pointer
|
||||
// in itab).
|
||||
midx := dot.Offset / int64(types.PtrSize)
|
||||
r.Add = ifaceMethodOffset(ityp, midx)
|
||||
r.Add = reflectdata.InterfaceMethodOffset(ityp, midx)
|
||||
r.Type = objabi.R_USEIFACEMETHOD
|
||||
}
|
||||
|
||||
@ -2095,7 +2096,7 @@ func walkprint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
|
||||
func callnew(t *types.Type) ir.Node {
|
||||
types.CalcSize(t)
|
||||
n := ir.NewUnaryExpr(base.Pos, ir.ONEWOBJ, typename(t))
|
||||
n := ir.NewUnaryExpr(base.Pos, ir.ONEWOBJ, reflectdata.TypePtr(t))
|
||||
n.SetType(types.NewPtr(t))
|
||||
n.SetTypecheck(1)
|
||||
n.MarkNonNil()
|
||||
@ -2589,7 +2590,7 @@ func mapfast(t *types.Type) int {
|
||||
if t.Elem().Width > 128 {
|
||||
return mapslow
|
||||
}
|
||||
switch algtype(t.Key()) {
|
||||
switch reflectdata.AlgType(t.Key()) {
|
||||
case types.AMEM32:
|
||||
if !t.Key().HasPointers() {
|
||||
return mapfast32
|
||||
@ -2733,7 +2734,7 @@ func appendslice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
|
||||
|
||||
// s = growslice(T, s, n)
|
||||
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn))}
|
||||
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), reflectdata.TypePtr(elemtype), s, nn))}
|
||||
nodes.Append(nif)
|
||||
|
||||
// s = s[:n]
|
||||
@ -2756,7 +2757,7 @@ func appendslice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
fn = typecheck.SubstArgTypes(fn, l1.Type().Elem(), l2.Type().Elem())
|
||||
ptr1, len1 := backingArrayPtrLen(cheapexpr(slice, &nodes))
|
||||
ptr2, len2 := backingArrayPtrLen(l2)
|
||||
ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, typename(elemtype), ptr1, len1, ptr2, len2)
|
||||
ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, reflectdata.TypePtr(elemtype), ptr1, len1, ptr2, len2)
|
||||
} else if base.Flag.Cfg.Instrumenting && !base.Flag.CompilingRuntime {
|
||||
// rely on runtime to instrument:
|
||||
// copy(s[len(l1):], l2)
|
||||
@ -2903,7 +2904,7 @@ func extendslice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
|
||||
|
||||
// s = growslice(T, s, n)
|
||||
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn))}
|
||||
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), reflectdata.TypePtr(elemtype), s, nn))}
|
||||
nodes = append(nodes, nif)
|
||||
|
||||
// s = s[:n]
|
||||
@ -3025,7 +3026,7 @@ func walkappend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
|
||||
fn := typecheck.LookupRuntime("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
|
||||
fn = typecheck.SubstArgTypes(fn, ns.Type().Elem(), ns.Type().Elem())
|
||||
|
||||
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, ns, mkcall1(fn, ns.Type(), nif.PtrInit(), typename(ns.Type().Elem()), ns,
|
||||
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, ns, mkcall1(fn, ns.Type(), nif.PtrInit(), reflectdata.TypePtr(ns.Type().Elem()), ns,
|
||||
ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns), na)))}
|
||||
|
||||
l = append(l, nif)
|
||||
@ -3073,7 +3074,7 @@ func copyany(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
|
||||
ptrL, lenL := backingArrayPtrLen(n.X)
|
||||
n.Y = cheapexpr(n.Y, init)
|
||||
ptrR, lenR := backingArrayPtrLen(n.Y)
|
||||
return mkcall1(fn, n.Type(), init, typename(n.X.Type().Elem()), ptrL, lenL, ptrR, lenR)
|
||||
return mkcall1(fn, n.Type(), init, reflectdata.TypePtr(n.X.Type().Elem()), ptrL, lenL, ptrR, lenR)
|
||||
}
|
||||
|
||||
if runtimecall {
|
||||
@ -3146,7 +3147,7 @@ func eqfor(t *types.Type) (n ir.Node, needsize bool) {
|
||||
n = typecheck.SubstArgTypes(n, t, t)
|
||||
return n, true
|
||||
case types.ASPECIAL:
|
||||
sym := typesymprefix(".eq", t)
|
||||
sym := reflectdata.TypeSymPrefix(".eq", t)
|
||||
n := typecheck.NewName(sym)
|
||||
ir.MarkFunc(n)
|
||||
n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
|
||||
@ -3200,7 +3201,7 @@ func walkcompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
|
||||
// l.tab != nil && l.tab._type == type(r)
|
||||
var eqtype ir.Node
|
||||
tab := ir.NewUnaryExpr(base.Pos, ir.OITAB, l)
|
||||
rtyp := typename(r.Type())
|
||||
rtyp := reflectdata.TypePtr(r.Type())
|
||||
if l.Type().IsEmptyInterface() {
|
||||
tab.SetType(types.NewPtr(types.Types[types.TUINT8]))
|
||||
tab.SetTypecheck(1)
|
||||
@ -3424,7 +3425,7 @@ func tracecmpArg(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node {
|
||||
func walkcompareInterface(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
|
||||
n.Y = cheapexpr(n.Y, init)
|
||||
n.X = cheapexpr(n.X, init)
|
||||
eqtab, eqdata := eqinterface(n.X, n.Y)
|
||||
eqtab, eqdata := reflectdata.EqInterface(n.X, n.Y)
|
||||
var cmp ir.Node
|
||||
if n.Op() == ir.OEQ {
|
||||
cmp = ir.NewLogicalExpr(base.Pos, ir.OANDAND, eqtab, eqdata)
|
||||
@ -3538,7 +3539,7 @@ func walkcompareString(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
|
||||
// prepare for rewrite below
|
||||
n.X = cheapexpr(n.X, init)
|
||||
n.Y = cheapexpr(n.Y, init)
|
||||
eqlen, eqmem := eqstring(n.X, n.Y)
|
||||
eqlen, eqmem := reflectdata.EqString(n.X, n.Y)
|
||||
// quick check of len before full compare for == or !=.
|
||||
// memequal then tests equality up to length len.
|
||||
if n.Op() == ir.OEQ {
|
||||
@ -3728,7 +3729,7 @@ func usefield(n *ir.SelectorExpr) {
|
||||
base.Errorf("tracked field must be exported (upper case)")
|
||||
}
|
||||
|
||||
sym := tracksym(outer, field)
|
||||
sym := reflectdata.TrackSym(outer, field)
|
||||
if ir.CurFunc.FieldTrack == nil {
|
||||
ir.CurFunc.FieldTrack = make(map[*types.Sym]struct{})
|
||||
}
|
||||
@ -3946,7 +3947,7 @@ func walkCheckPtrAlignment(n *ir.ConvExpr, init *ir.Nodes, count ir.Node) ir.Nod
|
||||
}
|
||||
|
||||
n.X = cheapexpr(n.X, init)
|
||||
init.Append(mkcall("checkptrAlignment", nil, init, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]), typename(elem), typecheck.Conv(count, types.Types[types.TUINTPTR])))
|
||||
init.Append(mkcall("checkptrAlignment", nil, init, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]), reflectdata.TypePtr(elem), typecheck.Conv(count, types.Types[types.TUINTPTR])))
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -2,38 +2,39 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gc
|
||||
package reflectdata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/objw"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// IsRegularMemory reports whether t can be compared/hashed as regular memory.
|
||||
func IsRegularMemory(t *types.Type) bool {
|
||||
// isRegularMemory reports whether t can be compared/hashed as regular memory.
|
||||
func isRegularMemory(t *types.Type) bool {
|
||||
a, _ := types.AlgType(t)
|
||||
return a == types.AMEM
|
||||
}
|
||||
|
||||
// EqCanPanic reports whether == on type t could panic (has an interface somewhere).
|
||||
// eqCanPanic reports whether == on type t could panic (has an interface somewhere).
|
||||
// t must be comparable.
|
||||
func EqCanPanic(t *types.Type) bool {
|
||||
func eqCanPanic(t *types.Type) bool {
|
||||
switch t.Kind() {
|
||||
default:
|
||||
return false
|
||||
case types.TINTER:
|
||||
return true
|
||||
case types.TARRAY:
|
||||
return EqCanPanic(t.Elem())
|
||||
return eqCanPanic(t.Elem())
|
||||
case types.TSTRUCT:
|
||||
for _, f := range t.FieldSlice() {
|
||||
if !f.Sym.IsBlank() && EqCanPanic(f.Type) {
|
||||
if !f.Sym.IsBlank() && eqCanPanic(f.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -41,9 +42,9 @@ func EqCanPanic(t *types.Type) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// algtype is like algtype1, except it returns the fixed-width AMEMxx variants
|
||||
// AlgType is like algtype1, except it returns the fixed-width AMEMxx variants
|
||||
// instead of the general AMEM kind when possible.
|
||||
func algtype(t *types.Type) types.AlgKind {
|
||||
func AlgType(t *types.Type) types.AlgKind {
|
||||
a, _ := types.AlgType(t)
|
||||
if a == types.AMEM {
|
||||
switch t.Width {
|
||||
@ -69,7 +70,7 @@ func algtype(t *types.Type) types.AlgKind {
|
||||
// the hash of a value of type t.
|
||||
// Note: the generated function must match runtime.typehash exactly.
|
||||
func genhash(t *types.Type) *obj.LSym {
|
||||
switch algtype(t) {
|
||||
switch AlgType(t) {
|
||||
default:
|
||||
// genhash is only called for types that have equality
|
||||
base.Fatalf("genhash %v", t)
|
||||
@ -119,7 +120,7 @@ func genhash(t *types.Type) *obj.LSym {
|
||||
break
|
||||
}
|
||||
|
||||
closure := typesymprefix(".hashfunc", t).Linksym()
|
||||
closure := TypeSymPrefix(".hashfunc", t).Linksym()
|
||||
if len(closure.P) > 0 { // already generated
|
||||
return closure
|
||||
}
|
||||
@ -139,7 +140,7 @@ func genhash(t *types.Type) *obj.LSym {
|
||||
}
|
||||
}
|
||||
|
||||
sym := typesymprefix(".hash", t)
|
||||
sym := TypeSymPrefix(".hash", t)
|
||||
if base.Flag.LowerR != 0 {
|
||||
fmt.Printf("genhash %v %v %v\n", closure, sym, t)
|
||||
}
|
||||
@ -199,7 +200,7 @@ func genhash(t *types.Type) *obj.LSym {
|
||||
}
|
||||
|
||||
// Hash non-memory fields with appropriate hash function.
|
||||
if !IsRegularMemory(f.Type) {
|
||||
if !isRegularMemory(f.Type) {
|
||||
hashel := hashfor(f.Type)
|
||||
call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
|
||||
nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
|
||||
@ -283,7 +284,7 @@ func hashfor(t *types.Type) ir.Node {
|
||||
default:
|
||||
// Note: the caller of hashfor ensured that this symbol
|
||||
// exists and has a body by calling genhash for t.
|
||||
sym = typesymprefix(".hash", t)
|
||||
sym = TypeSymPrefix(".hash", t)
|
||||
}
|
||||
|
||||
n := typecheck.NewName(sym)
|
||||
@ -312,7 +313,7 @@ func sysClosure(name string) *obj.LSym {
|
||||
// geneq returns a symbol which is the closure used to compute
|
||||
// equality for two objects of type t.
|
||||
func geneq(t *types.Type) *obj.LSym {
|
||||
switch algtype(t) {
|
||||
switch AlgType(t) {
|
||||
case types.ANOEQ:
|
||||
// The runtime will panic if it tries to compare
|
||||
// a type with a nil equality function.
|
||||
@ -362,11 +363,11 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
break
|
||||
}
|
||||
|
||||
closure := typesymprefix(".eqfunc", t).Linksym()
|
||||
closure := TypeSymPrefix(".eqfunc", t).Linksym()
|
||||
if len(closure.P) > 0 { // already generated
|
||||
return closure
|
||||
}
|
||||
sym := typesymprefix(".eq", t)
|
||||
sym := TypeSymPrefix(".eq", t)
|
||||
if base.Flag.LowerR != 0 {
|
||||
fmt.Printf("geneq %v\n", t)
|
||||
}
|
||||
@ -476,12 +477,12 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
// TODO: when the array size is small, unroll the length match checks.
|
||||
checkAll(3, false, func(pi, qi ir.Node) ir.Node {
|
||||
// Compare lengths.
|
||||
eqlen, _ := eqstring(pi, qi)
|
||||
eqlen, _ := EqString(pi, qi)
|
||||
return eqlen
|
||||
})
|
||||
checkAll(1, true, func(pi, qi ir.Node) ir.Node {
|
||||
// Compare contents.
|
||||
_, eqmem := eqstring(pi, qi)
|
||||
_, eqmem := EqString(pi, qi)
|
||||
return eqmem
|
||||
})
|
||||
case types.TFLOAT32, types.TFLOAT64:
|
||||
@ -520,8 +521,8 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
}
|
||||
|
||||
// Compare non-memory fields with field equality.
|
||||
if !IsRegularMemory(f.Type) {
|
||||
if EqCanPanic(f.Type) {
|
||||
if !isRegularMemory(f.Type) {
|
||||
if eqCanPanic(f.Type) {
|
||||
// Enforce ordering by starting a new set of reorderable conditions.
|
||||
conds = append(conds, []ir.Node{})
|
||||
}
|
||||
@ -529,13 +530,13 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
q := ir.NewSelectorExpr(base.Pos, ir.OXDOT, nq, f.Sym)
|
||||
switch {
|
||||
case f.Type.IsString():
|
||||
eqlen, eqmem := eqstring(p, q)
|
||||
eqlen, eqmem := EqString(p, q)
|
||||
and(eqlen)
|
||||
and(eqmem)
|
||||
default:
|
||||
and(ir.NewBinaryExpr(base.Pos, ir.OEQ, p, q))
|
||||
}
|
||||
if EqCanPanic(f.Type) {
|
||||
if eqCanPanic(f.Type) {
|
||||
// Also enforce ordering after something that can panic.
|
||||
conds = append(conds, []ir.Node{})
|
||||
}
|
||||
@ -597,7 +598,7 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
// return (or goto ret)
|
||||
fn.Body.Append(ir.NewLabelStmt(base.Pos, neq))
|
||||
fn.Body.Append(ir.NewAssignStmt(base.Pos, nr, ir.NewBool(false)))
|
||||
if EqCanPanic(t) || anyCall(fn) {
|
||||
if eqCanPanic(t) || anyCall(fn) {
|
||||
// Epilogue is large, so share it with the equal case.
|
||||
fn.Body.Append(ir.NewBranchStmt(base.Pos, ir.OGOTO, ret))
|
||||
} else {
|
||||
@ -655,13 +656,13 @@ func eqfield(p ir.Node, q ir.Node, field *types.Sym) ir.Node {
|
||||
return ne
|
||||
}
|
||||
|
||||
// eqstring returns the nodes
|
||||
// EqString returns the nodes
|
||||
// len(s) == len(t)
|
||||
// and
|
||||
// memequal(s.ptr, t.ptr, len(s))
|
||||
// which can be used to construct string equality comparison.
|
||||
// eqlen must be evaluated before eqmem, and shortcircuiting is required.
|
||||
func eqstring(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) {
|
||||
func EqString(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) {
|
||||
s = typecheck.Conv(s, types.Types[types.TSTRING])
|
||||
t = typecheck.Conv(t, types.Types[types.TSTRING])
|
||||
sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
|
||||
@ -680,13 +681,13 @@ func eqstring(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) {
|
||||
return cmp, call
|
||||
}
|
||||
|
||||
// eqinterface returns the nodes
|
||||
// EqInterface returns the nodes
|
||||
// s.tab == t.tab (or s.typ == t.typ, as appropriate)
|
||||
// and
|
||||
// ifaceeq(s.tab, s.data, t.data) (or efaceeq(s.typ, s.data, t.data), as appropriate)
|
||||
// which can be used to construct interface equality comparison.
|
||||
// eqtab must be evaluated before eqdata, and shortcircuiting is required.
|
||||
func eqinterface(s, t ir.Node) (eqtab *ir.BinaryExpr, eqdata *ir.CallExpr) {
|
||||
func EqInterface(s, t ir.Node) (eqtab *ir.BinaryExpr, eqdata *ir.CallExpr) {
|
||||
if !types.Identical(s.Type(), t.Type()) {
|
||||
base.Fatalf("eqinterface %v %v", s.Type(), t.Type())
|
||||
}
|
||||
@ -764,9 +765,24 @@ func memrun(t *types.Type, start int) (size int64, next int) {
|
||||
break
|
||||
}
|
||||
// Also, stop before a blank or non-memory field.
|
||||
if f := t.Field(next); f.Sym.IsBlank() || !IsRegularMemory(f.Type) {
|
||||
if f := t.Field(next); f.Sym.IsBlank() || !isRegularMemory(f.Type) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return t.Field(next-1).End() - t.Field(start).Offset, next
|
||||
}
|
||||
|
||||
func hashmem(t *types.Type) ir.Node {
|
||||
sym := ir.Pkgs.Runtime.Lookup("memhash")
|
||||
|
||||
n := typecheck.NewName(sym)
|
||||
ir.MarkFunc(n)
|
||||
n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
}, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
}))
|
||||
return n
|
||||
}
|
@ -2,11 +2,19 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gc
|
||||
package reflectdata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/bitvec"
|
||||
"cmd/compile/internal/escape"
|
||||
"cmd/compile/internal/inline"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/liveness"
|
||||
"cmd/compile/internal/objw"
|
||||
@ -16,11 +24,6 @@ import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type itabEntry struct {
|
||||
@ -52,7 +55,7 @@ var (
|
||||
ptabs []ptabEntry
|
||||
)
|
||||
|
||||
type Sig struct {
|
||||
type typeSig struct {
|
||||
name *types.Sym
|
||||
isym *types.Sym
|
||||
tsym *types.Sym
|
||||
@ -87,8 +90,8 @@ func makefield(name string, t *types.Type) *types.Field {
|
||||
return types.NewField(src.NoXPos, sym, t)
|
||||
}
|
||||
|
||||
// bmap makes the map bucket type given the type of the map.
|
||||
func bmap(t *types.Type) *types.Type {
|
||||
// MapBucketType makes the map bucket type given the type of the map.
|
||||
func MapBucketType(t *types.Type) *types.Type {
|
||||
if t.MapType().Bucket != nil {
|
||||
return t.MapType().Bucket
|
||||
}
|
||||
@ -194,14 +197,14 @@ func bmap(t *types.Type) *types.Type {
|
||||
return bucket
|
||||
}
|
||||
|
||||
// hmap builds a type representing a Hmap structure for the given map type.
|
||||
// MapType builds a type representing a Hmap structure for the given map type.
|
||||
// Make sure this stays in sync with runtime/map.go.
|
||||
func hmap(t *types.Type) *types.Type {
|
||||
func MapType(t *types.Type) *types.Type {
|
||||
if t.MapType().Hmap != nil {
|
||||
return t.MapType().Hmap
|
||||
}
|
||||
|
||||
bmap := bmap(t)
|
||||
bmap := MapBucketType(t)
|
||||
|
||||
// build a struct:
|
||||
// type hmap struct {
|
||||
@ -243,15 +246,15 @@ func hmap(t *types.Type) *types.Type {
|
||||
return hmap
|
||||
}
|
||||
|
||||
// hiter builds a type representing an Hiter structure for the given map type.
|
||||
// MapIterType builds a type representing an Hiter structure for the given map type.
|
||||
// Make sure this stays in sync with runtime/map.go.
|
||||
func hiter(t *types.Type) *types.Type {
|
||||
func MapIterType(t *types.Type) *types.Type {
|
||||
if t.MapType().Hiter != nil {
|
||||
return t.MapType().Hiter
|
||||
}
|
||||
|
||||
hmap := hmap(t)
|
||||
bmap := bmap(t)
|
||||
hmap := MapType(t)
|
||||
bmap := MapBucketType(t)
|
||||
|
||||
// build a struct:
|
||||
// type hiter struct {
|
||||
@ -302,50 +305,9 @@ func hiter(t *types.Type) *types.Type {
|
||||
return hiter
|
||||
}
|
||||
|
||||
// deferstruct makes a runtime._defer structure, with additional space for
|
||||
// stksize bytes of args.
|
||||
func deferstruct(stksize int64) *types.Type {
|
||||
makefield := func(name string, typ *types.Type) *types.Field {
|
||||
// Unlike the global makefield function, this one needs to set Pkg
|
||||
// because these types might be compared (in SSA CSE sorting).
|
||||
// TODO: unify this makefield and the global one above.
|
||||
sym := &types.Sym{Name: name, Pkg: types.LocalPkg}
|
||||
return types.NewField(src.NoXPos, sym, typ)
|
||||
}
|
||||
argtype := types.NewArray(types.Types[types.TUINT8], stksize)
|
||||
argtype.Width = stksize
|
||||
argtype.Align = 1
|
||||
// These fields must match the ones in runtime/runtime2.go:_defer and
|
||||
// cmd/compile/internal/gc/ssa.go:(*state).call.
|
||||
fields := []*types.Field{
|
||||
makefield("siz", types.Types[types.TUINT32]),
|
||||
makefield("started", types.Types[types.TBOOL]),
|
||||
makefield("heap", types.Types[types.TBOOL]),
|
||||
makefield("openDefer", types.Types[types.TBOOL]),
|
||||
makefield("sp", types.Types[types.TUINTPTR]),
|
||||
makefield("pc", types.Types[types.TUINTPTR]),
|
||||
// Note: the types here don't really matter. Defer structures
|
||||
// are always scanned explicitly during stack copying and GC,
|
||||
// so we make them uintptr type even though they are real pointers.
|
||||
makefield("fn", types.Types[types.TUINTPTR]),
|
||||
makefield("_panic", types.Types[types.TUINTPTR]),
|
||||
makefield("link", types.Types[types.TUINTPTR]),
|
||||
makefield("framepc", types.Types[types.TUINTPTR]),
|
||||
makefield("varp", types.Types[types.TUINTPTR]),
|
||||
makefield("fd", types.Types[types.TUINTPTR]),
|
||||
makefield("args", argtype),
|
||||
}
|
||||
|
||||
// build struct holding the above fields
|
||||
s := types.NewStruct(types.NoPkg, fields)
|
||||
s.SetNoalg(true)
|
||||
types.CalcStructSize(s)
|
||||
return s
|
||||
}
|
||||
|
||||
// methods returns the methods of the non-interface type t, sorted by name.
|
||||
// Generates stub functions as needed.
|
||||
func methods(t *types.Type) []*Sig {
|
||||
func methods(t *types.Type) []*typeSig {
|
||||
// method type
|
||||
mt := types.ReceiverBaseType(t)
|
||||
|
||||
@ -363,7 +325,7 @@ func methods(t *types.Type) []*Sig {
|
||||
|
||||
// make list of methods for t,
|
||||
// generating code if necessary.
|
||||
var ms []*Sig
|
||||
var ms []*typeSig
|
||||
for _, f := range mt.AllMethods().Slice() {
|
||||
if !f.IsMethod() {
|
||||
base.Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f)
|
||||
@ -388,7 +350,7 @@ func methods(t *types.Type) []*Sig {
|
||||
continue
|
||||
}
|
||||
|
||||
sig := &Sig{
|
||||
sig := &typeSig{
|
||||
name: method,
|
||||
isym: ir.MethodSym(it, method),
|
||||
tsym: ir.MethodSym(t, method),
|
||||
@ -418,8 +380,8 @@ func methods(t *types.Type) []*Sig {
|
||||
}
|
||||
|
||||
// imethods returns the methods of the interface type t, sorted by name.
|
||||
func imethods(t *types.Type) []*Sig {
|
||||
var methods []*Sig
|
||||
func imethods(t *types.Type) []*typeSig {
|
||||
var methods []*typeSig
|
||||
for _, f := range t.Fields().Slice() {
|
||||
if f.Type.Kind() != types.TFUNC || f.Sym == nil {
|
||||
continue
|
||||
@ -434,7 +396,7 @@ func imethods(t *types.Type) []*Sig {
|
||||
}
|
||||
}
|
||||
|
||||
sig := &Sig{
|
||||
sig := &typeSig{
|
||||
name: f.Sym,
|
||||
mtype: f.Type,
|
||||
type_: typecheck.NewMethodType(f.Type, nil),
|
||||
@ -622,7 +584,7 @@ func dextratype(lsym *obj.LSym, ot int, t *types.Type, dataAdd int) int {
|
||||
}
|
||||
|
||||
for _, a := range m {
|
||||
dtypesym(a.type_)
|
||||
WriteType(a.type_)
|
||||
}
|
||||
|
||||
ot = dgopkgpathOff(lsym, ot, typePkg(t))
|
||||
@ -673,7 +635,7 @@ func dextratypeData(lsym *obj.LSym, ot int, t *types.Type) int {
|
||||
nsym := dname(a.name.Name, "", pkg, exported)
|
||||
|
||||
ot = objw.SymPtrOff(lsym, ot, nsym)
|
||||
ot = dmethodptrOff(lsym, ot, dtypesym(a.mtype))
|
||||
ot = dmethodptrOff(lsym, ot, WriteType(a.mtype))
|
||||
ot = dmethodptrOff(lsym, ot, a.isym.Linksym())
|
||||
ot = dmethodptrOff(lsym, ot, a.tsym.Linksym())
|
||||
}
|
||||
@ -750,7 +712,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
|
||||
if t.Sym() != nil || methods(tptr) != nil {
|
||||
sptrWeak = false
|
||||
}
|
||||
sptr = dtypesym(tptr)
|
||||
sptr = WriteType(tptr)
|
||||
}
|
||||
|
||||
gcsym, useGCProg, ptrdata := dgcsym(t)
|
||||
@ -782,7 +744,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
|
||||
if t.Sym() != nil && t.Sym().Name != "" {
|
||||
tflag |= tflagNamed
|
||||
}
|
||||
if IsRegularMemory(t) {
|
||||
if isRegularMemory(t) {
|
||||
tflag |= tflagRegularMemory
|
||||
}
|
||||
|
||||
@ -848,20 +810,20 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
|
||||
return ot
|
||||
}
|
||||
|
||||
// tracksym returns the symbol for tracking use of field/method f, assumed
|
||||
// TrackSym returns the symbol for tracking use of field/method f, assumed
|
||||
// to be a member of struct/interface type t.
|
||||
func tracksym(t *types.Type, f *types.Field) *types.Sym {
|
||||
func TrackSym(t *types.Type, f *types.Field) *types.Sym {
|
||||
return ir.Pkgs.Track.Lookup(t.ShortString() + "." + f.Sym.Name)
|
||||
}
|
||||
|
||||
func typesymprefix(prefix string, t *types.Type) *types.Sym {
|
||||
func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {
|
||||
p := prefix + "." + t.ShortString()
|
||||
s := types.TypeSymLookup(p)
|
||||
|
||||
// This function is for looking up type-related generated functions
|
||||
// (e.g. eq and hash). Make sure they are indeed generated.
|
||||
signatmu.Lock()
|
||||
addsignat(t)
|
||||
NeedRuntimeType(t)
|
||||
signatmu.Unlock()
|
||||
|
||||
//print("algsym: %s -> %+S\n", p, s);
|
||||
@ -869,19 +831,19 @@ func typesymprefix(prefix string, t *types.Type) *types.Sym {
|
||||
return s
|
||||
}
|
||||
|
||||
func typenamesym(t *types.Type) *types.Sym {
|
||||
func TypeSym(t *types.Type) *types.Sym {
|
||||
if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
|
||||
base.Fatalf("typenamesym %v", t)
|
||||
}
|
||||
s := types.TypeSym(t)
|
||||
signatmu.Lock()
|
||||
addsignat(t)
|
||||
NeedRuntimeType(t)
|
||||
signatmu.Unlock()
|
||||
return s
|
||||
}
|
||||
|
||||
func typename(t *types.Type) *ir.AddrExpr {
|
||||
s := typenamesym(t)
|
||||
func TypePtr(t *types.Type) *ir.AddrExpr {
|
||||
s := TypeSym(t)
|
||||
if s.Def == nil {
|
||||
n := ir.NewNameAt(src.NoXPos, s)
|
||||
n.SetType(types.Types[types.TUINT8])
|
||||
@ -896,7 +858,7 @@ func typename(t *types.Type) *ir.AddrExpr {
|
||||
return n
|
||||
}
|
||||
|
||||
func itabname(t, itype *types.Type) *ir.AddrExpr {
|
||||
func ITabAddr(t, itype *types.Type) *ir.AddrExpr {
|
||||
if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() {
|
||||
base.Fatalf("itabname(%v, %v)", t, itype)
|
||||
}
|
||||
@ -978,7 +940,7 @@ func formalType(t *types.Type) *types.Type {
|
||||
return t
|
||||
}
|
||||
|
||||
func dtypesym(t *types.Type) *obj.LSym {
|
||||
func WriteType(t *types.Type) *obj.LSym {
|
||||
t = formalType(t)
|
||||
if t.IsUntyped() {
|
||||
base.Fatalf("dtypesym %v", t)
|
||||
@ -1028,9 +990,9 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
|
||||
case types.TARRAY:
|
||||
// ../../../../runtime/type.go:/arrayType
|
||||
s1 := dtypesym(t.Elem())
|
||||
s1 := WriteType(t.Elem())
|
||||
t2 := types.NewSlice(t.Elem())
|
||||
s2 := dtypesym(t2)
|
||||
s2 := WriteType(t2)
|
||||
ot = dcommontype(lsym, t)
|
||||
ot = objw.SymPtr(lsym, ot, s1, 0)
|
||||
ot = objw.SymPtr(lsym, ot, s2, 0)
|
||||
@ -1039,14 +1001,14 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
|
||||
case types.TSLICE:
|
||||
// ../../../../runtime/type.go:/sliceType
|
||||
s1 := dtypesym(t.Elem())
|
||||
s1 := WriteType(t.Elem())
|
||||
ot = dcommontype(lsym, t)
|
||||
ot = objw.SymPtr(lsym, ot, s1, 0)
|
||||
ot = dextratype(lsym, ot, t, 0)
|
||||
|
||||
case types.TCHAN:
|
||||
// ../../../../runtime/type.go:/chanType
|
||||
s1 := dtypesym(t.Elem())
|
||||
s1 := WriteType(t.Elem())
|
||||
ot = dcommontype(lsym, t)
|
||||
ot = objw.SymPtr(lsym, ot, s1, 0)
|
||||
ot = objw.Uintptr(lsym, ot, uint64(t.ChanDir()))
|
||||
@ -1054,15 +1016,15 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
|
||||
case types.TFUNC:
|
||||
for _, t1 := range t.Recvs().Fields().Slice() {
|
||||
dtypesym(t1.Type)
|
||||
WriteType(t1.Type)
|
||||
}
|
||||
isddd := false
|
||||
for _, t1 := range t.Params().Fields().Slice() {
|
||||
isddd = t1.IsDDD()
|
||||
dtypesym(t1.Type)
|
||||
WriteType(t1.Type)
|
||||
}
|
||||
for _, t1 := range t.Results().Fields().Slice() {
|
||||
dtypesym(t1.Type)
|
||||
WriteType(t1.Type)
|
||||
}
|
||||
|
||||
ot = dcommontype(lsym, t)
|
||||
@ -1082,20 +1044,20 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
|
||||
// Array of rtype pointers follows funcType.
|
||||
for _, t1 := range t.Recvs().Fields().Slice() {
|
||||
ot = objw.SymPtr(lsym, ot, dtypesym(t1.Type), 0)
|
||||
ot = objw.SymPtr(lsym, ot, WriteType(t1.Type), 0)
|
||||
}
|
||||
for _, t1 := range t.Params().Fields().Slice() {
|
||||
ot = objw.SymPtr(lsym, ot, dtypesym(t1.Type), 0)
|
||||
ot = objw.SymPtr(lsym, ot, WriteType(t1.Type), 0)
|
||||
}
|
||||
for _, t1 := range t.Results().Fields().Slice() {
|
||||
ot = objw.SymPtr(lsym, ot, dtypesym(t1.Type), 0)
|
||||
ot = objw.SymPtr(lsym, ot, WriteType(t1.Type), 0)
|
||||
}
|
||||
|
||||
case types.TINTER:
|
||||
m := imethods(t)
|
||||
n := len(m)
|
||||
for _, a := range m {
|
||||
dtypesym(a.type_)
|
||||
WriteType(a.type_)
|
||||
}
|
||||
|
||||
// ../../../../runtime/type.go:/interfaceType
|
||||
@ -1123,14 +1085,14 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
nsym := dname(a.name.Name, "", pkg, exported)
|
||||
|
||||
ot = objw.SymPtrOff(lsym, ot, nsym)
|
||||
ot = objw.SymPtrOff(lsym, ot, dtypesym(a.type_))
|
||||
ot = objw.SymPtrOff(lsym, ot, WriteType(a.type_))
|
||||
}
|
||||
|
||||
// ../../../../runtime/type.go:/mapType
|
||||
case types.TMAP:
|
||||
s1 := dtypesym(t.Key())
|
||||
s2 := dtypesym(t.Elem())
|
||||
s3 := dtypesym(bmap(t))
|
||||
s1 := WriteType(t.Key())
|
||||
s2 := WriteType(t.Elem())
|
||||
s3 := WriteType(MapBucketType(t))
|
||||
hasher := genhash(t.Key())
|
||||
|
||||
ot = dcommontype(lsym, t)
|
||||
@ -1154,7 +1116,7 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
} else {
|
||||
ot = objw.Uint8(lsym, ot, uint8(t.Elem().Width))
|
||||
}
|
||||
ot = objw.Uint16(lsym, ot, uint16(bmap(t).Width))
|
||||
ot = objw.Uint16(lsym, ot, uint16(MapBucketType(t).Width))
|
||||
if types.IsReflexive(t.Key()) {
|
||||
flags |= 4 // reflexive key
|
||||
}
|
||||
@ -1177,7 +1139,7 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
}
|
||||
|
||||
// ../../../../runtime/type.go:/ptrType
|
||||
s1 := dtypesym(t.Elem())
|
||||
s1 := WriteType(t.Elem())
|
||||
|
||||
ot = dcommontype(lsym, t)
|
||||
ot = objw.SymPtr(lsym, ot, s1, 0)
|
||||
@ -1188,7 +1150,7 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
case types.TSTRUCT:
|
||||
fields := t.Fields().Slice()
|
||||
for _, t1 := range fields {
|
||||
dtypesym(t1.Type)
|
||||
WriteType(t1.Type)
|
||||
}
|
||||
|
||||
// All non-exported struct field names within a struct
|
||||
@ -1216,7 +1178,7 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
for _, f := range fields {
|
||||
// ../../../../runtime/type.go:/structField
|
||||
ot = dnameField(lsym, ot, spkg, f)
|
||||
ot = objw.SymPtr(lsym, ot, dtypesym(f.Type), 0)
|
||||
ot = objw.SymPtr(lsym, ot, WriteType(f.Type), 0)
|
||||
offsetAnon := uint64(f.Offset) << 1
|
||||
if offsetAnon>>1 != uint64(f.Offset) {
|
||||
base.Fatalf("%v: bad field offset for %s", t, f.Sym.Name)
|
||||
@ -1257,9 +1219,9 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
return lsym
|
||||
}
|
||||
|
||||
// ifaceMethodOffset returns the offset of the i-th method in the interface
|
||||
// InterfaceMethodOffset returns the offset of the i-th method in the interface
|
||||
// type descriptor, ityp.
|
||||
func ifaceMethodOffset(ityp *types.Type, i int64) int64 {
|
||||
func InterfaceMethodOffset(ityp *types.Type, i int64) int64 {
|
||||
// interface type descriptor layout is struct {
|
||||
// _type // commonSize
|
||||
// pkgpath // 1 word
|
||||
@ -1273,7 +1235,7 @@ func ifaceMethodOffset(ityp *types.Type, i int64) int64 {
|
||||
|
||||
// for each itabEntry, gather the methods on
|
||||
// the concrete type that implement the interface
|
||||
func peekitabs() {
|
||||
func CompileITabs() {
|
||||
for i := range itabs {
|
||||
tab := &itabs[i]
|
||||
methods := genfun(tab.t, tab.itype)
|
||||
@ -1319,11 +1281,11 @@ func genfun(t, it *types.Type) []*obj.LSym {
|
||||
return out
|
||||
}
|
||||
|
||||
// itabsym uses the information gathered in
|
||||
// ITabSym uses the information gathered in
|
||||
// peekitabs to de-virtualize interface methods.
|
||||
// Since this is called by the SSA backend, it shouldn't
|
||||
// generate additional Nodes, Syms, etc.
|
||||
func itabsym(it *obj.LSym, offset int64) *obj.LSym {
|
||||
func ITabSym(it *obj.LSym, offset int64) *obj.LSym {
|
||||
var syms []*obj.LSym
|
||||
if it == nil {
|
||||
return nil
|
||||
@ -1348,24 +1310,15 @@ func itabsym(it *obj.LSym, offset int64) *obj.LSym {
|
||||
return syms[methodnum]
|
||||
}
|
||||
|
||||
// addsignat ensures that a runtime type descriptor is emitted for t.
|
||||
func addsignat(t *types.Type) {
|
||||
// NeedRuntimeType ensures that a runtime type descriptor is emitted for t.
|
||||
func NeedRuntimeType(t *types.Type) {
|
||||
if _, ok := signatset[t]; !ok {
|
||||
signatset[t] = struct{}{}
|
||||
signatslice = append(signatslice, t)
|
||||
}
|
||||
}
|
||||
|
||||
func addsignats(dcls []ir.Node) {
|
||||
// copy types from dcl list to signatset
|
||||
for _, n := range dcls {
|
||||
if n.Op() == ir.OTYPE {
|
||||
addsignat(n.Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpsignats() {
|
||||
func WriteRuntimeTypes() {
|
||||
// Process signatset. Use a loop, as dtypesym adds
|
||||
// entries to signatset while it is being processed.
|
||||
signats := make([]typeAndStr, len(signatslice))
|
||||
@ -1380,15 +1333,15 @@ func dumpsignats() {
|
||||
sort.Sort(typesByString(signats))
|
||||
for _, ts := range signats {
|
||||
t := ts.t
|
||||
dtypesym(t)
|
||||
WriteType(t)
|
||||
if t.Sym() != nil {
|
||||
dtypesym(types.NewPtr(t))
|
||||
WriteType(types.NewPtr(t))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumptabs() {
|
||||
func WriteTabs() {
|
||||
// process itabs
|
||||
for _, i := range itabs {
|
||||
// dump empty itab symbol into i.sym
|
||||
@ -1399,8 +1352,8 @@ func dumptabs() {
|
||||
// _ [4]byte
|
||||
// fun [1]uintptr // variable sized
|
||||
// }
|
||||
o := objw.SymPtr(i.lsym, 0, dtypesym(i.itype), 0)
|
||||
o = objw.SymPtr(i.lsym, o, dtypesym(i.t), 0)
|
||||
o := objw.SymPtr(i.lsym, 0, WriteType(i.itype), 0)
|
||||
o = objw.SymPtr(i.lsym, o, WriteType(i.t), 0)
|
||||
o = objw.Uint32(i.lsym, o, types.TypeHash(i.t)) // copy of type hash
|
||||
o += 4 // skip unused field
|
||||
for _, fn := range genfun(i.t, i.itype) {
|
||||
@ -1423,7 +1376,7 @@ func dumptabs() {
|
||||
// typ typeOff // pointer to symbol
|
||||
// }
|
||||
nsym := dname(p.s.Name, "", nil, true)
|
||||
tsym := dtypesym(p.t)
|
||||
tsym := WriteType(p.t)
|
||||
ot = objw.SymPtrOff(s, ot, nsym)
|
||||
ot = objw.SymPtrOff(s, ot, tsym)
|
||||
// Plugin exports symbols as interfaces. Mark their types
|
||||
@ -1441,14 +1394,14 @@ func dumptabs() {
|
||||
}
|
||||
}
|
||||
|
||||
func dumpimportstrings() {
|
||||
func WriteImportStrings() {
|
||||
// generate import strings for imported packages
|
||||
for _, p := range types.ImportedPkgList() {
|
||||
dimportpath(p)
|
||||
}
|
||||
}
|
||||
|
||||
func dumpbasictypes() {
|
||||
func WriteBasicTypes() {
|
||||
// do basic types if compiling package runtime.
|
||||
// they have to be in at least one package,
|
||||
// and runtime is always loaded implicitly,
|
||||
@ -1457,16 +1410,16 @@ func dumpbasictypes() {
|
||||
// but using runtime means fewer copies in object files.
|
||||
if base.Ctxt.Pkgpath == "runtime" {
|
||||
for i := types.Kind(1); i <= types.TBOOL; i++ {
|
||||
dtypesym(types.NewPtr(types.Types[i]))
|
||||
WriteType(types.NewPtr(types.Types[i]))
|
||||
}
|
||||
dtypesym(types.NewPtr(types.Types[types.TSTRING]))
|
||||
dtypesym(types.NewPtr(types.Types[types.TUNSAFEPTR]))
|
||||
WriteType(types.NewPtr(types.Types[types.TSTRING]))
|
||||
WriteType(types.NewPtr(types.Types[types.TUNSAFEPTR]))
|
||||
|
||||
// emit type structs for error and func(error) string.
|
||||
// The latter is the type of an auto-generated wrapper.
|
||||
dtypesym(types.NewPtr(types.ErrorType))
|
||||
WriteType(types.NewPtr(types.ErrorType))
|
||||
|
||||
dtypesym(typecheck.NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.ErrorType)}, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.Types[types.TSTRING])}))
|
||||
WriteType(typecheck.NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.ErrorType)}, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.Types[types.TSTRING])}))
|
||||
|
||||
// add paths for runtime and main, which 6l imports implicitly.
|
||||
dimportpath(ir.Pkgs.Runtime)
|
||||
@ -1611,8 +1564,8 @@ func dgcprog(t *types.Type) (*obj.LSym, int64) {
|
||||
if t.Width == types.BADWIDTH {
|
||||
base.Fatalf("dgcprog: %v badwidth", t)
|
||||
}
|
||||
lsym := typesymprefix(".gcprog", t).Linksym()
|
||||
var p GCProg
|
||||
lsym := TypeSymPrefix(".gcprog", t).Linksym()
|
||||
var p gcProg
|
||||
p.init(lsym)
|
||||
p.emit(t, 0)
|
||||
offset := p.w.BitIndex() * int64(types.PtrSize)
|
||||
@ -1623,13 +1576,13 @@ func dgcprog(t *types.Type) (*obj.LSym, int64) {
|
||||
return lsym, offset
|
||||
}
|
||||
|
||||
type GCProg struct {
|
||||
type gcProg struct {
|
||||
lsym *obj.LSym
|
||||
symoff int
|
||||
w gcprog.Writer
|
||||
}
|
||||
|
||||
func (p *GCProg) init(lsym *obj.LSym) {
|
||||
func (p *gcProg) init(lsym *obj.LSym) {
|
||||
p.lsym = lsym
|
||||
p.symoff = 4 // first 4 bytes hold program length
|
||||
p.w.Init(p.writeByte)
|
||||
@ -1639,11 +1592,11 @@ func (p *GCProg) init(lsym *obj.LSym) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *GCProg) writeByte(x byte) {
|
||||
func (p *gcProg) writeByte(x byte) {
|
||||
p.symoff = objw.Uint8(p.lsym, p.symoff, x)
|
||||
}
|
||||
|
||||
func (p *GCProg) end() {
|
||||
func (p *gcProg) end() {
|
||||
p.w.End()
|
||||
objw.Uint32(p.lsym, 0, uint32(p.symoff-4))
|
||||
objw.Global(p.lsym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL)
|
||||
@ -1652,7 +1605,7 @@ func (p *GCProg) end() {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *GCProg) emit(t *types.Type, offset int64) {
|
||||
func (p *gcProg) emit(t *types.Type, offset int64) {
|
||||
types.CalcSize(t)
|
||||
if !t.HasPointers() {
|
||||
return
|
||||
@ -1707,14 +1660,14 @@ func (p *GCProg) emit(t *types.Type, offset int64) {
|
||||
}
|
||||
}
|
||||
|
||||
// zeroaddr returns the address of a symbol with at least
|
||||
// ZeroAddr returns the address of a symbol with at least
|
||||
// size bytes of zeros.
|
||||
func zeroaddr(size int64) ir.Node {
|
||||
func ZeroAddr(size int64) ir.Node {
|
||||
if size >= 1<<31 {
|
||||
base.Fatalf("map elem too big %d", size)
|
||||
}
|
||||
if zerosize < size {
|
||||
zerosize = size
|
||||
if ZeroSize < size {
|
||||
ZeroSize = size
|
||||
}
|
||||
s := ir.Pkgs.Map.Lookup("zero")
|
||||
if s.Def == nil {
|
||||
@ -1729,3 +1682,155 @@ func zeroaddr(size int64) ir.Node {
|
||||
z.SetTypecheck(1)
|
||||
return z
|
||||
}
|
||||
|
||||
func CollectPTabs() {
|
||||
if !base.Ctxt.Flag_dynlink || types.LocalPkg.Name != "main" {
|
||||
return
|
||||
}
|
||||
for _, exportn := range typecheck.Target.Exports {
|
||||
s := exportn.Sym()
|
||||
nn := ir.AsNode(s.Def)
|
||||
if nn == nil {
|
||||
continue
|
||||
}
|
||||
if nn.Op() != ir.ONAME {
|
||||
continue
|
||||
}
|
||||
n := nn.(*ir.Name)
|
||||
if !types.IsExported(s.Name) {
|
||||
continue
|
||||
}
|
||||
if s.Pkg.Name != "main" {
|
||||
continue
|
||||
}
|
||||
if n.Type().Kind() == types.TFUNC && n.Class_ == ir.PFUNC {
|
||||
// function
|
||||
ptabs = append(ptabs, ptabEntry{s: s, t: s.Def.Type()})
|
||||
} else {
|
||||
// variable
|
||||
ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(s.Def.Type())})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a wrapper function to convert from
|
||||
// a receiver of type T to a receiver of type U.
|
||||
// That is,
|
||||
//
|
||||
// func (t T) M() {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// already exists; this function generates
|
||||
//
|
||||
// func (u U) M() {
|
||||
// u.M()
|
||||
// }
|
||||
//
|
||||
// where the types T and U are such that u.M() is valid
|
||||
// and calls the T.M method.
|
||||
// The resulting function is for use in method tables.
|
||||
//
|
||||
// rcvr - U
|
||||
// method - M func (t T)(), a TFIELD type struct
|
||||
// newnam - the eventual mangled name of this function
|
||||
func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
||||
if false && base.Flag.LowerR != 0 {
|
||||
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
|
||||
}
|
||||
|
||||
// Only generate (*T).M wrappers for T.M in T's own package.
|
||||
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
|
||||
rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg {
|
||||
return
|
||||
}
|
||||
|
||||
// Only generate I.M wrappers for I in I's own package
|
||||
// but keep doing it for error.Error (was issue #29304).
|
||||
if rcvr.IsInterface() && rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && rcvr != types.ErrorType {
|
||||
return
|
||||
}
|
||||
|
||||
base.Pos = base.AutogeneratedPos
|
||||
typecheck.DeclContext = ir.PEXTERN
|
||||
|
||||
tfn := ir.NewFuncType(base.Pos,
|
||||
ir.NewField(base.Pos, typecheck.Lookup(".this"), nil, rcvr),
|
||||
typecheck.NewFuncParams(method.Type.Params(), true),
|
||||
typecheck.NewFuncParams(method.Type.Results(), false))
|
||||
|
||||
fn := typecheck.DeclFunc(newnam, tfn)
|
||||
fn.SetDupok(true)
|
||||
|
||||
nthis := ir.AsNode(tfn.Type().Recv().Nname)
|
||||
|
||||
methodrcvr := method.Type.Recv().Type
|
||||
|
||||
// generate nil pointer check for better error
|
||||
if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
|
||||
// generating wrapper from *T to T.
|
||||
n := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
||||
n.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, nthis, typecheck.NodNil())
|
||||
call := ir.NewCallExpr(base.Pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)
|
||||
n.Body = []ir.Node{call}
|
||||
fn.Body.Append(n)
|
||||
}
|
||||
|
||||
dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
|
||||
|
||||
// generate call
|
||||
// It's not possible to use a tail call when dynamic linking on ppc64le. The
|
||||
// bad scenario is when a local call is made to the wrapper: the wrapper will
|
||||
// call the implementation, which might be in a different module and so set
|
||||
// the TOC to the appropriate value for that module. But if it returns
|
||||
// directly to the wrapper's caller, nothing will reset it to the correct
|
||||
// value for that function.
|
||||
if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) {
|
||||
// generate tail call: adjust pointer receiver and jump to embedded method.
|
||||
left := dot.X // skip final .M
|
||||
if !left.Type().IsPtr() {
|
||||
left = typecheck.NodAddr(left)
|
||||
}
|
||||
as := ir.NewAssignStmt(base.Pos, nthis, typecheck.ConvNop(left, rcvr))
|
||||
fn.Body.Append(as)
|
||||
fn.Body.Append(ir.NewBranchStmt(base.Pos, ir.ORETJMP, ir.MethodSym(methodrcvr, method.Sym)))
|
||||
} else {
|
||||
fn.SetWrapper(true) // ignore frame for panic+recover matching
|
||||
call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
|
||||
call.Args.Set(ir.ParamNames(tfn.Type()))
|
||||
call.IsDDD = tfn.Type().IsVariadic()
|
||||
if method.Type.NumResults() > 0 {
|
||||
ret := ir.NewReturnStmt(base.Pos, nil)
|
||||
ret.Results = []ir.Node{call}
|
||||
fn.Body.Append(ret)
|
||||
} else {
|
||||
fn.Body.Append(call)
|
||||
}
|
||||
}
|
||||
|
||||
if false && base.Flag.LowerR != 0 {
|
||||
ir.DumpList("genwrapper body", fn.Body)
|
||||
}
|
||||
|
||||
typecheck.FinishFuncBody()
|
||||
if base.Debug.DclStack != 0 {
|
||||
types.CheckDclstack()
|
||||
}
|
||||
|
||||
typecheck.Func(fn)
|
||||
ir.CurFunc = fn
|
||||
typecheck.Stmts(fn.Body)
|
||||
|
||||
// Inline calls within (*T).M wrappers. This is safe because we only
|
||||
// generate those wrappers within the same compilation unit as (T).M.
|
||||
// TODO(mdempsky): Investigate why we can't enable this more generally.
|
||||
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym() != nil {
|
||||
inline.InlineCalls(fn)
|
||||
}
|
||||
escape.Batch([]*ir.Func{fn}, false)
|
||||
|
||||
ir.CurFunc = nil
|
||||
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
|
||||
}
|
||||
|
||||
var ZeroSize int64
|
Loading…
Reference in New Issue
Block a user