diff options
Diffstat (limited to 'src/cmd/compile/internal/typecheck/iexport.go')
-rw-r--r-- | src/cmd/compile/internal/typecheck/iexport.go | 276 |
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 |