src/cmd/compile/internal/reflectdata/reflect.go GO 1,474 lines View on github.com → Search inside
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.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.