// arguments; the rest are explicit.
implicits int
- derivedReloc []int // reloc index of the derived type's descriptor
- derived []*types.Type // slice of previously computed derived types
+ derived []derivedInfo // reloc index of the derived type's descriptor
+ derivedTypes []*types.Type // slice of previously computed derived types
+
+ funcs []objInfo
+ funcsObj []ir.Node
}
func (r *reader) setType(n ir.Node, typ *types.Type) {
// @@@ Types
func (r *reader) typ() *types.Type {
+ return r.p.typIdx(r.typInfo(), r.dict)
+}
+
+func (r *reader) typInfo() typeInfo {
r.sync(syncType)
if r.bool() {
- return r.p.typIdx(r.len(), r.dict)
+ return typeInfo{idx: r.len(), derived: true}
}
- return r.p.typIdx(r.reloc(relocType), nil)
+ return typeInfo{idx: r.reloc(relocType), derived: false}
}
-func (pr *pkgReader) typIdx(idx int, dict *readerDict) *types.Type {
+func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) *types.Type {
+ idx := info.idx
var where **types.Type
- if dict != nil {
- where = &dict.derived[idx]
- idx = dict.derivedReloc[idx]
+ if info.derived {
+ where = &dict.derivedTypes[idx]
+ idx = dict.derived[idx].idx
} else {
where = &pr.typs[idx]
}
func (r *reader) obj() ir.Node {
r.sync(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)
+ }
+
+ obj = r.p.objIdx(fn.idx, nil, targs)
+ assert(r.dict.funcsObj[idx] == nil)
+ r.dict.funcsObj[idx] = obj
+ }
+ return obj
+ }
+
idx := r.reloc(relocObj)
explicits := make([]*types.Type, r.len())
{
rdict := pr.newReader(relocObjDict, idx, syncObject1)
- r.dict.derivedReloc = make([]int, rdict.len())
- r.dict.derived = make([]*types.Type, len(r.dict.derivedReloc))
+ r.dict.derived = make([]derivedInfo, rdict.len())
+ r.dict.derivedTypes = make([]*types.Type, len(r.dict.derived))
for i := range r.dict.derived {
- r.dict.derivedReloc[i] = rdict.reloc(relocType)
+ r.dict.derived[i] = derivedInfo{rdict.reloc(relocType), rdict.bool()}
+ }
+ 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}
}
}
}
type reader2Dict struct {
- bounds []reader2TypeBound
+ bounds []typeInfo
tparams []*types2.TypeParam
- derivedReloc []int
- derived []types2.Type
+ derived []derivedInfo
+ derivedTypes []types2.Type
}
type reader2TypeBound struct {
// @@@ Types
func (r *reader2) typ() types2.Type {
+ return r.p.typIdx(r.typInfo(), r.dict)
+}
+
+func (r *reader2) typInfo() typeInfo {
r.sync(syncType)
if r.bool() {
- return r.p.typIdx(r.len(), r.dict)
+ return typeInfo{idx: r.len(), derived: true}
}
- return r.p.typIdx(r.reloc(relocType), nil)
+ return typeInfo{idx: r.reloc(relocType), derived: false}
}
-func (pr *pkgReader2) typIdx(idx int, dict *reader2Dict) types2.Type {
+func (pr *pkgReader2) typIdx(info typeInfo, dict *reader2Dict) types2.Type {
+ idx := info.idx
var where *types2.Type
- if dict != nil {
- where = &dict.derived[idx]
- idx = dict.derivedReloc[idx]
+ if info.derived {
+ where = &dict.derivedTypes[idx]
+ idx = dict.derived[idx].idx
} else {
where = &pr.typs[idx]
}
func (r *reader2) obj() (types2.Object, []types2.Type) {
r.sync(syncObject)
+ assert(!r.bool())
+
pkg, name := r.p.objIdx(r.reloc(relocObj))
obj := pkg.Scope().Lookup(name)
{
rdict := r.p.newReader(relocObjDict, idx, syncObject1)
- r.dict.derivedReloc = make([]int, rdict.len())
- r.dict.derived = make([]types2.Type, len(r.dict.derivedReloc))
+ r.dict.derived = make([]derivedInfo, rdict.len())
+ r.dict.derivedTypes = make([]types2.Type, len(r.dict.derived))
for i := range r.dict.derived {
- r.dict.derivedReloc[i] = rdict.reloc(relocType)
+ 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 {
base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits)
}
- r.dict.bounds = make([]reader2TypeBound, r.len())
+ r.dict.bounds = make([]typeInfo, r.len())
for i := range r.dict.bounds {
- b := &r.dict.bounds[i]
- r.sync(syncType)
- b.derived = r.bool()
- if b.derived {
- b.boundIdx = r.len()
- } else {
- b.boundIdx = r.reloc(relocType)
- }
+ r.dict.bounds[i] = r.typInfo()
}
}
}
for i, bound := range r.dict.bounds {
- var dict *reader2Dict
- if bound.derived {
- dict = r.dict
- }
- boundType := r.p.typIdx(bound.boundIdx, dict)
- r.dict.tparams[i].SetBound(boundType)
+ r.dict.tparams[i].SetBound(r.p.typIdx(bound, r.dict))
}
return names
// derived is a slice of type indices for computing derived types
// (i.e., types that depend on the declaration's type parameters).
- derived []int
+ derived []derivedInfo
// derivedIdx maps a Type to its corresponding index within the
// derived slice, if present.
derivedIdx map[types2.Type]int
+
+ // funcs lists references to generic functions that were
+ // instantiated with derived types (i.e., that require
+ // sub-dictionaries when called at run time).
+ funcs []objInfo
+}
+
+type derivedInfo struct {
+ idx int
+ needed bool
+}
+
+type typeInfo struct {
+ idx int
+ derived bool
+}
+
+type objInfo struct {
+ idx int // index for the generic function declaration
+ explicits []typeInfo // info for the type arguments
+}
+
+func (info objInfo) anyDerived() bool {
+ for _, explicit := range info.explicits {
+ if explicit.derived {
+ return true
+ }
+ }
+ return false
+}
+
+func (info objInfo) equals(other objInfo) bool {
+ if info.idx != other.idx {
+ return false
+ }
+ assert(len(info.explicits) == len(other.explicits))
+ for i, targ := range info.explicits {
+ if targ != other.explicits[i] {
+ return false
+ }
+ }
+ return true
}
func (pw *pkgWriter) newWriter(k reloc, marker syncMarker) *writer {
// @@@ Types
func (w *writer) typ(typ types2.Type) {
- idx, derived := w.p.typIdx(typ, w.dict)
+ w.typInfo(w.p.typIdx(typ, w.dict))
+}
+func (w *writer) typInfo(info typeInfo) {
w.sync(syncType)
- if w.bool(derived) {
- w.len(idx)
+ if w.bool(info.derived) {
+ w.len(info.idx)
w.derived = true
} else {
- w.reloc(relocType, idx)
+ w.reloc(relocType, info.idx)
}
}
//
// typIdx also reports whether typ is a derived type; that is, whether
// its identity depends on type parameters.
-func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) (int, bool) {
+func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
if quirksMode() {
typ = pw.dups.orig(typ)
}
if idx, ok := pw.typsIdx[typ]; ok {
- return idx, false
+ return typeInfo{idx: idx, derived: false}
}
if dict != nil {
if idx, ok := dict.derivedIdx[typ]; ok {
- return idx, true
+ return typeInfo{idx: idx, derived: true}
}
}
if w.derived {
idx := len(dict.derived)
- dict.derived = append(dict.derived, w.flush())
+ dict.derived = append(dict.derived, derivedInfo{idx: w.flush()})
dict.derivedIdx[typ] = idx
- return idx, true
+ return typeInfo{idx: idx, derived: true}
}
pw.typsIdx[typ] = w.idx
- return w.flush(), false
+ return typeInfo{idx: w.flush(), derived: false}
}
func (w *writer) structType(typ *types2.Struct) {
// @@@ Objects
func (w *writer) obj(obj types2.Object, explicits []types2.Type) {
+ explicitInfos := make([]typeInfo, len(explicits))
+ for i, explicit := range explicits {
+ explicitInfos[i] = w.p.typIdx(explicit, 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(syncObject)
+ w.bool(true)
+ w.len(idx)
+ return
+ }
+
+ // TODO(mdempsky): Push up into typIdx; this shouldn't be needed
+ // except while writing out types.
if isDefinedType(obj) && obj.Pkg() == w.p.curpkg {
decl, ok := w.p.typDecls[obj.(*types2.TypeName)]
assert(ok)
}
w.sync(syncObject)
- w.reloc(relocObj, w.p.objIdx(obj))
+ w.bool(false)
+ w.reloc(relocObj, info.idx)
- w.len(len(explicits))
- for _, explicit := range explicits {
- w.typ(explicit)
+ w.len(len(info.explicits))
+ for _, info := range info.explicits {
+ w.typInfo(info)
}
}
w.ext.flush()
// Done writing out the object description; write out the list of
- // derived types that we found along the way.
- //
- // TODO(mdempsky): Record details about how derived types are
- // actually used so reader can optimize its runtime dictionaries.
- //
- // TODO(mdempsky): Record details about which instantiated functions
- // are used too.
+ // derived types and instantiated functions found along the way.
wdict.len(len(dict.derived))
for _, typ := range dict.derived {
- wdict.reloc(relocType, typ)
+ wdict.reloc(relocType, typ.idx)
+ 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()
obj, targs := lookupObj(w.p.info, expr)
if tv, ok := w.p.info.Types[expr]; ok {
+ // TODO(mdempsky): Be more judicious about which types are marked as "needed".
+ w.needType(tv.Type)
+
if tv.IsType() {
w.code(exprType)
w.typ(tv.Type)
w.len(int(op))
}
+func (w *writer) needType(typ types2.Type) {
+ // Decompose tuple into component element types.
+ if typ, ok := typ.(*types2.Tuple); ok {
+ for i := 0; i < typ.Len(); i++ {
+ w.needType(typ.At(i).Type())
+ }
+ return
+ }
+
+ if info := w.p.typIdx(typ, w.dict); info.derived {
+ w.dict.derived[info.idx].needed = true
+ }
+}
+
// @@@ Package initialization
// Caution: This code is still clumsy, because toolstash -cmp is