mirror of
https://github.com/golang/go
synced 2024-11-11 19:01:37 -07:00
cmd/compile: add itabs to unified IR dictionaries
This CL changes unified IR to include itabs in its serialized dictionary format. Change-Id: I334c972dc1bc19293f955bb23cfb66844da7adec Reviewed-on: https://go-review.googlesource.com/c/go/+/390355 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
parent
d168c4f296
commit
ac3ba97907
@ -147,6 +147,13 @@ type readerDict struct {
|
||||
|
||||
funcs []objInfo
|
||||
funcsObj []ir.Node
|
||||
|
||||
itabs []itabInfo2
|
||||
}
|
||||
|
||||
type itabInfo2 struct {
|
||||
typ *types.Type
|
||||
lsym *obj.LSym
|
||||
}
|
||||
|
||||
func setType(n ir.Node, typ *types.Type) {
|
||||
@ -745,6 +752,22 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx int, implicits, explicits []
|
||||
dict.funcs[i] = objInfo{idx: objIdx, explicits: targs}
|
||||
}
|
||||
|
||||
dict.itabs = make([]itabInfo2, r.Len())
|
||||
for i := range dict.itabs {
|
||||
typ := pr.typIdx(typeInfo{idx: 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}
|
||||
}
|
||||
|
||||
return &dict
|
||||
}
|
||||
|
||||
@ -1438,7 +1461,7 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node {
|
||||
cases = nil // TODO(mdempsky): Unclear if this matters.
|
||||
}
|
||||
for i := range cases {
|
||||
cases[i] = r.exprType(iface, true)
|
||||
cases[i] = r.exprType(true)
|
||||
}
|
||||
} else {
|
||||
cases = r.exprList()
|
||||
@ -1538,7 +1561,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
return typecheck.Callee(r.obj())
|
||||
|
||||
case exprType:
|
||||
return r.exprType(nil, false)
|
||||
return r.exprType(false)
|
||||
|
||||
case exprConst:
|
||||
pos := r.pos()
|
||||
@ -1603,7 +1626,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
case exprAssert:
|
||||
x := r.expr()
|
||||
pos := r.pos()
|
||||
typ := r.exprType(x.Type(), false)
|
||||
typ := r.exprType(false)
|
||||
|
||||
if typ, ok := typ.(*ir.DynamicType); ok && typ.Op() == ir.ODYNAMICTYPE {
|
||||
return typed(typ.Type(), ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, x, typ.X))
|
||||
@ -1753,11 +1776,7 @@ func (r *reader) exprs() []ir.Node {
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (r *reader) exprType(iface *types.Type, nilOK bool) ir.Node {
|
||||
if iface != nil {
|
||||
base.Assertf(iface.IsInterface(), "%L must be an interface type", iface)
|
||||
}
|
||||
|
||||
func (r *reader) exprType(nilOK bool) ir.Node {
|
||||
r.Sync(pkgbits.SyncExprType)
|
||||
|
||||
if nilOK && r.Bool() {
|
||||
@ -1765,30 +1784,29 @@ func (r *reader) exprType(iface *types.Type, nilOK bool) ir.Node {
|
||||
}
|
||||
|
||||
pos := r.pos()
|
||||
info := r.typInfo()
|
||||
typ := r.p.typIdx(info, r.dict, true)
|
||||
|
||||
if info.derived {
|
||||
// TODO(mdempsky): Handle with runtime dictionary lookup.
|
||||
var typ *types.Type
|
||||
var lsym *obj.LSym
|
||||
|
||||
var lsym *obj.LSym
|
||||
if r.Bool() {
|
||||
itab := r.dict.itabs[r.Len()]
|
||||
typ, lsym = itab.typ, itab.lsym
|
||||
} else {
|
||||
info := r.typInfo()
|
||||
typ = r.p.typIdx(info, r.dict, true)
|
||||
|
||||
// For assertions from non-empty interfaces to non-interfaces,
|
||||
// we need the ITab instead.
|
||||
if iface != nil && !iface.IsEmptyInterface() && !typ.IsInterface() {
|
||||
lsym = reflectdata.ITabLsym(typ, iface)
|
||||
} else {
|
||||
lsym = reflectdata.TypeLinksym(typ)
|
||||
if !info.derived {
|
||||
// TODO(mdempsky): ir.TypeNode should probably return a typecheck'd node.
|
||||
n := ir.TypeNode(typ)
|
||||
n.SetTypecheck(1)
|
||||
return n
|
||||
}
|
||||
|
||||
ptr := typecheck.Expr(typecheck.NodAddr(ir.NewLinksymExpr(pos, lsym, types.Types[types.TUINT8])))
|
||||
return typed(typ, ir.NewDynamicType(pos, ptr))
|
||||
lsym = reflectdata.TypeLinksym(typ)
|
||||
}
|
||||
|
||||
// TODO(mdempsky): ir.TypeNode should probably return a typecheck'd node.
|
||||
n := ir.TypeNode(typ)
|
||||
n.SetTypecheck(1)
|
||||
return n
|
||||
ptr := typecheck.Expr(typecheck.NodAddr(ir.NewLinksymExpr(pos, lsym, types.Types[types.TUINT8])))
|
||||
return typed(typ, ir.NewDynamicType(pos, ptr))
|
||||
}
|
||||
|
||||
func (r *reader) op() ir.Op {
|
||||
|
@ -103,6 +103,10 @@ type writerDict struct {
|
||||
// instantiated with derived types (i.e., that require
|
||||
// sub-dictionaries when called at run time).
|
||||
funcs []objInfo
|
||||
|
||||
// itabs lists itabs that are needed for dynamic type assertions
|
||||
// (including type switches).
|
||||
itabs []itabInfo
|
||||
}
|
||||
|
||||
type derivedInfo struct {
|
||||
@ -120,6 +124,11 @@ type objInfo struct {
|
||||
explicits []typeInfo // info for the type arguments
|
||||
}
|
||||
|
||||
type itabInfo struct {
|
||||
typIdx int // always a derived type index
|
||||
iface typeInfo // always a non-empty interface type
|
||||
}
|
||||
|
||||
func (info objInfo) anyDerived() bool {
|
||||
for _, explicit := range info.explicits {
|
||||
if explicit.derived {
|
||||
@ -633,6 +642,13 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) {
|
||||
}
|
||||
}
|
||||
|
||||
nitabs := len(dict.itabs)
|
||||
w.Len(nitabs)
|
||||
for _, itab := range dict.itabs {
|
||||
w.Len(itab.typIdx)
|
||||
w.typInfo(itab.iface)
|
||||
}
|
||||
|
||||
assert(len(dict.derived) == nderived)
|
||||
assert(len(dict.funcs) == nfuncs)
|
||||
}
|
||||
@ -1388,10 +1404,7 @@ func (w *writer) exprs(exprs []syntax.Expr) {
|
||||
}
|
||||
|
||||
func (w *writer) exprType(iface types2.Type, typ syntax.Expr, nilOK bool) {
|
||||
if iface != nil {
|
||||
_, ok := iface.Underlying().(*types2.Interface)
|
||||
base.Assertf(ok, "%v must be an interface type", iface)
|
||||
}
|
||||
base.Assertf(iface == nil || isInterface(iface), "%v must be nil or an interface type", iface)
|
||||
|
||||
tv, ok := w.p.info.Types[typ]
|
||||
assert(ok)
|
||||
@ -1403,8 +1416,40 @@ func (w *writer) exprType(iface types2.Type, typ syntax.Expr, nilOK bool) {
|
||||
}
|
||||
|
||||
assert(tv.IsType())
|
||||
info := w.p.typIdx(tv.Type, w.dict)
|
||||
|
||||
w.pos(typ)
|
||||
w.typ(tv.Type)
|
||||
|
||||
if w.Bool(info.derived && iface != nil && !iface.Underlying().(*types2.Interface).Empty()) {
|
||||
ifaceInfo := w.p.typIdx(iface, w.dict)
|
||||
|
||||
idx := -1
|
||||
for i, itab := range w.dict.itabs {
|
||||
if itab.typIdx == info.idx && itab.iface == ifaceInfo {
|
||||
idx = i
|
||||
}
|
||||
}
|
||||
if idx < 0 {
|
||||
idx = len(w.dict.itabs)
|
||||
w.dict.itabs = append(w.dict.itabs, itabInfo{typIdx: info.idx, iface: ifaceInfo})
|
||||
}
|
||||
w.Len(idx)
|
||||
return
|
||||
}
|
||||
|
||||
w.typInfo(info)
|
||||
}
|
||||
|
||||
func isInterface(typ types2.Type) bool {
|
||||
if _, ok := typ.(*types2.TypeParam); ok {
|
||||
// typ is a type parameter and may be instantiated as either a
|
||||
// concrete or interface type, so the writer can't depend on
|
||||
// knowing this.
|
||||
base.Fatalf("%v is a type parameter", typ)
|
||||
}
|
||||
|
||||
_, ok := typ.Underlying().(*types2.Interface)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (w *writer) op(op ir.Op) {
|
||||
|
Loading…
Reference in New Issue
Block a user