diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/compile/internal/gc/abiutils_test.go | 5 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/go.go | 2 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/main.go | 11 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/obj.go | 60 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/order.go | 3 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/pgen.go | 3 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/range.go | 5 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/sinit.go | 5 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/ssa.go | 52 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/subr.go | 140 | ||||
| -rw-r--r-- | src/cmd/compile/internal/gc/walk.go | 81 | ||||
| -rw-r--r-- | src/cmd/compile/internal/reflectdata/alg.go (renamed from src/cmd/compile/internal/gc/alg.go) | 78 | ||||
| -rw-r--r-- | src/cmd/compile/internal/reflectdata/reflect.go (renamed from src/cmd/compile/internal/gc/reflect.go) | 379 |
13 files changed, 418 insertions, 406 deletions
diff --git a/src/cmd/compile/internal/gc/abiutils_test.go b/src/cmd/compile/internal/gc/abiutils_test.go index fe9a838688..4b2a30d00c 100644 --- a/src/cmd/compile/internal/gc/abiutils_test.go +++ b/src/cmd/compile/internal/gc/abiutils_test.go @@ -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()) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 6f97d43fef..ba838a5ff5 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -12,8 +12,6 @@ import ( var pragcgobuf [][]string -var zerosize int64 - // interface to back end type Arch struct { diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index bb6ace6562..e66b877fd0 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -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. diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 50935d4e98..4db2ad9d4a 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -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()) + } + } +} diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index 32a355ae6b..d1c5bb04a1 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -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 { diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index dcba5c7ecb..4d990e7dba 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -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 { diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go index c040811932..4ba0654aef 100644 --- a/src/cmd/compile/internal/gc/range.go +++ b/src/cmd/compile/internal/gc/range.go @@ -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)) } diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go index d818be94a4..337b67af46 100644 --- a/src/cmd/compile/internal/gc/sinit.go +++ b/src/cmd/compile/internal/gc/sinit.go @@ -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. diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 51eeb9315a..997bcb6d5e 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -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 +} diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 362c5162b6..89baaf7eee 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -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 } diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 9c2484f3dc..9b49b06c34 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -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 } diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/reflectdata/alg.go index 4fc8cf04ef..8391486e50 100644 --- a/src/cmd/compile/internal/gc/alg.go +++ b/src/cmd/compile/internal/reflectdata/alg.go @@ -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 +} diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 42f441a44a..a5e2fb407a 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -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 |
