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.