mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[dev.unified] cmd/compile: start using runtime dictionaries
This CL switches unified IR to start using runtime dictionaries, rather than pure stenciling. In particular, for each instantiated function `F[T]`, it now: 1. Generates a global variable `F[T]-dict` of type `[N]uintptr`, with all of the `*runtime._type` values needed by `F[T]`. 2. Generates a function `F[T]-shaped`, with an extra `.dict *[N]uintptr` parameter and indexing into that parameter for derived types. (N.B., this function is not yet actually using shape types.) 3. Changes `F[T]` to instead be a wrapper function that calls `F[T]-shaped` passing `&F[T]-dict` as the `.dict` parameter. This is done in one pass to make sure the overall wiring is all working (especially, function literals and inlining). Subsequent CLs will write more information into `F[T]-dict` and update `F[T]-shaped` to use it instead of relying on `T`-derived information itself. Once that's done, `F[T]-shaped` can be changed to `F[shapify(T)]` (e.g., `F[go.shape.int]`) and deduplicated. Change-Id: I0e802a4d9934794e01a6bfc367820af893335155 Reviewed-on: https://go-review.googlesource.com/c/go/+/420416 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
994ff78ba0
commit
c9f2150cfb
@ -17,6 +17,7 @@ import (
|
||||
"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"
|
||||
@ -61,14 +62,16 @@ func newPkgReader(pr pkgbits.PkgDecoder) *pkgReader {
|
||||
// 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
|
||||
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
|
||||
return r
|
||||
}
|
||||
|
||||
@ -98,6 +101,12 @@ type reader struct {
|
||||
|
||||
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
|
||||
@ -119,7 +128,13 @@ type reader struct {
|
||||
// Label to return to.
|
||||
retlabel *types.Sym
|
||||
|
||||
inlvars, retvars ir.Nodes
|
||||
// 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 {
|
||||
@ -737,12 +752,7 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, ex
|
||||
// For stenciling, we can just skip over the type parameters.
|
||||
for range dict.targs[dict.implicits:] {
|
||||
// Skip past bounds without actually evaluating them.
|
||||
r.Sync(pkgbits.SyncType)
|
||||
if r.Bool() {
|
||||
r.Len()
|
||||
} else {
|
||||
r.Reloc(pkgbits.RelocType)
|
||||
}
|
||||
r.typInfo()
|
||||
}
|
||||
|
||||
dict.derived = make([]derivedInfo, r.Len())
|
||||
@ -806,9 +816,7 @@ func (r *reader) method(rext *reader) *types.Field {
|
||||
_, recv := r.param()
|
||||
typ := r.signature(pkg, recv)
|
||||
|
||||
fnsym := sym
|
||||
fnsym = ir.MethodSym(recv.Type, fnsym)
|
||||
name := ir.NewNameAt(pos, fnsym)
|
||||
name := ir.NewNameAt(pos, ir.MethodSym(recv.Type, sym))
|
||||
setType(name, typ)
|
||||
|
||||
name.Func = ir.NewFunc(r.pos())
|
||||
@ -981,7 +989,7 @@ var importBodyReader = map[*types.Sym]pkgReaderIndex{}
|
||||
func bodyReaderFor(fn *ir.Func) (pri pkgReaderIndex, ok bool) {
|
||||
if fn.Nname.Defn != nil {
|
||||
pri, ok = bodyReader[fn]
|
||||
assert(ok) // must always be available
|
||||
base.AssertfAt(ok, base.Pos, "must have bodyReader for %v", fn) // must always be available
|
||||
} else {
|
||||
pri, ok = importBodyReader[fn.Sym()]
|
||||
}
|
||||
@ -999,7 +1007,38 @@ func (r *reader) addBody(fn *ir.Func) {
|
||||
// generic functions; see comment in funcExt.
|
||||
assert(fn.Nname.Defn != nil)
|
||||
|
||||
pri := pkgReaderIndex{r.p, r.Reloc(pkgbits.RelocBody), r.dict}
|
||||
idx := r.Reloc(pkgbits.RelocBody)
|
||||
|
||||
var shapedFn *ir.Func
|
||||
if r.hasTypeParams() && fn.OClosure == nil {
|
||||
name := fn.Nname
|
||||
sym := name.Sym()
|
||||
|
||||
shapedSym := sym.Pkg.Lookup(sym.Name + "-shaped")
|
||||
|
||||
// TODO(mdempsky): Once we actually start shaping functions, we'll
|
||||
// need to deduplicate them.
|
||||
shaped := ir.NewDeclNameAt(name.Pos(), ir.ONAME, shapedSym)
|
||||
setType(shaped, shapeSig(fn, r.dict)) // TODO(mdempsky): Use shape types.
|
||||
|
||||
shapedFn = ir.NewFunc(fn.Pos())
|
||||
shaped.Func = shapedFn
|
||||
shapedFn.Nname = shaped
|
||||
shapedFn.SetDupok(true)
|
||||
|
||||
shaped.Class = 0 // so MarkFunc doesn't complain
|
||||
ir.MarkFunc(shaped)
|
||||
|
||||
shaped.Defn = shapedFn
|
||||
|
||||
shapedFn.Pragma = fn.Pragma // TODO(mdempsky): How does stencil.go handle pragmas?
|
||||
typecheck.Func(shapedFn)
|
||||
|
||||
bodyReader[shapedFn] = pkgReaderIndex{r.p, idx, r.dict, nil}
|
||||
todoBodies = append(todoBodies, shapedFn)
|
||||
}
|
||||
|
||||
pri := pkgReaderIndex{r.p, idx, r.dict, shapedFn}
|
||||
bodyReader[fn] = pri
|
||||
|
||||
if r.curfn == nil {
|
||||
@ -1020,6 +1059,9 @@ func (pri pkgReaderIndex) funcBody(fn *ir.Func) {
|
||||
func (r *reader) funcBody(fn *ir.Func) {
|
||||
r.curfn = fn
|
||||
r.closureVars = fn.ClosureVars
|
||||
if len(r.closureVars) != 0 && r.hasTypeParams() {
|
||||
r.dictParam = r.closureVars[len(r.closureVars)-1] // dictParam is last; see reader.funcLit
|
||||
}
|
||||
|
||||
ir.WithFunc(fn, func() {
|
||||
r.funcargs(fn)
|
||||
@ -1028,6 +1070,11 @@ func (r *reader) funcBody(fn *ir.Func) {
|
||||
return
|
||||
}
|
||||
|
||||
if r.shapedFn != nil {
|
||||
r.callShaped(fn.Pos())
|
||||
return
|
||||
}
|
||||
|
||||
body := r.stmts()
|
||||
if body == nil {
|
||||
body = []ir.Node{typecheck.Stmt(ir.NewBlockStmt(src.NoXPos, nil))}
|
||||
@ -1039,6 +1086,139 @@ func (r *reader) funcBody(fn *ir.Func) {
|
||||
r.marker.WriteTo(fn)
|
||||
}
|
||||
|
||||
// callShaped emits a tail call to r.shapedFn, passing along the
|
||||
// arguments to the current function.
|
||||
func (r *reader) callShaped(pos src.XPos) {
|
||||
sig := r.curfn.Nname.Type()
|
||||
|
||||
var args ir.Nodes
|
||||
|
||||
// First argument is a pointer to the -dict global variable.
|
||||
args.Append(r.dictPtr())
|
||||
|
||||
// Collect the arguments to the current function, so we can pass
|
||||
// them along to the shaped function. (This is unfortunately quite
|
||||
// hairy.)
|
||||
for _, params := range &types.RecvsParams {
|
||||
for _, param := range params(sig).FieldSlice() {
|
||||
var arg ir.Node
|
||||
if param.Nname != nil {
|
||||
name := param.Nname.(*ir.Name)
|
||||
if !ir.IsBlank(name) {
|
||||
if r.inlCall != nil {
|
||||
// During inlining, we want the respective inlvar where we
|
||||
// assigned the callee's arguments.
|
||||
arg = r.inlvars[len(args)-1]
|
||||
} else {
|
||||
// Otherwise, we can use the parameter itself directly.
|
||||
base.AssertfAt(name.Curfn == r.curfn, name.Pos(), "%v has curfn %v, but want %v", name, name.Curfn, r.curfn)
|
||||
arg = name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For anonymous and blank parameters, we don't have an *ir.Name
|
||||
// to use as the argument. However, since we know the shaped
|
||||
// function won't use the value either, we can just pass the
|
||||
// zero value. (Also unfortunately, we don't have an easy
|
||||
// zero-value IR node; so we use a default-initialized temporary
|
||||
// variable.)
|
||||
if arg == nil {
|
||||
tmp := typecheck.TempAt(pos, r.curfn, param.Type)
|
||||
r.curfn.Body.Append(
|
||||
typecheck.Stmt(ir.NewDecl(pos, ir.ODCL, tmp)),
|
||||
typecheck.Stmt(ir.NewAssignStmt(pos, tmp, nil)),
|
||||
)
|
||||
arg = tmp
|
||||
}
|
||||
|
||||
args.Append(arg)
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the function as a wrapper so it doesn't show up in stack
|
||||
// traces.
|
||||
r.curfn.SetWrapper(true)
|
||||
|
||||
call := typecheck.Call(pos, r.shapedFn.Nname, args, sig.IsVariadic()).(*ir.CallExpr)
|
||||
|
||||
var stmt ir.Node
|
||||
if sig.NumResults() != 0 {
|
||||
stmt = typecheck.Stmt(ir.NewReturnStmt(pos, []ir.Node{call}))
|
||||
} else {
|
||||
stmt = call
|
||||
}
|
||||
r.curfn.Body.Append(stmt)
|
||||
}
|
||||
|
||||
// dictPtr returns a pointer to the runtime dictionary variable needed
|
||||
// for the current function to call its shaped variant.
|
||||
func (r *reader) dictPtr() ir.Node {
|
||||
var fn *ir.Func
|
||||
if r.inlCall != nil {
|
||||
// During inlining, r.curfn is named after the caller (not the
|
||||
// callee), because it's relevant to closure naming, sigh.
|
||||
fn = r.inlFunc
|
||||
} else {
|
||||
fn = r.curfn
|
||||
}
|
||||
|
||||
var baseSym *types.Sym
|
||||
if recv := fn.Nname.Type().Recv(); recv != nil {
|
||||
// All methods of a given instantiated receiver type share the
|
||||
// same dictionary.
|
||||
baseSym = deref(recv.Type).Sym()
|
||||
} else {
|
||||
baseSym = fn.Nname.Sym()
|
||||
}
|
||||
|
||||
sym := baseSym.Pkg.Lookup(baseSym.Name + "-dict")
|
||||
|
||||
if sym.Def == nil {
|
||||
dict := ir.NewNameAt(r.curfn.Pos(), sym)
|
||||
dict.Class = ir.PEXTERN
|
||||
|
||||
lsym := dict.Linksym()
|
||||
ot := 0
|
||||
|
||||
for idx, info := range r.dict.derived {
|
||||
if info.needed {
|
||||
typ := r.p.typIdx(typeInfo{idx: pkgbits.Index(idx), derived: true}, r.dict, false)
|
||||
rtype := reflectdata.TypeLinksym(typ)
|
||||
ot = objw.SymPtr(lsym, ot, rtype, 0)
|
||||
} else {
|
||||
// TODO(mdempsky): Compact unused runtime dictionary space.
|
||||
ot = objw.Uintptr(lsym, ot, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mdempsky): Write out more dictionary information.
|
||||
|
||||
objw.Global(lsym, int32(ot), obj.DUPOK|obj.RODATA)
|
||||
|
||||
dict.SetType(r.dict.varType())
|
||||
dict.SetTypecheck(1)
|
||||
|
||||
sym.Def = dict
|
||||
}
|
||||
|
||||
return typecheck.Expr(ir.NewAddrExpr(r.curfn.Pos(), sym.Def.(*ir.Name)))
|
||||
}
|
||||
|
||||
// numWords returns the number of words that dict's runtime dictionary
|
||||
// variable requires.
|
||||
func (dict *readerDict) numWords() int64 {
|
||||
var num int
|
||||
num += len(dict.derivedTypes)
|
||||
// TODO(mdempsky): Add space for more dictionary information.
|
||||
return int64(num)
|
||||
}
|
||||
|
||||
// varType returns the type of dict's runtime dictionary variable.
|
||||
func (dict *readerDict) varType() *types.Type {
|
||||
return types.NewArray(types.Types[types.TUINTPTR], dict.numWords())
|
||||
}
|
||||
|
||||
func (r *reader) funcargs(fn *ir.Func) {
|
||||
sig := fn.Nname.Type()
|
||||
|
||||
@ -1096,16 +1276,20 @@ func (r *reader) funcarg(param *types.Field, sym *types.Sym, ctxt ir.Class) {
|
||||
func (r *reader) addLocal(name *ir.Name, ctxt ir.Class) {
|
||||
assert(ctxt == ir.PAUTO || ctxt == ir.PPARAM || ctxt == ir.PPARAMOUT)
|
||||
|
||||
r.Sync(pkgbits.SyncAddLocal)
|
||||
if r.p.SyncMarkers() {
|
||||
want := r.Int()
|
||||
if have := len(r.locals); have != want {
|
||||
base.FatalfAt(name.Pos(), "locals table has desynced")
|
||||
if name.Sym().Name == dictParamName {
|
||||
r.dictParam = name
|
||||
} else {
|
||||
r.Sync(pkgbits.SyncAddLocal)
|
||||
if r.p.SyncMarkers() {
|
||||
want := r.Int()
|
||||
if have := len(r.locals); have != want {
|
||||
base.FatalfAt(name.Pos(), "locals table has desynced")
|
||||
}
|
||||
}
|
||||
r.locals = append(r.locals, name)
|
||||
}
|
||||
|
||||
name.SetUsed(true)
|
||||
r.locals = append(r.locals, name)
|
||||
|
||||
// TODO(mdempsky): Move earlier.
|
||||
if ir.IsBlank(name) {
|
||||
@ -2000,6 +2184,11 @@ func (r *reader) funcLit() ir.Node {
|
||||
for len(fn.ClosureVars) < cap(fn.ClosureVars) {
|
||||
ir.NewClosureVar(r.pos(), fn, r.useLocal())
|
||||
}
|
||||
if param := r.dictParam; param != nil {
|
||||
// If we have a dictionary parameter, capture it too. For
|
||||
// simplicity, we capture it last and unconditionally.
|
||||
ir.NewClosureVar(param.Pos(), fn, param)
|
||||
}
|
||||
|
||||
r.addBody(fn)
|
||||
|
||||
@ -2024,39 +2213,60 @@ func (r *reader) exprs() []ir.Node {
|
||||
return nodes
|
||||
}
|
||||
|
||||
// rtype returns an expression of type *runtime._type.
|
||||
// dictWord returns an expression to return the specified
|
||||
// uintptr-typed word from the dictionary parameter.
|
||||
func (r *reader) dictWord(pos src.XPos, idx int64) ir.Node {
|
||||
base.AssertfAt(r.dictParam != nil, pos, "expected dictParam in %v", r.curfn)
|
||||
return typecheck.Expr(ir.NewIndexExpr(pos, r.dictParam, ir.NewBasicLit(pos, constant.MakeInt64(idx))))
|
||||
}
|
||||
|
||||
// rtype reads a type reference from the element bitstream, and
|
||||
// returns an expression of type *runtime._type representing that
|
||||
// type.
|
||||
func (r *reader) rtype(pos src.XPos) ir.Node {
|
||||
r.Sync(pkgbits.SyncRType)
|
||||
// TODO(mdempsky): For derived types, use dictionary instead.
|
||||
return reflectdata.TypePtrAt(pos, r.typ())
|
||||
return r.rtypeInfo(pos, r.typInfo())
|
||||
}
|
||||
|
||||
// rtypeInfo returns an expression of type *runtime._type representing
|
||||
// the given decoded type reference.
|
||||
func (r *reader) rtypeInfo(pos src.XPos, info typeInfo) ir.Node {
|
||||
if !info.derived {
|
||||
typ := r.p.typIdx(info, r.dict, true)
|
||||
return reflectdata.TypePtrAt(pos, typ)
|
||||
}
|
||||
return typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, types.NewPtr(types.Types[types.TUINT8]), r.dictWord(pos, int64(info.idx))))
|
||||
}
|
||||
|
||||
// convRTTI returns expressions appropriate for populating an
|
||||
// ir.ConvExpr's TypeWord and SrcRType fields, respectively.
|
||||
func (r *reader) convRTTI(pos src.XPos) (typeWord, srcRType ir.Node) {
|
||||
r.Sync(pkgbits.SyncConvRTTI)
|
||||
src := r.typ()
|
||||
dst := r.typ()
|
||||
srcInfo := r.typInfo()
|
||||
dstInfo := r.typInfo()
|
||||
|
||||
dst := r.p.typIdx(dstInfo, r.dict, true)
|
||||
if !dst.IsInterface() {
|
||||
return
|
||||
}
|
||||
|
||||
src := r.p.typIdx(srcInfo, r.dict, true)
|
||||
|
||||
// See reflectdata.ConvIfaceTypeWord.
|
||||
switch {
|
||||
case dst.IsEmptyInterface():
|
||||
if !src.IsInterface() {
|
||||
typeWord = reflectdata.TypePtrAt(pos, src) // direct eface construction
|
||||
typeWord = r.rtypeInfo(pos, srcInfo) // direct eface construction
|
||||
}
|
||||
case !src.IsInterface():
|
||||
typeWord = reflectdata.ITabAddrAt(pos, src, dst) // direct iface construction
|
||||
default:
|
||||
typeWord = reflectdata.TypePtrAt(pos, dst) // convI2I
|
||||
typeWord = r.rtypeInfo(pos, dstInfo) // convI2I
|
||||
}
|
||||
|
||||
// See reflectdata.ConvIfaceSrcRType.
|
||||
if !src.IsInterface() {
|
||||
srcRType = reflectdata.TypePtrAt(pos, src)
|
||||
srcRType = r.rtypeInfo(pos, srcInfo)
|
||||
}
|
||||
|
||||
return
|
||||
@ -2096,7 +2306,7 @@ func (r *reader) exprType() ir.Node {
|
||||
return n
|
||||
}
|
||||
|
||||
rtype = lsymPtr(reflectdata.TypeLinksym(typ))
|
||||
rtype = r.rtypeInfo(pos, info)
|
||||
}
|
||||
|
||||
dt := ir.NewDynamicType(pos, rtype)
|
||||
@ -2275,6 +2485,9 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
|
||||
for i, cv := range r.inlFunc.ClosureVars {
|
||||
r.closureVars[i] = cv.Outer
|
||||
}
|
||||
if len(r.closureVars) != 0 && r.hasTypeParams() {
|
||||
r.dictParam = r.closureVars[len(r.closureVars)-1] // dictParam is last; see reader.funcLit
|
||||
}
|
||||
|
||||
r.funcargs(fn)
|
||||
|
||||
@ -2337,8 +2550,12 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
|
||||
nparams := len(r.curfn.Dcl)
|
||||
|
||||
ir.WithFunc(r.curfn, func() {
|
||||
r.curfn.Body = r.stmts()
|
||||
r.curfn.Endlineno = r.pos()
|
||||
if r.shapedFn != nil {
|
||||
r.callShaped(call.Pos())
|
||||
} else {
|
||||
r.curfn.Body = r.stmts()
|
||||
r.curfn.Endlineno = r.pos()
|
||||
}
|
||||
|
||||
// TODO(mdempsky): This shouldn't be necessary. Inlining might
|
||||
// read in new function/method declarations, which could
|
||||
@ -2800,3 +3017,40 @@ func setBasePos(pos src.XPos) {
|
||||
// Set the position for any error messages we might print (e.g. too large types).
|
||||
base.Pos = pos
|
||||
}
|
||||
|
||||
// dictParamName is the name of the synthetic dictionary parameter
|
||||
// added to shaped functions.
|
||||
const dictParamName = ".dict"
|
||||
|
||||
// shapeSig returns a copy of fn's signature, except adding a
|
||||
// dictionary parameter and promoting the receiver parameter (if any)
|
||||
// to a normal parameter.
|
||||
//
|
||||
// The parameter types.Fields are all copied too, so their Nname
|
||||
// fields can be initialized for use by the shape function.
|
||||
func shapeSig(fn *ir.Func, dict *readerDict) *types.Type {
|
||||
sig := fn.Nname.Type()
|
||||
recv := sig.Recv()
|
||||
nrecvs := 0
|
||||
if recv != nil {
|
||||
nrecvs++
|
||||
}
|
||||
|
||||
params := make([]*types.Field, 1+nrecvs+sig.Params().Fields().Len())
|
||||
params[0] = types.NewField(fn.Pos(), fn.Sym().Pkg.Lookup(dictParamName), types.NewPtr(dict.varType()))
|
||||
if recv != nil {
|
||||
params[1] = types.NewField(recv.Pos, recv.Sym, recv.Type)
|
||||
}
|
||||
for i, param := range sig.Params().Fields().Slice() {
|
||||
d := types.NewField(param.Pos, param.Sym, param.Type)
|
||||
d.SetIsDDD(param.IsDDD())
|
||||
params[1+nrecvs+i] = d
|
||||
}
|
||||
|
||||
results := make([]*types.Field, sig.Results().Fields().Len())
|
||||
for i, result := range sig.Results().Fields().Slice() {
|
||||
results[i] = types.NewField(result.Pos, result.Sym, result.Type)
|
||||
}
|
||||
|
||||
return types.NewSignature(types.LocalPkg, nil, nil, params, results)
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ func readPackage(pr *pkgReader, importpkg *types.Pkg, localStub bool) {
|
||||
|
||||
path, name, code := r.p.PeekObj(idx)
|
||||
if code != pkgbits.ObjStub {
|
||||
objReader[types.NewPkg(path, "").Lookup(name)] = pkgReaderIndex{pr, idx, nil}
|
||||
objReader[types.NewPkg(path, "").Lookup(name)] = pkgReaderIndex{pr, idx, nil, nil}
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,7 +271,7 @@ func readPackage(pr *pkgReader, importpkg *types.Pkg, localStub bool) {
|
||||
|
||||
sym := types.NewPkg(path, "").Lookup(name)
|
||||
if _, ok := importBodyReader[sym]; !ok {
|
||||
importBodyReader[sym] = pkgReaderIndex{pr, idx, nil}
|
||||
importBodyReader[sym] = pkgReaderIndex{pr, idx, nil, nil}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ type writerDict struct {
|
||||
// A derivedInfo represents a reference to an encoded generic Go type.
|
||||
type derivedInfo struct {
|
||||
idx pkgbits.Index
|
||||
needed bool // TODO(mdempsky): Remove; will break x/tools importer
|
||||
needed bool
|
||||
}
|
||||
|
||||
// A typeInfo represents a reference to an encoded Go type.
|
||||
@ -1952,15 +1952,26 @@ func (w *writer) exprs(exprs []syntax.Expr) {
|
||||
// expression of type *runtime._type representing typ.
|
||||
func (w *writer) rtype(typ types2.Type) {
|
||||
w.Sync(pkgbits.SyncRType)
|
||||
w.typ(typ)
|
||||
w.typNeeded(typ)
|
||||
}
|
||||
|
||||
// typNeeded writes a reference to typ, and records that its
|
||||
// *runtime._type is needed.
|
||||
func (w *writer) typNeeded(typ types2.Type) {
|
||||
info := w.p.typIdx(typ, w.dict)
|
||||
w.typInfo(info)
|
||||
|
||||
if info.derived {
|
||||
w.dict.derived[info.idx].needed = true
|
||||
}
|
||||
}
|
||||
|
||||
// convRTTI writes information so that the reader can construct
|
||||
// expressions for converting from src to dst.
|
||||
func (w *writer) convRTTI(src, dst types2.Type) {
|
||||
w.Sync(pkgbits.SyncConvRTTI)
|
||||
w.typ(src)
|
||||
w.typ(dst)
|
||||
w.typNeeded(src)
|
||||
w.typNeeded(dst)
|
||||
}
|
||||
|
||||
func (w *writer) exprType(iface types2.Type, typ syntax.Expr) {
|
||||
@ -1992,6 +2003,9 @@ func (w *writer) exprType(iface types2.Type, typ syntax.Expr) {
|
||||
}
|
||||
|
||||
w.typInfo(info)
|
||||
if info.derived {
|
||||
w.dict.derived[info.idx].needed = true
|
||||
}
|
||||
}
|
||||
|
||||
func (dict *writerDict) methodExprIdx(recvInfo typeInfo, methodInfo selectorInfo) int {
|
||||
|
@ -76,7 +76,7 @@ func TestDebugLinesPushback(t *testing.T) {
|
||||
fn := "(*List[go.shape.int_0]).PushBack"
|
||||
if buildcfg.Experiment.Unified {
|
||||
// Unified mangles differently
|
||||
fn = "(*List[int]).PushBack"
|
||||
fn = "(*List[int]).PushBack-shaped"
|
||||
}
|
||||
testDebugLines(t, "-N -l", "pushback.go", fn, []int{17, 18, 19, 20, 21, 22, 24}, true)
|
||||
}
|
||||
@ -95,7 +95,7 @@ func TestDebugLinesConvert(t *testing.T) {
|
||||
fn := "G[go.shape.int_0]"
|
||||
if buildcfg.Experiment.Unified {
|
||||
// Unified mangles differently
|
||||
fn = "G[int]"
|
||||
fn = "G[int]-shaped"
|
||||
}
|
||||
testDebugLines(t, "-N -l", "convertline.go", fn, []int{9, 10, 11}, true)
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
// - v1: adds the flags uint32 word
|
||||
//
|
||||
// TODO(mdempsky): For the next version bump:
|
||||
// - remove the unused dict.derived.needed bool
|
||||
// - remove the legacy "has init" bool from the public root
|
||||
const currentVersion uint32 = 1
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user