aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder/writer.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/noder/writer.go')
-rw-r--r--src/cmd/compile/internal/noder/writer.go339
1 files changed, 290 insertions, 49 deletions
diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index 52fa542f6b..a90b2d3bbd 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -172,12 +172,37 @@ type writerDict struct {
// derivedIdx maps a Type to its corresponding index within the
// derived slice, if present.
derivedIdx map[types2.Type]pkgbits.Index
+
+ // These slices correspond to entries in the runtime dictionary.
+ typeParamMethodExprs []writerMethodExprInfo
+ subdicts []objInfo
+ rtypes []typeInfo
+ itabs []itabInfo
+}
+
+type itabInfo struct {
+ typ typeInfo
+ iface typeInfo
+}
+
+// typeParamIndex returns the index of the given type parameter within
+// the dictionary. This may differ from typ.Index() when there are
+// implicit type parameters due to defined types declared within a
+// generic function or method.
+func (dict *writerDict) typeParamIndex(typ *types2.TypeParam) int {
+ for idx, implicit := range dict.implicits {
+ if implicit.Type().(*types2.TypeParam) == typ {
+ return idx
+ }
+ }
+
+ return len(dict.implicits) + typ.Index()
}
// A derivedInfo represents a reference to an encoded generic Go type.
type derivedInfo struct {
idx pkgbits.Index
- needed bool
+ needed bool // TODO(mdempsky): Remove.
}
// A typeInfo represents a reference to an encoded Go type.
@@ -234,6 +259,75 @@ func (info objInfo) equals(other objInfo) bool {
return true
}
+type writerMethodExprInfo struct {
+ typeParamIdx int
+ methodInfo selectorInfo
+}
+
+// typeParamMethodExprIdx returns the index where the given encoded
+// method expression function pointer appears within this dictionary's
+// type parameters method expressions section, adding it if necessary.
+func (dict *writerDict) typeParamMethodExprIdx(typeParamIdx int, methodInfo selectorInfo) int {
+ newInfo := writerMethodExprInfo{typeParamIdx, methodInfo}
+
+ for idx, oldInfo := range dict.typeParamMethodExprs {
+ if oldInfo == newInfo {
+ return idx
+ }
+ }
+
+ idx := len(dict.typeParamMethodExprs)
+ dict.typeParamMethodExprs = append(dict.typeParamMethodExprs, newInfo)
+ return idx
+}
+
+// subdictIdx returns the index where the given encoded object's
+// runtime dictionary appears within this dictionary's subdictionary
+// section, adding it if necessary.
+func (dict *writerDict) subdictIdx(newInfo objInfo) int {
+ for idx, oldInfo := range dict.subdicts {
+ if oldInfo.equals(newInfo) {
+ return idx
+ }
+ }
+
+ idx := len(dict.subdicts)
+ dict.subdicts = append(dict.subdicts, newInfo)
+ return idx
+}
+
+// rtypeIdx returns the index where the given encoded type's
+// *runtime._type value appears within this dictionary's rtypes
+// section, adding it if necessary.
+func (dict *writerDict) rtypeIdx(newInfo typeInfo) int {
+ for idx, oldInfo := range dict.rtypes {
+ if oldInfo == newInfo {
+ return idx
+ }
+ }
+
+ idx := len(dict.rtypes)
+ dict.rtypes = append(dict.rtypes, newInfo)
+ return idx
+}
+
+// itabIdx returns the index where the given encoded type pair's
+// *runtime.itab value appears within this dictionary's itabs section,
+// adding it if necessary.
+func (dict *writerDict) itabIdx(typInfo, ifaceInfo typeInfo) int {
+ newInfo := itabInfo{typInfo, ifaceInfo}
+
+ for idx, oldInfo := range dict.itabs {
+ if oldInfo == newInfo {
+ return idx
+ }
+ }
+
+ idx := len(dict.itabs)
+ dict.itabs = append(dict.itabs, newInfo)
+ return idx
+}
+
func (pw *pkgWriter) newWriter(k pkgbits.RelocKind, marker pkgbits.SyncMarker) *writer {
return &writer{
Encoder: pw.NewEncoder(k, marker),
@@ -412,19 +506,9 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
w.obj(obj, targs)
case *types2.TypeParam:
- index := func() int {
- for idx, name := range w.dict.implicits {
- if name.Type().(*types2.TypeParam) == typ {
- return idx
- }
- }
-
- return len(w.dict.implicits) + typ.Index()
- }()
-
w.derived = true
w.Code(pkgbits.TypeTypeParam)
- w.Len(index)
+ w.Len(w.dict.typeParamIndex(typ))
case *types2.Array:
w.Code(pkgbits.TypeArray)
@@ -757,6 +841,33 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) {
w.Bool(typ.needed)
}
+ // Write runtime dictionary information.
+ //
+ // N.B., the go/types importer reads up to the section, but doesn't
+ // read any further, so it's safe to change. (See TODO above.)
+
+ w.Len(len(dict.typeParamMethodExprs))
+ for _, info := range dict.typeParamMethodExprs {
+ w.Len(info.typeParamIdx)
+ w.selectorInfo(info.methodInfo)
+ }
+
+ w.Len(len(dict.subdicts))
+ for _, info := range dict.subdicts {
+ w.objInfo(info)
+ }
+
+ w.Len(len(dict.rtypes))
+ for _, info := range dict.rtypes {
+ w.typInfo(info)
+ }
+
+ w.Len(len(dict.itabs))
+ for _, info := range dict.itabs {
+ w.typInfo(info.typ)
+ w.typInfo(info.iface)
+ }
+
assert(len(dict.derived) == nderived)
}
@@ -960,17 +1071,21 @@ func (w *writer) funcargs(sig *types2.Signature) {
func (w *writer) funcarg(param *types2.Var, result bool) {
if param.Name() != "" || result {
- w.addLocal(param)
+ w.addLocal(param, true)
}
}
// addLocal records the declaration of a new local variable.
-func (w *writer) addLocal(obj *types2.Var) {
- w.Sync(pkgbits.SyncAddLocal)
+func (w *writer) addLocal(obj *types2.Var, isParam bool) {
idx := len(w.localsIdx)
- if w.p.SyncMarkers() {
- w.Int(idx)
+
+ if !isParam {
+ w.Sync(pkgbits.SyncAddLocal)
+ if w.p.SyncMarkers() {
+ w.Int(idx)
+ }
}
+
if w.localsIdx == nil {
w.localsIdx = make(map[*types2.Var]int)
}
@@ -1161,7 +1276,7 @@ func (w *writer) assign(expr syntax.Expr) {
// TODO(mdempsky): Minimize locals index size by deferring
// this until the variables actually come into scope.
- w.addLocal(obj)
+ w.addLocal(obj, false)
return
}
}
@@ -1424,7 +1539,7 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) {
obj := obj.(*types2.Var)
w.typ(obj.Type())
- w.addLocal(obj)
+ w.addLocal(obj, false)
}
w.stmts(clause.Body)
@@ -1494,7 +1609,8 @@ func (w *writer) expr(expr syntax.Expr) {
obj := obj.(*types2.Func)
w.Code(exprFuncInst)
- w.obj(obj, targs)
+ w.pos(expr)
+ w.funcInst(obj, targs)
return
}
@@ -1540,9 +1656,9 @@ func (w *writer) expr(expr syntax.Expr) {
case types2.MethodVal:
w.Code(exprMethodVal)
- w.recvExpr(expr, sel)
+ typ := w.recvExpr(expr, sel)
w.pos(expr)
- w.selector(sel.Obj())
+ w.methodExpr(expr, typ, sel)
case types2.MethodExpr:
w.Code(exprMethodExpr)
@@ -1551,9 +1667,27 @@ func (w *writer) expr(expr syntax.Expr) {
assert(ok)
assert(tv.IsType())
- w.typ(tv.Type)
+ index := sel.Index()
+ implicits := index[:len(index)-1]
+
+ typ := tv.Type
+ w.typ(typ)
+
+ w.Len(len(implicits))
+ for _, ix := range implicits {
+ w.Len(ix)
+ typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type()
+ }
+
+ recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type()
+ if w.Bool(isPtrTo(typ, recv)) { // need deref
+ typ = recv
+ } else if w.Bool(isPtrTo(recv, typ)) { // need addr
+ typ = recv
+ }
+
w.pos(expr)
- w.selector(sel.Obj())
+ w.methodExpr(expr, typ, sel)
}
case *syntax.IndexExpr:
@@ -1695,18 +1829,28 @@ func (w *writer) expr(expr syntax.Expr) {
}
writeFunExpr := func() {
- if selector, ok := unparen(expr.Fun).(*syntax.SelectorExpr); ok {
+ fun := unparen(expr.Fun)
+
+ if selector, ok := fun.(*syntax.SelectorExpr); ok {
if sel, ok := w.p.info.Selections[selector]; ok && sel.Kind() == types2.MethodVal {
- w.recvExpr(selector, sel)
w.Bool(true) // method call
- w.pos(selector)
- w.selector(sel.Obj())
+ typ := w.recvExpr(selector, sel)
+ w.methodExpr(selector, typ, sel)
return
}
}
- w.expr(expr.Fun)
w.Bool(false) // not a method call (i.e., normal function call)
+
+ if obj, inst := lookupObj(w.p.info, fun); w.Bool(obj != nil && inst.TypeArgs.Len() != 0) {
+ obj := obj.(*types2.Func)
+
+ w.pos(fun)
+ w.funcInst(obj, inst.TypeArgs)
+ return
+ }
+
+ w.expr(fun)
}
sigType := types2.CoreType(tv.Type).(*types2.Signature)
@@ -1742,7 +1886,8 @@ func (w *writer) optExpr(expr syntax.Expr) {
}
// recvExpr writes out expr.X, but handles any implicit addressing,
-// dereferencing, and field selections.
+// dereferencing, and field selections appropriate for the method
+// selection.
func (w *writer) recvExpr(expr *syntax.SelectorExpr, sel *types2.Selection) types2.Type {
index := sel.Index()
implicits := index[:len(index)-1]
@@ -1758,13 +1903,6 @@ func (w *writer) recvExpr(expr *syntax.SelectorExpr, sel *types2.Selection) type
w.Len(ix)
}
- isPtrTo := func(from, to types2.Type) bool {
- if from, ok := from.(*types2.Pointer); ok {
- return types2.Identical(from.Elem(), to)
- }
- return false
- }
-
recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type()
if w.Bool(isPtrTo(typ, recv)) { // needs deref
typ = recv
@@ -1775,6 +1913,84 @@ func (w *writer) recvExpr(expr *syntax.SelectorExpr, sel *types2.Selection) type
return typ
}
+// funcInst writes a reference to an instantiated function.
+func (w *writer) funcInst(obj *types2.Func, targs *types2.TypeList) {
+ info := w.p.objInstIdx(obj, targs, w.dict)
+
+ // Type arguments list contains derived types; we can emit a static
+ // call to the shaped function, but need to dynamically compute the
+ // runtime dictionary pointer.
+ if w.Bool(info.anyDerived()) {
+ w.Len(w.dict.subdictIdx(info))
+ return
+ }
+
+ // Type arguments list is statically known; we can emit a static
+ // call with a statically reference to the respective runtime
+ // dictionary.
+ w.objInfo(info)
+}
+
+// methodExpr writes out a reference to the method selected by
+// expr. sel should be the corresponding types2.Selection, and recv
+// the type produced after any implicit addressing, dereferencing, and
+// field selection. (Note: recv might differ from sel.Obj()'s receiver
+// parameter in the case of interface types, and is needed for
+// handling type parameter methods.)
+func (w *writer) methodExpr(expr *syntax.SelectorExpr, recv types2.Type, sel *types2.Selection) {
+ fun := sel.Obj().(*types2.Func)
+ sig := fun.Type().(*types2.Signature)
+
+ w.typ(recv)
+ w.signature(sig)
+ w.pos(expr)
+ w.selector(fun)
+
+ // Method on a type parameter. These require an indirect call
+ // through the current function's runtime dictionary.
+ if typeParam, ok := recv.(*types2.TypeParam); w.Bool(ok) {
+ typeParamIdx := w.dict.typeParamIndex(typeParam)
+ methodInfo := w.p.selectorIdx(fun)
+
+ w.Len(w.dict.typeParamMethodExprIdx(typeParamIdx, methodInfo))
+ return
+ }
+
+ if isInterface(recv) != isInterface(sig.Recv().Type()) {
+ w.p.fatalf(expr, "isInterface inconsistency: %v and %v", recv, sig.Recv().Type())
+ }
+
+ if !isInterface(recv) {
+ if named, ok := deref2(recv).(*types2.Named); ok {
+ obj, targs := splitNamed(named)
+ info := w.p.objInstIdx(obj, targs, w.dict)
+
+ // Method on a derived receiver type. These can be handled by a
+ // static call to the shaped method, but require dynamically
+ // looking up the appropriate dictionary argument in the current
+ // function's runtime dictionary.
+ if w.p.hasImplicitTypeParams(obj) || info.anyDerived() {
+ w.Bool(true) // dynamic subdictionary
+ w.Len(w.dict.subdictIdx(info))
+ return
+ }
+
+ // Method on a fully known receiver type. These can be handled
+ // by a static call to the shaped method, and with a static
+ // reference to the receiver type's dictionary.
+ if targs.Len() != 0 {
+ w.Bool(false) // no dynamic subdictionary
+ w.Bool(true) // static dictionary
+ w.objInfo(info)
+ return
+ }
+ }
+ }
+
+ w.Bool(false) // no dynamic subdictionary
+ w.Bool(false) // no static dictionary
+}
+
// multiExpr writes a sequence of expressions, where the i'th value is
// implicitly converted to dstType(i). It also handles when exprs is a
// single, multi-valued expression (e.g., the multi-valued argument in
@@ -1930,18 +2146,34 @@ func (w *writer) exprs(exprs []syntax.Expr) {
// rtype writes information so that the reader can construct an
// expression of type *runtime._type representing typ.
func (w *writer) rtype(typ types2.Type) {
+ typ = types2.Default(typ)
+
w.Sync(pkgbits.SyncRType)
- 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 w.Bool(info.derived) {
+ w.Len(w.dict.rtypeIdx(info))
+ } else {
+ w.typInfo(info)
+ }
+}
+
+func isUntyped(typ types2.Type) bool {
+ basic, ok := typ.(*types2.Basic)
+ return ok && basic.Info()&types2.IsUntyped != 0
+}
+
+func (w *writer) itab(typ, iface types2.Type) {
+ typ = types2.Default(typ)
+ iface = types2.Default(iface)
- if info.derived {
- w.dict.derived[info.idx].needed = true
+ typInfo := w.p.typIdx(typ, w.dict)
+ ifaceInfo := w.p.typIdx(iface, w.dict)
+ if w.Bool(typInfo.derived || ifaceInfo.derived) {
+ w.Len(w.dict.itabIdx(typInfo, ifaceInfo))
+ } else {
+ w.typInfo(typInfo)
+ w.typInfo(ifaceInfo)
}
}
@@ -1949,8 +2181,7 @@ func (w *writer) typNeeded(typ types2.Type) {
// expressions for converting from src to dst.
func (w *writer) convRTTI(src, dst types2.Type) {
w.Sync(pkgbits.SyncConvRTTI)
- w.typNeeded(src)
- w.typNeeded(dst)
+ w.itab(src, dst)
}
func (w *writer) exprType(iface types2.Type, typ syntax.Expr) {
@@ -1963,9 +2194,13 @@ func (w *writer) exprType(iface types2.Type, typ syntax.Expr) {
w.Sync(pkgbits.SyncExprType)
w.pos(typ)
- w.typNeeded(tv.Type)
if w.Bool(iface != nil && !iface.Underlying().(*types2.Interface).Empty()) {
- w.typ(iface)
+ w.itab(tv.Type, iface)
+ } else {
+ w.rtype(tv.Type)
+
+ info := w.p.typIdx(tv.Type, w.dict)
+ w.Bool(info.derived)
}
}
@@ -2435,3 +2670,9 @@ func asPragmaFlag(p syntax.Pragma) ir.PragmaFlag {
}
return p.(*pragmas).Flag
}
+
+// isPtrTo reports whether from is the type *to.
+func isPtrTo(from, to types2.Type) bool {
+ ptr, ok := from.(*types2.Pointer)
+ return ok && types2.Identical(ptr.Elem(), to)
+}