1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45package reflectdata67import (8 "encoding/binary"9 "fmt"10 "internal/abi"11 "slices"12 "sort"13 "strings"14 "sync"1516 "cmd/compile/internal/base"17 "cmd/compile/internal/bitvec"18 "cmd/compile/internal/ir"19 "cmd/compile/internal/objw"20 "cmd/compile/internal/rttype"21 "cmd/compile/internal/staticdata"22 "cmd/compile/internal/typebits"23 "cmd/compile/internal/typecheck"24 "cmd/compile/internal/types"25 "cmd/internal/obj"26 "cmd/internal/objabi"27 "cmd/internal/src"28)2930type ptabEntry struct {31 s *types.Sym32 t *types.Type33}3435// runtime interface and reflection data structures36var (37 // protects signatset and signatslice38 signatmu sync.Mutex39 // Tracking which types need runtime type descriptor40 signatset = make(map[*types.Type]struct{})41 // Queue of types wait to be generated runtime type descriptor42 signatslice []typeAndStr4344 gcsymmu sync.Mutex // protects gcsymset and gcsymslice45 gcsymset = make(map[*types.Type]struct{})46)4748type typeSig struct {49 name *types.Sym50 isym *obj.LSym51 tsym *obj.LSym52 type_ *types.Type53 mtype *types.Type54}5556func commonSize() int { return int(rttype.Type.Size()) } // Sizeof(runtime._type{})5758func uncommonSize(t *types.Type) int { // Sizeof(runtime.uncommontype{})59 if t.TFlag()&abi.TFlagUncommon == 0 {60 return 061 }62 return int(rttype.UncommonType.Size())63}6465func makefield(name string, t *types.Type) *types.Field {66 sym := (*types.Pkg)(nil).Lookup(name)67 return types.NewField(src.NoXPos, sym, t)68}6970// methods returns the methods of the non-interface type t, sorted by name.71// Generates stub functions as needed.72func methods(t *types.Type) []*typeSig {73 if t.HasShape() {74 // Shape types have no methods.75 return nil76 }77 // method type78 mt := types.ReceiverBaseType(t)7980 if mt == nil {81 return nil82 }83 typecheck.CalcMethods(mt)8485 // make list of methods for t,86 // generating code if necessary.87 var ms []*typeSig88 for _, f := range mt.AllMethods() {89 if f.Sym == nil {90 base.Fatalf("method with no sym on %v", mt)91 }92 if !f.IsMethod() {93 base.Fatalf("non-method on %v method %v %v", mt, f.Sym, f)94 }95 if f.Type.Recv() == nil {96 base.Fatalf("receiver with no type on %v method %v %v", mt, f.Sym, f)97 }98 if f.Nointerface() && !t.IsFullyInstantiated() {99 // Skip creating method wrappers if f is nointerface. But, if100 // t is an instantiated type, we still have to call101 // methodWrapper, because methodWrapper generates the actual102 // generic method on the type as well.103 continue104 }105106 // get receiver type for this particular method.107 // if pointer receiver but non-pointer t and108 // this is not an embedded pointer inside a struct,109 // method does not apply.110 if !types.IsMethodApplicable(t, f) {111 continue112 }113114 sig := &typeSig{115 name: f.Sym,116 isym: methodWrapper(t, f, true),117 tsym: methodWrapper(t, f, false),118 type_: typecheck.NewMethodType(f.Type, t),119 mtype: typecheck.NewMethodType(f.Type, nil),120 }121 if f.Nointerface() {122 // In the case of a nointerface method on an instantiated123 // type, don't actually append the typeSig.124 continue125 }126 ms = append(ms, sig)127 }128129 return ms130}131132// imethods returns the methods of the interface type t, sorted by name.133func imethods(t *types.Type) []*typeSig {134 var methods []*typeSig135 for _, f := range t.AllMethods() {136 if f.Type.Kind() != types.TFUNC || f.Sym == nil {137 continue138 }139 if f.Sym.IsBlank() {140 base.Fatalf("unexpected blank symbol in interface method set")141 }142 if n := len(methods); n > 0 {143 last := methods[n-1]144 if types.CompareSyms(last.name, f.Sym) >= 0 {145 base.Fatalf("sigcmp vs sortinter %v %v", last.name, f.Sym)146 }147 }148149 sig := &typeSig{150 name: f.Sym,151 mtype: f.Type,152 type_: typecheck.NewMethodType(f.Type, nil),153 }154 methods = append(methods, sig)155156 // NOTE(rsc): Perhaps an oversight that157 // IfaceType.Method is not in the reflect data.158 // Generate the method body, so that compiled159 // code can refer to it.160 methodWrapper(t, f, false)161 }162163 return methods164}165166func dimportpath(p *types.Pkg) {167 if p.Pathsym != nil {168 return169 }170171 if p == types.LocalPkg && base.Ctxt.Pkgpath == "" {172 panic("missing pkgpath")173 }174175 // If we are compiling the runtime package, there are two runtime packages around176 // -- localpkg and Pkgs.Runtime. We don't want to produce import path symbols for177 // both of them, so just produce one for localpkg.178 if base.Ctxt.Pkgpath == "runtime" && p == ir.Pkgs.Runtime {179 return180 }181182 s := base.Ctxt.Lookup("type:.importpath." + p.Prefix + ".")183 ot := dnameData(s, 0, p.Path, "", nil, false, false)184 objw.Global(s, int32(ot), obj.DUPOK|obj.RODATA)185 s.Set(obj.AttrContentAddressable, true)186 s.Align = 1187 p.Pathsym = s188}189190func dgopkgpath(c rttype.Cursor, pkg *types.Pkg) {191 c = c.Field("Bytes")192 if pkg == nil {193 c.WritePtr(nil)194 return195 }196197 dimportpath(pkg)198 c.WritePtr(pkg.Pathsym)199}200201// dgopkgpathOff writes an offset relocation to the pkg path symbol to c.202func dgopkgpathOff(c rttype.Cursor, pkg *types.Pkg) {203 if pkg == nil {204 c.WriteInt32(0)205 return206 }207208 dimportpath(pkg)209 c.WriteSymPtrOff(pkg.Pathsym, false)210}211212// dnameField dumps a reflect.name for a struct field.213func dnameField(c rttype.Cursor, spkg *types.Pkg, ft *types.Field) {214 if !types.IsExported(ft.Sym.Name) && ft.Sym.Pkg != spkg {215 base.Fatalf("package mismatch for %v", ft.Sym)216 }217 nsym := dname(ft.Sym.Name, ft.Note, nil, types.IsExported(ft.Sym.Name), ft.Embedded != 0)218 c.Field("Bytes").WritePtr(nsym)219}220221// dnameData writes the contents of a reflect.name into s at offset ot.222func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported, embedded bool) int {223 if len(name) >= 1<<29 {224 base.Fatalf("name too long: %d %s...", len(name), name[:1024])225 }226 if len(tag) >= 1<<29 {227 base.Fatalf("tag too long: %d %s...", len(tag), tag[:1024])228 }229 var nameLen [binary.MaxVarintLen64]byte230 nameLenLen := binary.PutUvarint(nameLen[:], uint64(len(name)))231 var tagLen [binary.MaxVarintLen64]byte232 tagLenLen := binary.PutUvarint(tagLen[:], uint64(len(tag)))233234 // Encode name and tag. See reflect/type.go for details.235 var bits byte236 l := 1 + nameLenLen + len(name)237 if exported {238 bits |= 1 << 0239 }240 if len(tag) > 0 {241 l += tagLenLen + len(tag)242 bits |= 1 << 1243 }244 if pkg != nil {245 bits |= 1 << 2246 }247 if embedded {248 bits |= 1 << 3249 }250 b := make([]byte, l)251 b[0] = bits252 copy(b[1:], nameLen[:nameLenLen])253 copy(b[1+nameLenLen:], name)254 if len(tag) > 0 {255 tb := b[1+nameLenLen+len(name):]256 copy(tb, tagLen[:tagLenLen])257 copy(tb[tagLenLen:], tag)258 }259260 ot = int(s.WriteBytes(base.Ctxt, int64(ot), b))261262 if pkg != nil {263 c := rttype.NewCursor(s, int64(ot), types.Types[types.TUINT32])264 dgopkgpathOff(c, pkg)265 ot += 4266 }267268 return ot269}270271var dnameCount int272273// dname creates a reflect.name for a struct field or method.274func dname(name, tag string, pkg *types.Pkg, exported, embedded bool) *obj.LSym {275 // Write out data as "type:." to signal two things to the276 // linker, first that when dynamically linking, the symbol277 // should be moved to a relro section, and second that the278 // contents should not be decoded as a type.279 sname := "type:.namedata."280 if pkg == nil {281 // In the common case, share data with other packages.282 if name == "" {283 if exported {284 sname += "-noname-exported." + tag285 } else {286 sname += "-noname-unexported." + tag287 }288 } else {289 if exported {290 sname += name + "." + tag291 } else {292 sname += name + "-" + tag293 }294 }295 } else {296 // TODO(mdempsky): We should be able to share these too (except297 // maybe when dynamic linking).298 sname = fmt.Sprintf("%s%s.%d", sname, types.LocalPkg.Prefix, dnameCount)299 dnameCount++300 }301 if embedded {302 sname += ".embedded"303 }304 s := base.Ctxt.Lookup(sname)305 if len(s.P) > 0 {306 return s307 }308 ot := dnameData(s, 0, name, tag, pkg, exported, embedded)309 objw.Global(s, int32(ot), obj.DUPOK|obj.RODATA)310 s.Set(obj.AttrContentAddressable, true)311 s.Align = 1312 return s313}314315// dextratype dumps the fields of a runtime.uncommontype.316// dataAdd is the offset in bytes after the header where the317// backing array of the []method field should be written.318func dextratype(lsym *obj.LSym, off int64, t *types.Type, dataAdd int) {319 m := methods(t)320 if t.Sym() == nil && len(m) == 0 {321 base.Fatalf("extra requested of type with no extra info %v", t)322 }323 noff := types.RoundUp(off, int64(types.PtrSize))324 if noff != off {325 base.Fatalf("unexpected alignment in dextratype for %v", t)326 }327328 for _, a := range m {329 writeType(a.type_)330 }331332 c := rttype.NewCursor(lsym, off, rttype.UncommonType)333 dgopkgpathOff(c.Field("PkgPath"), typePkg(t))334335 dataAdd += uncommonSize(t)336 mcount := len(m)337 if mcount != int(uint16(mcount)) {338 base.Fatalf("too many methods on %v: %d", t, mcount)339 }340 xcount := sort.Search(mcount, func(i int) bool { return !types.IsExported(m[i].name.Name) })341 if dataAdd != int(uint32(dataAdd)) {342 base.Fatalf("methods are too far away on %v: %d", t, dataAdd)343 }344345 c.Field("Mcount").WriteUint16(uint16(mcount))346 c.Field("Xcount").WriteUint16(uint16(xcount))347 c.Field("Moff").WriteUint32(uint32(dataAdd))348 // Note: there is an unused uint32 field here.349350 // Write the backing array for the []method field.351 array := rttype.NewArrayCursor(lsym, off+int64(dataAdd), rttype.Method, mcount)352 for i, a := range m {353 exported := types.IsExported(a.name.Name)354 var pkg *types.Pkg355 if !exported && a.name.Pkg != typePkg(t) {356 pkg = a.name.Pkg357 }358 nsym := dname(a.name.Name, "", pkg, exported, false)359360 e := array.Elem(i)361 e.Field("Name").WriteSymPtrOff(nsym, false)362 dmethodptrOff(e.Field("Mtyp"), writeType(a.mtype))363 dmethodptrOff(e.Field("Ifn"), a.isym)364 dmethodptrOff(e.Field("Tfn"), a.tsym)365 }366}367368func typePkg(t *types.Type) *types.Pkg {369 tsym := t.Sym()370 if tsym == nil {371 switch t.Kind() {372 case types.TARRAY, types.TSLICE, types.TPTR, types.TCHAN:373 if t.Elem() != nil {374 tsym = t.Elem().Sym()375 }376 }377 }378 if tsym != nil && tsym.Pkg != types.BuiltinPkg {379 return tsym.Pkg380 }381 return nil382}383384func dmethodptrOff(c rttype.Cursor, x *obj.LSym) {385 c.WriteInt32(0)386 c.Reloc(obj.Reloc{Type: objabi.R_METHODOFF, Sym: x})387}388389var kinds = []abi.Kind{390 types.TINT: abi.Int,391 types.TUINT: abi.Uint,392 types.TINT8: abi.Int8,393 types.TUINT8: abi.Uint8,394 types.TINT16: abi.Int16,395 types.TUINT16: abi.Uint16,396 types.TINT32: abi.Int32,397 types.TUINT32: abi.Uint32,398 types.TINT64: abi.Int64,399 types.TUINT64: abi.Uint64,400 types.TUINTPTR: abi.Uintptr,401 types.TFLOAT32: abi.Float32,402 types.TFLOAT64: abi.Float64,403 types.TBOOL: abi.Bool,404 types.TSTRING: abi.String,405 types.TPTR: abi.Pointer,406 types.TSTRUCT: abi.Struct,407 types.TINTER: abi.Interface,408 types.TCHAN: abi.Chan,409 types.TMAP: abi.Map,410 types.TARRAY: abi.Array,411 types.TSLICE: abi.Slice,412 types.TFUNC: abi.Func,413 types.TCOMPLEX64: abi.Complex64,414 types.TCOMPLEX128: abi.Complex128,415 types.TUNSAFEPTR: abi.UnsafePointer,416}417418func ABIKindOfType(t *types.Type) abi.Kind {419 return kinds[t.Kind()]420}421422var (423 memhashvarlen *obj.LSym424 memequalvarlen *obj.LSym425)426427// dcommontype dumps the contents of a reflect.rtype (runtime._type) to c.428func dcommontype(c rttype.Cursor, t *types.Type) {429 types.CalcSize(t)430 eqfunc := geneq(t)431432 sptrWeak := true433 var sptr *obj.LSym434 if !t.IsPtr() || t.IsPtrElem() {435 tptr := types.NewPtr(t)436 if t.Sym() != nil || methods(tptr) != nil {437 sptrWeak = false438 }439 sptr = writeType(tptr)440 }441442 gcsym, onDemand, ptrdata := dgcsym(t, true, true)443 if !onDemand {444 delete(gcsymset, t)445 }446447 // ../../../../reflect/type.go:/^type.rtype448 // actual type structure449 // type rtype struct {450 // size uintptr451 // ptrdata uintptr452 // hash uint32453 // tflag tflag454 // align uint8455 // fieldAlign uint8456 // kind uint8457 // equal func(unsafe.Pointer, unsafe.Pointer) bool458 // gcdata *byte459 // str nameOff460 // ptrToThis typeOff461 // }462 c.Field("Size_").WriteUintptr(uint64(t.Size()))463 c.Field("PtrBytes").WriteUintptr(uint64(ptrdata))464 c.Field("Hash").WriteUint32(types.TypeHash(t))465466 exported := false467 p := t.NameString()468 // If we're writing out type T,469 // we are very likely to write out type *T as well.470 // Use the string "*T"[1:] for "T", so that the two471 // share storage. This is a cheap way to reduce the472 // amount of space taken up by reflect strings.473 if t.TFlag()&abi.TFlagExtraStar != 0 {474 p = "*" + p475 if t.Sym() != nil {476 exported = types.IsExported(t.Sym().Name)477 }478 } else {479 if t.Elem() != nil && t.Elem().Sym() != nil {480 exported = types.IsExported(t.Elem().Sym().Name)481 }482 }483484 c.Field("TFlag").WriteUint8(uint8(t.TFlag()))485486 // runtime (and common sense) expects alignment to be a power of two.487 i := int(uint8(t.Alignment()))488489 if i == 0 {490 i = 1491 }492 if i&(i-1) != 0 {493 base.Fatalf("invalid alignment %d for %v", uint8(t.Alignment()), t)494 }495 c.Field("Align_").WriteUint8(uint8(t.Alignment()))496 c.Field("FieldAlign_").WriteUint8(uint8(t.Alignment()))497498 c.Field("Kind_").WriteUint8(uint8(ABIKindOfType(t)))499500 c.Field("Equal").WritePtr(eqfunc)501 c.Field("GCData").WritePtr(gcsym)502503 nsym := dname(p, "", nil, exported, false)504 c.Field("Str").WriteSymPtrOff(nsym, false)505 c.Field("PtrToThis").WriteSymPtrOff(sptr, sptrWeak)506}507508// TrackSym returns the symbol for tracking use of field/method f, assumed509// to be a member of struct/interface type t.510func TrackSym(t *types.Type, f *types.Field) *obj.LSym {511 return base.PkgLinksym("go:track", t.LinkString()+"."+f.Sym.Name, obj.ABI0)512}513514func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {515 p := prefix + "." + t.LinkString()516 s := types.TypeSymLookup(p)517518 // This function is for looking up type-related generated functions519 // (e.g. eq and hash). Make sure they are indeed generated.520 signatmu.Lock()521 NeedRuntimeType(t)522 signatmu.Unlock()523524 //print("algsym: %s -> %+S\n", p, s);525526 return s527}528529func TypeSym(t *types.Type) *types.Sym {530 if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {531 base.Fatalf("TypeSym %v", t)532 }533 if t.Kind() == types.TFUNC && t.Recv() != nil {534 base.Fatalf("misuse of method type: %v", t)535 }536 s := types.TypeSym(t)537 signatmu.Lock()538 NeedRuntimeType(t)539 signatmu.Unlock()540 return s541}542543func TypeLinksymPrefix(prefix string, t *types.Type) *obj.LSym {544 return TypeSymPrefix(prefix, t).Linksym()545}546547func TypeLinksymLookup(name string) *obj.LSym {548 return types.TypeSymLookup(name).Linksym()549}550551func TypeLinksym(t *types.Type) *obj.LSym {552 lsym := TypeSym(t).Linksym()553 setTypeInfo(lsym, t)554 return lsym555}556557func setTypeInfo(lsym *obj.LSym, t *types.Type) {558 signatmu.Lock()559 if lsym.Extra == nil {560 ti := lsym.NewTypeInfo()561 ti.Type = t562 }563 signatmu.Unlock()564}565566// TypePtrAt returns an expression that evaluates to the567// *runtime._type value for t.568func TypePtrAt(pos src.XPos, t *types.Type) *ir.AddrExpr {569 return typecheck.LinksymAddr(pos, TypeLinksym(t), types.Types[types.TUINT8])570}571572// ITabLsym returns the LSym representing the itab for concrete type typ implementing573// interface iface. A dummy tab will be created in the unusual case where typ doesn't574// implement iface. Normally, this wouldn't happen, because the typechecker would575// have reported a compile-time error. This situation can only happen when the576// destination type of a type assert or a type in a type switch is parameterized, so577// it may sometimes, but not always, be a type that can't implement the specified578// interface.579func ITabLsym(typ, iface *types.Type) *obj.LSym {580 return itabLsym(typ, iface, true)581}582583func itabLsym(typ, iface *types.Type, allowNonImplement bool) *obj.LSym {584 s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString())585 lsym := s.Linksym()586 signatmu.Lock()587 if lsym.Extra == nil {588 ii := lsym.NewItabInfo()589 ii.Type = typ590 }591 signatmu.Unlock()592593 if !existed {594 writeITab(lsym, typ, iface, allowNonImplement)595 }596 return lsym597}598599// ITabAddrAt returns an expression that evaluates to the600// *runtime.itab value for concrete type typ implementing interface601// iface.602func ITabAddrAt(pos src.XPos, typ, iface *types.Type) *ir.AddrExpr {603 lsym := itabLsym(typ, iface, false)604 return typecheck.LinksymAddr(pos, lsym, types.Types[types.TUINT8])605}606607// needkeyupdate reports whether map updates with t as a key608// need the key to be updated.609func needkeyupdate(t *types.Type) bool {610 switch t.Kind() {611 case types.TBOOL, types.TINT, types.TUINT, types.TINT8, types.TUINT8, types.TINT16, types.TUINT16, types.TINT32, types.TUINT32,612 types.TINT64, types.TUINT64, types.TUINTPTR, types.TPTR, types.TUNSAFEPTR, types.TCHAN:613 return false614615 case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, // floats and complex can be +0/-0616 types.TINTER,617 types.TSTRING: // strings might have smaller backing stores618 return true619620 case types.TARRAY:621 return needkeyupdate(t.Elem())622623 case types.TSTRUCT:624 for _, t1 := range t.Fields() {625 if needkeyupdate(t1.Type) {626 return true627 }628 }629 return false630631 default:632 base.Fatalf("bad type for map key: %v", t)633 return true634 }635}636637// hashMightPanic reports whether the hash of a map key of type t might panic.638func hashMightPanic(t *types.Type) bool {639 switch t.Kind() {640 case types.TINTER:641 return true642643 case types.TARRAY:644 return hashMightPanic(t.Elem())645646 case types.TSTRUCT:647 for _, t1 := range t.Fields() {648 if hashMightPanic(t1.Type) {649 return true650 }651 }652 return false653654 default:655 return false656 }657}658659// formalType replaces predeclared aliases with real types.660// They've been separate internally to make error messages661// better, but we have to merge them in the reflect tables.662func formalType(t *types.Type) *types.Type {663 switch t {664 case types.AnyType, types.ByteType, types.RuneType:665 return types.Types[t.Kind()]666 }667 return t668}669670func writeType(t *types.Type) *obj.LSym {671 t = formalType(t)672 if t.IsUntyped() {673 base.Fatalf("writeType %v", t)674 }675676 s := types.TypeSym(t)677 lsym := s.Linksym()678679 // special case (look for runtime below):680 // when compiling package runtime,681 // emit the type structures for int, float, etc.682 tbase := t683 if t.IsPtr() && t.Sym() == nil && t.Elem().Sym() != nil {684 tbase = t.Elem()685 }686 if tbase.Kind() == types.TFORW {687 base.Fatalf("unresolved defined type: %v", tbase)688 }689690 // This is a fake type we generated for our builtin pseudo-runtime691 // package. We'll emit a description for the real type while692 // compiling package runtime, so we don't need or want to emit one693 // from this fake type.694 if sym := tbase.Sym(); sym != nil && sym.Pkg == ir.Pkgs.Runtime {695 return lsym696 }697698 if s.Siggen() {699 return lsym700 }701 s.SetSiggen(true)702703 if !tbase.HasShape() {704 setTypeInfo(lsym, t) // ensure lsym.Extra is set705 }706707 if !NeedEmit(tbase) {708 u := t709 for u.IsPtr() {710 u = u.Elem()711 }712 typecheck.CalcMethods(types.ReceiverBaseType(u))713714 if i := typecheck.BaseTypeIndex(t); i >= 0 {715 lsym.Pkg = tbase.Sym().Pkg.Prefix716 lsym.SymIdx = int32(i)717 lsym.Set(obj.AttrIndexed, true)718 }719720 // TODO(mdempsky): Investigate whether this still happens.721 // If we know we don't need to emit code for a type,722 // we should have a link-symbol index for it.723 // See also TODO in NeedEmit.724 return lsym725 }726727 // Type layout Written by Marker728 // +--------------------------------+ - 0729 // | abi/internal.Type | dcommontype730 // +--------------------------------+ - A731 // | additional type-dependent | code in the switch below732 // | fields, e.g. |733 // | abi/internal.ArrayType.Len |734 // +--------------------------------+ - B735 // | internal/abi.UncommonType | dextratype736 // | This section is optional, |737 // | if type has a name or methods |738 // +--------------------------------+ - C739 // | variable-length data | code in the switch below740 // | referenced by |741 // | type-dependent fields, e.g. |742 // | abi/internal.StructType.Fields |743 // | dataAdd = size of this section |744 // +--------------------------------+ - D745 // | method list, if any | dextratype746 // +--------------------------------+ - E747748 // internal/abi.Type.DescriptorSize is aware of this type layout,749 // and must be changed if the layout change.750751 // UncommonType section is included if we have a name or a method.752 extra := t.Sym() != nil || len(methods(t)) != 0753754 // Decide the underlying type of the descriptor, and remember755 // the size we need for variable-length data.756 var rt *types.Type757 dataAdd := 0758 switch t.Kind() {759 default:760 rt = rttype.Type761 case types.TARRAY:762 rt = rttype.ArrayType763 case types.TSLICE:764 rt = rttype.SliceType765 case types.TCHAN:766 rt = rttype.ChanType767 case types.TFUNC:768 rt = rttype.FuncType769 dataAdd = (t.NumRecvs() + t.NumParams() + t.NumResults()) * types.PtrSize770 case types.TINTER:771 rt = rttype.InterfaceType772 dataAdd = len(imethods(t)) * int(rttype.IMethod.Size())773 case types.TMAP:774 rt = rttype.MapType775 case types.TPTR:776 rt = rttype.PtrType777 // TODO: use rttype.Type for Elem() is ANY?778 case types.TSTRUCT:779 rt = rttype.StructType780 dataAdd = t.NumFields() * int(rttype.StructField.Size())781 }782783 // Compute offsets of each section.784 B := rt.Size()785 C := B786 if extra {787 C = B + rttype.UncommonType.Size()788 }789 D := C + int64(dataAdd)790 E := D + int64(len(methods(t)))*rttype.Method.Size()791792 // Write the runtime._type793 c := rttype.NewCursor(lsym, 0, rt)794 if rt == rttype.Type {795 dcommontype(c, t)796 } else {797 dcommontype(c.Field("Type"), t)798 }799800 // Write additional type-specific data801 // (Both the fixed size and variable-sized sections.)802 switch t.Kind() {803 case types.TARRAY:804 // internal/abi.ArrayType805 s1 := writeType(t.Elem())806 t2 := types.NewSlice(t.Elem())807 s2 := writeType(t2)808 c.Field("Elem").WritePtr(s1)809 c.Field("Slice").WritePtr(s2)810 c.Field("Len").WriteUintptr(uint64(t.NumElem()))811812 case types.TSLICE:813 // internal/abi.SliceType814 s1 := writeType(t.Elem())815 c.Field("Elem").WritePtr(s1)816817 case types.TCHAN:818 // internal/abi.ChanType819 s1 := writeType(t.Elem())820 c.Field("Elem").WritePtr(s1)821 c.Field("Dir").WriteInt(int64(t.ChanDir()))822823 case types.TFUNC:824 // internal/abi.FuncType825 for _, t1 := range t.RecvParamsResults() {826 writeType(t1.Type)827 }828 inCount := t.NumRecvs() + t.NumParams()829 outCount := t.NumResults()830 if t.IsVariadic() {831 outCount |= 1 << 15832 }833834 c.Field("InCount").WriteUint16(uint16(inCount))835 c.Field("OutCount").WriteUint16(uint16(outCount))836837 // Array of rtype pointers follows funcType.838 typs := t.RecvParamsResults()839 array := rttype.NewArrayCursor(lsym, C, types.Types[types.TUNSAFEPTR], len(typs))840 for i, t1 := range typs {841 array.Elem(i).WritePtr(writeType(t1.Type))842 }843844 case types.TINTER:845 // internal/abi.InterfaceType846 m := imethods(t)847 n := len(m)848 for _, a := range m {849 writeType(a.type_)850 }851852 var tpkg *types.Pkg853 if t.Sym() != nil && t != types.Types[t.Kind()] && t != types.ErrorType {854 tpkg = t.Sym().Pkg855 }856 dgopkgpath(c.Field("PkgPath"), tpkg)857 c.Field("Methods").WriteSlice(lsym, C, int64(n), int64(n))858859 array := rttype.NewArrayCursor(lsym, C, rttype.IMethod, n)860 for i, a := range m {861 exported := types.IsExported(a.name.Name)862 var pkg *types.Pkg863 if !exported && a.name.Pkg != tpkg {864 pkg = a.name.Pkg865 }866 nsym := dname(a.name.Name, "", pkg, exported, false)867868 e := array.Elem(i)869 e.Field("Name").WriteSymPtrOff(nsym, false)870 e.Field("Typ").WriteSymPtrOff(writeType(a.type_), false)871 }872873 case types.TMAP:874 writeMapType(t, lsym, c)875876 case types.TPTR:877 // internal/abi.PtrType878 if t.Elem().Kind() == types.TANY {879 base.Fatalf("bad pointer base type")880 }881882 s1 := writeType(t.Elem())883 c.Field("Elem").WritePtr(s1)884885 case types.TSTRUCT:886 // internal/abi.StructType887 fields := t.Fields()888 for _, t1 := range fields {889 writeType(t1.Type)890 }891892 // All non-exported struct field names within a struct893 // type must originate from a single package. By894 // identifying and recording that package within the895 // struct type descriptor, we can omit that896 // information from the field descriptors.897 var spkg *types.Pkg898 for _, f := range fields {899 if !types.IsExported(f.Sym.Name) {900 spkg = f.Sym.Pkg901 break902 }903 }904905 dgopkgpath(c.Field("PkgPath"), spkg)906 c.Field("Fields").WriteSlice(lsym, C, int64(len(fields)), int64(len(fields)))907908 array := rttype.NewArrayCursor(lsym, C, rttype.StructField, len(fields))909 for i, f := range fields {910 e := array.Elem(i)911 dnameField(e.Field("Name"), spkg, f)912 e.Field("Typ").WritePtr(writeType(f.Type))913 e.Field("Offset").WriteUintptr(uint64(f.Offset))914 }915 }916917 // Write the extra info, if any.918 if extra {919 dextratype(lsym, B, t, dataAdd)920 }921922 // Note: DUPOK is required to ensure that we don't end up with more923 // than one type descriptor for a given type, if the type descriptor924 // can be defined in multiple packages, that is, unnamed types,925 // instantiated types and shape types.926 dupok := 0927 if tbase.Sym() == nil || tbase.IsFullyInstantiated() || tbase.HasShape() {928 dupok = obj.DUPOK929 }930931 objw.Global(lsym, int32(E), int16(dupok|obj.RODATA))932933 // The linker will leave a table of all the typelinks for934 // types in the binary, so the runtime can find them.935 //936 // When buildmode=shared, all types are in typelinks so the937 // runtime can deduplicate type pointers.938 keep := base.Ctxt.Flag_dynlink939 if !keep && t.Sym() == nil {940 // For an unnamed type, we only need the link if the type can941 // be created at run time by reflect.PointerTo and similar942 // functions. If the type exists in the program, those943 // functions must return the existing type structure rather944 // than creating a new one.945 switch t.Kind() {946 case types.TPTR, types.TARRAY, types.TCHAN, types.TFUNC, types.TMAP, types.TSLICE, types.TSTRUCT:947 keep = true948 }949 }950 // Do not put Noalg types in typelinks. See issue #22605.951 if types.TypeHasNoAlg(t) {952 keep = false953 }954 lsym.Set(obj.AttrMakeTypelink, keep)955 lsym.Align = int16(types.PtrSize)956957 return lsym958}959960// InterfaceMethodOffset returns the offset of the i-th method in the interface961// type descriptor, ityp.962func InterfaceMethodOffset(ityp *types.Type, i int64) int64 {963 // interface type descriptor layout is struct {964 // _type // commonSize965 // pkgpath // 1 word966 // []imethod // 3 words (pointing to [...]imethod below)967 // uncommontype // uncommonSize968 // [...]imethod969 // }970 // The size of imethod is 8.971 return int64(commonSize()+4*types.PtrSize+uncommonSize(ityp)) + i*8972}973974// NeedRuntimeType ensures that a runtime type descriptor is emitted for t.975func NeedRuntimeType(t *types.Type) {976 if _, ok := signatset[t]; !ok {977 signatset[t] = struct{}{}978 signatslice = append(signatslice, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})979 }980}981982func WriteRuntimeTypes() {983 // Process signatslice. Use a loop, as writeType adds984 // entries to signatslice while it is being processed.985 for len(signatslice) > 0 {986 signats := signatslice987 // Sort for reproducible builds.988 slices.SortFunc(signats, typesStrCmp)989 for _, ts := range signats {990 t := ts.t991 writeType(t)992 if t.Sym() != nil {993 writeType(types.NewPtr(t))994 }995 }996 signatslice = signatslice[len(signats):]997 }998}9991000func WriteGCSymbols() {1001 // Emit GC data symbols.1002 gcsyms := make([]typeAndStr, 0, len(gcsymset))1003 for t := range gcsymset {1004 gcsyms = append(gcsyms, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})1005 }1006 slices.SortFunc(gcsyms, typesStrCmp)1007 for _, ts := range gcsyms {1008 dgcsym(ts.t, true, false)1009 }1010}10111012// writeITab writes the itab for concrete type typ implementing interface iface. If1013// allowNonImplement is true, allow the case where typ does not implement iface, and just1014// create a dummy itab with zeroed-out method entries.1015func writeITab(lsym *obj.LSym, typ, iface *types.Type, allowNonImplement bool) {1016 // TODO(mdempsky): Fix methodWrapper, geneq, and genhash (and maybe1017 // others) to stop clobbering these.1018 oldpos, oldfn := base.Pos, ir.CurFunc1019 defer func() { base.Pos, ir.CurFunc = oldpos, oldfn }()10201021 if typ == nil || (typ.IsPtr() && typ.Elem() == nil) || typ.IsUntyped() || iface == nil || !iface.IsInterface() || iface.IsEmptyInterface() {1022 base.Fatalf("writeITab(%v, %v)", typ, iface)1023 }10241025 sigs := iface.AllMethods()1026 entries := make([]*obj.LSym, 0, len(sigs))10271028 // both sigs and methods are sorted by name,1029 // so we can find the intersection in a single pass1030 for _, m := range methods(typ) {1031 if m.name == sigs[0].Sym {1032 entries = append(entries, m.isym)1033 if m.isym == nil {1034 panic("NO ISYM")1035 }1036 sigs = sigs[1:]1037 if len(sigs) == 0 {1038 break1039 }1040 }1041 }1042 completeItab := len(sigs) == 01043 if !allowNonImplement && !completeItab {1044 base.Fatalf("incomplete itab")1045 }10461047 // dump empty itab symbol into i.sym1048 // type itab struct {1049 // inter *interfacetype1050 // _type *_type1051 // hash uint32 // copy of _type.hash. Used for type switches.1052 // _ [4]byte1053 // fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.1054 // }1055 c := rttype.NewCursor(lsym, 0, rttype.ITab)1056 c.Field("Inter").WritePtr(writeType(iface))1057 c.Field("Type").WritePtr(writeType(typ))1058 c.Field("Hash").WriteUint32(types.TypeHash(typ)) // copy of type hash10591060 var delta int641061 c = c.Field("Fun")1062 if !completeItab {1063 // If typ doesn't implement iface, make method entries be zero.1064 c.Elem(0).WriteUintptr(0)1065 } else {1066 var a rttype.ArrayCursor1067 a, delta = c.ModifyArray(len(entries))1068 for i, fn := range entries {1069 a.Elem(i).WritePtrWeak(fn) // method pointer for each method1070 }1071 }1072 // Nothing writes static itabs, so they are read only.1073 objw.Global(lsym, int32(rttype.ITab.Size()+delta), int16(obj.DUPOK|obj.RODATA))1074 lsym.Set(obj.AttrContentAddressable, true)1075 lsym.Align = int16(types.PtrSize)1076}10771078func WritePluginTable() {1079 ptabs := typecheck.Target.PluginExports1080 if len(ptabs) == 0 {1081 return1082 }10831084 lsym := base.Ctxt.Lookup("go:plugin.tabs")1085 ot := 01086 for _, p := range ptabs {1087 // Dump ptab symbol into go.pluginsym package.1088 //1089 // type ptab struct {1090 // name nameOff1091 // typ typeOff // pointer to symbol1092 // }1093 nsym := dname(p.Sym().Name, "", nil, true, false)1094 t := p.Type()1095 if p.Class != ir.PFUNC {1096 t = types.NewPtr(t)1097 }1098 tsym := writeType(t)1099 ot = objw.SymPtrOff(lsym, ot, nsym)1100 ot = objw.SymPtrOff(lsym, ot, tsym)1101 // Plugin exports symbols as interfaces. Mark their types1102 // as UsedInIface.1103 tsym.Set(obj.AttrUsedInIface, true)1104 }1105 objw.Global(lsym, int32(ot), int16(obj.RODATA))11061107 lsym = base.Ctxt.Lookup("go:plugin.exports")1108 ot = 01109 for _, p := range ptabs {1110 ot = objw.SymPtr(lsym, ot, p.Linksym(), 0)1111 }1112 objw.Global(lsym, int32(ot), int16(obj.RODATA))1113}11141115// writtenByWriteBasicTypes reports whether typ is written by WriteBasicTypes.1116// WriteBasicTypes always writes pointer types; any pointer has been stripped off typ already.1117func writtenByWriteBasicTypes(typ *types.Type) bool {1118 if typ.Sym() == nil && typ.Kind() == types.TFUNC {1119 // func(error) string1120 if typ.NumRecvs() == 0 &&1121 typ.NumParams() == 1 && typ.NumResults() == 1 &&1122 typ.Param(0).Type == types.ErrorType &&1123 typ.Result(0).Type == types.Types[types.TSTRING] {1124 return true1125 }1126 }11271128 // Now we have left the basic types plus any and error, plus slices of them.1129 // Strip the slice.1130 if typ.Sym() == nil && typ.IsSlice() {1131 typ = typ.Elem()1132 }11331134 // Basic types.1135 sym := typ.Sym()1136 if sym != nil && (sym.Pkg == types.BuiltinPkg || sym.Pkg == types.UnsafePkg) {1137 return true1138 }1139 // any or error1140 return (sym == nil && typ.IsEmptyInterface()) || typ == types.ErrorType1141}11421143func WriteBasicTypes() {1144 // do basic types if compiling package runtime.1145 // they have to be in at least one package,1146 // and runtime is always loaded implicitly,1147 // so this is as good as any.1148 // another possible choice would be package main,1149 // but using runtime means fewer copies in object files.1150 // The code here needs to be in sync with writtenByWriteBasicTypes above.1151 if base.Ctxt.Pkgpath != "runtime" {1152 return1153 }11541155 // Note: always write NewPtr(t) because NeedEmit's caller strips the pointer.1156 var list []*types.Type1157 for i := types.Kind(1); i <= types.TBOOL; i++ {1158 list = append(list, types.Types[i])1159 }1160 list = append(list,1161 types.Types[types.TSTRING],1162 types.Types[types.TUNSAFEPTR],1163 types.AnyType,1164 types.ErrorType)1165 for _, t := range list {1166 writeType(types.NewPtr(t))1167 writeType(types.NewPtr(types.NewSlice(t)))1168 }11691170 // emit type for func(error) string,1171 // which is the type of an auto-generated wrapper.1172 writeType(types.NewPtr(types.NewSignature(nil, []*types.Field{1173 types.NewField(base.Pos, nil, types.ErrorType),1174 }, []*types.Field{1175 types.NewField(base.Pos, nil, types.Types[types.TSTRING]),1176 })))1177}11781179type typeAndStr struct {1180 t *types.Type1181 short string // "short" here means TypeSymName1182 regular string1183}11841185func typesStrCmp(a, b typeAndStr) int {1186 // put named types before unnamed types1187 if a.t.Sym() != nil && b.t.Sym() == nil {1188 return -11189 }1190 if a.t.Sym() == nil && b.t.Sym() != nil {1191 return +11192 }11931194 if r := strings.Compare(a.short, b.short); r != 0 {1195 return r1196 }1197 // When the only difference between the types is whether1198 // they refer to byte or uint8, such as **byte vs **uint8,1199 // the types' NameStrings can be identical.1200 // To preserve deterministic sort ordering, sort these by String().1201 //1202 // TODO(mdempsky): This all seems suspect. Using LinkString would1203 // avoid naming collisions, and there shouldn't be a reason to care1204 // about "byte" vs "uint8": they share the same runtime type1205 // descriptor anyway.1206 if r := strings.Compare(a.regular, b.regular); r != 0 {1207 return r1208 }1209 // Identical anonymous interfaces defined in different locations1210 // will be equal for the above checks, but different in DWARF output.1211 // Sort by source position to ensure deterministic order.1212 // See issues 27013 and 30202.1213 if a.t.Kind() == types.TINTER && len(a.t.AllMethods()) > 0 {1214 if a.t.AllMethods()[0].Pos.Before(b.t.AllMethods()[0].Pos) {1215 return -11216 }1217 return +11218 }1219 return 01220}12211222// GCSym returns a data symbol containing GC information for type t.1223// GC information is always a bitmask, never a gc program.1224// GCSym may be called in concurrent backend, so it does not emit the symbol1225// content.1226func GCSym(t *types.Type, onDemandAllowed bool) (lsym *obj.LSym, ptrdata int64) {1227 // Record that we need to emit the GC symbol.1228 gcsymmu.Lock()1229 if _, ok := gcsymset[t]; !ok {1230 gcsymset[t] = struct{}{}1231 }1232 gcsymmu.Unlock()12331234 lsym, _, ptrdata = dgcsym(t, false, onDemandAllowed)1235 return1236}12371238// dgcsym returns a data symbol containing GC information for type t, along1239// with a boolean reporting whether the gc mask should be computed on demand1240// at runtime, and the ptrdata field to record in the reflect type information.1241// When write is true, it writes the symbol data.1242func dgcsym(t *types.Type, write, onDemandAllowed bool) (lsym *obj.LSym, onDemand bool, ptrdata int64) {1243 ptrdata = types.PtrDataSize(t)1244 if !onDemandAllowed || t.TFlag()&abi.TFlagGCMaskOnDemand == 0 {1245 lsym = dgcptrmask(t, write)1246 return1247 }12481249 onDemand = true1250 lsym = dgcptrmaskOnDemand(t, write)1251 return1252}12531254// dgcptrmask emits and returns the symbol containing a pointer mask for type t.1255func dgcptrmask(t *types.Type, write bool) *obj.LSym {1256 // Bytes we need for the ptrmask.1257 n := (types.PtrDataSize(t)/int64(types.PtrSize) + 7) / 81258 // Runtime wants ptrmasks padded to a multiple of uintptr in size.1259 n = (n + int64(types.PtrSize) - 1) &^ (int64(types.PtrSize) - 1)1260 ptrmask := make([]byte, n)1261 fillptrmask(t, ptrmask)1262 p := fmt.Sprintf("runtime.gcbits.%x", ptrmask)12631264 lsym := base.Ctxt.Lookup(p)1265 if write && !lsym.OnList() {1266 for i, x := range ptrmask {1267 objw.Uint8(lsym, i, x)1268 }1269 objw.Global(lsym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)1270 lsym.Set(obj.AttrContentAddressable, true)1271 // The runtime expects ptrmasks to be aligned1272 // as a uintptr.1273 lsym.Align = int16(types.PtrSize)1274 }1275 return lsym1276}12771278// fillptrmask fills in ptrmask with 1s corresponding to the1279// word offsets in t that hold pointers.1280// ptrmask is assumed to fit at least types.PtrDataSize(t)/PtrSize bits.1281func fillptrmask(t *types.Type, ptrmask []byte) {1282 if !t.HasPointers() {1283 return1284 }12851286 vec := bitvec.New(8 * int32(len(ptrmask)))1287 typebits.Set(t, 0, vec)12881289 nptr := types.PtrDataSize(t) / int64(types.PtrSize)1290 for i := int64(0); i < nptr; i++ {1291 if vec.Get(int32(i)) {1292 ptrmask[i/8] |= 1 << (uint(i) % 8)1293 }1294 }1295}12961297// dgcptrmaskOnDemand emits and returns the symbol that should be referenced by1298// the GCData field of a type, for large types.1299func dgcptrmaskOnDemand(t *types.Type, write bool) *obj.LSym {1300 lsym := TypeLinksymPrefix(".gcmask", t)1301 if write && !lsym.OnList() {1302 // Note: contains a pointer, but a pointer to a1303 // persistentalloc allocation. Starts with nil.1304 // Allocated in BSS.1305 objw.Global(lsym, int32(types.PtrSize), obj.DUPOK|obj.NOPTR|obj.LOCAL)1306 }1307 return lsym1308}13091310// ZeroAddr returns the address of a symbol with at least1311// size bytes of zeros.1312func ZeroAddr(size int64) ir.Node {1313 if size >= 1<<31 {1314 base.Fatalf("map elem too big %d", size)1315 }1316 if ZeroSize < size {1317 ZeroSize = size1318 }1319 lsym := base.PkgLinksym("go:map", "zero", obj.ABI0)1320 x := ir.NewLinksymExpr(base.Pos, lsym, types.Types[types.TUINT8])1321 return typecheck.Expr(typecheck.NodAddr(x))1322}13231324// NeedEmit reports whether typ is a type that we need to emit code1325// for (e.g., runtime type descriptors, method wrappers).1326func NeedEmit(typ *types.Type) bool {1327 // TODO(mdempsky): Export data should keep track of which anonymous1328 // and instantiated types were emitted, so at least downstream1329 // packages can skip re-emitting them.1330 //1331 // Perhaps we can just generalize the linker-symbol indexing to1332 // track the index of arbitrary types, not just defined types, and1333 // use its presence to detect this. The same idea would work for1334 // instantiated generic functions too.13351336 switch sym := typ.Sym(); {1337 case writtenByWriteBasicTypes(typ):1338 return base.Ctxt.Pkgpath == "runtime"13391340 case sym == nil:1341 // Anonymous type; possibly never seen before or ever again.1342 // Need to emit to be safe (however, see TODO above).1343 return true13441345 case sym.Pkg == types.LocalPkg:1346 // Local defined type; our responsibility.1347 return true13481349 case typ.IsFullyInstantiated():1350 // Instantiated type; possibly instantiated with unique type arguments.1351 // Need to emit to be safe (however, see TODO above).1352 return true13531354 case typ.HasShape():1355 // Shape type; need to emit even though it lives in the .shape package.1356 // TODO: make sure the linker deduplicates them (see dupok in writeType above).1357 return true13581359 default:1360 // Should have been emitted by an imported package.1361 return false1362 }1363}13641365// Generate a wrapper function to convert from1366// a receiver of type T to a receiver of type U.1367// That is,1368//1369// func (t T) M() {1370// ...1371// }1372//1373// already exists; this function generates1374//1375// func (u U) M() {1376// u.M()1377// }1378//1379// where the types T and U are such that u.M() is valid1380// and calls the T.M method.1381// The resulting function is for use in method tables.1382//1383// rcvr - U1384// method - M func (t T)(), a TFIELD type struct1385//1386// Also wraps methods on instantiated generic types for use in itab entries.1387// For an instantiated generic type G[int], we generate wrappers like:1388// G[int] pointer shaped:1389//1390// func (x G[int]) f(arg) {1391// .inst.G[int].f(dictionary, x, arg)1392// }1393//1394// G[int] not pointer shaped:1395//1396// func (x *G[int]) f(arg) {1397// .inst.G[int].f(dictionary, *x, arg)1398// }1399//1400// These wrappers are always fully stenciled.1401func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSym {1402 if forItab && !types.IsDirectIface(rcvr) {1403 rcvr = rcvr.PtrTo()1404 }14051406 newnam := ir.MethodSym(rcvr, method.Sym)1407 lsym := newnam.Linksym()14081409 // Unified IR creates its own wrappers.1410 return lsym1411}14121413var ZeroSize int6414141415// MarkTypeUsedInInterface marks that type t is converted to an interface.1416// This information is used in the linker in dead method elimination.1417func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) {1418 if t.HasShape() {1419 // Shape types shouldn't be put in interfaces, so we shouldn't ever get here.1420 base.Fatalf("shape types have no methods %+v", t)1421 }1422 MarkTypeSymUsedInInterface(TypeLinksym(t), from)1423}1424func MarkTypeSymUsedInInterface(tsym *obj.LSym, from *obj.LSym) {1425 // Emit a marker relocation. The linker will know the type is converted1426 // to an interface if "from" is reachable.1427 from.AddRel(base.Ctxt, obj.Reloc{Type: objabi.R_USEIFACE, Sym: tsym})1428}14291430// MarkUsedIfaceMethod marks that an interface method is used in the current1431// function. n is OCALLINTER node.1432func MarkUsedIfaceMethod(n *ir.CallExpr) {1433 // skip unnamed functions (func _())1434 if ir.CurFunc.LSym == nil {1435 return1436 }1437 dot := n.Fun.(*ir.SelectorExpr)1438 ityp := dot.X.Type()1439 if ityp.HasShape() {1440 // Here we're calling a method on a generic interface. Something like:1441 //1442 // type I[T any] interface { foo() T }1443 // func f[T any](x I[T]) {1444 // ... = x.foo()1445 // }1446 // f[int](...)1447 // f[string](...)1448 //1449 // In this case, in f we're calling foo on a generic interface.1450 // Which method could that be? Normally we could match the method1451 // both by name and by type. But in this case we don't really know1452 // the type of the method we're calling. It could be func()int1453 // or func()string. So we match on just the function name, instead1454 // of both the name and the type used for the non-generic case below.1455 // TODO: instantiations at least know the shape of the instantiated1456 // type, and the linker could do more complicated matching using1457 // some sort of fuzzy shape matching. For now, only use the name1458 // of the method for matching.1459 ir.CurFunc.LSym.AddRel(base.Ctxt, obj.Reloc{1460 Type: objabi.R_USENAMEDMETHOD,1461 Sym: staticdata.StringSymNoCommon(dot.Sel.Name),1462 })1463 return1464 }14651466 // dot.Offset() is the method index * PtrSize (the offset of code pointer in itab).1467 midx := dot.Offset() / int64(types.PtrSize)1468 ir.CurFunc.LSym.AddRel(base.Ctxt, obj.Reloc{1469 Type: objabi.R_USEIFACEMETHOD,1470 Sym: TypeLinksym(ityp),1471 Add: InterfaceMethodOffset(ityp, midx),1472 })1473}
Findings
✓ No findings reported for this file.