src/cmd/compile/internal/noder/reader.go GO 4,343 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,343.
1// Copyright 2021 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 noder67import (8	"encoding/hex"9	"fmt"10	"go/constant"11	"internal/buildcfg"12	"internal/pkgbits"13	"path/filepath"14	"slices"15	"strings"1617	"cmd/compile/internal/base"18	"cmd/compile/internal/dwarfgen"19	"cmd/compile/internal/inline"20	"cmd/compile/internal/inline/interleaved"21	"cmd/compile/internal/ir"22	"cmd/compile/internal/objw"23	"cmd/compile/internal/pgoir"24	"cmd/compile/internal/reflectdata"25	"cmd/compile/internal/staticinit"26	"cmd/compile/internal/typecheck"27	"cmd/compile/internal/types"28	"cmd/internal/hash"29	"cmd/internal/obj"30	"cmd/internal/objabi"31	"cmd/internal/src"32)3334// This file implements cmd/compile backend's reader for the Unified35// IR export data.3637// A pkgReader reads Unified IR export data.38type pkgReader struct {39	pkgbits.PkgDecoder4041	// Indices for encoded things; lazily populated as needed.42	//43	// Note: Objects (i.e., ir.Names) are lazily instantiated by44	// populating their types.Sym.Def; see objReader below.4546	posBases []*src.PosBase47	pkgs     []*types.Pkg48	typs     []*types.Type4950	// offset for rewriting the given (absolute!) index into the output,51	// but bitwise inverted so we can detect if we're missing the entry52	// or not.53	newindex []index54}5556func newPkgReader(pr pkgbits.PkgDecoder) *pkgReader {57	return &pkgReader{58		PkgDecoder: pr,5960		posBases: make([]*src.PosBase, pr.NumElems(pkgbits.SectionPosBase)),61		pkgs:     make([]*types.Pkg, pr.NumElems(pkgbits.SectionPkg)),62		typs:     make([]*types.Type, pr.NumElems(pkgbits.SectionType)),6364		newindex: make([]index, pr.TotalElems()),65	}66}6768// A pkgReaderIndex compactly identifies an index (and its69// corresponding dictionary) within a package's export data.70type pkgReaderIndex struct {71	pr        *pkgReader72	idx       index73	dict      *readerDict74	methodSym *types.Sym7576	synthetic func(pos src.XPos, r *reader)77}7879func (pri pkgReaderIndex) asReader(k pkgbits.SectionKind, marker pkgbits.SyncMarker) *reader {80	if pri.synthetic != nil {81		return &reader{synthetic: pri.synthetic}82	}8384	r := pri.pr.newReader(k, pri.idx, marker)85	r.dict = pri.dict86	r.methodSym = pri.methodSym87	return r88}8990func (pr *pkgReader) newReader(k pkgbits.SectionKind, idx index, marker pkgbits.SyncMarker) *reader {91	return &reader{92		Decoder: pr.NewDecoder(k, idx, marker),93		p:       pr,94	}95}9697// A reader provides APIs for reading an individual element.98type reader struct {99	pkgbits.Decoder100101	p *pkgReader102103	dict *readerDict104105	// funcLitGen is a counter for closure names.106	funcLitGen int107	// rangeLitGen is a counter for range func closure names.108	rangeLitGen int109110	// TODO(mdempsky): The state below is all specific to reading111	// function bodies. It probably makes sense to split it out112	// separately so that it doesn't take up space in every reader113	// instance.114115	curfn       *ir.Func116	locals      []*ir.Name117	closureVars []*ir.Name118119	// funarghack is used during inlining to suppress setting120	// Field.Nname to the inlined copies of the parameters. This is121	// necessary because we reuse the same types.Type as the original122	// function, and most of the compiler still relies on field.Nname to123	// find parameters/results.124	funarghack bool125126	// methodSym is the name of method's name, if reading a method.127	// It's nil if reading a normal function or closure body.128	methodSym *types.Sym129130	// dictParam is the .dict param, if any.131	dictParam *ir.Name132133	// synthetic is a callback function to construct a synthetic134	// function body. It's used for creating the bodies of function135	// literals used to curry arguments to shaped functions.136	synthetic func(pos src.XPos, r *reader)137138	// scopeVars is a stack tracking the number of variables declared in139	// the current function at the moment each open scope was opened.140	scopeVars         []int141	marker            dwarfgen.ScopeMarker142	lastCloseScopePos src.XPos143144	// === details for handling inline body expansion ===145146	// If we're reading in a function body because of inlining, this is147	// the call that we're inlining for.148	inlCaller    *ir.Func149	inlCall      *ir.CallExpr150	inlFunc      *ir.Func151	inlTreeIndex int152	inlPosBases  map[*src.PosBase]*src.PosBase153154	// suppressInlPos tracks whether position base rewriting for155	// inlining should be suppressed. See funcLit.156	suppressInlPos int157158	delayResults bool159160	// Label to return to.161	retlabel *types.Sym162}163164// A readerDict represents an instantiated "compile-time dictionary,"165// used for resolving any derived types needed for instantiating a166// generic object.167//168// A compile-time dictionary can either be "shaped" or "non-shaped."169// Shaped compile-time dictionaries are only used for instantiating170// shaped type definitions and function bodies, while non-shaped171// compile-time dictionaries are used for instantiating runtime172// dictionaries.173type readerDict struct {174	shaped bool // whether this is a shaped dictionary175176	// baseSym is the symbol for the object this dictionary belongs to.177	// If the object is an instantiated function or defined type, then178	// baseSym is the mangled symbol, including any type arguments.179	baseSym *types.Sym180181	// For non-shaped dictionaries, shapedObj is a reference to the182	// corresponding shaped object (always a function or defined type).183	shapedObj *ir.Name184185	// targs holds the implicit and explicit type arguments in use for186	// reading the current object. For example:187	//188	//	func F[T any]() {189	//		type X[U any] struct { t T; u U }190	//		var _ X[string]191	//	}192	//193	//	var _ = F[int]194	//195	// While instantiating F[int], we need to in turn instantiate196	// X[string]. [int] and [string] are explicit type arguments for F197	// and X, respectively; but [int] is also the implicit type198	// arguments for X.199	//200	// (As an analogy to function literals, explicits are the function201	// literal's formal parameters, while implicits are variables202	// captured by the function literal.)203	targs []*types.Type204205	// implicits counts how many of types within targs are implicit type206	// arguments; the rest are explicit.207	implicits int208	// receivers counts how many of types within targs are receiver type209	// arguments; they are explicit.210	receivers int211212	derived      []derivedInfo // reloc index of the derived type's descriptor213	derivedTypes []*types.Type // slice of previously computed derived types214215	// These slices correspond to entries in the runtime dictionary.216	typeParamMethodExprs []readerMethodExprInfo217	subdicts             []objInfo218	rtypes               []typeInfo219	itabs                []itabInfo220}221222type readerMethodExprInfo struct {223	typeParamIdx int224	method       *types.Sym225}226227func setType(n ir.Node, typ *types.Type) {228	n.SetType(typ)229	n.SetTypecheck(1)230}231232func setValue(name *ir.Name, val constant.Value) {233	name.SetVal(val)234	name.Defn = nil235}236237// @@@ Positions238239// pos reads a position from the bitstream.240func (r *reader) pos() src.XPos {241	return base.Ctxt.PosTable.XPos(r.pos0())242}243244// origPos reads a position from the bitstream, and returns both the245// original raw position and an inlining-adjusted position.246func (r *reader) origPos() (origPos, inlPos src.XPos) {247	r.suppressInlPos++248	origPos = r.pos()249	r.suppressInlPos--250	inlPos = r.inlPos(origPos)251	return252}253254func (r *reader) pos0() src.Pos {255	r.Sync(pkgbits.SyncPos)256	if !r.Bool() {257		return src.NoPos258	}259260	posBase := r.posBase()261	line := r.Uint()262	col := r.Uint()263	return src.MakePos(posBase, line, col)264}265266// posBase reads a position base from the bitstream.267func (r *reader) posBase() *src.PosBase {268	return r.inlPosBase(r.p.posBaseIdx(r.Reloc(pkgbits.SectionPosBase)))269}270271// posBaseIdx returns the specified position base, reading it first if272// needed.273func (pr *pkgReader) posBaseIdx(idx index) *src.PosBase {274	if b := pr.posBases[idx]; b != nil {275		return b276	}277278	r := pr.newReader(pkgbits.SectionPosBase, idx, pkgbits.SyncPosBase)279	var b *src.PosBase280281	absFilename := r.String()282	filename := absFilename283284	// For build artifact stability, the export data format only285	// contains the "absolute" filename as returned by objabi.AbsFile.286	// However, some tests (e.g., test/run.go's asmcheck tests) expect287	// to see the full, original filename printed out. Re-expanding288	// "$GOROOT" to buildcfg.GOROOT is a close-enough approximation to289	// satisfy this.290	//291	// The export data format only ever uses slash paths292	// (for cross-operating-system reproducible builds),293	// but error messages need to use native paths (backslash on Windows)294	// as if they had been specified on the command line.295	// (The go command always passes native paths to the compiler.)296	const dollarGOROOT = "$GOROOT"297	if buildcfg.GOROOT != "" && strings.HasPrefix(filename, dollarGOROOT) {298		filename = filepath.FromSlash(buildcfg.GOROOT + filename[len(dollarGOROOT):])299	}300301	if r.Bool() {302		b = src.NewFileBase(filename, absFilename)303	} else {304		pos := r.pos0()305		line := r.Uint()306		col := r.Uint()307		b = src.NewLinePragmaBase(pos, filename, absFilename, line, col)308	}309310	pr.posBases[idx] = b311	return b312}313314// inlPosBase returns the inlining-adjusted src.PosBase corresponding315// to oldBase, which must be a non-inlined position. When not316// inlining, this is just oldBase.317func (r *reader) inlPosBase(oldBase *src.PosBase) *src.PosBase {318	if index := oldBase.InliningIndex(); index >= 0 {319		base.Fatalf("oldBase %v already has inlining index %v", oldBase, index)320	}321322	if r.inlCall == nil || r.suppressInlPos != 0 {323		return oldBase324	}325326	if newBase, ok := r.inlPosBases[oldBase]; ok {327		return newBase328	}329330	newBase := src.NewInliningBase(oldBase, r.inlTreeIndex)331	r.inlPosBases[oldBase] = newBase332	return newBase333}334335// inlPos returns the inlining-adjusted src.XPos corresponding to336// xpos, which must be a non-inlined position. When not inlining, this337// is just xpos.338func (r *reader) inlPos(xpos src.XPos) src.XPos {339	pos := base.Ctxt.PosTable.Pos(xpos)340	pos.SetBase(r.inlPosBase(pos.Base()))341	return base.Ctxt.PosTable.XPos(pos)342}343344// @@@ Packages345346// pkg reads a package reference from the bitstream.347func (r *reader) pkg() *types.Pkg {348	r.Sync(pkgbits.SyncPkg)349	return r.p.pkgIdx(r.Reloc(pkgbits.SectionPkg))350}351352// pkgIdx returns the specified package from the export data, reading353// it first if needed.354func (pr *pkgReader) pkgIdx(idx index) *types.Pkg {355	if pkg := pr.pkgs[idx]; pkg != nil {356		return pkg357	}358359	pkg := pr.newReader(pkgbits.SectionPkg, idx, pkgbits.SyncPkgDef).doPkg()360	pr.pkgs[idx] = pkg361	return pkg362}363364// doPkg reads a package definition from the bitstream.365func (r *reader) doPkg() *types.Pkg {366	path := r.String()367	switch path {368	case "":369		path = r.p.PkgPath()370	case "builtin":371		return types.BuiltinPkg372	case "unsafe":373		return types.UnsafePkg374	}375376	name := r.String()377378	pkg := types.NewPkg(path, "")379380	if pkg.Name == "" {381		pkg.Name = name382	} else {383		base.Assertf(pkg.Name == name, "package %q has name %q, but want %q", pkg.Path, pkg.Name, name)384	}385386	return pkg387}388389// @@@ Types390391func (r *reader) typ() *types.Type {392	return r.typWrapped(true)393}394395// typWrapped is like typ, but allows suppressing generation of396// unnecessary wrappers as a compile-time optimization.397func (r *reader) typWrapped(wrapped bool) *types.Type {398	return r.p.typIdx(r.typInfo(), r.dict, wrapped)399}400401func (r *reader) typInfo() typeInfo {402	r.Sync(pkgbits.SyncType)403	if r.Bool() {404		return typeInfo{idx: index(r.Len()), derived: true}405	}406	return typeInfo{idx: r.Reloc(pkgbits.SectionType), derived: false}407}408409// typListIdx returns a list of the specified types, resolving derived410// types within the given dictionary.411func (pr *pkgReader) typListIdx(infos []typeInfo, dict *readerDict) []*types.Type {412	typs := make([]*types.Type, len(infos))413	for i, info := range infos {414		typs[i] = pr.typIdx(info, dict, true)415	}416	return typs417}418419// typIdx returns the specified type. If info specifies a derived420// type, it's resolved within the given dictionary. If wrapped is421// true, then method wrappers will be generated, if appropriate.422func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict, wrapped bool) *types.Type {423	idx := info.idx424	var where **types.Type425	if info.derived {426		where = &dict.derivedTypes[idx]427		idx = dict.derived[idx].idx428	} else {429		where = &pr.typs[idx]430	}431432	if typ := *where; typ != nil {433		return typ434	}435436	r := pr.newReader(pkgbits.SectionType, idx, pkgbits.SyncTypeIdx)437	r.dict = dict438439	typ := r.doTyp()440	if typ == nil {441		base.Fatalf("doTyp returned nil for info=%v", info)442	}443444	// For recursive type declarations involving interfaces and aliases,445	// above r.doTyp() call may have already set pr.typs[idx], so just446	// double check and return the type.447	//448	// Example:449	//450	//     type F = func(I)451	//452	//     type I interface {453	//         m(F)454	//     }455	//456	// The writer writes data types in following index order:457	//458	//     0: func(I)459	//     1: I460	//     2: interface{m(func(I))}461	//462	// The reader resolves it in following index order:463	//464	//     0 -> 1 -> 2 -> 0 -> 1465	//466	// and can divide in logically 2 steps:467	//468	//  - 0 -> 1     : first time the reader reach type I,469	//                 it creates new named type with symbol I.470	//471	//  - 2 -> 0 -> 1: the reader ends up reaching symbol I again,472	//                 now the symbol I was setup in above step, so473	//                 the reader just return the named type.474	//475	// Now, the functions called return, the pr.typs looks like below:476	//477	//  - 0 -> 1 -> 2 -> 0 : [<T> I <T>]478	//  - 0 -> 1 -> 2      : [func(I) I <T>]479	//  - 0 -> 1           : [func(I) I interface { "".m(func("".I)) }]480	//481	// The idx 1, corresponding with type I was resolved successfully482	// after r.doTyp() call.483484	if prev := *where; prev != nil {485		return prev486	}487488	if wrapped {489		// Only cache if we're adding wrappers, so that other callers that490		// find a cached type know it was wrapped.491		*where = typ492493		r.needWrapper(typ)494	}495496	if !typ.IsUntyped() {497		types.CheckSize(typ)498	}499500	return typ501}502503func (r *reader) doTyp() *types.Type {504	switch tag := pkgbits.CodeType(r.Code(pkgbits.SyncType)); tag {505	default:506		panic(fmt.Sprintf("unexpected type: %v", tag))507508	case pkgbits.TypeBasic:509		return *basics[r.Len()]510511	case pkgbits.TypeNamed:512		obj := r.obj()513		assert(obj.Op() == ir.OTYPE)514		return obj.Type()515516	case pkgbits.TypeTypeParam:517		return r.dict.targs[r.Len()]518519	case pkgbits.TypeArray:520		len := int64(r.Uint64())521		return types.NewArray(r.typ(), len)522	case pkgbits.TypeChan:523		dir := dirs[r.Len()]524		return types.NewChan(r.typ(), dir)525	case pkgbits.TypeMap:526		return types.NewMap(r.typ(), r.typ())527	case pkgbits.TypePointer:528		return types.NewPtr(r.typ())529	case pkgbits.TypeSignature:530		return r.signature(nil)531	case pkgbits.TypeSlice:532		return types.NewSlice(r.typ())533	case pkgbits.TypeStruct:534		return r.structType()535	case pkgbits.TypeInterface:536		return r.interfaceType()537	case pkgbits.TypeUnion:538		return r.unionType()539	}540}541542func (r *reader) unionType() *types.Type {543	// In the types1 universe, we only need to handle value types.544	// Impure interfaces (i.e., interfaces with non-trivial type sets545	// like "int | string") can only appear as type parameter bounds,546	// and this is enforced by the types2 type checker.547	//548	// However, type unions can still appear in pure interfaces if the549	// type union is equivalent to "any". E.g., typeparam/issue52124.go550	// declares variables with the type "interface { any | int }".551	//552	// To avoid needing to represent type unions in types1 (since we553	// don't have any uses for that today anyway), we simply fold them554	// to "any".555556	// TODO(mdempsky): Restore consistency check to make sure folding to557	// "any" is safe. This is unfortunately tricky, because a pure558	// interface can reference impure interfaces too, including559	// cyclically (#60117).560	if false {561		pure := false562		for i, n := 0, r.Len(); i < n; i++ {563			_ = r.Bool() // tilde564			term := r.typ()565			if term.IsEmptyInterface() {566				pure = true567			}568		}569		if !pure {570			base.Fatalf("impure type set used in value type")571		}572	}573574	return types.Types[types.TINTER]575}576577func (r *reader) interfaceType() *types.Type {578	nmethods, nembeddeds := r.Len(), r.Len()579	implicit := nmethods == 0 && nembeddeds == 1 && r.Bool()580	assert(!implicit) // implicit interfaces only appear in constraints581582	fields := make([]*types.Field, nmethods+nembeddeds)583	methods, embeddeds := fields[:nmethods], fields[nmethods:]584585	for i := range methods {586		methods[i] = types.NewField(r.pos(), r.selector(), r.signature(types.FakeRecv()))587	}588	for i := range embeddeds {589		embeddeds[i] = types.NewField(src.NoXPos, nil, r.typ())590	}591592	if len(fields) == 0 {593		return types.Types[types.TINTER] // empty interface594	}595	return types.NewInterface(fields)596}597598func (r *reader) structType() *types.Type {599	fields := make([]*types.Field, r.Len())600	for i := range fields {601		field := types.NewField(r.pos(), r.selector(), r.typ())602		field.Note = r.String()603		if r.Bool() {604			field.Embedded = 1605		}606		fields[i] = field607	}608	return types.NewStruct(fields)609}610611func (r *reader) signature(recv *types.Field) *types.Type {612	r.Sync(pkgbits.SyncSignature)613614	params := r.params()615	results := r.params()616	if r.Bool() { // variadic617		params[len(params)-1].SetIsDDD(true)618	}619620	return types.NewSignature(recv, params, results)621}622623func (r *reader) params() []*types.Field {624	r.Sync(pkgbits.SyncParams)625	params := make([]*types.Field, r.Len())626	for i := range params {627		params[i] = r.param()628	}629	return params630}631632func (r *reader) param() *types.Field {633	r.Sync(pkgbits.SyncParam)634	return types.NewField(r.pos(), r.localIdent(), r.typ())635}636637// @@@ Objects638639// objReader maps qualified identifiers (represented as *types.Sym) to640// a pkgReader and corresponding index that can be used for reading641// that object's definition.642var objReader = map[*types.Sym]pkgReaderIndex{}643644// obj reads an instantiated object reference from the bitstream.645func (r *reader) obj() ir.Node {646	return r.p.objInstIdx(r.objInfo(), r.dict, false)647}648649// objInfo reads an instantiated object reference from the bitstream650// and returns the encoded reference to it, without instantiating it.651func (r *reader) objInfo() objInfo {652	r.Sync(pkgbits.SyncObject)653	if r.Version().Has(pkgbits.DerivedFuncInstance) {654		assert(!r.Bool())655	}656	idx := r.Reloc(pkgbits.SectionObj)657658	explicits := make([]typeInfo, r.Len())659	for i := range explicits {660		explicits[i] = r.typInfo()661	}662663	return objInfo{idx, explicits}664}665666// objInstIdx returns the encoded, instantiated object. If shaped is667// true, then the shaped variant of the object is returned instead.668func (pr *pkgReader) objInstIdx(info objInfo, dict *readerDict, shaped bool) ir.Node {669	explicits := pr.typListIdx(info.explicits, dict)670671	var implicits []*types.Type672	if dict != nil {673		implicits = dict.targs674	}675676	return pr.objIdx(info.idx, implicits, explicits, shaped)677}678679// objIdx returns the specified object, instantiated with the given680// type arguments, if any.681// If shaped is true, then the shaped variant of the object is returned682// instead.683func (pr *pkgReader) objIdx(idx index, implicits, explicits []*types.Type, shaped bool) ir.Node {684	n, err := pr.objIdxMayFail(idx, implicits, explicits, shaped)685	if err != nil {686		base.Fatalf("%v", err)687	}688	return n689}690691// objIdxMayFail is equivalent to objIdx, but returns an error rather than692// failing the build if this object requires type arguments and the incorrect693// number of type arguments were passed.694//695// Other sources of internal failure (such as duplicate definitions) still fail696// the build.697func (pr *pkgReader) objIdxMayFail(idx index, implicits, explicits []*types.Type, shaped bool) (ir.Node, error) {698	rname := pr.newReader(pkgbits.SectionName, idx, pkgbits.SyncObject1)699	_, sym := rname.qualifiedIdent()700	tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))701702	if tag == pkgbits.ObjStub {703		assert(!sym.IsBlank())704		switch sym.Pkg {705		case types.BuiltinPkg, types.UnsafePkg:706			return sym.Def.(ir.Node), nil707		}708		if pri, ok := objReader[sym]; ok {709			return pri.pr.objIdxMayFail(pri.idx, nil, explicits, shaped)710		}711		if sym.Pkg.Path == "runtime" {712			return typecheck.LookupRuntime(sym.Name), nil713		}714		base.Fatalf("unresolved stub: %v", sym)715	}716717	dict, err := pr.objDictIdx(sym, idx, implicits, explicits, shaped)718	if err != nil {719		return nil, err720	}721722	sym = dict.baseSym723	if !sym.IsBlank() && sym.Def != nil {724		return sym.Def.(*ir.Name), nil725	}726727	r := pr.newReader(pkgbits.SectionObj, idx, pkgbits.SyncObject1)728	rext := pr.newReader(pkgbits.SectionObjExt, idx, pkgbits.SyncObject1)729730	r.dict = dict731	rext.dict = dict732733	do := func(op ir.Op, hasTParams bool) *ir.Name {734		pos := r.pos()735		setBasePos(pos)736		if hasTParams {737			r.typeParamNames()738		}739740		name := ir.NewDeclNameAt(pos, op, sym)741		name.Class = ir.PEXTERN // may be overridden later742		if !sym.IsBlank() {743			if sym.Def != nil {744				base.FatalfAt(name.Pos(), "already have a definition for %v", name)745			}746			assert(sym.Def == nil)747			sym.Def = name748		}749		return name750	}751752	switch tag {753	default:754		panic("unexpected object")755756	case pkgbits.ObjAlias:757		name := do(ir.OTYPE, false)758759		if r.Version().Has(pkgbits.AliasTypeParamNames) {760			r.typeParamNames()761		}762763		// Clumsy dance: the r.typ() call here might recursively find this764		// type alias name, before we've set its type (#66873). So we765		// temporarily clear sym.Def and then restore it later, if still766		// unset.767		hack := sym.Def == name768		if hack {769			sym.Def = nil770		}771		typ := r.typ()772		if hack {773			if sym.Def != nil {774				name = sym.Def.(*ir.Name)775				assert(types.IdenticalStrict(name.Type(), typ))776				return name, nil777			}778			sym.Def = name779		}780781		setType(name, typ)782		name.SetAlias(true)783		return name, nil784785	case pkgbits.ObjConst:786		name := do(ir.OLITERAL, false)787		typ := r.typ()788		val := FixValue(typ, r.Value())789		setType(name, typ)790		setValue(name, val)791		return name, nil792793	case pkgbits.ObjFunc:794		npos := r.pos()795		setBasePos(npos)796797		var sel *types.Sym798		var recv *types.Field799		if r.Version().Has(pkgbits.GenericMethods) && r.Bool() {800			sel = r.selector()801			r.recvTypeParamNames()802			recv = r.param()803		} else {804			if sym.Name == "init" {805				sym = Renameinit()806			}807		}808		r.typeParamNames()809		typ := r.signature(recv)810		fpos := r.pos()811812		fn := ir.NewFunc(fpos, npos, sym, typ)813		if r.hasTypeParams() && r.dict.shaped {814			typ.SetHasShape(true)815		}816817		name := fn.Nname818		if !sym.IsBlank() {819			if sym.Def != nil {820				base.FatalfAt(name.Pos(), "already have a definition for %v", name)821			}822			assert(sym.Def == nil)823			sym.Def = name824		}825826		if r.hasTypeParams() {827			name.Func.SetDupok(true)828			if r.dict.shaped {829				setType(name, shapeSig(name.Func, r.dict))830			} else {831				todoDicts = append(todoDicts, func() {832					r.dict.shapedObj = pr.objIdx(idx, implicits, explicits, true).(*ir.Name)833				})834			}835		}836837		rext.funcExt(name, sel)838		return name, nil839840	case pkgbits.ObjType:841		name := do(ir.OTYPE, true)842		typ := types.NewNamed(name)843		setType(name, typ)844		if r.hasTypeParams() && r.dict.shaped {845			typ.SetHasShape(true)846		}847848		// Important: We need to do this before SetUnderlying.849		rext.typeExt(name)850851		// We need to defer CheckSize until we've called SetUnderlying to852		// handle recursive types.853		types.DeferCheckSize()854		typ.SetUnderlying(r.typWrapped(false))855		types.ResumeCheckSize()856857		if r.hasTypeParams() && !r.dict.shaped {858			todoDicts = append(todoDicts, func() {859				r.dict.shapedObj = pr.objIdx(idx, implicits, explicits, true).(*ir.Name)860			})861		}862863		methods := make([]*types.Field, r.Len())864		for i := range methods {865			methods[i] = r.method(rext)866		}867		if len(methods) != 0 {868			typ.SetMethods(methods)869		}870871		if !r.dict.shaped {872			r.needWrapper(typ)873		}874875		return name, nil876877	case pkgbits.ObjVar:878		name := do(ir.ONAME, false)879		setType(name, r.typ())880		rext.varExt(name)881		return name, nil882	}883}884885// mangle shapes the non-shaped symbol sym under the current dictionary.886func (dict *readerDict) mangle(sym *types.Sym) *types.Sym {887	if !dict.hasTypeParams() {888		return sym889	}890891	var buf strings.Builder892	// If sym is a locally defined generic type, we need the suffix to893	// stay at the end after mangling so that types/fmt.go can strip it894	// out again when writing the type's runtime descriptor (#54456).895	n0, vsuff := types.SplitVargenSuffix(sym.Name)896	n1, msuff := types.SplitMethSuffix(sym.Name)897898	// Methods are never locally defined.899	var n string900	assert(vsuff == "" || msuff == "")901	if vsuff != "" {902		n = n0903	} else {904		n = n1905	}906907	var j int908	assert(dict.implicits == 0 || dict.receivers == 0)909	if msuff != "" {910		j = dict.receivers // consume receiver type arguments911	} else {912		j = len(dict.targs) // consume all type arguments913	}914915	// put type arguments inside parenthesis; (*T)[int] -> (*T[int])916	n, ok := strings.CutSuffix(n, ")")917918	// type arguments, if any919	buf.WriteString(n)920	if j > 0 {921		buf.WriteByte('[')922		for i := 0; i < j; i++ {923			if i > 0 {924				if i == dict.implicits {925					buf.WriteByte(';')926				} else {927					buf.WriteByte(',')928				}929			}930			buf.WriteString(dict.targs[i].LinkString())931		}932		buf.WriteByte(']')933	}934935	if ok {936		buf.WriteString(")")937	}938939	buf.WriteString(vsuff)940	buf.WriteString(msuff)941942	// method arguments, if any943	if msuff != "" {944		buf.WriteByte('[')945		for i := j; i < len(dict.targs); i++ {946			if i > j {947				buf.WriteByte(',')948			}949			buf.WriteString(dict.targs[i].LinkString())950		}951		buf.WriteByte(']')952	}953954	return sym.Pkg.Lookup(buf.String())955}956957// Shapify returns the shape type for targ.958//959// If basic is true, then the type argument is used to instantiate a960// type parameter whose constraint is a basic interface.961func Shapify(targ *types.Type, basic bool) *types.Type {962	if targ.Kind() == types.TFORW {963		if targ.IsFullyInstantiated() {964			// For recursive instantiated type argument, it may  still be a TFORW965			// when shapifying happens. If we don't have targ's underlying type,966			// shapify won't work. The worst case is we end up not reusing code967			// optimally in some tricky cases.968			if base.Debug.Shapify != 0 {969				base.Warn("skipping shaping of recursive type %v", targ)970			}971			if targ.HasShape() {972				return targ973			}974		} else {975			base.Fatalf("%v is missing its underlying type", targ)976		}977	}978	// For fully instantiated shape interface type, use it as-is. Otherwise, the instantiation979	// involved recursive generic interface may cause mismatching in function signature, see issue #65362.980	if targ.Kind() == types.TINTER && targ.IsFullyInstantiated() && targ.HasShape() {981		return targ982	}983984	// When a pointer type is used to instantiate a type parameter985	// constrained by a basic interface, we know the pointer's element986	// type can't matter to the generated code. In this case, we can use987	// an arbitrary pointer type as the shape type. (To match the988	// non-unified frontend, we use `*byte`.)989	//990	// Otherwise, we simply use the type's underlying type as its shape.991	//992	// TODO(mdempsky): It should be possible to do much more aggressive993	// shaping still; e.g., collapsing all pointer-shaped types into a994	// common type, collapsing scalars of the same size/alignment into a995	// common type, recursively shaping the element types of composite996	// types, and discarding struct field names and tags. However, we'll997	// need to start tracking how type parameters are actually used to998	// implement some of these optimizations.999	under := targ.Underlying()1000	if basic && targ.IsPtr() && !targ.Elem().NotInHeap() {1001		under = types.NewPtr(types.Types[types.TUINT8])1002	}10031004	// Hash long type names to bound symbol name length seen by users,1005	// particularly for large protobuf structs (#65030).1006	uls := under.LinkString()1007	if base.Debug.MaxShapeLen != 0 &&1008		len(uls) > base.Debug.MaxShapeLen {1009		h := hash.Sum32([]byte(uls))1010		uls = hex.EncodeToString(h[:])1011	}10121013	sym := types.ShapePkg.Lookup(uls)1014	if sym.Def == nil {1015		name := ir.NewDeclNameAt(under.Pos(), ir.OTYPE, sym)1016		typ := types.NewNamed(name)1017		typ.SetUnderlying(under)1018		sym.Def = typed(typ, name)1019	}1020	res := sym.Def.Type()1021	assert(res.IsShape())1022	assert(res.HasShape())1023	return res1024}10251026// objDictIdx reads and returns the specified object dictionary.1027func (pr *pkgReader) objDictIdx(sym *types.Sym, idx index, implicits, explicits []*types.Type, shaped bool) (*readerDict, error) {1028	r := pr.newReader(pkgbits.SectionObjDict, idx, pkgbits.SyncObject1)10291030	dict := readerDict{1031		shaped: shaped,1032	}10331034	nimplicits := r.Len()1035	nreceivers := 01036	if r.Version().Has(pkgbits.GenericMethods) {1037		nreceivers = r.Len()1038	}1039	nexplicits := r.Len() + nreceivers10401041	if nimplicits > len(implicits) || nexplicits != len(explicits) {1042		return nil, fmt.Errorf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits))1043	}10441045	dict.targs = append(implicits[:nimplicits:nimplicits], explicits...)1046	dict.implicits = nimplicits1047	dict.receivers = nreceivers10481049	// Within the compiler, we can just skip over the type parameters.1050	for range dict.targs[dict.implicits:] {1051		// Skip past bounds without actually evaluating them.1052		r.typInfo()1053	}10541055	dict.derived = make([]derivedInfo, r.Len())1056	dict.derivedTypes = make([]*types.Type, len(dict.derived))1057	for i := range dict.derived {1058		dict.derived[i] = derivedInfo{idx: r.Reloc(pkgbits.SectionType)}1059		if r.Version().Has(pkgbits.DerivedInfoNeeded) {1060			assert(!r.Bool())1061		}1062	}10631064	// Runtime dictionary information; private to the compiler.10651066	// If any type argument is already shaped, then we're constructing a1067	// shaped object, even if not explicitly requested (i.e., calling1068	// objIdx with shaped==true). This can happen with instantiating1069	// types that are referenced within a function body.1070	for _, targ := range dict.targs {1071		if targ.HasShape() {1072			dict.shaped = true1073			break1074		}1075	}10761077	// And if we're constructing a shaped object, then shapify all type1078	// arguments.1079	for i, targ := range dict.targs {1080		basic := r.Bool()1081		if dict.shaped {1082			dict.targs[i] = Shapify(targ, basic)1083		}1084	}10851086	dict.baseSym = dict.mangle(sym)10871088	dict.typeParamMethodExprs = make([]readerMethodExprInfo, r.Len())1089	for i := range dict.typeParamMethodExprs {1090		typeParamIdx := r.Len()1091		method := r.selector()10921093		dict.typeParamMethodExprs[i] = readerMethodExprInfo{typeParamIdx, method}1094	}10951096	dict.subdicts = make([]objInfo, r.Len())1097	for i := range dict.subdicts {1098		dict.subdicts[i] = r.objInfo()1099	}11001101	dict.rtypes = make([]typeInfo, r.Len())1102	for i := range dict.rtypes {1103		dict.rtypes[i] = r.typInfo()1104	}11051106	dict.itabs = make([]itabInfo, r.Len())1107	for i := range dict.itabs {1108		dict.itabs[i] = itabInfo{typ: r.typInfo(), iface: r.typInfo()}1109	}11101111	return &dict, nil1112}11131114func (r *reader) recvTypeParamNames() {1115	r.Sync(pkgbits.SyncTypeParamNames)11161117	for range r.dict.targs[r.dict.implicits : r.dict.implicits+r.dict.receivers] {1118		r.pos()1119		r.localIdent()1120	}1121}11221123func (r *reader) typeParamNames() {1124	r.Sync(pkgbits.SyncTypeParamNames)11251126	for range r.dict.targs[r.dict.implicits+r.dict.receivers:] {1127		r.pos()1128		r.localIdent()1129	}1130}11311132func (r *reader) method(rext *reader) *types.Field {1133	r.Sync(pkgbits.SyncMethod)1134	npos := r.pos()1135	sym := r.selector()1136	r.typeParamNames()1137	recv := r.param()1138	typ := r.signature(recv)11391140	fpos := r.pos()1141	fn := ir.NewFunc(fpos, npos, ir.MethodSym(recv.Type, sym), typ)1142	name := fn.Nname11431144	if r.hasTypeParams() {1145		name.Func.SetDupok(true)1146		if r.dict.shaped {1147			typ = shapeSig(name.Func, r.dict)1148			setType(name, typ)1149		}1150	}11511152	rext.funcExt(name, sym)11531154	meth := types.NewField(name.Func.Pos(), sym, typ)1155	meth.Nname = name1156	meth.SetNointerface(name.Func.Pragma&ir.Nointerface != 0)11571158	return meth1159}11601161func (r *reader) qualifiedIdent() (pkg *types.Pkg, sym *types.Sym) {1162	r.Sync(pkgbits.SyncSym)1163	pkg = r.pkg()1164	if name := r.String(); name != "" {1165		sym = pkg.Lookup(name)1166	}1167	return1168}11691170func (r *reader) localIdent() *types.Sym {1171	r.Sync(pkgbits.SyncLocalIdent)1172	pkg := r.pkg()1173	if name := r.String(); name != "" {1174		return pkg.Lookup(name)1175	}1176	return nil1177}11781179func (r *reader) selector() *types.Sym {1180	r.Sync(pkgbits.SyncSelector)1181	pkg := r.pkg()1182	name := r.String()1183	if types.IsExported(name) {1184		pkg = types.LocalPkg1185	}1186	return pkg.Lookup(name)1187}11881189func (r *reader) hasTypeParams() bool {1190	return r.dict.hasTypeParams()1191}11921193func (dict *readerDict) hasTypeParams() bool {1194	return dict != nil && len(dict.targs) != 01195}11961197// @@@ Compiler extensions11981199func (r *reader) funcExt(name *ir.Name, method *types.Sym) {1200	r.Sync(pkgbits.SyncFuncExt)12011202	fn := name.Func12031204	// XXX: Workaround because linker doesn't know how to copy Pos.1205	if !fn.Pos().IsKnown() {1206		fn.SetPos(name.Pos())1207	}12081209	// Normally, we only compile local functions, which saves redundant compilation work.1210	// n.Defn is not nil for local functions, and is nil for imported function. But for1211	// generic functions, we might have an instantiation that no other package has seen before.1212	// So we need to be conservative and compile it again.1213	//1214	// That's why name.Defn is set here, so ir.VisitFuncsBottomUp can analyze function.1215	// TODO(mdempsky,cuonglm): find a cleaner way to handle this.1216	if name.Sym().Pkg == types.LocalPkg || r.hasTypeParams() {1217		name.Defn = fn1218	}12191220	fn.Pragma = r.pragmaFlag()1221	r.linkname(name)12221223	if buildcfg.GOARCH == "wasm" {1224		importmod := r.String()1225		importname := r.String()1226		exportname := r.String()12271228		if importmod != "" && importname != "" {1229			fn.WasmImport = &ir.WasmImport{1230				Module: importmod,1231				Name:   importname,1232			}1233		}1234		if exportname != "" {1235			if method != nil {1236				base.ErrorfAt(fn.Pos(), 0, "cannot use //go:wasmexport on a method")1237			}1238			fn.WasmExport = &ir.WasmExport{Name: exportname}1239		}1240	}12411242	if r.Bool() {1243		assert(name.Defn == nil)12441245		fn.ABI = obj.ABI(r.Uint64())12461247		// Escape analysis.1248		for _, f := range name.Type().RecvParams() {1249			f.Note = r.String()1250		}12511252		if r.Bool() {1253			fn.Inl = &ir.Inline{1254				Cost:            int32(r.Len()),1255				CanDelayResults: r.Bool(),1256			}1257			if buildcfg.Experiment.NewInliner {1258				fn.Inl.Properties = r.String()1259			}1260		}1261	} else {1262		r.addBody(name.Func, method)1263	}1264	r.Sync(pkgbits.SyncEOF)1265}12661267func (r *reader) typeExt(name *ir.Name) {1268	r.Sync(pkgbits.SyncTypeExt)12691270	typ := name.Type()12711272	if r.hasTypeParams() {1273		// Mark type as fully instantiated to ensure the type descriptor is written1274		// out as DUPOK and method wrappers are generated even for imported types.1275		typ.SetIsFullyInstantiated(true)1276		// HasShape should be set if any type argument is or has a shape type.1277		for _, targ := range r.dict.targs {1278			if targ.HasShape() {1279				typ.SetHasShape(true)1280				break1281			}1282		}1283	}12841285	name.SetPragma(r.pragmaFlag())12861287	typecheck.SetBaseTypeIndex(typ, r.Int64(), r.Int64())1288}12891290func (r *reader) varExt(name *ir.Name) {1291	r.Sync(pkgbits.SyncVarExt)1292	r.linkname(name)1293}12941295func (r *reader) linkname(name *ir.Name) {1296	assert(name.Op() == ir.ONAME)1297	r.Sync(pkgbits.SyncLinkname)12981299	if idx := r.Int64(); idx >= 0 {1300		lsym := name.Linksym()1301		lsym.SymIdx = int32(idx)1302		lsym.Set(obj.AttrIndexed, true)1303	} else {1304		linkname := r.String()1305		std := r.Bool()1306		sym := name.Sym()1307		sym.Linkname = linkname1308		if sym.Pkg == types.LocalPkg && linkname != "" {1309			// Mark linkname in the current package. We don't mark the1310			// ones that are imported and propagated (e.g. through1311			// inlining or instantiation, which are marked in their1312			// corresponding packages). So we can tell in which package1313			// the linkname is used (pulled), and the linker can1314			// make a decision for allowing or disallowing it.1315			if std {1316				sym.Linksym().Set(obj.AttrLinknameStd, true)1317			} else {1318				sym.Linksym().Set(obj.AttrLinkname, true)1319			}1320		}1321	}1322}13231324func (r *reader) pragmaFlag() ir.PragmaFlag {1325	r.Sync(pkgbits.SyncPragma)1326	return ir.PragmaFlag(r.Int())1327}13281329// @@@ Function bodies13301331// bodyReader tracks where the serialized IR for a local or imported,1332// generic function's body can be found.1333var bodyReader = map[*ir.Func]pkgReaderIndex{}13341335// importBodyReader tracks where the serialized IR for an imported,1336// static (i.e., non-generic) function body can be read.1337var importBodyReader = map[*types.Sym]pkgReaderIndex{}13381339// bodyReaderFor returns the pkgReaderIndex for reading fn's1340// serialized IR, and whether one was found.1341func bodyReaderFor(fn *ir.Func) (pri pkgReaderIndex, ok bool) {1342	if fn.Nname.Defn != nil {1343		pri, ok = bodyReader[fn]1344		base.AssertfAt(ok, base.Pos, "must have bodyReader for %v", fn) // must always be available1345	} else {1346		pri, ok = importBodyReader[fn.Sym()]1347	}1348	return1349}13501351// todoDicts holds the list of dictionaries that still need their1352// runtime dictionary objects constructed.1353var todoDicts []func()13541355// todoBodies holds the list of function bodies that still need to be1356// constructed.1357var todoBodies []*ir.Func13581359// addBody reads a function body reference from the element bitstream,1360// and associates it with fn.1361func (r *reader) addBody(fn *ir.Func, method *types.Sym) {1362	// addBody should only be called for local functions or imported1363	// generic functions; see comment in funcExt.1364	assert(fn.Nname.Defn != nil)13651366	idx := r.Reloc(pkgbits.SectionBody)13671368	pri := pkgReaderIndex{r.p, idx, r.dict, method, nil}1369	bodyReader[fn] = pri13701371	if r.curfn == nil {1372		todoBodies = append(todoBodies, fn)1373		return1374	}13751376	pri.funcBody(fn)1377}13781379func (pri pkgReaderIndex) funcBody(fn *ir.Func) {1380	r := pri.asReader(pkgbits.SectionBody, pkgbits.SyncFuncBody)1381	panicking := true1382	defer func() {1383		if panicking {1384			// TODO not sure what the best way to print in this context is.1385			// If code panics in unified IR reading, you want *something* like this.1386			// Whoever ends up debugging the next unified IR failure, please1387			// improve this (base.Warnf?) if you can figure out how.1388			fmt.Printf("****** panic traversed funcBody of %v\n", fn)1389		}1390	}()1391	r.funcBody(fn)1392	panicking = false13931394}13951396// funcBody reads a function body definition from the element1397// bitstream, and populates fn with it.1398func (r *reader) funcBody(fn *ir.Func) {1399	r.curfn = fn1400	r.closureVars = fn.ClosureVars1401	if len(r.closureVars) != 0 && r.hasTypeParams() {1402		r.dictParam = r.closureVars[len(r.closureVars)-1] // dictParam is last; see reader.funcLit1403	}14041405	ir.WithFunc(fn, func() {1406		r.declareParams()14071408		if r.syntheticBody(fn.Pos()) {1409			return1410		}14111412		if !r.Bool() {1413			return1414		}14151416		body := r.stmts()1417		if body == nil {1418			body = []ir.Node{typecheck.Stmt(ir.NewBlockStmt(src.NoXPos, nil))}1419		}1420		fn.Body = body1421		fn.Endlineno = r.pos()1422	})14231424	r.marker.WriteTo(fn)1425}14261427// syntheticBody adds a synthetic body to r.curfn if appropriate, and1428// reports whether it did.1429func (r *reader) syntheticBody(pos src.XPos) bool {1430	if r.synthetic != nil {1431		r.synthetic(pos, r)1432		return true1433	}14341435	// If this function has type parameters and isn't shaped, then we1436	// just tail call its corresponding shaped variant.1437	if r.hasTypeParams() && !r.dict.shaped {1438		r.callShaped(pos)1439		return true1440	}14411442	return false1443}14441445// callShaped emits a tail call to r.shapedFn, passing along the1446// arguments to the current function.1447func (r *reader) callShaped(pos src.XPos) {1448	shapedObj := r.dict.shapedObj1449	assert(shapedObj != nil)14501451	var shapedFn ir.Node1452	if r.methodSym == nil {1453		// Instantiating a generic function; shapedObj is the shaped function itself.1454		assert(shapedObj.Op() == ir.ONAME && shapedObj.Class == ir.PFUNC)1455		shapedFn = shapedObj1456	} else {1457		// Instantiating a generic type's method; shapedObj is the shaped method itself1458		// if the method is generic — else, it is the shaped type declaring the method.1459		shapedFn = shapedMethodExpr(pos, shapedObj, r.methodSym)1460	}14611462	params := r.syntheticArgs()14631464	// Construct the arguments list: receiver (if any), then runtime1465	// dictionary, and finally normal parameters.1466	//1467	// Note: For simplicity, shaped methods are added as normal methods1468	// on their shaped types. So existing code (e.g., packages ir and1469	// typecheck) expects the shaped type to appear as the receiver1470	// parameter (or first parameter, as a method expression). Hence1471	// putting the dictionary parameter after that is the least invasive1472	// solution at the moment.1473	var args ir.Nodes1474	if r.methodSym != nil {1475		args.Append(params[0])1476		params = params[1:]1477	}1478	args.Append(typecheck.Expr(ir.NewAddrExpr(pos, r.p.dictNameOf(r.dict))))1479	args.Append(params...)14801481	r.syntheticTailCall(pos, shapedFn, args)1482}14831484// syntheticArgs returns the recvs and params arguments passed to the1485// current function.1486func (r *reader) syntheticArgs() ir.Nodes {1487	sig := r.curfn.Nname.Type()1488	return ir.ToNodes(r.curfn.Dcl[:sig.NumRecvs()+sig.NumParams()])1489}14901491// syntheticTailCall emits a tail call to fn, passing the given1492// arguments list.1493func (r *reader) syntheticTailCall(pos src.XPos, fn ir.Node, args ir.Nodes) {1494	// Mark the function as a wrapper so it doesn't show up in stack1495	// traces.1496	r.curfn.SetWrapper(true)14971498	call := typecheck.Call(pos, fn, args, fn.Type().IsVariadic()).(*ir.CallExpr)14991500	var stmt ir.Node1501	if fn.Type().NumResults() != 0 {1502		stmt = typecheck.Stmt(ir.NewReturnStmt(pos, []ir.Node{call}))1503	} else {1504		stmt = call1505	}1506	r.curfn.Body.Append(stmt)1507}15081509// dictNameOf returns the runtime dictionary corresponding to dict.1510func (pr *pkgReader) dictNameOf(dict *readerDict) *ir.Name {1511	pos := base.AutogeneratedPos15121513	// Check that we only instantiate runtime dictionaries with real types.1514	base.AssertfAt(!dict.shaped, pos, "runtime dictionary of shaped object %v", dict.baseSym)15151516	sym := dict.baseSym.Pkg.Lookup(objabi.GlobalDictPrefix + "." + dict.baseSym.Name)1517	if sym.Def != nil {1518		return sym.Def.(*ir.Name)1519	}15201521	name := ir.NewNameAt(pos, sym, dict.varType())1522	name.Class = ir.PEXTERN1523	sym.Def = name // break cycles with mutual subdictionaries15241525	lsym := name.Linksym()1526	ot := 015271528	assertOffset := func(section string, offset int) {1529		base.AssertfAt(ot == offset*types.PtrSize, pos, "writing section %v at offset %v, but it should be at %v*%v", section, ot, offset, types.PtrSize)1530	}15311532	assertOffset("type param method exprs", dict.typeParamMethodExprsOffset())1533	for _, info := range dict.typeParamMethodExprs {1534		typeParam := dict.targs[info.typeParamIdx]1535		method := typecheck.NewMethodExpr(pos, typeParam, info.method)15361537		rsym := method.FuncName().Linksym()1538		assert(rsym.ABI() == obj.ABIInternal) // must be ABIInternal; see ir.OCFUNC in ssagen/ssa.go15391540		ot = objw.SymPtr(lsym, ot, rsym, 0)1541	}15421543	assertOffset("subdictionaries", dict.subdictsOffset())1544	for _, info := range dict.subdicts {1545		explicits := pr.typListIdx(info.explicits, dict)15461547		// Careful: Due to subdictionary cycles, name may not be fully1548		// initialized yet.1549		name := pr.objDictName(info.idx, dict.targs, explicits)15501551		ot = objw.SymPtr(lsym, ot, name.Linksym(), 0)1552	}15531554	assertOffset("rtypes", dict.rtypesOffset())1555	for _, info := range dict.rtypes {1556		typ := pr.typIdx(info, dict, true)1557		ot = objw.SymPtr(lsym, ot, reflectdata.TypeLinksym(typ), 0)15581559		// TODO(mdempsky): Double check this.1560		reflectdata.MarkTypeUsedInInterface(typ, lsym)1561	}15621563	// For each (typ, iface) pair, we write the *runtime.itab pointer1564	// for the pair. For pairs that don't actually require an itab1565	// (i.e., typ is an interface, or iface is an empty interface), we1566	// write a nil pointer instead. This is wasteful, but rare in1567	// practice (e.g., instantiating a type parameter with an interface1568	// type).1569	assertOffset("itabs", dict.itabsOffset())1570	for _, info := range dict.itabs {1571		typ := pr.typIdx(info.typ, dict, true)1572		iface := pr.typIdx(info.iface, dict, true)15731574		if !typ.IsInterface() && iface.IsInterface() && !iface.IsEmptyInterface() {1575			ot = objw.SymPtr(lsym, ot, reflectdata.ITabLsym(typ, iface), 0)1576		} else {1577			ot += types.PtrSize1578		}15791580		// TODO(mdempsky): Double check this.1581		reflectdata.MarkTypeUsedInInterface(typ, lsym)1582		reflectdata.MarkTypeUsedInInterface(iface, lsym)1583	}15841585	objw.Global(lsym, int32(ot), obj.DUPOK|obj.RODATA)15861587	return name1588}15891590// typeParamMethodExprsOffset returns the offset of the runtime1591// dictionary's type parameter method expressions section, in words.1592func (dict *readerDict) typeParamMethodExprsOffset() int {1593	return 01594}15951596// subdictsOffset returns the offset of the runtime dictionary's1597// subdictionary section, in words.1598func (dict *readerDict) subdictsOffset() int {1599	return dict.typeParamMethodExprsOffset() + len(dict.typeParamMethodExprs)1600}16011602// rtypesOffset returns the offset of the runtime dictionary's rtypes1603// section, in words.1604func (dict *readerDict) rtypesOffset() int {1605	return dict.subdictsOffset() + len(dict.subdicts)1606}16071608// itabsOffset returns the offset of the runtime dictionary's itabs1609// section, in words.1610func (dict *readerDict) itabsOffset() int {1611	return dict.rtypesOffset() + len(dict.rtypes)1612}16131614// numWords returns the total number of words that comprise dict's1615// runtime dictionary variable.1616func (dict *readerDict) numWords() int64 {1617	return int64(dict.itabsOffset() + len(dict.itabs))1618}16191620// varType returns the type of dict's runtime dictionary variable.1621func (dict *readerDict) varType() *types.Type {1622	return types.NewArray(types.Types[types.TUINTPTR], dict.numWords())1623}16241625func (r *reader) declareParams() {1626	r.curfn.DeclareParams(!r.funarghack)16271628	for _, name := range r.curfn.Dcl {1629		if name.Sym().Name == dictParamName {1630			r.dictParam = name1631			continue1632		}16331634		r.addLocal(name)1635	}1636}16371638func (r *reader) addLocal(name *ir.Name) {1639	if r.synthetic == nil {1640		r.Sync(pkgbits.SyncAddLocal)1641		if r.p.SyncMarkers() {1642			want := r.Int()1643			if have := len(r.locals); have != want {1644				base.FatalfAt(name.Pos(), "locals table has desynced")1645			}1646		}1647		r.varDictIndex(name)1648	}16491650	r.locals = append(r.locals, name)1651}16521653func (r *reader) useLocal() *ir.Name {1654	r.Sync(pkgbits.SyncUseObjLocal)1655	if r.Bool() {1656		return r.locals[r.Len()]1657	}1658	return r.closureVars[r.Len()]1659}16601661func (r *reader) openScope() {1662	r.Sync(pkgbits.SyncOpenScope)1663	pos := r.pos()16641665	if base.Flag.Dwarf {1666		r.scopeVars = append(r.scopeVars, len(r.curfn.Dcl))1667		r.marker.Push(pos)1668	}1669}16701671func (r *reader) closeScope() {1672	r.Sync(pkgbits.SyncCloseScope)1673	r.lastCloseScopePos = r.pos()16741675	r.closeAnotherScope()1676}16771678// closeAnotherScope is like closeScope, but it reuses the same mark1679// position as the last closeScope call. This is useful for "for" and1680// "if" statements, as their implicit blocks always end at the same1681// position as an explicit block.1682func (r *reader) closeAnotherScope() {1683	r.Sync(pkgbits.SyncCloseAnotherScope)16841685	if base.Flag.Dwarf {1686		scopeVars := r.scopeVars[len(r.scopeVars)-1]1687		r.scopeVars = r.scopeVars[:len(r.scopeVars)-1]16881689		// Quirkish: noder decides which scopes to keep before1690		// typechecking, whereas incremental typechecking during IR1691		// construction can result in new autotemps being allocated. To1692		// produce identical output, we ignore autotemps here for the1693		// purpose of deciding whether to retract the scope.1694		//1695		// This is important for net/http/fcgi, because it contains:1696		//1697		//	var body io.ReadCloser1698		//	if len(content) > 0 {1699		//		body, req.pw = io.Pipe()1700		//	} else { … }1701		//1702		// Notably, io.Pipe is inlinable, and inlining it introduces a ~R01703		// variable at the call site.1704		//1705		// Noder does not preserve the scope where the io.Pipe() call1706		// resides, because it doesn't contain any declared variables in1707		// source. So the ~R0 variable ends up being assigned to the1708		// enclosing scope instead.1709		//1710		// However, typechecking this assignment also introduces1711		// autotemps, because io.Pipe's results need conversion before1712		// they can be assigned to their respective destination variables.1713		//1714		// TODO(mdempsky): We should probably just keep all scopes, and1715		// let dwarfgen take care of pruning them instead.1716		retract := true1717		for _, n := range r.curfn.Dcl[scopeVars:] {1718			if !n.AutoTemp() {1719				retract = false1720				break1721			}1722		}17231724		if retract {1725			// no variables were declared in this scope, so we can retract it.1726			r.marker.Unpush()1727		} else {1728			r.marker.Pop(r.lastCloseScopePos)1729		}1730	}1731}17321733// @@@ Statements17341735func (r *reader) stmt() ir.Node {1736	return block(r.stmts())1737}17381739func block(stmts []ir.Node) ir.Node {1740	switch len(stmts) {1741	case 0:1742		return nil1743	case 1:1744		return stmts[0]1745	default:1746		return ir.NewBlockStmt(stmts[0].Pos(), stmts)1747	}1748}17491750func (r *reader) stmts() ir.Nodes {1751	assert(ir.CurFunc == r.curfn)1752	var res ir.Nodes17531754	r.Sync(pkgbits.SyncStmts)1755	for {1756		tag := codeStmt(r.Code(pkgbits.SyncStmt1))1757		if tag == stmtEnd {1758			r.Sync(pkgbits.SyncStmtsEnd)1759			return res1760		}17611762		if n := r.stmt1(tag, &res); n != nil {1763			res.Append(typecheck.Stmt(n))1764		}1765	}1766}17671768func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node {1769	var label *types.Sym1770	if n := len(*out); n > 0 {1771		if ls, ok := (*out)[n-1].(*ir.LabelStmt); ok {1772			label = ls.Label1773		}1774	}17751776	switch tag {1777	default:1778		panic("unexpected statement")17791780	case stmtAssign:1781		pos := r.pos()1782		names, lhs := r.assignList()1783		rhs := r.multiExpr()17841785		if len(rhs) == 0 {1786			for _, name := range names {1787				as := ir.NewAssignStmt(pos, name, nil)1788				as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, name))1789				out.Append(typecheck.Stmt(as))1790			}1791			return nil1792		}17931794		if len(lhs) == 1 && len(rhs) == 1 {1795			n := ir.NewAssignStmt(pos, lhs[0], rhs[0])1796			n.Def = r.initDefn(n, names)1797			return n1798		}17991800		n := ir.NewAssignListStmt(pos, ir.OAS2, lhs, rhs)1801		n.Def = r.initDefn(n, names)1802		return n18031804	case stmtAssignOp:1805		op := r.op()1806		lhs := r.expr()1807		pos := r.pos()1808		rhs := r.expr()1809		return ir.NewAssignOpStmt(pos, op, lhs, rhs)18101811	case stmtIncDec:1812		op := r.op()1813		lhs := r.expr()1814		pos := r.pos()1815		n := ir.NewAssignOpStmt(pos, op, lhs, ir.NewOne(pos, lhs.Type()))1816		n.IncDec = true1817		return n18181819	case stmtBlock:1820		out.Append(r.blockStmt()...)1821		return nil18221823	case stmtBranch:1824		pos := r.pos()1825		op := r.op()1826		sym := r.optLabel()1827		return ir.NewBranchStmt(pos, op, sym)18281829	case stmtCall:1830		pos := r.pos()1831		op := r.op()1832		call := r.expr()1833		stmt := ir.NewGoDeferStmt(pos, op, call)1834		if op == ir.ODEFER {1835			x := r.optExpr()1836			if x != nil {1837				stmt.DeferAt = x.(ir.Expr)1838			}1839		}1840		return stmt18411842	case stmtExpr:1843		return r.expr()18441845	case stmtFor:1846		return r.forStmt(label)18471848	case stmtIf:1849		return r.ifStmt()18501851	case stmtLabel:1852		pos := r.pos()1853		sym := r.label()1854		return ir.NewLabelStmt(pos, sym)18551856	case stmtReturn:1857		pos := r.pos()1858		results := r.multiExpr()1859		return ir.NewReturnStmt(pos, results)18601861	case stmtSelect:1862		return r.selectStmt(label)18631864	case stmtSend:1865		pos := r.pos()1866		ch := r.expr()1867		value := r.expr()1868		return ir.NewSendStmt(pos, ch, value)18691870	case stmtSwitch:1871		return r.switchStmt(label)1872	}1873}18741875func (r *reader) assignList() ([]*ir.Name, []ir.Node) {1876	lhs := make([]ir.Node, r.Len())1877	var names []*ir.Name18781879	for i := range lhs {1880		expr, def := r.assign()1881		lhs[i] = expr1882		if def {1883			names = append(names, expr.(*ir.Name))1884		}1885	}18861887	return names, lhs1888}18891890// assign returns an assignee expression. It also reports whether the1891// returned expression is a newly declared variable.1892func (r *reader) assign() (ir.Node, bool) {1893	switch tag := codeAssign(r.Code(pkgbits.SyncAssign)); tag {1894	default:1895		panic("unhandled assignee expression")18961897	case assignBlank:1898		return typecheck.AssignExpr(ir.BlankNode), false18991900	case assignDef:1901		pos := r.pos()1902		setBasePos(pos) // test/fixedbugs/issue49767.go depends on base.Pos being set for the r.typ() call here, ugh1903		name := r.curfn.NewLocal(pos, r.localIdent(), r.typ())1904		r.addLocal(name)1905		return name, true19061907	case assignExpr:1908		return r.expr(), false1909	}1910}19111912func (r *reader) blockStmt() []ir.Node {1913	r.Sync(pkgbits.SyncBlockStmt)1914	r.openScope()1915	stmts := r.stmts()1916	r.closeScope()1917	return stmts1918}19191920func (r *reader) forStmt(label *types.Sym) ir.Node {1921	r.Sync(pkgbits.SyncForStmt)19221923	r.openScope()19241925	if r.Bool() {1926		pos := r.pos()1927		rang := ir.NewRangeStmt(pos, nil, nil, nil, nil, false)1928		rang.Label = label19291930		names, lhs := r.assignList()1931		if len(lhs) >= 1 {1932			rang.Key = lhs[0]1933			if len(lhs) >= 2 {1934				rang.Value = lhs[1]1935			}1936		}1937		rang.Def = r.initDefn(rang, names)19381939		rang.X = r.expr()1940		if rang.X.Type().IsMap() {1941			rang.RType = r.rtype(pos)1942		}1943		if rang.Key != nil && !ir.IsBlank(rang.Key) {1944			rang.KeyTypeWord, rang.KeySrcRType = r.convRTTI(pos)1945		}1946		if rang.Value != nil && !ir.IsBlank(rang.Value) {1947			rang.ValueTypeWord, rang.ValueSrcRType = r.convRTTI(pos)1948		}19491950		rang.Body = r.blockStmt()1951		rang.DistinctVars = r.Bool()1952		r.closeAnotherScope()19531954		return rang1955	}19561957	pos := r.pos()1958	init := r.stmt()1959	cond := r.optExpr()1960	post := r.stmt()1961	body := r.blockStmt()1962	perLoopVars := r.Bool()1963	r.closeAnotherScope()19641965	if ir.IsConst(cond, constant.Bool) && !ir.BoolVal(cond) {1966		return init // simplify "for init; false; post { ... }" into "init"1967	}19681969	stmt := ir.NewForStmt(pos, init, cond, post, body, perLoopVars)1970	stmt.Label = label1971	return stmt1972}19731974func (r *reader) ifStmt() ir.Node {1975	r.Sync(pkgbits.SyncIfStmt)1976	r.openScope()1977	pos := r.pos()1978	init := r.stmts()1979	cond := r.expr()1980	staticCond := r.Int()1981	var then, els []ir.Node1982	if staticCond >= 0 {1983		then = r.blockStmt()1984	} else {1985		r.lastCloseScopePos = r.pos()1986	}1987	if staticCond <= 0 {1988		els = r.stmts()1989	}1990	r.closeAnotherScope()19911992	if staticCond != 0 {1993		// We may have removed a dead return statement, which can trip up1994		// later passes (#62211). To avoid confusion, we instead flatten1995		// the if statement into a block.19961997		if cond.Op() != ir.OLITERAL {1998			init.Append(typecheck.Stmt(ir.NewAssignStmt(pos, ir.BlankNode, cond))) // for side effects1999		}2000		init.Append(then...)

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.