1
0
mirror of https://github.com/golang/go synced 2024-11-17 04:24:47 -07:00

cmd/compile/internal/noder: explicitly handle function instantiations

This CL changes unified IR to explicitly handle function
instantiations within expression handling, rather than leaving it to
the underlying object reading logic.

Change-Id: I009a56013fbe9fbc4dabf80eea98993d34af4272
Reviewed-on: https://go-review.googlesource.com/c/go/+/421817
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Matthew Dempsky 2022-08-05 20:29:51 -07:00
parent 6b80b62fd1
commit 2e6ffd6c5d
4 changed files with 67 additions and 46 deletions

View File

@ -54,6 +54,7 @@ const (
exprNew
exprMake
exprNil
exprFuncInst
)
type codeAssign int

View File

@ -558,24 +558,7 @@ 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()
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)
}
obj = r.p.objIdx(fn.idx, nil, targs)
assert(r.dict.funcsObj[idx] == nil)
r.dict.funcsObj[idx] = obj
}
return obj
}
assert(!r.Bool()) // TODO(mdempsky): Remove; was derived func inst.
idx := r.Reloc(pkgbits.RelocObj)
explicits := make([]*types.Type, r.Len())
@ -1860,6 +1843,25 @@ func (r *reader) expr() (res ir.Node) {
// TODO(mdempsky): Handle builtins directly in exprCall, like method calls?
return typecheck.Callee(r.obj())
case exprFuncInst:
if r.Bool() {
idx := r.Len()
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)
}
obj = r.p.objIdx(fn.idx, nil, targs)
assert(r.dict.funcsObj[idx] == nil)
r.dict.funcsObj[idx] = obj
}
return obj
}
return r.obj()
case exprConst:
pos := r.pos()
typ := r.typ()

View File

@ -591,34 +591,14 @@ func (w *writer) param(param *types2.Var) {
// arguments used to instantiate it (i.e., used to substitute the
// object's own declared type parameters).
func (w *writer) obj(obj types2.Object, explicits *types2.TypeList) {
explicitInfos := make([]typeInfo, explicits.Len())
for i := range explicitInfos {
explicitInfos[i] = w.p.typIdx(explicits.At(i), w.dict)
}
info := objInfo{idx: w.p.objIdx(obj), explicits: explicitInfos}
if _, ok := obj.(*types2.Func); ok && info.anyDerived() {
idx := -1
for i, prev := range w.dict.funcs {
if prev.equals(info) {
idx = i
}
}
if idx < 0 {
idx = len(w.dict.funcs)
w.dict.funcs = append(w.dict.funcs, info)
}
// TODO(mdempsky): Push up into expr; this shouldn't appear
// outside of expression context.
w.Sync(pkgbits.SyncObject)
w.Bool(true)
w.Len(idx)
return
}
w.objInfo(w.p.objInstIdx(obj, explicits, w.dict))
}
// objInfo writes a use of the given encoded object into the
// bitstream.
func (w *writer) objInfo(info objInfo) {
w.Sync(pkgbits.SyncObject)
w.Bool(false)
w.Bool(false) // TODO(mdempsky): Remove; was derived func inst.
w.Reloc(pkgbits.RelocObj, info.idx)
w.Len(len(info.explicits))
@ -627,6 +607,17 @@ func (w *writer) obj(obj types2.Object, explicits *types2.TypeList) {
}
}
// objInstIdx returns the indices for an object and a corresponding
// list of type arguments used to instantiate it, adding them to the
// export data as needed.
func (pw *pkgWriter) objInstIdx(obj types2.Object, explicits *types2.TypeList, dict *writerDict) objInfo {
explicitInfos := make([]typeInfo, explicits.Len())
for i := range explicitInfos {
explicitInfos[i] = pw.typIdx(explicits.At(i), dict)
}
return objInfo{idx: pw.objIdx(obj), explicits: explicitInfos}
}
// objIdx returns the index for the given Object, adding it to the
// export data as needed.
func (pw *pkgWriter) objIdx(obj types2.Object) pkgbits.Index {
@ -1551,15 +1542,27 @@ func (w *writer) expr(expr syntax.Expr) {
}
if obj != nil {
if targs.Len() != 0 {
obj := obj.(*types2.Func)
info := w.p.objInstIdx(obj, targs, w.dict)
w.Code(exprFuncInst)
if w.Bool(info.anyDerived()) {
w.Len(w.dict.funcIdx(info))
return
}
w.objInfo(info)
return
}
if isGlobal(obj) {
w.Code(exprGlobal)
w.obj(obj, targs)
w.obj(obj, nil)
return
}
obj := obj.(*types2.Var)
assert(!obj.IsField())
assert(targs.Len() == 0)
w.Code(exprLocal)
w.useLocal(expr.Pos(), obj)
@ -1782,6 +1785,20 @@ func sliceElem(typ types2.Type) types2.Type {
return types2.CoreType(typ).(*types2.Slice).Elem()
}
// funcIdx returns the index of a given encoded function instantiation
// within the dictionary, adding it if not already present.
func (dict *writerDict) funcIdx(newInfo objInfo) int {
for idx, oldInfo := range dict.funcs {
if oldInfo.equals(newInfo) {
return idx
}
}
idx := len(dict.funcs)
dict.funcs = append(dict.funcs, newInfo)
return idx
}
func (w *writer) optExpr(expr syntax.Expr) {
if w.Bool(expr != nil) {
w.expr(expr)

View File

@ -23,6 +23,7 @@ import (
//
// TODO(mdempsky): For the next version bump:
// - remove the legacy "has init" bool from the public root
// - remove obj's "derived func instance" bool
const currentVersion uint32 = 1
// A PkgEncoder provides methods for encoding a package's Unified IR