diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/iexport.go')
-rw-r--r-- | src/cmd/compile/internal/gc/iexport.go | 753 |
1 files changed, 379 insertions, 374 deletions
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go index 1f53d8ca7d..ef52e40f21 100644 --- a/src/cmd/compile/internal/gc/iexport.go +++ b/src/cmd/compile/internal/gc/iexport.go @@ -204,12 +204,15 @@ package gc import ( "bufio" "bytes" + "cmd/compile/internal/base" + "cmd/compile/internal/ir" "cmd/compile/internal/types" "cmd/internal/goobj" "cmd/internal/src" "crypto/md5" "encoding/binary" "fmt" + "go/constant" "io" "math/big" "sort" @@ -243,22 +246,21 @@ const ( ) func iexport(out *bufio.Writer) { - // Mark inline bodies that are reachable through exported types. + // Mark inline bodies that are reachable through exported objects. // (Phase 0 of bexport.go.) { // TODO(mdempsky): Separate from bexport logic. p := &exporter{marked: make(map[*types.Type]bool)} for _, n := range exportlist { - sym := n.Sym - p.markType(asNode(sym.Def).Type) + p.markObject(n) } } p := iexporter{ allPkgs: map[*types.Pkg]bool{}, stringIndex: map[string]uint64{}, - declIndex: map[*Node]uint64{}, - inlineIndex: map[*Node]uint64{}, + declIndex: map[ir.Node]uint64{}, + inlineIndex: map[ir.Node]uint64{}, typIndex: map[*types.Type]uint64{}, } @@ -266,7 +268,7 @@ func iexport(out *bufio.Writer) { p.typIndex[pt] = uint64(i) } if len(p.typIndex) > predeclReserved { - Fatalf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved) + base.Fatalf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved) } // Initialize work queue with exported declarations. @@ -277,8 +279,8 @@ func iexport(out *bufio.Writer) { // Loop until no more work. We use a queue because while // writing out inline bodies, we may discover additional // declarations that are needed. - for !p.declTodo.empty() { - p.doDecl(p.declTodo.popLeft()) + for !p.declTodo.Empty() { + p.doDecl(p.declTodo.PopLeft()) } // Append indices to data0 section. @@ -304,30 +306,30 @@ func iexport(out *bufio.Writer) { // Add fingerprint (used by linker object file). // Attach this to the end, so tools (e.g. gcimporter) don't care. - copy(Ctxt.Fingerprint[:], h.Sum(nil)[:]) - out.Write(Ctxt.Fingerprint[:]) + copy(base.Ctxt.Fingerprint[:], h.Sum(nil)[:]) + out.Write(base.Ctxt.Fingerprint[:]) } // writeIndex writes out an object index. mainIndex indicates whether // we're writing out the main index, which is also read by // non-compiler tools and includes a complete package description // (i.e., name and height). -func (w *exportWriter) writeIndex(index map[*Node]uint64, mainIndex bool) { +func (w *exportWriter) writeIndex(index map[ir.Node]uint64, mainIndex bool) { // Build a map from packages to objects from that package. - pkgObjs := map[*types.Pkg][]*Node{} + pkgObjs := map[*types.Pkg][]ir.Node{} // For the main index, make sure to include every package that // we reference, even if we're not exporting (or reexporting) // any symbols from it. if mainIndex { - pkgObjs[localpkg] = nil + pkgObjs[ir.LocalPkg] = nil for pkg := range w.p.allPkgs { pkgObjs[pkg] = nil } } for n := range index { - pkgObjs[n.Sym.Pkg] = append(pkgObjs[n.Sym.Pkg], n) + pkgObjs[n.Sym().Pkg] = append(pkgObjs[n.Sym().Pkg], n) } var pkgs []*types.Pkg @@ -335,7 +337,7 @@ func (w *exportWriter) writeIndex(index map[*Node]uint64, mainIndex bool) { pkgs = append(pkgs, pkg) sort.Slice(objs, func(i, j int) bool { - return objs[i].Sym.Name < objs[j].Sym.Name + return objs[i].Sym().Name < objs[j].Sym().Name }) } @@ -354,7 +356,7 @@ func (w *exportWriter) writeIndex(index map[*Node]uint64, mainIndex bool) { objs := pkgObjs[pkg] w.uint64(uint64(len(objs))) for _, n := range objs { - w.string(n.Sym.Name) + w.string(n.Sym().Name) w.uint64(index[n]) } } @@ -366,14 +368,14 @@ type iexporter struct { // main index. allPkgs map[*types.Pkg]bool - declTodo nodeQueue + declTodo ir.NodeQueue strings intWriter stringIndex map[string]uint64 data0 intWriter - declIndex map[*Node]uint64 - inlineIndex map[*Node]uint64 + declIndex map[ir.Node]uint64 + inlineIndex map[ir.Node]uint64 typIndex map[*types.Type]uint64 } @@ -392,13 +394,13 @@ func (p *iexporter) stringOff(s string) uint64 { } // pushDecl adds n to the declaration work queue, if not already present. -func (p *iexporter) pushDecl(n *Node) { - if n.Sym == nil || asNode(n.Sym.Def) != n && n.Op != OTYPE { - Fatalf("weird Sym: %v, %v", n, n.Sym) +func (p *iexporter) pushDecl(n ir.Node) { + if n.Sym() == nil || ir.AsNode(n.Sym().Def) != n && n.Op() != ir.OTYPE { + base.Fatalf("weird Sym: %v, %v", n, n.Sym()) } // Don't export predeclared declarations. - if n.Sym.Pkg == builtinpkg || n.Sym.Pkg == unsafepkg { + if n.Sym().Pkg == ir.BuiltinPkg || n.Sym().Pkg == unsafepkg { return } @@ -407,7 +409,7 @@ func (p *iexporter) pushDecl(n *Node) { } p.declIndex[n] = ^uint64(0) // mark n present in work queue - p.declTodo.pushRight(n) + p.declTodo.PushRight(n) } // exportWriter handles writing out individual data section chunks. @@ -421,56 +423,56 @@ type exportWriter struct { prevColumn int64 } -func (p *iexporter) doDecl(n *Node) { +func (p *iexporter) doDecl(n ir.Node) { w := p.newWriter() - w.setPkg(n.Sym.Pkg, false) + w.setPkg(n.Sym().Pkg, false) - switch n.Op { - case ONAME: + switch n.Op() { + case ir.ONAME: switch n.Class() { - case PEXTERN: + case ir.PEXTERN: // Variable. w.tag('V') - w.pos(n.Pos) - w.typ(n.Type) + w.pos(n.Pos()) + w.typ(n.Type()) w.varExt(n) - case PFUNC: - if n.IsMethod() { - Fatalf("unexpected method: %v", n) + case ir.PFUNC: + if ir.IsMethod(n) { + base.Fatalf("unexpected method: %v", n) } // Function. w.tag('F') - w.pos(n.Pos) - w.signature(n.Type) + w.pos(n.Pos()) + w.signature(n.Type()) w.funcExt(n) default: - Fatalf("unexpected class: %v, %v", n, n.Class()) + base.Fatalf("unexpected class: %v, %v", n, n.Class()) } - case OLITERAL: + case ir.OLITERAL: // Constant. n = typecheck(n, ctxExpr) w.tag('C') - w.pos(n.Pos) - w.value(n.Type, n.Val()) + w.pos(n.Pos()) + w.value(n.Type(), n.Val()) - case OTYPE: - if IsAlias(n.Sym) { + case ir.OTYPE: + if IsAlias(n.Sym()) { // Alias. w.tag('A') - w.pos(n.Pos) - w.typ(n.Type) + w.pos(n.Pos()) + w.typ(n.Type()) break } // Defined type. w.tag('T') - w.pos(n.Pos) + w.pos(n.Pos()) - underlying := n.Type.Orig + underlying := n.Type().Orig if underlying == types.Errortype.Orig { // For "type T error", use error as the // underlying type instead of error's own @@ -482,7 +484,7 @@ func (p *iexporter) doDecl(n *Node) { } w.typ(underlying) - t := n.Type + t := n.Type() if t.IsInterface() { w.typeExt(t) break @@ -503,7 +505,7 @@ func (p *iexporter) doDecl(n *Node) { } default: - Fatalf("unexpected node: %v", n) + base.Fatalf("unexpected node: %v", n) } p.declIndex[n] = w.flush() @@ -513,17 +515,17 @@ func (w *exportWriter) tag(tag byte) { w.data.WriteByte(tag) } -func (p *iexporter) doInline(f *Node) { +func (p *iexporter) doInline(f ir.Node) { w := p.newWriter() w.setPkg(fnpkg(f), false) - w.stmtList(asNodes(f.Func.Inl.Body)) + w.stmtList(ir.AsNodes(f.Func().Inl.Body)) p.inlineIndex[f] = w.flush() } func (w *exportWriter) pos(pos src.XPos) { - p := Ctxt.PosTable.Pos(pos) + p := base.Ctxt.PosTable.Pos(pos) file := p.Base().AbsFilename() line := int64(p.RelLine()) column := int64(p.RelCol()) @@ -568,18 +570,18 @@ func (w *exportWriter) pkg(pkg *types.Pkg) { w.string(pkg.Path) } -func (w *exportWriter) qualifiedIdent(n *Node) { +func (w *exportWriter) qualifiedIdent(n ir.Node) { // Ensure any referenced declarations are written out too. w.p.pushDecl(n) - s := n.Sym + s := n.Sym() w.string(s.Name) w.pkg(s.Pkg) } func (w *exportWriter) selector(s *types.Sym) { if w.currPkg == nil { - Fatalf("missing currPkg") + base.Fatalf("missing currPkg") } // Method selectors are rewritten into method symbols (of the @@ -591,10 +593,10 @@ func (w *exportWriter) selector(s *types.Sym) { } else { pkg := w.currPkg if types.IsExported(name) { - pkg = localpkg + pkg = ir.LocalPkg } if s.Pkg != pkg { - Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path) + base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path) } } @@ -632,8 +634,8 @@ func (w *exportWriter) startType(k itag) { func (w *exportWriter) doTyp(t *types.Type) { if t.Sym != nil { - if t.Sym.Pkg == builtinpkg || t.Sym.Pkg == unsafepkg { - Fatalf("builtin type missing from typIndex: %v", t) + if t.Sym.Pkg == ir.BuiltinPkg || t.Sym.Pkg == unsafepkg { + base.Fatalf("builtin type missing from typIndex: %v", t) } w.startType(definedType) @@ -642,35 +644,35 @@ func (w *exportWriter) doTyp(t *types.Type) { } switch t.Etype { - case TPTR: + case types.TPTR: w.startType(pointerType) w.typ(t.Elem()) - case TSLICE: + case types.TSLICE: w.startType(sliceType) w.typ(t.Elem()) - case TARRAY: + case types.TARRAY: w.startType(arrayType) w.uint64(uint64(t.NumElem())) w.typ(t.Elem()) - case TCHAN: + case types.TCHAN: w.startType(chanType) w.uint64(uint64(t.ChanDir())) w.typ(t.Elem()) - case TMAP: + case types.TMAP: w.startType(mapType) w.typ(t.Key()) w.typ(t.Elem()) - case TFUNC: + case types.TFUNC: w.startType(signatureType) w.setPkg(t.Pkg(), true) w.signature(t) - case TSTRUCT: + case types.TSTRUCT: w.startType(structType) w.setPkg(t.Pkg(), true) @@ -683,7 +685,7 @@ func (w *exportWriter) doTyp(t *types.Type) { w.string(f.Note) } - case TINTER: + case types.TINTER: var embeddeds, methods []*types.Field for _, m := range t.Methods().Slice() { if m.Sym != nil { @@ -710,7 +712,7 @@ func (w *exportWriter) doTyp(t *types.Type) { } default: - Fatalf("unexpected type: %v", t) + base.Fatalf("unexpected type: %v", t) } } @@ -718,7 +720,7 @@ func (w *exportWriter) setPkg(pkg *types.Pkg, write bool) { if pkg == nil { // TODO(mdempsky): Proactively set Pkg for types and // remove this fallback logic. - pkg = localpkg + pkg = ir.LocalPkg } if write { @@ -745,44 +747,40 @@ func (w *exportWriter) paramList(fs []*types.Field) { func (w *exportWriter) param(f *types.Field) { w.pos(f.Pos) - w.localIdent(origSym(f.Sym), 0) + w.localIdent(ir.OrigSym(f.Sym), 0) w.typ(f.Type) } -func constTypeOf(typ *types.Type) Ctype { +func constTypeOf(typ *types.Type) constant.Kind { switch typ { case types.UntypedInt, types.UntypedRune: - return CTINT + return constant.Int case types.UntypedFloat: - return CTFLT + return constant.Float case types.UntypedComplex: - return CTCPLX + return constant.Complex } switch typ.Etype { - case TCHAN, TFUNC, TMAP, TNIL, TINTER, TPTR, TSLICE, TUNSAFEPTR: - return CTNIL - case TBOOL: - return CTBOOL - case TSTRING: - return CTSTR - case TINT, TINT8, TINT16, TINT32, TINT64, - TUINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINTPTR: - return CTINT - case TFLOAT32, TFLOAT64: - return CTFLT - case TCOMPLEX64, TCOMPLEX128: - return CTCPLX - } - - Fatalf("unexpected constant type: %v", typ) + case types.TBOOL: + return constant.Bool + case types.TSTRING: + return constant.String + case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64, + types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR: + return constant.Int + case types.TFLOAT32, types.TFLOAT64: + return constant.Float + case types.TCOMPLEX64, types.TCOMPLEX128: + return constant.Complex + } + + base.Fatalf("unexpected constant type: %v", typ) return 0 } -func (w *exportWriter) value(typ *types.Type, v Val) { - if vt := idealType(v.Ctype()); typ.IsUntyped() && typ != vt { - Fatalf("exporter: untyped type mismatch, have: %v, want: %v", typ, vt) - } +func (w *exportWriter) value(typ *types.Type, v constant.Value) { + ir.AssertValidTypeForConst(typ, v) w.typ(typ) // Each type has only one admissible constant representation, @@ -791,21 +789,17 @@ func (w *exportWriter) value(typ *types.Type, v Val) { // and provides a useful consistency check. switch constTypeOf(typ) { - case CTNIL: - // Only one value; nothing to encode. - _ = v.U.(*NilVal) - case CTBOOL: - w.bool(v.U.(bool)) - case CTSTR: - w.string(v.U.(string)) - case CTINT: - w.mpint(&v.U.(*Mpint).Val, typ) - case CTFLT: - w.mpfloat(&v.U.(*Mpflt).Val, typ) - case CTCPLX: - x := v.U.(*Mpcplx) - w.mpfloat(&x.Real.Val, typ) - w.mpfloat(&x.Imag.Val, typ) + case constant.Bool: + w.bool(constant.BoolVal(v)) + case constant.String: + w.string(constant.StringVal(v)) + case constant.Int: + w.mpint(v, typ) + case constant.Float: + w.mpfloat(v, typ) + case constant.Complex: + w.mpfloat(constant.Real(v), typ) + w.mpfloat(constant.Imag(v), typ) } } @@ -815,9 +809,9 @@ func intSize(typ *types.Type) (signed bool, maxBytes uint) { } switch typ.Etype { - case TFLOAT32, TCOMPLEX64: + case types.TFLOAT32, types.TCOMPLEX64: return true, 3 - case TFLOAT64, TCOMPLEX128: + case types.TFLOAT64, types.TCOMPLEX128: return true, 7 } @@ -827,7 +821,7 @@ func intSize(typ *types.Type) (signed bool, maxBytes uint) { // The go/types API doesn't expose sizes to importers, so they // don't know how big these types are. switch typ.Etype { - case TINT, TUINT, TUINTPTR: + case types.TINT, types.TUINT, types.TUINTPTR: maxBytes = 8 } @@ -854,20 +848,24 @@ func intSize(typ *types.Type) (signed bool, maxBytes uint) { // single byte. // // TODO(mdempsky): Is this level of complexity really worthwhile? -func (w *exportWriter) mpint(x *big.Int, typ *types.Type) { +func (w *exportWriter) mpint(x constant.Value, typ *types.Type) { signed, maxBytes := intSize(typ) - negative := x.Sign() < 0 + negative := constant.Sign(x) < 0 if !signed && negative { - Fatalf("negative unsigned integer; type %v, value %v", typ, x) + base.Fatalf("negative unsigned integer; type %v, value %v", typ, x) + } + + b := constant.Bytes(x) // little endian + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] } - b := x.Bytes() if len(b) > 0 && b[0] == 0 { - Fatalf("leading zeros") + base.Fatalf("leading zeros") } if uint(len(b)) > maxBytes { - Fatalf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x) + base.Fatalf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x) } maxSmall := 256 - maxBytes @@ -904,7 +902,7 @@ func (w *exportWriter) mpint(x *big.Int, typ *types.Type) { } } if n < maxSmall || n >= 256 { - Fatalf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n) + base.Fatalf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n) } w.data.WriteByte(byte(n)) @@ -917,9 +915,10 @@ func (w *exportWriter) mpint(x *big.Int, typ *types.Type) { // mantissa is an integer. The value is written out as mantissa (as a // multi-precision integer) and then the exponent, except exponent is // omitted if mantissa is zero. -func (w *exportWriter) mpfloat(f *big.Float, typ *types.Type) { +func (w *exportWriter) mpfloat(v constant.Value, typ *types.Type) { + f := bigFloatVal(v) if f.IsInf() { - Fatalf("infinite constant") + base.Fatalf("infinite constant") } // Break into f = mant × 2**exp, with 0.5 <= mant < 1. @@ -933,9 +932,9 @@ func (w *exportWriter) mpfloat(f *big.Float, typ *types.Type) { manti, acc := mant.Int(nil) if acc != big.Exact { - Fatalf("mantissa scaling failed for %f (%s)", f, acc) + base.Fatalf("mantissa scaling failed for %f (%s)", f, acc) } - w.mpint(manti, typ) + w.mpint(makeInt(manti), typ) if manti.Sign() != 0 { w.int64(exp) } @@ -956,37 +955,37 @@ func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) } // Compiler-specific extensions. -func (w *exportWriter) varExt(n *Node) { - w.linkname(n.Sym) - w.symIdx(n.Sym) +func (w *exportWriter) varExt(n ir.Node) { + w.linkname(n.Sym()) + w.symIdx(n.Sym()) } -func (w *exportWriter) funcExt(n *Node) { - w.linkname(n.Sym) - w.symIdx(n.Sym) +func (w *exportWriter) funcExt(n ir.Node) { + w.linkname(n.Sym()) + w.symIdx(n.Sym()) // Escape analysis. for _, fs := range &types.RecvsParams { - for _, f := range fs(n.Type).FieldSlice() { + for _, f := range fs(n.Type()).FieldSlice() { w.string(f.Note) } } // Inline body. - if n.Func.Inl != nil { - w.uint64(1 + uint64(n.Func.Inl.Cost)) - if n.Func.ExportInline() { + if n.Func().Inl != nil { + w.uint64(1 + uint64(n.Func().Inl.Cost)) + if n.Func().ExportInline() { w.p.doInline(n) } // Endlineno for inlined function. - if n.Name.Defn != nil { - w.pos(n.Name.Defn.Func.Endlineno) + if n.Name().Defn != nil { + w.pos(n.Name().Defn.Func().Endlineno) } else { // When the exported node was defined externally, // e.g. io exports atomic.(*Value).Load or bytes exports errors.New. // Keep it as we don't distinguish this case in iimport.go. - w.pos(n.Func.Endlineno) + w.pos(n.Func().Endlineno) } } else { w.uint64(0) @@ -995,7 +994,7 @@ func (w *exportWriter) funcExt(n *Node) { func (w *exportWriter) methExt(m *types.Field) { w.bool(m.Nointerface()) - w.funcExt(asNode(m.Type.Nname())) + w.funcExt(ir.AsNode(m.Nname)) } func (w *exportWriter) linkname(s *types.Sym) { @@ -1031,15 +1030,15 @@ func (w *exportWriter) typeExt(t *types.Type) { // Inline bodies. -func (w *exportWriter) stmtList(list Nodes) { +func (w *exportWriter) stmtList(list ir.Nodes) { for _, n := range list.Slice() { w.node(n) } - w.op(OEND) + w.op(ir.OEND) } -func (w *exportWriter) node(n *Node) { - if opprec[n.Op] < 0 { +func (w *exportWriter) node(n ir.Node) { + if ir.OpPrec[n.Op()] < 0 { w.stmt(n) } else { w.expr(n) @@ -1048,149 +1047,149 @@ func (w *exportWriter) node(n *Node) { // Caution: stmt will emit more than one node for statement nodes n that have a non-empty // n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.). -func (w *exportWriter) stmt(n *Node) { - if n.Ninit.Len() > 0 && !stmtwithinit(n.Op) { +func (w *exportWriter) stmt(n ir.Node) { + if n.Init().Len() > 0 && !ir.StmtWithInit(n.Op()) { // can't use stmtList here since we don't want the final OEND - for _, n := range n.Ninit.Slice() { + for _, n := range n.Init().Slice() { w.stmt(n) } } - switch op := n.Op; op { - case ODCL: - w.op(ODCL) - w.pos(n.Left.Pos) - w.localName(n.Left) - w.typ(n.Left.Type) + switch op := n.Op(); op { + case ir.ODCL: + w.op(ir.ODCL) + w.pos(n.Left().Pos()) + w.localName(n.Left()) + w.typ(n.Left().Type()) // case ODCLFIELD: // unimplemented - handled by default case - case OAS: + case ir.OAS: // Don't export "v = <N>" initializing statements, hope they're always // preceded by the DCL which will be re-parsed and typecheck to reproduce // the "v = <N>" again. - if n.Right != nil { - w.op(OAS) - w.pos(n.Pos) - w.expr(n.Left) - w.expr(n.Right) + if n.Right() != nil { + w.op(ir.OAS) + w.pos(n.Pos()) + w.expr(n.Left()) + w.expr(n.Right()) } - case OASOP: - w.op(OASOP) - w.pos(n.Pos) + case ir.OASOP: + w.op(ir.OASOP) + w.pos(n.Pos()) w.op(n.SubOp()) - w.expr(n.Left) + w.expr(n.Left()) if w.bool(!n.Implicit()) { - w.expr(n.Right) + w.expr(n.Right()) } - case OAS2: - w.op(OAS2) - w.pos(n.Pos) - w.exprList(n.List) - w.exprList(n.Rlist) + case ir.OAS2: + w.op(ir.OAS2) + w.pos(n.Pos()) + w.exprList(n.List()) + w.exprList(n.Rlist()) - case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: - w.op(OAS2) - w.pos(n.Pos) - w.exprList(n.List) - w.exprList(asNodes([]*Node{n.Right})) + case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV: + w.op(ir.OAS2) + w.pos(n.Pos()) + w.exprList(n.List()) + w.exprList(ir.AsNodes([]ir.Node{n.Right()})) - case ORETURN: - w.op(ORETURN) - w.pos(n.Pos) - w.exprList(n.List) + case ir.ORETURN: + w.op(ir.ORETURN) + w.pos(n.Pos()) + w.exprList(n.List()) // case ORETJMP: // unreachable - generated by compiler for trampolin routines - case OGO, ODEFER: + case ir.OGO, ir.ODEFER: w.op(op) - w.pos(n.Pos) - w.expr(n.Left) - - case OIF: - w.op(OIF) - w.pos(n.Pos) - w.stmtList(n.Ninit) - w.expr(n.Left) - w.stmtList(n.Nbody) - w.stmtList(n.Rlist) - - case OFOR: - w.op(OFOR) - w.pos(n.Pos) - w.stmtList(n.Ninit) - w.exprsOrNil(n.Left, n.Right) - w.stmtList(n.Nbody) - - case ORANGE: - w.op(ORANGE) - w.pos(n.Pos) - w.stmtList(n.List) - w.expr(n.Right) - w.stmtList(n.Nbody) - - case OSELECT, OSWITCH: + w.pos(n.Pos()) + w.expr(n.Left()) + + case ir.OIF: + w.op(ir.OIF) + w.pos(n.Pos()) + w.stmtList(n.Init()) + w.expr(n.Left()) + w.stmtList(n.Body()) + w.stmtList(n.Rlist()) + + case ir.OFOR: + w.op(ir.OFOR) + w.pos(n.Pos()) + w.stmtList(n.Init()) + w.exprsOrNil(n.Left(), n.Right()) + w.stmtList(n.Body()) + + case ir.ORANGE: + w.op(ir.ORANGE) + w.pos(n.Pos()) + w.stmtList(n.List()) + w.expr(n.Right()) + w.stmtList(n.Body()) + + case ir.OSELECT, ir.OSWITCH: w.op(op) - w.pos(n.Pos) - w.stmtList(n.Ninit) - w.exprsOrNil(n.Left, nil) + w.pos(n.Pos()) + w.stmtList(n.Init()) + w.exprsOrNil(n.Left(), nil) w.caseList(n) // case OCASE: // handled by caseList - case OFALL: - w.op(OFALL) - w.pos(n.Pos) + case ir.OFALL: + w.op(ir.OFALL) + w.pos(n.Pos()) - case OBREAK, OCONTINUE: + case ir.OBREAK, ir.OCONTINUE: w.op(op) - w.pos(n.Pos) - w.exprsOrNil(n.Left, nil) + w.pos(n.Pos()) + w.exprsOrNil(n.Left(), nil) - case OEMPTY: + case ir.OEMPTY: // nothing to emit - case OGOTO, OLABEL: + case ir.OGOTO, ir.OLABEL: w.op(op) - w.pos(n.Pos) - w.string(n.Sym.Name) + w.pos(n.Pos()) + w.string(n.Sym().Name) default: - Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op) + base.Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op()) } } -func (w *exportWriter) caseList(sw *Node) { - namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil +func (w *exportWriter) caseList(sw ir.Node) { + namedTypeSwitch := sw.Op() == ir.OSWITCH && sw.Left() != nil && sw.Left().Op() == ir.OTYPESW && sw.Left().Left() != nil - cases := sw.List.Slice() + cases := sw.List().Slice() w.uint64(uint64(len(cases))) for _, cas := range cases { - if cas.Op != OCASE { - Fatalf("expected OCASE, got %v", cas) + if cas.Op() != ir.OCASE { + base.Fatalf("expected OCASE, got %v", cas) } - w.pos(cas.Pos) - w.stmtList(cas.List) + w.pos(cas.Pos()) + w.stmtList(cas.List()) if namedTypeSwitch { - w.localName(cas.Rlist.First()) + w.localName(cas.Rlist().First()) } - w.stmtList(cas.Nbody) + w.stmtList(cas.Body()) } } -func (w *exportWriter) exprList(list Nodes) { +func (w *exportWriter) exprList(list ir.Nodes) { for _, n := range list.Slice() { w.expr(n) } - w.op(OEND) + w.op(ir.OEND) } -func (w *exportWriter) expr(n *Node) { +func (w *exportWriter) expr(n ir.Node) { // from nodefmt (fmt.go) // // nodefmt reverts nodes back to their original - we don't need to do @@ -1201,64 +1200,70 @@ func (w *exportWriter) expr(n *Node) { // } // from exprfmt (fmt.go) - for n.Op == OPAREN || n.Implicit() && (n.Op == ODEREF || n.Op == OADDR || n.Op == ODOT || n.Op == ODOTPTR) { - n = n.Left + for n.Op() == ir.OPAREN || n.Implicit() && (n.Op() == ir.ODEREF || n.Op() == ir.OADDR || n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR) { + n = n.Left() } - switch op := n.Op; op { + switch op := n.Op(); op { // expressions // (somewhat closely following the structure of exprfmt in fmt.go) - case OLITERAL: - if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n { - w.expr(n.Orig) + case ir.ONIL: + if !n.Type().HasNil() { + base.Fatalf("unexpected type for nil: %v", n.Type()) + } + if n.Orig() != nil && n.Orig() != n { + w.expr(n.Orig()) break } - w.op(OLITERAL) - w.pos(n.Pos) - w.value(n.Type, n.Val()) + w.op(ir.OLITERAL) + w.pos(n.Pos()) + w.typ(n.Type()) - case ONAME: + case ir.OLITERAL: + w.op(ir.OLITERAL) + w.pos(n.Pos()) + w.value(n.Type(), n.Val()) + + case ir.OMETHEXPR: // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method, // but for export, this should be rendered as (*pkg.T).meth. // These nodes have the special property that they are names with a left OTYPE and a right ONAME. - if n.isMethodExpression() { - w.op(OXDOT) - w.pos(n.Pos) - w.expr(n.Left) // n.Left.Op == OTYPE - w.selector(n.Right.Sym) - break - } + w.op(ir.OXDOT) + w.pos(n.Pos()) + w.expr(n.Left()) // n.Left.Op == OTYPE + w.selector(n.Right().Sym()) + case ir.ONAME: // Package scope name. - if (n.Class() == PEXTERN || n.Class() == PFUNC) && !n.isBlank() { - w.op(ONONAME) + if (n.Class() == ir.PEXTERN || n.Class() == ir.PFUNC) && !ir.IsBlank(n) { + w.op(ir.ONONAME) w.qualifiedIdent(n) break } // Function scope name. - w.op(ONAME) + w.op(ir.ONAME) w.localName(n) // case OPACK, ONONAME: // should have been resolved by typechecking - handled by default case - case OTYPE: - w.op(OTYPE) - w.typ(n.Type) + case ir.OTYPE: + w.op(ir.OTYPE) + w.typ(n.Type()) - case OTYPESW: - w.op(OTYPESW) - w.pos(n.Pos) + case ir.OTYPESW: + w.op(ir.OTYPESW) + w.pos(n.Pos()) var s *types.Sym - if n.Left != nil { - if n.Left.Op != ONONAME { - Fatalf("expected ONONAME, got %v", n.Left) + if n.Left() != nil { + if n.Left().Op() != ir.ONONAME { + base.Fatalf("expected ONONAME, got %v", n.Left()) } - s = n.Left.Sym + s = n.Left().Sym() } w.localIdent(s, 0) // declared pseudo-variable, if any - w.exprsOrNil(n.Right, nil) + w.exprsOrNil(n.Right(), nil) // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: // should have been resolved by typechecking - handled by default case @@ -1269,163 +1274,163 @@ func (w *exportWriter) expr(n *Node) { // case OCOMPLIT: // should have been resolved by typechecking - handled by default case - case OPTRLIT: - w.op(OADDR) - w.pos(n.Pos) - w.expr(n.Left) + case ir.OPTRLIT: + w.op(ir.OADDR) + w.pos(n.Pos()) + w.expr(n.Left()) - case OSTRUCTLIT: - w.op(OSTRUCTLIT) - w.pos(n.Pos) - w.typ(n.Type) - w.elemList(n.List) // special handling of field names + case ir.OSTRUCTLIT: + w.op(ir.OSTRUCTLIT) + w.pos(n.Pos()) + w.typ(n.Type()) + w.elemList(n.List()) // special handling of field names - case OARRAYLIT, OSLICELIT, OMAPLIT: - w.op(OCOMPLIT) - w.pos(n.Pos) - w.typ(n.Type) - w.exprList(n.List) + case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT: + w.op(ir.OCOMPLIT) + w.pos(n.Pos()) + w.typ(n.Type()) + w.exprList(n.List()) - case OKEY: - w.op(OKEY) - w.pos(n.Pos) - w.exprsOrNil(n.Left, n.Right) + case ir.OKEY: + w.op(ir.OKEY) + w.pos(n.Pos()) + w.exprsOrNil(n.Left(), n.Right()) // case OSTRUCTKEY: // unreachable - handled in case OSTRUCTLIT by elemList - case OCALLPART: + case ir.OCALLPART: // An OCALLPART is an OXDOT before type checking. - w.op(OXDOT) - w.pos(n.Pos) - w.expr(n.Left) + w.op(ir.OXDOT) + w.pos(n.Pos()) + w.expr(n.Left()) // Right node should be ONAME - w.selector(n.Right.Sym) - - case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: - w.op(OXDOT) - w.pos(n.Pos) - w.expr(n.Left) - w.selector(n.Sym) - - case ODOTTYPE, ODOTTYPE2: - w.op(ODOTTYPE) - w.pos(n.Pos) - w.expr(n.Left) - w.typ(n.Type) - - case OINDEX, OINDEXMAP: - w.op(OINDEX) - w.pos(n.Pos) - w.expr(n.Left) - w.expr(n.Right) - - case OSLICE, OSLICESTR, OSLICEARR: - w.op(OSLICE) - w.pos(n.Pos) - w.expr(n.Left) + w.selector(n.Right().Sym()) + + case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH: + w.op(ir.OXDOT) + w.pos(n.Pos()) + w.expr(n.Left()) + w.selector(n.Sym()) + + case ir.ODOTTYPE, ir.ODOTTYPE2: + w.op(ir.ODOTTYPE) + w.pos(n.Pos()) + w.expr(n.Left()) + w.typ(n.Type()) + + case ir.OINDEX, ir.OINDEXMAP: + w.op(ir.OINDEX) + w.pos(n.Pos()) + w.expr(n.Left()) + w.expr(n.Right()) + + case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR: + w.op(ir.OSLICE) + w.pos(n.Pos()) + w.expr(n.Left()) low, high, _ := n.SliceBounds() w.exprsOrNil(low, high) - case OSLICE3, OSLICE3ARR: - w.op(OSLICE3) - w.pos(n.Pos) - w.expr(n.Left) + case ir.OSLICE3, ir.OSLICE3ARR: + w.op(ir.OSLICE3) + w.pos(n.Pos()) + w.expr(n.Left()) low, high, max := n.SliceBounds() w.exprsOrNil(low, high) w.expr(max) - case OCOPY, OCOMPLEX: + case ir.OCOPY, ir.OCOMPLEX: // treated like other builtin calls (see e.g., OREAL) w.op(op) - w.pos(n.Pos) - w.expr(n.Left) - w.expr(n.Right) - w.op(OEND) - - case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR: - w.op(OCONV) - w.pos(n.Pos) - w.expr(n.Left) - w.typ(n.Type) - - case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN: + w.pos(n.Pos()) + w.expr(n.Left()) + w.expr(n.Right()) + w.op(ir.OEND) + + case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR: + w.op(ir.OCONV) + w.pos(n.Pos()) + w.expr(n.Left()) + w.typ(n.Type()) + + case ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN: w.op(op) - w.pos(n.Pos) - if n.Left != nil { - w.expr(n.Left) - w.op(OEND) + w.pos(n.Pos()) + if n.Left() != nil { + w.expr(n.Left()) + w.op(ir.OEND) } else { - w.exprList(n.List) // emits terminating OEND + w.exprList(n.List()) // emits terminating OEND } // only append() calls may contain '...' arguments - if op == OAPPEND { + if op == ir.OAPPEND { w.bool(n.IsDDD()) } else if n.IsDDD() { - Fatalf("exporter: unexpected '...' with %v call", op) + base.Fatalf("exporter: unexpected '...' with %v call", op) } - case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: - w.op(OCALL) - w.pos(n.Pos) - w.stmtList(n.Ninit) - w.expr(n.Left) - w.exprList(n.List) + case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG: + w.op(ir.OCALL) + w.pos(n.Pos()) + w.stmtList(n.Init()) + w.expr(n.Left()) + w.exprList(n.List()) w.bool(n.IsDDD()) - case OMAKEMAP, OMAKECHAN, OMAKESLICE: + case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE: w.op(op) // must keep separate from OMAKE for importer - w.pos(n.Pos) - w.typ(n.Type) + w.pos(n.Pos()) + w.typ(n.Type()) switch { default: // empty list - w.op(OEND) - case n.List.Len() != 0: // pre-typecheck - w.exprList(n.List) // emits terminating OEND - case n.Right != nil: - w.expr(n.Left) - w.expr(n.Right) - w.op(OEND) - case n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()): - w.expr(n.Left) - w.op(OEND) + w.op(ir.OEND) + case n.List().Len() != 0: // pre-typecheck + w.exprList(n.List()) // emits terminating OEND + case n.Right() != nil: + w.expr(n.Left()) + w.expr(n.Right()) + w.op(ir.OEND) + case n.Left() != nil && (n.Op() == ir.OMAKESLICE || !n.Left().Type().IsUntyped()): + w.expr(n.Left()) + w.op(ir.OEND) } // unary expressions - case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV: + case ir.OPLUS, ir.ONEG, ir.OADDR, ir.OBITNOT, ir.ODEREF, ir.ONOT, ir.ORECV: w.op(op) - w.pos(n.Pos) - w.expr(n.Left) + w.pos(n.Pos()) + w.expr(n.Left()) // binary expressions - case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT, - OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR: + case ir.OADD, ir.OAND, ir.OANDAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, + ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.OOROR, ir.ORSH, ir.OSEND, ir.OSUB, ir.OXOR: w.op(op) - w.pos(n.Pos) - w.expr(n.Left) - w.expr(n.Right) + w.pos(n.Pos()) + w.expr(n.Left()) + w.expr(n.Right()) - case OADDSTR: - w.op(OADDSTR) - w.pos(n.Pos) - w.exprList(n.List) + case ir.OADDSTR: + w.op(ir.OADDSTR) + w.pos(n.Pos()) + w.exprList(n.List()) - case ODCLCONST: + case ir.ODCLCONST: // if exporting, DCLCONST should just be removed as its usage // has already been replaced with literals default: - Fatalf("cannot export %v (%d) node\n"+ - "\t==> please file an issue and assign to gri@", n.Op, int(n.Op)) + base.Fatalf("cannot export %v (%d) node\n"+ + "\t==> please file an issue and assign to gri@", n.Op(), int(n.Op())) } } -func (w *exportWriter) op(op Op) { +func (w *exportWriter) op(op ir.Op) { w.uint64(uint64(op)) } -func (w *exportWriter) exprsOrNil(a, b *Node) { +func (w *exportWriter) exprsOrNil(a, b ir.Node) { ab := 0 if a != nil { ab |= 1 @@ -1442,15 +1447,15 @@ func (w *exportWriter) exprsOrNil(a, b *Node) { } } -func (w *exportWriter) elemList(list Nodes) { +func (w *exportWriter) elemList(list ir.Nodes) { w.uint64(uint64(list.Len())) for _, n := range list.Slice() { - w.selector(n.Sym) - w.expr(n.Left) + w.selector(n.Sym()) + w.expr(n.Left()) } } -func (w *exportWriter) localName(n *Node) { +func (w *exportWriter) localName(n ir.Node) { // Escape analysis happens after inline bodies are saved, but // we're using the same ONAME nodes, so we might still see // PAUTOHEAP here. @@ -1459,11 +1464,11 @@ func (w *exportWriter) localName(n *Node) { // PPARAM/PPARAMOUT, because we only want to include vargen in // non-param names. var v int32 - if n.Class() == PAUTO || (n.Class() == PAUTOHEAP && n.Name.Param.Stackcopy == nil) { - v = n.Name.Vargen + if n.Class() == ir.PAUTO || (n.Class() == ir.PAUTOHEAP && n.Name().Param.Stackcopy == nil) { + v = n.Name().Vargen } - w.localIdent(n.Sym, v) + w.localIdent(n.Sym(), v) } func (w *exportWriter) localIdent(s *types.Sym, v int32) { @@ -1481,18 +1486,18 @@ func (w *exportWriter) localIdent(s *types.Sym, v int32) { // TODO(mdempsky): Fix autotmp hack. if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, ".autotmp_") { - Fatalf("unexpected dot in identifier: %v", name) + base.Fatalf("unexpected dot in identifier: %v", name) } if v > 0 { if strings.Contains(name, "·") { - Fatalf("exporter: unexpected · in symbol name") + base.Fatalf("exporter: unexpected · in symbol name") } name = fmt.Sprintf("%s·%d", name, v) } if !types.IsExported(name) && s.Pkg != w.currPkg { - Fatalf("weird package in name: %v => %v, not %q", s, name, w.currPkg.Path) + base.Fatalf("weird package in name: %v => %v, not %q", s, name, w.currPkg.Path) } w.string(name) |