[dev.typeparams] cmd/compile: cleanup unified IR file format a little

This CL makes two changes:

1. It moves object symbols and code tags into a new "relocName"
relocation, which should eventually allow getting rid of objStub.

2. It moves the type parameter data into the relocObjDict relocation,
so everything related to writing out dictionaries is contained there.

Change-Id: If0f7ff7d9384e8664957c3180bf6f20e97bcff6e
Reviewed-on: https://go-review.googlesource.com/c/go/+/336051
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Matthew Dempsky 2021-07-20 16:52:37 -07:00
parent d5f6ba943c
commit 897970688b
7 changed files with 124 additions and 116 deletions

View file

@ -110,7 +110,7 @@ func (l *linker) relocPkg(pr *pkgReader, idx int) int {
} }
func (l *linker) relocObj(pr *pkgReader, idx int) int { func (l *linker) relocObj(pr *pkgReader, idx int) int {
path, name, tag, _ := pr.peekObj(idx) path, name, tag := pr.peekObj(idx)
sym := types.NewPkg(path, "").Lookup(name) sym := types.NewPkg(path, "").Lookup(name)
if newidx, ok := l.decls[sym]; ok { if newidx, ok := l.decls[sym]; ok {
@ -127,7 +127,7 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int {
pr = pri.pr pr = pri.pr
idx = pri.idx idx = pri.idx
path2, name2, tag2, _ := pr.peekObj(idx) path2, name2, tag2 := pr.peekObj(idx)
sym2 := types.NewPkg(path2, "").Lookup(name2) sym2 := types.NewPkg(path2, "").Lookup(name2)
assert(sym == sym2) assert(sym == sym2)
assert(tag2 != objStub) assert(tag2 != objStub)
@ -135,13 +135,16 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int {
w := l.pw.newEncoderRaw(relocObj) w := l.pw.newEncoderRaw(relocObj)
wext := l.pw.newEncoderRaw(relocObjExt) wext := l.pw.newEncoderRaw(relocObjExt)
wname := l.pw.newEncoderRaw(relocName)
wdict := l.pw.newEncoderRaw(relocObjDict) wdict := l.pw.newEncoderRaw(relocObjDict)
l.decls[sym] = w.idx l.decls[sym] = w.idx
assert(wext.idx == w.idx) assert(wext.idx == w.idx)
assert(wname.idx == w.idx)
assert(wdict.idx == w.idx) assert(wdict.idx == w.idx)
l.relocCommon(pr, &w, relocObj, idx) l.relocCommon(pr, &w, relocObj, idx)
l.relocCommon(pr, &wname, relocName, idx)
l.relocCommon(pr, &wdict, relocObjDict, idx) l.relocCommon(pr, &wdict, relocObjDict, idx)
var obj *ir.Name var obj *ir.Name
@ -279,33 +282,15 @@ func (pr *pkgDecoder) peekPkgPath(idx int) string {
return path return path
} }
func (pr *pkgDecoder) peekObj(idx int) (string, string, codeObj, []int) { func (pr *pkgDecoder) peekObj(idx int) (string, string, codeObj) {
r := pr.newDecoder(relocObj, idx, syncObject1) r := pr.newDecoder(relocName, idx, syncObject1)
r.sync(syncSym) r.sync(syncSym)
r.sync(syncPkg) r.sync(syncPkg)
path := pr.peekPkgPath(r.reloc(relocPkg)) path := pr.peekPkgPath(r.reloc(relocPkg))
name := r.string() name := r.string()
assert(name != "") assert(name != "")
r.sync(syncTypeParamBounds)
r.len() // implicits
bounds := make([]int, r.len())
for i := range bounds {
r.sync(syncType)
if r.bool() {
r.len()
} else {
r.reloc(relocType)
}
// TODO(mdempsky): This result now needs to include the 'derived'
// bool too, but none of the callers currently depend on it
// anyway. Either fix it to be meaningful, or just get rid of it
// altogether.
bounds[i] = -1
}
tag := codeObj(r.code(syncCodeObj)) tag := codeObj(r.code(syncCodeObj))
return path, name, tag, bounds return path, name, tag
} }

View file

@ -534,18 +534,10 @@ func (r *reader) obj() ir.Node {
} }
func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node { func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node {
r := pr.newReader(relocObj, idx, syncObject1) rname := pr.newReader(relocName, idx, syncObject1)
r.ext = pr.newReader(relocObjExt, idx, syncObject1) _, sym := rname.qualifiedIdent()
tag := codeObj(rname.code(syncCodeObj))
_, sym := r.qualifiedIdent()
dict := &readerDict{}
r.dict = dict
r.ext.dict = dict
r.typeParamBounds(sym, implicits, explicits)
tag := codeObj(r.code(syncCodeObj))
if tag == objStub { if tag == objStub {
assert(!sym.IsBlank()) assert(!sym.IsBlank())
switch sym.Pkg { switch sym.Pkg {
@ -556,30 +548,19 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
return pri.pr.objIdx(pri.idx, nil, explicits) return pri.pr.objIdx(pri.idx, nil, explicits)
} }
if haveLegacyImports { if haveLegacyImports {
assert(!r.hasTypeParams()) assert(len(explicits) == 0)
return typecheck.Resolve(ir.NewIdent(src.NoXPos, sym)) return typecheck.Resolve(ir.NewIdent(src.NoXPos, sym))
} }
base.Fatalf("unresolved stub: %v", sym) base.Fatalf("unresolved stub: %v", sym)
} }
{ dict := pr.objDictIdx(sym, idx, implicits, explicits)
rdict := pr.newReader(relocObjDict, idx, syncObject1)
r.dict.derived = make([]derivedInfo, rdict.len()) r := pr.newReader(relocObj, idx, syncObject1)
r.dict.derivedTypes = make([]*types.Type, len(r.dict.derived)) r.ext = pr.newReader(relocObjExt, idx, syncObject1)
for i := range r.dict.derived {
r.dict.derived[i] = derivedInfo{rdict.reloc(relocType), rdict.bool()} r.dict = dict
} r.ext.dict = dict
r.dict.funcs = make([]objInfo, rdict.len())
r.dict.funcsObj = make([]ir.Node, len(r.dict.funcs))
for i := range r.dict.funcs {
objIdx := rdict.reloc(relocObj)
targs := make([]typeInfo, rdict.len())
for j := range targs {
targs[j] = rdict.typInfo()
}
r.dict.funcs[i] = objInfo{idx: objIdx, explicits: targs}
}
}
sym = r.mangle(sym) sym = r.mangle(sym)
if !sym.IsBlank() && sym.Def != nil { if !sym.IsBlank() && sym.Def != nil {
@ -692,8 +673,10 @@ func (r *reader) mangle(sym *types.Sym) *types.Sym {
return sym.Pkg.Lookup(buf.String()) return sym.Pkg.Lookup(buf.String())
} }
func (r *reader) typeParamBounds(sym *types.Sym, implicits, explicits []*types.Type) { func (pr *pkgReader) objDictIdx(sym *types.Sym, idx int, implicits, explicits []*types.Type) *readerDict {
r.sync(syncTypeParamBounds) r := pr.newReader(relocObjDict, idx, syncObject1)
var dict readerDict
nimplicits := r.len() nimplicits := r.len()
nexplicits := r.len() nexplicits := r.len()
@ -702,12 +685,11 @@ func (r *reader) typeParamBounds(sym *types.Sym, implicits, explicits []*types.T
base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits)) base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits))
} }
r.dict.targs = append(implicits[:nimplicits:nimplicits], explicits...) dict.targs = append(implicits[:nimplicits:nimplicits], explicits...)
r.dict.implicits = nimplicits dict.implicits = nimplicits
// For stenciling, we can just skip over the type parameters. // For stenciling, we can just skip over the type parameters.
for range dict.targs[dict.implicits:] {
for range r.dict.targs[r.dict.implicits:] {
// Skip past bounds without actually evaluating them. // Skip past bounds without actually evaluating them.
r.sync(syncType) r.sync(syncType)
if r.bool() { if r.bool() {
@ -716,6 +698,25 @@ func (r *reader) typeParamBounds(sym *types.Sym, implicits, explicits []*types.T
r.reloc(relocType) r.reloc(relocType)
} }
} }
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(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(relocObj)
targs := make([]typeInfo, r.len())
for j := range targs {
targs[j] = r.typInfo()
}
dict.funcs[i] = objInfo{idx: objIdx, explicits: targs}
}
return &dict
} }
func (r *reader) typeParamNames() { func (r *reader) typeParamNames() {
@ -790,7 +791,11 @@ func (r *reader) selector() (origPkg *types.Pkg, sym *types.Sym) {
} }
func (r *reader) hasTypeParams() bool { func (r *reader) hasTypeParams() bool {
return r.dict != nil && len(r.dict.targs) != 0 return r.dict.hasTypeParams()
}
func (dict *readerDict) hasTypeParams() bool {
return dict != nil && len(dict.targs) != 0
} }
// @@@ Compiler extensions // @@@ Compiler extensions

View file

@ -358,29 +358,22 @@ func (r *reader2) obj() (types2.Object, []types2.Type) {
} }
func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) { func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
r := pr.newReader(relocObj, idx, syncObject1) rname := pr.newReader(relocName, idx, syncObject1)
r.dict = &reader2Dict{}
objPkg, objName := r.qualifiedIdent() objPkg, objName := rname.qualifiedIdent()
assert(objName != "") assert(objName != "")
r.typeParamBounds() tag := codeObj(rname.code(syncCodeObj))
tag := codeObj(r.code(syncCodeObj))
if tag == objStub { if tag == objStub {
assert(objPkg == nil) assert(objPkg == nil)
return objPkg, objName return objPkg, objName
} }
{ dict := pr.objDictIdx(idx)
rdict := r.p.newReader(relocObjDict, idx, syncObject1)
r.dict.derived = make([]derivedInfo, rdict.len()) r := pr.newReader(relocObj, idx, syncObject1)
r.dict.derivedTypes = make([]types2.Type, len(r.dict.derived)) r.dict = dict
for i := range r.dict.derived {
r.dict.derived[i] = derivedInfo{rdict.reloc(relocType), rdict.bool()}
}
// function references follow, but reader2 doesn't need those
}
objPkg.Scope().InsertLazy(objName, func() types2.Object { objPkg.Scope().InsertLazy(objName, func() types2.Object {
switch tag { switch tag {
@ -439,17 +432,29 @@ func (r *reader2) value() (types2.Type, constant.Value) {
return r.typ(), r.rawValue() return r.typ(), r.rawValue()
} }
func (r *reader2) typeParamBounds() { func (pr *pkgReader2) objDictIdx(idx int) *reader2Dict {
r.sync(syncTypeParamBounds) r := pr.newReader(relocObjDict, idx, syncObject1)
var dict reader2Dict
if implicits := r.len(); implicits != 0 { if implicits := r.len(); implicits != 0 {
base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits) base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits)
} }
r.dict.bounds = make([]typeInfo, r.len()) dict.bounds = make([]typeInfo, r.len())
for i := range r.dict.bounds { for i := range dict.bounds {
r.dict.bounds[i] = r.typInfo() dict.bounds[i] = r.typInfo()
} }
dict.derived = make([]derivedInfo, r.len())
dict.derivedTypes = make([]types2.Type, len(dict.derived))
for i := range dict.derived {
dict.derived[i] = derivedInfo{r.reloc(relocType), r.bool()}
}
// function references follow, but reader2 doesn't need those
return &dict
} }
func (r *reader2) typeParamNames() []*types2.TypeName { func (r *reader2) typeParamNames() []*types2.TypeName {

View file

@ -31,6 +31,7 @@ const (
relocMeta relocMeta
relocPosBase relocPosBase
relocPkg relocPkg
relocName
relocType relocType
relocObj relocObj
relocObjExt relocObjExt

View file

@ -183,4 +183,5 @@ const (
syncTypeParamNames syncTypeParamNames
syncTypeParamBounds syncTypeParamBounds
syncImplicitTypes syncImplicitTypes
syncObjectName
) )

View file

@ -263,7 +263,7 @@ func readPackage(pr *pkgReader, importpkg *types.Pkg) {
idx := r.reloc(relocObj) idx := r.reloc(relocObj)
assert(r.len() == 0) assert(r.len() == 0)
path, name, code, _ := r.p.peekObj(idx) path, name, code := r.p.peekObj(idx)
if code != objStub { if code != objStub {
objReader[types.NewPkg(path, "").Lookup(name)] = pkgReaderIndex{pr, idx, nil} objReader[types.NewPkg(path, "").Lookup(name)] = pkgReaderIndex{pr, idx, nil}
} }
@ -298,7 +298,7 @@ func writeNewExport(out io.Writer) {
idx := r.reloc(relocObj) idx := r.reloc(relocObj)
assert(r.len() == 0) assert(r.len() == 0)
xpath, xname, xtag, _ := pr.peekObj(idx) xpath, xname, xtag := pr.peekObj(idx)
assert(xpath == pr.pkgPath) assert(xpath == pr.pkgPath)
assert(xtag != objStub) assert(xtag != objStub)

View file

@ -505,60 +505,45 @@ func (pw *pkgWriter) objIdx(obj types2.Object) int {
w := pw.newWriter(relocObj, syncObject1) w := pw.newWriter(relocObj, syncObject1)
w.ext = pw.newWriter(relocObjExt, syncObject1) w.ext = pw.newWriter(relocObjExt, syncObject1)
wname := pw.newWriter(relocName, syncObject1)
wdict := pw.newWriter(relocObjDict, syncObject1) wdict := pw.newWriter(relocObjDict, syncObject1)
pw.globalsIdx[obj] = w.idx // break cycles pw.globalsIdx[obj] = w.idx // break cycles
assert(w.ext.idx == w.idx) assert(w.ext.idx == w.idx)
assert(wname.idx == w.idx)
assert(wdict.idx == w.idx) assert(wdict.idx == w.idx)
w.dict = dict w.dict = dict
w.ext.dict = dict w.ext.dict = dict
// Ident goes first so importer can avoid unnecessary work if code := w.doObj(obj)
// they've already resolved this object.
w.qualifiedIdent(obj)
w.typeParamBounds(objTypeParams(obj))
w.doObj(obj)
w.flush() w.flush()
w.ext.flush() w.ext.flush()
// Done writing out the object description; write out the list of wname.qualifiedIdent(obj)
// derived types and instantiated functions found along the way. wname.code(code)
wdict.len(len(dict.derived)) wname.flush()
for _, typ := range dict.derived {
wdict.reloc(relocType, typ.idx) wdict.objDict(obj, w.dict)
wdict.bool(typ.needed)
}
wdict.len(len(dict.funcs))
for _, fn := range dict.funcs {
wdict.reloc(relocObj, fn.idx)
wdict.len(len(fn.explicits))
for _, targ := range fn.explicits {
wdict.typInfo(targ)
}
}
wdict.flush() wdict.flush()
return w.idx return w.idx
} }
func (w *writer) doObj(obj types2.Object) { func (w *writer) doObj(obj types2.Object) codeObj {
if obj.Pkg() != w.p.curpkg { if obj.Pkg() != w.p.curpkg {
w.code(objStub) return objStub
return
} }
switch obj := obj.(type) { switch obj := obj.(type) {
default: default:
w.p.unexpected("object", obj) w.p.unexpected("object", obj)
panic("unreachable")
case *types2.Const: case *types2.Const:
w.code(objConst)
w.pos(obj) w.pos(obj)
w.value(obj.Type(), obj.Val()) w.value(obj.Type(), obj.Val())
return objConst
case *types2.Func: case *types2.Func:
decl, ok := w.p.funDecls[obj] decl, ok := w.p.funDecls[obj]
@ -584,28 +569,26 @@ func (w *writer) doObj(obj types2.Object) {
sig = types2.NewSignature(nil, types2.NewTuple(params...), sig.Results(), sig.Variadic()) sig = types2.NewSignature(nil, types2.NewTuple(params...), sig.Results(), sig.Variadic())
} }
w.code(objFunc)
w.pos(obj) w.pos(obj)
w.typeParamNames(sig.TParams()) w.typeParamNames(sig.TParams())
w.signature(sig) w.signature(sig)
w.pos(decl) w.pos(decl)
w.ext.funcExt(obj) w.ext.funcExt(obj)
return objFunc
case *types2.TypeName: case *types2.TypeName:
decl, ok := w.p.typDecls[obj] decl, ok := w.p.typDecls[obj]
assert(ok) assert(ok)
if obj.IsAlias() { if obj.IsAlias() {
w.code(objAlias)
w.pos(obj) w.pos(obj)
w.typ(obj.Type()) w.typ(obj.Type())
break return objAlias
} }
named := obj.Type().(*types2.Named) named := obj.Type().(*types2.Named)
assert(named.TArgs() == nil) assert(named.TArgs() == nil)
w.code(objType)
w.pos(obj) w.pos(obj)
w.typeParamNames(named.TParams()) w.typeParamNames(named.TParams())
w.ext.typeExt(obj) w.ext.typeExt(obj)
@ -616,11 +599,13 @@ func (w *writer) doObj(obj types2.Object) {
w.method(named.Method(i)) w.method(named.Method(i))
} }
return objType
case *types2.Var: case *types2.Var:
w.code(objVar)
w.pos(obj) w.pos(obj)
w.typ(obj.Type()) w.typ(obj.Type())
w.ext.varExt(obj) w.ext.varExt(obj)
return objVar
} }
} }
@ -638,15 +623,41 @@ func (w *writer) value(typ types2.Type, val constant.Value) {
w.rawValue(val) w.rawValue(val)
} }
func (w *writer) typeParamBounds(tparams []*types2.TypeName) { // objDict writes the dictionary needed for reading the given object.
w.sync(syncTypeParamBounds) func (w *writer) objDict(obj types2.Object, dict *writerDict) {
// TODO(mdempsky): Split objDict into multiple entries? reader.go
// doesn't care about the type parameter bounds, and reader2.go
// doesn't care about referenced functions.
w.len(len(w.dict.implicits)) w.dict = dict // TODO(mdempsky): This is a bit sketchy.
w.len(len(dict.implicits))
tparams := objTypeParams(obj)
w.len(len(tparams)) w.len(len(tparams))
for _, tparam := range tparams { for _, tparam := range tparams {
w.typ(tparam.Type().(*types2.TypeParam).Bound()) w.typ(tparam.Type().(*types2.TypeParam).Bound())
} }
nderived := len(dict.derived)
w.len(nderived)
for _, typ := range dict.derived {
w.reloc(relocType, typ.idx)
w.bool(typ.needed)
}
nfuncs := len(dict.funcs)
w.len(nfuncs)
for _, fn := range dict.funcs {
w.reloc(relocObj, fn.idx)
w.len(len(fn.explicits))
for _, targ := range fn.explicits {
w.typInfo(targ)
}
}
assert(len(dict.derived) == nderived)
assert(len(dict.funcs) == nfuncs)
} }
func (w *writer) typeParamNames(tparams []*types2.TypeName) { func (w *writer) typeParamNames(tparams []*types2.TypeName) {