Newer
Older
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package noder
import (
"bytes"
"fmt"
"go/constant"
"internal/pkgbits"
"strings"
"cmd/compile/internal/base"
"cmd/compile/internal/deadcode"
"cmd/compile/internal/dwarfgen"
"cmd/compile/internal/inline"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw"
"cmd/compile/internal/reflectdata"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src"
)
// This file implements cmd/compile backend's reader for the Unified
// IR export data.
// A pkgReader reads Unified IR export data.
type pkgReader struct {
pkgbits.PkgDecoder
// Indices for encoded things; lazily populated as needed.
//
// Note: Objects (i.e., ir.Names) are lazily instantiated by
// populating their types.Sym.Def; see objReader below.
posBases []*src.PosBase
pkgs []*types.Pkg
typs []*types.Type
// offset for rewriting the given (absolute!) index into the output,
// but bitwise inverted so we can detect if we're missing the entry
// or not.
func newPkgReader(pr pkgbits.PkgDecoder) *pkgReader {
return &pkgReader{
PkgDecoder: pr,
posBases: make([]*src.PosBase, pr.NumElems(pkgbits.RelocPosBase)),
pkgs: make([]*types.Pkg, pr.NumElems(pkgbits.RelocPkg)),
typs: make([]*types.Type, pr.NumElems(pkgbits.RelocType)),
newindex: make([]pkgbits.Index, pr.TotalElems()),
// A pkgReaderIndex compactly identifies an index (and its
// corresponding dictionary) within a package's export data.
type pkgReaderIndex struct {
pr *pkgReader
idx pkgbits.Index
dict *readerDict
shapedFn *ir.Func
func (pri pkgReaderIndex) asReader(k pkgbits.RelocKind, marker pkgbits.SyncMarker) *reader {
r := pri.pr.newReader(k, pri.idx, marker)
r.dict = pri.dict
r.shapedFn = pri.shapedFn
func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
Decoder: pr.NewDecoder(k, idx, marker),
p: pr,
}
}
// A writer provides APIs for reading an individual element.
type reader struct {
pkgbits.Decoder
p *pkgReader
dict *readerDict
// TODO(mdempsky): The state below is all specific to reading
// function bodies. It probably makes sense to split it out
// separately so that it doesn't take up space in every reader
// instance.
curfn *ir.Func
locals []*ir.Name
closureVars []*ir.Name
funarghack bool
// shapedFn is the shape-typed version of curfn, if any.
shapedFn *ir.Func
// dictParam is the .dict param, if any.
dictParam *ir.Name
// scopeVars is a stack tracking the number of variables declared in
// the current function at the moment each open scope was opened.
scopeVars []int
marker dwarfgen.ScopeMarker
lastCloseScopePos src.XPos
// === details for handling inline body expansion ===
// If we're reading in a function body because of inlining, this is
// the call that we're inlining for.
inlCaller *ir.Func
inlCall *ir.CallExpr
inlFunc *ir.Func
inlTreeIndex int
inlPosBases map[*src.PosBase]*src.PosBase
delayResults bool
// Label to return to.
retlabel *types.Sym
// inlvars is the list of variables that the inlinee's arguments are
// assigned to, one for each receiver and normal parameter, in order.
inlvars ir.Nodes
// retvars is the list of variables that the inlinee's results are
// assigned to, one for each result parameter, in order.
retvars ir.Nodes
type readerDict struct {
// targs holds the implicit and explicit type arguments in use for
// reading the current object. For example:
//
// func F[T any]() {
// type X[U any] struct { t T; u U }
// var _ X[string]
// }
//
// var _ = F[int]
//
// While instantiating F[int], we need to in turn instantiate
// X[string]. [int] and [string] are explicit type arguments for F
// and X, respectively; but [int] is also the implicit type
// arguments for X.
//
// (As an analogy to function literals, explicits are the function
// literal's formal parameters, while implicits are variables
// captured by the function literal.)
targs []*types.Type
// implicits counts how many of types within targs are implicit type
// arguments; the rest are explicit.
implicits int
Matthew Dempsky
committed
derived []derivedInfo // reloc index of the derived type's descriptor
derivedTypes []*types.Type // slice of previously computed derived types
funcs []objInfo
funcsObj []ir.Node
itabs []itabInfo2
methodExprs []ir.Node
}
type itabInfo2 struct {
typ *types.Type
lsym *obj.LSym
}
func setType(n ir.Node, typ *types.Type) {
n.SetType(typ)
n.SetTypecheck(1)
}
func setValue(name *ir.Name, val constant.Value) {
name.SetVal(val)
name.Defn = nil
}
// @@@ Positions
// pos reads a position from the bitstream.
func (r *reader) pos() src.XPos {
return base.Ctxt.PosTable.XPos(r.pos0())
}
func (r *reader) pos0() src.Pos {
r.Sync(pkgbits.SyncPos)
if !r.Bool() {
return src.NoPos
}
posBase := r.posBase()
line := r.Uint()
col := r.Uint()
return src.MakePos(posBase, line, col)
}
// posBase reads a position base from the bitstream.
func (r *reader) posBase() *src.PosBase {
return r.inlPosBase(r.p.posBaseIdx(r.Reloc(pkgbits.RelocPosBase)))
// posBaseIdx returns the specified position base, reading it first if
// needed.
func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) *src.PosBase {
if b := pr.posBases[idx]; b != nil {
return b
}
r := pr.newReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)
var b *src.PosBase
absFilename := r.String()
filename := absFilename
// For build artifact stability, the export data format only
// contains the "absolute" filename as returned by objabi.AbsFile.
// However, some tests (e.g., test/run.go's asmcheck tests) expect
// to see the full, original filename printed out. Re-expanding
// "$GOROOT" to buildcfg.GOROOT is a close-enough approximation to
// satisfy this.
//
// TODO(mdempsky): De-duplicate this logic with similar logic in
// cmd/link/internal/ld's expandGoroot. However, this will probably
// require being more consistent about when we use native vs UNIX
// file paths.
const dollarGOROOT = "$GOROOT"
if buildcfg.GOROOT != "" && strings.HasPrefix(filename, dollarGOROOT) {
filename = buildcfg.GOROOT + filename[len(dollarGOROOT):]
}
b = src.NewFileBase(filename, absFilename)
} else {
pos := r.pos0()
line := r.Uint()
col := r.Uint()
b = src.NewLinePragmaBase(pos, filename, absFilename, line, col)
}
pr.posBases[idx] = b
return b
}
// TODO(mdempsky): Document this.
func (r *reader) inlPosBase(oldBase *src.PosBase) *src.PosBase {
if r.inlCall == nil {
return oldBase
}
if newBase, ok := r.inlPosBases[oldBase]; ok {
return newBase
}
newBase := src.NewInliningBase(oldBase, r.inlTreeIndex)
r.inlPosBases[oldBase] = newBase
return newBase
}
// TODO(mdempsky): Document this.
func (r *reader) updatePos(xpos src.XPos) src.XPos {
pos := base.Ctxt.PosTable.Pos(xpos)
pos.SetBase(r.inlPosBase(pos.Base()))
return base.Ctxt.PosTable.XPos(pos)
}
// @@@ Packages
// pkg reads a package reference from the bitstream.
func (r *reader) pkg() *types.Pkg {
r.Sync(pkgbits.SyncPkg)
return r.p.pkgIdx(r.Reloc(pkgbits.RelocPkg))
// pkgIdx returns the specified package from the export data, reading
// it first if needed.
func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types.Pkg {
if pkg := pr.pkgs[idx]; pkg != nil {
return pkg
}
pkg := pr.newReader(pkgbits.RelocPkg, idx, pkgbits.SyncPkgDef).doPkg()
pr.pkgs[idx] = pkg
return pkg
}
// doPkg reads a package definition from the bitstream.
func (r *reader) doPkg() *types.Pkg {
path := r.String()
switch path {
case "":
path = r.p.PkgPath()
case "builtin":
return types.BuiltinPkg
case "unsafe":
return types.UnsafePkg
name := r.String()
pkg := types.NewPkg(path, "")
if pkg.Name == "" {
pkg.Name = name
} else {
Matthew Dempsky
committed
base.Assertf(pkg.Name == name, "package %q has name %q, but want %q", pkg.Path, pkg.Name, name)
}
return pkg
}
// @@@ Types
func (r *reader) typ() *types.Type {
return r.typWrapped(true)
}
// typWrapped is like typ, but allows suppressing generation of
// unnecessary wrappers as a compile-time optimization.
func (r *reader) typWrapped(wrapped bool) *types.Type {
return r.p.typIdx(r.typInfo(), r.dict, wrapped)
Matthew Dempsky
committed
}
func (r *reader) typInfo() typeInfo {
r.Sync(pkgbits.SyncType)
if r.Bool() {
return typeInfo{idx: pkgbits.Index(r.Len()), derived: true}
}
return typeInfo{idx: r.Reloc(pkgbits.RelocType), derived: false}
func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict, wrapped bool) *types.Type {
Matthew Dempsky
committed
idx := info.idx
var where **types.Type
Matthew Dempsky
committed
if info.derived {
where = &dict.derivedTypes[idx]
idx = dict.derived[idx].idx
} else {
where = &pr.typs[idx]
}
if typ := *where; typ != nil {
return typ
}
r := pr.newReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx)
r.dict = dict
typ := r.doTyp()
assert(typ != nil)
Cuong Manh Le
committed
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
// For recursive type declarations involving interfaces and aliases,
// above r.doTyp() call may have already set pr.typs[idx], so just
// double check and return the type.
//
// Example:
//
// type F = func(I)
//
// type I interface {
// m(F)
// }
//
// The writer writes data types in following index order:
//
// 0: func(I)
// 1: I
// 2: interface{m(func(I))}
//
// The reader resolves it in following index order:
//
// 0 -> 1 -> 2 -> 0 -> 1
//
// and can divide in logically 2 steps:
//
// - 0 -> 1 : first time the reader reach type I,
// it creates new named type with symbol I.
//
// - 2 -> 0 -> 1: the reader ends up reaching symbol I again,
// now the symbol I was setup in above step, so
// the reader just return the named type.
//
// Now, the functions called return, the pr.typs looks like below:
//
// - 0 -> 1 -> 2 -> 0 : [<T> I <T>]
// - 0 -> 1 -> 2 : [func(I) I <T>]
// - 0 -> 1 : [func(I) I interface { "".m(func("".I)) }]
//
// The idx 1, corresponding with type I was resolved successfully
// after r.doTyp() call.
if prev := *where; prev != nil {
return prev
if wrapped {
// Only cache if we're adding wrappers, so that other callers that
// find a cached type know it was wrapped.
*where = typ
r.needWrapper(typ)
}
if !typ.IsUntyped() {
types.CheckSize(typ)
}
return typ
}
func (r *reader) doTyp() *types.Type {
switch tag := pkgbits.CodeType(r.Code(pkgbits.SyncType)); tag {
default:
panic(fmt.Sprintf("unexpected type: %v", tag))
case pkgbits.TypeBasic:
return *basics[r.Len()]
case pkgbits.TypeNamed:
obj := r.obj()
assert(obj.Op() == ir.OTYPE)
return obj.Type()
case pkgbits.TypeTypeParam:
return r.dict.targs[r.Len()]
case pkgbits.TypeArray:
len := int64(r.Uint64())
return types.NewArray(r.typ(), len)
case pkgbits.TypeChan:
dir := dirs[r.Len()]
return types.NewChan(r.typ(), dir)
case pkgbits.TypeMap:
return types.NewMap(r.typ(), r.typ())
case pkgbits.TypePointer:
return types.NewPtr(r.typ())
case pkgbits.TypeSignature:
return r.signature(types.LocalPkg, nil)
case pkgbits.TypeSlice:
return types.NewSlice(r.typ())
case pkgbits.TypeStruct:
return r.structType()
case pkgbits.TypeInterface:
return r.interfaceType()
case pkgbits.TypeUnion:
return r.unionType()
func (r *reader) unionType() *types.Type {
terms := make([]*types.Type, r.Len())
tildes := make([]bool, len(terms))
for i := range terms {
tildes[i] = r.Bool()
terms[i] = r.typ()
}
return types.NewUnion(terms, tildes)
}
func (r *reader) interfaceType() *types.Type {
tpkg := types.LocalPkg // TODO(mdempsky): Remove after iexport is gone.
nmethods, nembeddeds := r.Len(), r.Len()
implicit := nmethods == 0 && nembeddeds == 1 && r.Bool()
assert(!implicit) // implicit interfaces only appear in constraints
fields := make([]*types.Field, nmethods+nembeddeds)
methods, embeddeds := fields[:nmethods], fields[nmethods:]
for i := range methods {
pos := r.pos()
pkg, sym := r.selector()
tpkg = pkg
mtyp := r.signature(pkg, types.FakeRecv())
methods[i] = types.NewField(pos, sym, mtyp)
}
for i := range embeddeds {
embeddeds[i] = types.NewField(src.NoXPos, nil, r.typ())
}
if len(fields) == 0 {
return types.Types[types.TINTER] // empty interface
}
return types.NewInterface(tpkg, fields, false)
}
func (r *reader) structType() *types.Type {
tpkg := types.LocalPkg // TODO(mdempsky): Remove after iexport is gone.
fields := make([]*types.Field, r.Len())
for i := range fields {
pos := r.pos()
pkg, sym := r.selector()
tpkg = pkg
ftyp := r.typ()
tag := r.String()
embedded := r.Bool()
f := types.NewField(pos, sym, ftyp)
f.Note = tag
if embedded {
f.Embedded = 1
}
fields[i] = f
}
return types.NewStruct(tpkg, fields)
}
func (r *reader) signature(tpkg *types.Pkg, recv *types.Field) *types.Type {
r.Sync(pkgbits.SyncSignature)
params := r.params(&tpkg)
results := r.params(&tpkg)
if r.Bool() { // variadic
params[len(params)-1].SetIsDDD(true)
}
return types.NewSignature(tpkg, recv, nil, params, results)
}
func (r *reader) params(tpkg **types.Pkg) []*types.Field {
r.Sync(pkgbits.SyncParams)
fields := make([]*types.Field, r.Len())
for i := range fields {
*tpkg, fields[i] = r.param()
}
return fields
}
func (r *reader) param() (*types.Pkg, *types.Field) {
r.Sync(pkgbits.SyncParam)
pos := r.pos()
pkg, sym := r.localIdent()
typ := r.typ()
return pkg, types.NewField(pos, sym, typ)
}
// @@@ Objects
// objReader maps qualified identifiers (represented as *types.Sym) to
// a pkgReader and corresponding index that can be used for reading
// that object's definition.
var objReader = map[*types.Sym]pkgReaderIndex{}
// obj reads an instantiated object reference from the bitstream.
func (r *reader) obj() ir.Node {
r.Sync(pkgbits.SyncObject)
if r.Bool() {
idx := r.Len()
Matthew Dempsky
committed
obj := r.dict.funcsObj[idx]
if obj == nil {
fn := r.dict.funcs[idx]
targs := make([]*types.Type, len(fn.explicits))
for i, targ := range fn.explicits {
targs[i] = r.p.typIdx(targ, r.dict, true)
Matthew Dempsky
committed
}
obj = r.p.objIdx(fn.idx, nil, targs)
assert(r.dict.funcsObj[idx] == nil)
r.dict.funcsObj[idx] = obj
}
return obj
}
idx := r.Reloc(pkgbits.RelocObj)
explicits := make([]*types.Type, r.Len())
for i := range explicits {
explicits[i] = r.typ()
}
var implicits []*types.Type
if r.dict != nil {
implicits = r.dict.targs
}
return r.p.objIdx(idx, implicits, explicits)
// objIdx returns the specified object from the bitstream,
// instantiated with the given type arguments, if any.
func (pr *pkgReader) objIdx(idx pkgbits.Index, implicits, explicits []*types.Type) ir.Node {
rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
_, sym := rname.qualifiedIdent()
tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
if tag == pkgbits.ObjStub {
assert(!sym.IsBlank())
switch sym.Pkg {
case types.BuiltinPkg, types.UnsafePkg:
return sym.Def.(ir.Node)
}
if pri, ok := objReader[sym]; ok {
return pri.pr.objIdx(pri.idx, nil, explicits)
}
base.Fatalf("unresolved stub: %v", sym)
}
dict := pr.objDictIdx(sym, idx, implicits, explicits)
r := pr.newReader(pkgbits.RelocObj, idx, pkgbits.SyncObject1)
rext := pr.newReader(pkgbits.RelocObjExt, idx, pkgbits.SyncObject1)
r.dict = dict
rext.dict = dict
sym = r.mangle(sym)
if !sym.IsBlank() && sym.Def != nil {
return sym.Def.(*ir.Name)
}
do := func(op ir.Op, hasTParams bool) *ir.Name {
pos := r.pos()
Cuong Manh Le
committed
setBasePos(pos)
if hasTParams {
r.typeParamNames()
}
name := ir.NewDeclNameAt(pos, op, sym)
name.Class = ir.PEXTERN // may be overridden later
if !sym.IsBlank() {
if sym.Def != nil {
base.FatalfAt(name.Pos(), "already have a definition for %v", name)
}
assert(sym.Def == nil)
sym.Def = name
}
return name
}
switch tag {
default:
panic("unexpected object")
case pkgbits.ObjAlias:
name := do(ir.OTYPE, false)
setType(name, r.typ())
name.SetAlias(true)
return name
case pkgbits.ObjConst:
name := do(ir.OLITERAL, false)
val := FixValue(typ, r.Value())
setType(name, typ)
setValue(name, val)
case pkgbits.ObjFunc:
if sym.Name == "init" {
}
name := do(ir.ONAME, true)
setType(name, r.signature(sym.Pkg, nil))
name.Func = ir.NewFunc(r.pos())
name.Func.Nname = name
if r.hasTypeParams() {
name.Func.SetDupok(true)
}
rext.funcExt(name)
case pkgbits.ObjType:
name := do(ir.OTYPE, true)
typ := types.NewNamed(name)
setType(name, typ)
// Important: We need to do this before SetUnderlying.
rext.typeExt(name)
// We need to defer CheckSize until we've called SetUnderlying to
// handle recursive types.
types.DeferCheckSize()
typ.SetUnderlying(r.typWrapped(false))
types.ResumeCheckSize()
methods := make([]*types.Field, r.Len())
for i := range methods {
methods[i] = r.method(rext)
}
if len(methods) != 0 {
typ.Methods().Set(methods)
}
r.needWrapper(typ)
case pkgbits.ObjVar:
name := do(ir.ONAME, false)
setType(name, r.typ())
rext.varExt(name)
return name
}
}
func (r *reader) mangle(sym *types.Sym) *types.Sym {
Cuong Manh Le
committed
if !r.hasTypeParams() {
return sym
}
var buf bytes.Buffer
buf.WriteString(sym.Name)
buf.WriteByte('[')
for i, targ := range r.dict.targs {
if i > 0 {
if i == r.dict.implicits {
buf.WriteByte(';')
} else {
buf.WriteByte(',')
}
}
buf.WriteString(targ.LinkString())
}
buf.WriteByte(']')
return sym.Pkg.Lookup(buf.String())
}
// objDictIdx reads and returns the specified object dictionary.
func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, explicits []*types.Type) *readerDict {
r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
var dict readerDict
nimplicits := r.Len()
nexplicits := r.Len()
if nimplicits > len(implicits) || nexplicits != len(explicits) {
base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits))
dict.targs = append(implicits[:nimplicits:nimplicits], explicits...)
dict.implicits = nimplicits
// For stenciling, we can just skip over the type parameters.
for range dict.targs[dict.implicits:] {
// Skip past bounds without actually evaluating them.
r.typInfo()
dict.derived = make([]derivedInfo, r.Len())
dict.derivedTypes = make([]*types.Type, len(dict.derived))
for i := range dict.derived {
dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()}
}
dict.funcs = make([]objInfo, r.Len())
dict.funcsObj = make([]ir.Node, len(dict.funcs))
for i := range dict.funcs {
objIdx := r.Reloc(pkgbits.RelocObj)
targs := make([]typeInfo, r.Len())
for j := range targs {
targs[j] = r.typInfo()
}
dict.funcs[i] = objInfo{idx: objIdx, explicits: targs}
}
dict.itabs = make([]itabInfo2, r.Len())
for i := range dict.itabs {
typ := pr.typIdx(typeInfo{idx: pkgbits.Index(r.Len()), derived: true}, &dict, true)
ifaceInfo := r.typInfo()
var lsym *obj.LSym
if typ.IsInterface() {
lsym = reflectdata.TypeLinksym(typ)
} else {
iface := pr.typIdx(ifaceInfo, &dict, true)
lsym = reflectdata.ITabLsym(typ, iface)
}
dict.itabs[i] = itabInfo2{typ: typ, lsym: lsym}
}
dict.methodExprs = make([]ir.Node, r.Len())
for i := range dict.methodExprs {
recv := pr.typIdx(typeInfo{idx: pkgbits.Index(r.Len()), derived: true}, &dict, true)
_, sym := r.selector()
dict.methodExprs[i] = typecheck.Expr(ir.NewSelectorExpr(src.NoXPos, ir.OXDOT, ir.TypeNode(recv), sym))
}
return &dict
}
func (r *reader) typeParamNames() {
r.Sync(pkgbits.SyncTypeParamNames)
for range r.dict.targs[r.dict.implicits:] {
r.pos()
r.localIdent()
}
}
func (r *reader) method(rext *reader) *types.Field {
r.Sync(pkgbits.SyncMethod)
pos := r.pos()
pkg, sym := r.selector()
r.typeParamNames()
_, recv := r.param()
typ := r.signature(pkg, recv)
name := ir.NewNameAt(pos, ir.MethodSym(recv.Type, sym))
setType(name, typ)
name.Func = ir.NewFunc(r.pos())
name.Func.Nname = name
if r.hasTypeParams() {
name.Func.SetDupok(true)
}
rext.funcExt(name)
meth := types.NewField(name.Func.Pos(), sym, typ)
meth.Nname = name
meth.SetNointerface(name.Func.Pragma&ir.Nointerface != 0)
return meth
}
func (r *reader) qualifiedIdent() (pkg *types.Pkg, sym *types.Sym) {
r.Sync(pkgbits.SyncSym)
if name := r.String(); name != "" {
sym = pkg.Lookup(name)
}
return
}
func (r *reader) localIdent() (pkg *types.Pkg, sym *types.Sym) {
r.Sync(pkgbits.SyncLocalIdent)
if name := r.String(); name != "" {
sym = pkg.Lookup(name)
}
return
}
func (r *reader) selector() (origPkg *types.Pkg, sym *types.Sym) {
r.Sync(pkgbits.SyncSelector)
origPkg = r.pkg()
name := r.String()
pkg := origPkg
if types.IsExported(name) {
pkg = types.LocalPkg
}
sym = pkg.Lookup(name)
return
}
Cuong Manh Le
committed
func (r *reader) hasTypeParams() bool {
return r.dict.hasTypeParams()
}
func (dict *readerDict) hasTypeParams() bool {
return dict != nil && len(dict.targs) != 0
Cuong Manh Le
committed
}
// @@@ Compiler extensions
func (r *reader) funcExt(name *ir.Name) {
r.Sync(pkgbits.SyncFuncExt)
name.Class = 0 // so MarkFunc doesn't complain
ir.MarkFunc(name)
fn := name.Func
// XXX: Workaround because linker doesn't know how to copy Pos.
if !fn.Pos().IsKnown() {
fn.SetPos(name.Pos())
}
// Normally, we only compile local functions, which saves redundant compilation work.
// n.Defn is not nil for local functions, and is nil for imported function. But for
// generic functions, we might have an instantiation that no other package has seen before.
// So we need to be conservative and compile it again.
//
// That's why name.Defn is set here, so ir.VisitFuncsBottomUp can analyze function.
// TODO(mdempsky,cuonglm): find a cleaner way to handle this.
Cuong Manh Le
committed
if name.Sym().Pkg == types.LocalPkg || r.hasTypeParams() {
name.Defn = fn
}
fn.Pragma = r.pragmaFlag()
r.linkname(name)
Matthew Dempsky
committed
typecheck.Func(fn)
assert(name.Defn == nil)
fn.ABI = obj.ABI(r.Uint64())
// Escape analysis.
for _, fs := range &types.RecvsParams {
for _, f := range fs(name.Type()).FieldSlice() {
f.Note = r.String()
fn.Inl = &ir.Inline{
Cost: int32(r.Len()),
CanDelayResults: r.Bool(),
}
}
} else {
r.addBody(name.Func)
r.Sync(pkgbits.SyncEOF)
}
func (r *reader) typeExt(name *ir.Name) {
r.Sync(pkgbits.SyncTypeExt)
typ := name.Type()
Cuong Manh Le
committed
if r.hasTypeParams() {
// Set "RParams" (really type arguments here, not parameters) so
// this type is treated as "fully instantiated". This ensures the
// type descriptor is written out as DUPOK and method wrappers are
// generated even for imported types.
var targs []*types.Type
targs = append(targs, r.dict.targs...)
typ.SetRParams(targs)
}
name.SetPragma(r.pragmaFlag())
if name.Pragma()&ir.NotInHeap != 0 {
typ.SetNotInHeap(true)
}
typecheck.SetBaseTypeIndex(typ, r.Int64(), r.Int64())
}
func (r *reader) varExt(name *ir.Name) {
r.Sync(pkgbits.SyncVarExt)
r.linkname(name)
}
func (r *reader) linkname(name *ir.Name) {
assert(name.Op() == ir.ONAME)
r.Sync(pkgbits.SyncLinkname)
if idx := r.Int64(); idx >= 0 {
lsym := name.Linksym()
lsym.SymIdx = int32(idx)
lsym.Set(obj.AttrIndexed, true)
} else {
name.Sym().Linkname = r.String()
}
}
func (r *reader) pragmaFlag() ir.PragmaFlag {
r.Sync(pkgbits.SyncPragma)
return ir.PragmaFlag(r.Int())
}
// @@@ Function bodies
// bodyReader tracks where the serialized IR for a local or imported,
// generic function's body can be found.
var bodyReader = map[*ir.Func]pkgReaderIndex{}
// importBodyReader tracks where the serialized IR for an imported,
// static (i.e., non-generic) function body can be read.
var importBodyReader = map[*types.Sym]pkgReaderIndex{}
// bodyReaderFor returns the pkgReaderIndex for reading fn's
// serialized IR, and whether one was found.
func bodyReaderFor(fn *ir.Func) (pri pkgReaderIndex, ok bool) {
if fn.Nname.Defn != nil {
pri, ok = bodyReader[fn]
base.AssertfAt(ok, base.Pos, "must have bodyReader for %v", fn) // must always be available
} else {
pri, ok = importBodyReader[fn.Sym()]
}
return
}
// todoBodies holds the list of function bodies that still need to be
// constructed.