aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/typecheck/iexport.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/typecheck/iexport.go')
-rw-r--r--src/cmd/compile/internal/typecheck/iexport.go276
1 files changed, 260 insertions, 16 deletions
diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go
index 43cc4e4a25..8f8931e495 100644
--- a/src/cmd/compile/internal/typecheck/iexport.go
+++ b/src/cmd/compile/internal/typecheck/iexport.go
@@ -633,6 +633,79 @@ func (w *exportWriter) selector(s *types.Sym) {
w.string(s.Name)
}
+func (w *exportWriter) typ(t *types.Type) {
+ w.data.uint64(w.p.typOff(t))
+}
+
+// The "exotic" functions in this section encode a wider range of
+// items than the standard encoding functions above. These include
+// types that do not appear in declarations, only in code, such as
+// method types. These methods need to be separate from the standard
+// encoding functions because we don't want to modify the encoding
+// generated by the standard functions (because that exported
+// information is read by tools besides the compiler).
+
+// exoticType exports a type to the writer.
+func (w *exportWriter) exoticType(t *types.Type) {
+ switch {
+ case t == nil:
+ // Calls-as-statements have no type.
+ w.data.uint64(exoticTypeNil)
+ case t.IsStruct() && t.StructType().Funarg != types.FunargNone:
+ // These are weird structs for representing tuples of types returned
+ // by multi-return functions.
+ // They don't fit the standard struct type mold. For instance,
+ // they don't have any package info.
+ w.data.uint64(exoticTypeTuple)
+ w.uint64(uint64(t.StructType().Funarg))
+ w.uint64(uint64(t.NumFields()))
+ for _, f := range t.FieldSlice() {
+ w.pos(f.Pos)
+ s := f.Sym
+ if s == nil {
+ w.uint64(0)
+ } else if s.Pkg == nil {
+ w.uint64(exoticTypeSymNoPkg)
+ w.string(s.Name)
+ } else {
+ w.uint64(exoticTypeSymWithPkg)
+ w.pkg(s.Pkg)
+ w.string(s.Name)
+ }
+ w.typ(f.Type)
+ if f.Embedded != 0 || f.Note != "" {
+ panic("extra info in funarg struct field")
+ }
+ }
+ case t.Kind() == types.TFUNC && t.Recv() != nil:
+ w.data.uint64(exoticTypeRecv)
+ // interface method types have a fake receiver type.
+ isFakeRecv := t.Recv().Type == types.FakeRecvType()
+ w.bool(isFakeRecv)
+ if !isFakeRecv {
+ w.exoticParam(t.Recv())
+ }
+ w.exoticSignature(t)
+
+ default:
+ // A regular type.
+ w.data.uint64(exoticTypeRegular)
+ w.typ(t)
+ }
+}
+
+const (
+ exoticTypeNil = iota
+ exoticTypeTuple
+ exoticTypeRecv
+ exoticTypeRegular
+)
+const (
+ exoticTypeSymNil = iota
+ exoticTypeSymNoPkg
+ exoticTypeSymWithPkg
+)
+
// Export a selector, but one whose package may not match
// the package being compiled. This is a separate function
// because the standard selector() serialization format is fixed
@@ -653,8 +726,42 @@ func (w *exportWriter) exoticSelector(s *types.Sym) {
}
}
-func (w *exportWriter) typ(t *types.Type) {
- w.data.uint64(w.p.typOff(t))
+func (w *exportWriter) exoticSignature(t *types.Type) {
+ hasPkg := t.Pkg() != nil
+ w.bool(hasPkg)
+ if hasPkg {
+ w.pkg(t.Pkg())
+ }
+ w.exoticParamList(t.Params().FieldSlice())
+ w.exoticParamList(t.Results().FieldSlice())
+}
+
+func (w *exportWriter) exoticParamList(fs []*types.Field) {
+ w.uint64(uint64(len(fs)))
+ for _, f := range fs {
+ w.exoticParam(f)
+ }
+
+}
+func (w *exportWriter) exoticParam(f *types.Field) {
+ w.pos(f.Pos)
+ w.exoticSym(f.Sym)
+ w.uint64(uint64(f.Offset))
+ w.exoticType(f.Type)
+ w.bool(f.IsDDD())
+}
+func (w *exportWriter) exoticSym(s *types.Sym) {
+ if s == nil {
+ w.string("")
+ return
+ }
+ if s.Name == "" {
+ base.Fatalf("empty symbol name")
+ }
+ w.string(s.Name)
+ if !types.IsExported(s.Name) {
+ w.pkg(s.Pkg)
+ }
}
func (p *iexporter) newWriter() *exportWriter {
@@ -1133,6 +1240,7 @@ func (w *exportWriter) writeNames(dcl []*ir.Name) {
}
func (w *exportWriter) funcBody(fn *ir.Func) {
+ //fmt.Printf("Exporting %s\n", fn.Nname.Sym().Name)
w.writeNames(fn.Inl.Dcl)
w.stmtList(fn.Inl.Body)
@@ -1208,7 +1316,11 @@ func (w *exportWriter) stmt(n ir.Node) {
case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
n := n.(*ir.AssignListStmt)
- w.op(ir.OAS2)
+ if go117ExportTypes {
+ w.op(n.Op())
+ } else {
+ w.op(ir.OAS2)
+ }
w.pos(n.Pos())
w.exprList(n.Lhs)
w.exprList(n.Rhs)
@@ -1220,7 +1332,7 @@ func (w *exportWriter) stmt(n ir.Node) {
w.exprList(n.Results)
// case ORETJMP:
- // unreachable - generated by compiler for trampolin routines
+ // unreachable - generated by compiler for trampoline routines
case ir.OGO, ir.ODEFER:
n := n.(*ir.GoDeferStmt)
@@ -1357,10 +1469,15 @@ func (w *exportWriter) expr(n ir.Node) {
if (n.Class == ir.PEXTERN || n.Class == ir.PFUNC) && !ir.IsBlank(n) {
w.op(ir.ONONAME)
w.qualifiedIdent(n)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
break
}
// Function scope name.
+ // We don't need a type here, as the type will be provided at the
+ // declaration of n.
w.op(ir.ONAME)
w.localName(n)
@@ -1418,9 +1535,16 @@ func (w *exportWriter) expr(n ir.Node) {
case ir.OPTRLIT:
n := n.(*ir.AddrExpr)
- w.op(ir.OADDR)
+ if go117ExportTypes {
+ w.op(ir.OPTRLIT)
+ } else {
+ w.op(ir.OADDR)
+ }
w.pos(n.Pos())
w.expr(n.X)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
case ir.OSTRUCTLIT:
n := n.(*ir.CompLitExpr)
@@ -1431,11 +1555,17 @@ func (w *exportWriter) expr(n ir.Node) {
case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
n := n.(*ir.CompLitExpr)
- w.op(ir.OCOMPLIT)
+ if go117ExportTypes {
+ w.op(n.Op())
+ } else {
+ w.op(ir.OCOMPLIT)
+ }
w.pos(n.Pos())
w.typ(n.Type())
w.exprList(n.List)
-
+ if go117ExportTypes && n.Op() == ir.OSLICELIT {
+ w.uint64(uint64(n.Len))
+ }
case ir.OKEY:
n := n.(*ir.KeyExpr)
w.op(ir.OKEY)
@@ -1448,39 +1578,89 @@ func (w *exportWriter) expr(n ir.Node) {
case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
n := n.(*ir.SelectorExpr)
- w.op(ir.OXDOT)
+ if go117ExportTypes {
+ if n.Op() == ir.OXDOT {
+ base.Fatalf("shouldn't encounter XDOT in new exporter")
+ }
+ w.op(n.Op())
+ } else {
+ w.op(ir.OXDOT)
+ }
w.pos(n.Pos())
w.expr(n.X)
w.exoticSelector(n.Sel)
+ if go117ExportTypes {
+ w.exoticType(n.Type())
+ if n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR || n.Op() == ir.ODOTINTER || n.Op() == ir.OMETHEXPR {
+ w.exoticParam(n.Selection)
+ if n.Op() == ir.OMETHEXPR {
+ name := ir.MethodExprName(n)
+ w.bool(name != nil)
+ if name != nil {
+ w.exoticType(name.Type())
+ }
+ }
+ }
+ // n.Selection is not required for ODOTMETH and OCALLPART. It will
+ // be reconstructed during import.
+ }
case ir.ODOTTYPE, ir.ODOTTYPE2:
n := n.(*ir.TypeAssertExpr)
- w.op(ir.ODOTTYPE)
+ if go117ExportTypes {
+ w.op(n.Op())
+ } else {
+ w.op(ir.ODOTTYPE)
+ }
w.pos(n.Pos())
w.expr(n.X)
w.typ(n.Type())
case ir.OINDEX, ir.OINDEXMAP:
n := n.(*ir.IndexExpr)
- w.op(ir.OINDEX)
+ if go117ExportTypes {
+ w.op(n.Op())
+ } else {
+ w.op(ir.OINDEX)
+ }
w.pos(n.Pos())
w.expr(n.X)
w.expr(n.Index)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ if n.Op() == ir.OINDEXMAP {
+ w.bool(n.Assigned)
+ }
+ }
case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR:
n := n.(*ir.SliceExpr)
- w.op(ir.OSLICE)
+ if go117ExportTypes {
+ w.op(n.Op())
+ } else {
+ w.op(ir.OSLICE)
+ }
w.pos(n.Pos())
w.expr(n.X)
w.exprsOrNil(n.Low, n.High)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
case ir.OSLICE3, ir.OSLICE3ARR:
n := n.(*ir.SliceExpr)
- w.op(ir.OSLICE3)
+ if go117ExportTypes {
+ w.op(n.Op())
+ } else {
+ w.op(ir.OSLICE3)
+ }
w.pos(n.Pos())
w.expr(n.X)
w.exprsOrNil(n.Low, n.High)
w.expr(n.Max)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
case ir.OCOPY, ir.OCOMPLEX:
// treated like other builtin calls (see e.g., OREAL)
@@ -1489,11 +1669,19 @@ func (w *exportWriter) expr(n ir.Node) {
w.pos(n.Pos())
w.expr(n.X)
w.expr(n.Y)
- w.op(ir.OEND)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ } else {
+ w.op(ir.OEND)
+ }
case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR:
n := n.(*ir.ConvExpr)
- w.op(ir.OCONV)
+ if go117ExportTypes {
+ w.op(n.Op())
+ } else {
+ w.op(ir.OCONV)
+ }
w.pos(n.Pos())
w.typ(n.Type())
w.expr(n.X)
@@ -1503,7 +1691,13 @@ func (w *exportWriter) expr(n ir.Node) {
w.op(n.Op())
w.pos(n.Pos())
w.expr(n.X)
- w.op(ir.OEND)
+ if go117ExportTypes {
+ if n.Op() != ir.OPANIC {
+ w.typ(n.Type())
+ }
+ } else {
+ w.op(ir.OEND)
+ }
case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
n := n.(*ir.CallExpr)
@@ -1516,15 +1710,28 @@ func (w *exportWriter) expr(n ir.Node) {
} else if n.IsDDD {
base.Fatalf("exporter: unexpected '...' with %v call", n.Op())
}
+ if go117ExportTypes {
+ if n.Op() != ir.ODELETE && n.Op() != ir.OPRINT && n.Op() != ir.OPRINTN {
+ w.typ(n.Type())
+ }
+ }
case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
n := n.(*ir.CallExpr)
- w.op(ir.OCALL)
+ if go117ExportTypes {
+ w.op(n.Op())
+ } else {
+ w.op(ir.OCALL)
+ }
w.pos(n.Pos())
w.stmtList(n.Init())
w.expr(n.X)
w.exprList(n.Args)
w.bool(n.IsDDD)
+ if go117ExportTypes {
+ w.exoticType(n.Type())
+ w.uint64(uint64(n.Use))
+ }
case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
n := n.(*ir.MakeExpr)
@@ -1540,6 +1747,12 @@ func (w *exportWriter) expr(n ir.Node) {
w.expr(n.Cap)
w.op(ir.OEND)
case n.Len != nil && (n.Op() == ir.OMAKESLICE || !n.Len.Type().IsUntyped()):
+ // Note: the extra conditional exists because make(T) for
+ // T a map or chan type, gets an untyped zero added as
+ // an argument. Don't serialize that argument here.
+ w.expr(n.Len)
+ w.op(ir.OEND)
+ case n.Len != nil && go117ExportTypes:
w.expr(n.Len)
w.op(ir.OEND)
}
@@ -1550,18 +1763,27 @@ func (w *exportWriter) expr(n ir.Node) {
w.op(n.Op())
w.pos(n.Pos())
w.expr(n.X)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
case ir.OADDR:
n := n.(*ir.AddrExpr)
w.op(n.Op())
w.pos(n.Pos())
w.expr(n.X)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
case ir.ODEREF:
n := n.(*ir.StarExpr)
w.op(n.Op())
w.pos(n.Pos())
w.expr(n.X)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
case ir.OSEND:
n := n.(*ir.SendStmt)
@@ -1578,6 +1800,9 @@ func (w *exportWriter) expr(n ir.Node) {
w.pos(n.Pos())
w.expr(n.X)
w.expr(n.Y)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
case ir.OANDAND, ir.OOROR:
n := n.(*ir.LogicalExpr)
@@ -1585,12 +1810,18 @@ func (w *exportWriter) expr(n ir.Node) {
w.pos(n.Pos())
w.expr(n.X)
w.expr(n.Y)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
case ir.OADDSTR:
n := n.(*ir.AddStringExpr)
w.op(ir.OADDSTR)
w.pos(n.Pos())
w.exprList(n.List)
+ if go117ExportTypes {
+ w.typ(n.Type())
+ }
case ir.ODCLCONST:
// if exporting, DCLCONST should just be removed as its usage
@@ -1633,6 +1864,9 @@ func (w *exportWriter) fieldList(list ir.Nodes) {
w.pos(n.Pos())
w.selector(n.Field)
w.expr(n.Value)
+ if go117ExportTypes {
+ w.uint64(uint64(n.Offset))
+ }
}
}
@@ -1693,3 +1927,13 @@ func (w *intWriter) uint64(x uint64) {
n := binary.PutUvarint(buf[:], x)
w.Write(buf[:n])
}
+
+// If go117ExportTypes is true, then we write type information when
+// exporting function bodies, so those function bodies don't need to
+// be re-typechecked on import.
+// This flag adds some other info to the serialized stream as well
+// which was previously recomputed during typechecking, like
+// specializing opcodes (e.g. OXDOT to ODOTPTR) and ancillary
+// information (e.g. length field for OSLICELIT).
+const go117ExportTypes = true
+const Go117ExportTypes = go117ExportTypes