Commit 5f525ca6 authored by Ian Lance Taylor's avatar Ian Lance Taylor

cmd/compile: change ODOT and friends to use Sym, not Right

The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot.  Before this change this was
represented by using an ONAME Node in the Right field.  This ONAME node
served no useful purpose.  This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.

When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.

Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before.  One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node.  The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now.  I will send separate CLs,
that will break toolstash -cmp, to clean these up.

This CL passes toolstash -cmp.

Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent fc6bcdee
...@@ -112,7 +112,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { ...@@ -112,7 +112,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
// A special case to make write barriers more efficient. // A special case to make write barriers more efficient.
// Comparing the first field of a named struct can be done directly. // Comparing the first field of a named struct can be done directly.
base := n1 base := n1
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Right.Sym { if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Sym {
base = n1.Left base = n1.Left
} }
......
...@@ -242,7 +242,7 @@ func genhash(sym *Sym, t *Type) { ...@@ -242,7 +242,7 @@ func genhash(sym *Sym, t *Type) {
if algtype1(f.Type, nil) != AMEM { if algtype1(f.Type, nil) != AMEM {
hashel := hashfor(f.Type) hashel := hashfor(f.Type)
call := Nod(OCALL, hashel, nil) call := Nod(OCALL, hashel, nil)
nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages? nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
na := Nod(OADDR, nx, nil) na := Nod(OADDR, nx, nil)
na.Etype = 1 // no escape to heap na.Etype = 1 // no escape to heap
call.List.Append(na) call.List.Append(na)
...@@ -258,7 +258,7 @@ func genhash(sym *Sym, t *Type) { ...@@ -258,7 +258,7 @@ func genhash(sym *Sym, t *Type) {
// h = hashel(&p.first, size, h) // h = hashel(&p.first, size, h)
hashel := hashmem(f.Type) hashel := hashmem(f.Type)
call := Nod(OCALL, hashel, nil) call := Nod(OCALL, hashel, nil)
nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages? nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
na := Nod(OADDR, nx, nil) na := Nod(OADDR, nx, nil)
na.Etype = 1 // no escape to heap na.Etype = 1 // no escape to heap
call.List.Append(na) call.List.Append(na)
...@@ -436,7 +436,7 @@ func geneq(sym *Sym, t *Type) { ...@@ -436,7 +436,7 @@ func geneq(sym *Sym, t *Type) {
// Compare non-memory fields with field equality. // Compare non-memory fields with field equality.
if algtype1(f.Type, nil) != AMEM { if algtype1(f.Type, nil) != AMEM {
and(eqfield(np, nq, newname(f.Sym))) and(eqfield(np, nq, f.Sym))
i++ i++
continue continue
} }
...@@ -449,11 +449,11 @@ func geneq(sym *Sym, t *Type) { ...@@ -449,11 +449,11 @@ func geneq(sym *Sym, t *Type) {
if s := fields[i:next]; len(s) <= 2 { if s := fields[i:next]; len(s) <= 2 {
// Two or fewer fields: use plain field equality. // Two or fewer fields: use plain field equality.
for _, f := range s { for _, f := range s {
and(eqfield(np, nq, newname(f.Sym))) and(eqfield(np, nq, f.Sym))
} }
} else { } else {
// More than two fields: use memequal. // More than two fields: use memequal.
and(eqmem(np, nq, newname(f.Sym), size)) and(eqmem(np, nq, f.Sym, size))
} }
i = next i = next
} }
...@@ -502,19 +502,19 @@ func geneq(sym *Sym, t *Type) { ...@@ -502,19 +502,19 @@ func geneq(sym *Sym, t *Type) {
// eqfield returns the node // eqfield returns the node
// p.field == q.field // p.field == q.field
func eqfield(p *Node, q *Node, field *Node) *Node { func eqfield(p *Node, q *Node, field *Sym) *Node {
nx := Nod(OXDOT, p, field) nx := NodSym(OXDOT, p, field)
ny := Nod(OXDOT, q, field) ny := NodSym(OXDOT, q, field)
ne := Nod(OEQ, nx, ny) ne := Nod(OEQ, nx, ny)
return ne return ne
} }
// eqmem returns the node // eqmem returns the node
// memequal(&p.field, &q.field [, size]) // memequal(&p.field, &q.field [, size])
func eqmem(p *Node, q *Node, field *Node, size int64) *Node { func eqmem(p *Node, q *Node, field *Sym, size int64) *Node {
nx := Nod(OADDR, Nod(OXDOT, p, field), nil) nx := Nod(OADDR, NodSym(OXDOT, p, field), nil)
nx.Etype = 1 // does not escape nx.Etype = 1 // does not escape
ny := Nod(OADDR, Nod(OXDOT, q, field), nil) ny := Nod(OADDR, NodSym(OXDOT, q, field), nil)
ny.Etype = 1 // does not escape ny.Etype = 1 // does not escape
typecheck(&nx, Erv) typecheck(&nx, Erv)
typecheck(&ny, Erv) typecheck(&ny, Erv)
......
...@@ -890,7 +890,7 @@ func (p *exporter) node(n *Node) { ...@@ -890,7 +890,7 @@ func (p *exporter) node(n *Node) {
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT: case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
p.node(n.Left) p.node(n.Left)
p.sym(n.Right.Sym) p.sym(n.Sym)
case ODOTTYPE, ODOTTYPE2: case ODOTTYPE, ODOTTYPE2:
p.node(n.Left) p.node(n.Left)
......
...@@ -658,7 +658,7 @@ func (p *importer) node() *Node { ...@@ -658,7 +658,7 @@ func (p *importer) node() *Node {
obj.Used = true obj.Used = true
return oldname(s) return oldname(s)
} }
return Nod(OXDOT, obj, newname(sel)) return NodSym(OXDOT, obj, sel)
case ODOTTYPE, ODOTTYPE2: case ODOTTYPE, ODOTTYPE2:
n.Left = p.node() n.Left = p.node()
......
...@@ -802,7 +802,7 @@ func cgen_wbptr(n, res *Node) { ...@@ -802,7 +802,7 @@ func cgen_wbptr(n, res *Node) {
} }
wbVar := syslook("writeBarrier") wbVar := syslook("writeBarrier")
wbEnabled := Nod(ODOT, wbVar, newname(wbVar.Type.Field(0).Sym)) wbEnabled := NodSym(ODOT, wbVar, wbVar.Type.Field(0).Sym)
wbEnabled = typecheck(&wbEnabled, Erv) wbEnabled = typecheck(&wbEnabled, Erv)
pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1) pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst) Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
...@@ -2440,11 +2440,6 @@ func cgen_callinter(n *Node, res *Node, proc int) { ...@@ -2440,11 +2440,6 @@ func cgen_callinter(n *Node, res *Node, proc int) {
Fatalf("cgen_callinter: not ODOTINTER %v", Oconv(i.Op, 0)) Fatalf("cgen_callinter: not ODOTINTER %v", Oconv(i.Op, 0))
} }
f := i.Right // field
if f.Op != ONAME {
Fatalf("cgen_callinter: not ONAME %v", Oconv(f.Op, 0))
}
i = i.Left // interface i = i.Left // interface
if !i.Addable { if !i.Addable {
......
...@@ -462,7 +462,7 @@ func walkclosure(func_ *Node, init *Nodes) *Node { ...@@ -462,7 +462,7 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
return clos return clos
} }
func typecheckpartialcall(fn *Node, sym *Node) { func typecheckpartialcall(fn *Node, sym *Sym) {
switch fn.Op { switch fn.Op {
case ODOTINTER, ODOTMETH: case ODOTINTER, ODOTMETH:
break break
...@@ -474,21 +474,21 @@ func typecheckpartialcall(fn *Node, sym *Node) { ...@@ -474,21 +474,21 @@ func typecheckpartialcall(fn *Node, sym *Node) {
// Create top-level function. // Create top-level function.
xfunc := makepartialcall(fn, fn.Type, sym) xfunc := makepartialcall(fn, fn.Type, sym)
fn.Func = xfunc.Func fn.Func = xfunc.Func
fn.Right = sym fn.Right = newname(sym)
fn.Op = OCALLPART fn.Op = OCALLPART
fn.Type = xfunc.Type fn.Type = xfunc.Type
} }
var makepartialcall_gopkg *Pkg var makepartialcall_gopkg *Pkg
func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node { func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
var p string var p string
rcvrtype := fn.Left.Type rcvrtype := fn.Left.Type
if exportname(meth.Sym.Name) { if exportname(meth.Name) {
p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Sym.Name) p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Name)
} else { } else {
p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, FmtLeft|FmtShort), Sconv(meth.Sym, FmtLeft)) p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, FmtLeft|FmtShort), Sconv(meth, FmtLeft))
} }
basetype := rcvrtype basetype := rcvrtype
if Isptr[rcvrtype.Etype] { if Isptr[rcvrtype.Etype] {
...@@ -592,7 +592,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node { ...@@ -592,7 +592,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
body = append(body, Nod(OAS, ptr, Nod(OADDR, cv, nil))) body = append(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
} }
call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil) call := Nod(OCALL, NodSym(OXDOT, ptr, meth), nil)
call.List.Set(callargs) call.List.Set(callargs)
call.Isddd = ddd call.Isddd = ddd
if t0.Results().NumFields() == 0 { if t0.Results().NumFields() == 0 {
......
...@@ -1432,7 +1432,7 @@ func (c *nowritebarrierrecChecker) visitcode(n *Node) { ...@@ -1432,7 +1432,7 @@ func (c *nowritebarrierrecChecker) visitcode(n *Node) {
func (c *nowritebarrierrecChecker) visitcall(n *Node) { func (c *nowritebarrierrecChecker) visitcall(n *Node) {
fn := n.Left fn := n.Left
if n.Op == OCALLMETH { if n.Op == OCALLMETH {
fn = n.Left.Right.Sym.Def fn = n.Left.Sym.Def
} }
if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil { if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil {
return return
......
...@@ -131,7 +131,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 { ...@@ -131,7 +131,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
if n.Op == OCALLFUNC || n.Op == OCALLMETH { if n.Op == OCALLFUNC || n.Op == OCALLMETH {
fn := n.Left fn := n.Left
if n.Op == OCALLMETH { if n.Op == OCALLMETH {
fn = n.Left.Right.Sym.Def fn = n.Left.Sym.Def
} }
if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil { if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil {
m := v.visit(fn.Name.Defn) m := v.visit(fn.Name.Defn)
...@@ -1421,7 +1421,7 @@ func esccall(e *EscState, n *Node, up *Node) { ...@@ -1421,7 +1421,7 @@ func esccall(e *EscState, n *Node, up *Node) {
indirect = fn.Op != ONAME || fn.Class != PFUNC indirect = fn.Op != ONAME || fn.Class != PFUNC
case OCALLMETH: case OCALLMETH:
fn = n.Left.Right.Sym.Def fn = n.Left.Sym.Def
if fn != nil { if fn != nil {
fntype = fn.Type fntype = fn.Type
} else { } else {
......
...@@ -1249,12 +1249,7 @@ func exprfmt(n *Node, prec int) string { ...@@ -1249,12 +1249,7 @@ func exprfmt(n *Node, prec int) string {
} }
return ":" return ":"
case OXDOT, case OCALLPART:
ODOT,
ODOTPTR,
ODOTINTER,
ODOTMETH,
OCALLPART:
var f string var f string
f += exprfmt(n.Left, nprec) f += exprfmt(n.Left, nprec)
if n.Right == nil || n.Right.Sym == nil { if n.Right == nil || n.Right.Sym == nil {
...@@ -1264,6 +1259,16 @@ func exprfmt(n *Node, prec int) string { ...@@ -1264,6 +1259,16 @@ func exprfmt(n *Node, prec int) string {
f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, FmtShort|FmtByte)) f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, FmtShort|FmtByte))
return f return f
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
var f string
f += exprfmt(n.Left, nprec)
if n.Sym == nil {
f += ".<nil>"
return f
}
f += fmt.Sprintf(".%v", Sconv(n.Sym, FmtShort|FmtByte))
return f
case ODOTTYPE, ODOTTYPE2: case ODOTTYPE, ODOTTYPE2:
var f string var f string
f += exprfmt(n.Left, nprec) f += exprfmt(n.Left, nprec)
......
...@@ -948,7 +948,7 @@ func cgen_callmeth(n *Node, proc int) { ...@@ -948,7 +948,7 @@ func cgen_callmeth(n *Node, proc int) {
n2 := *n n2 := *n
n2.Op = OCALLFUNC n2.Op = OCALLFUNC
n2.Left = l.Right n2.Left = newname(l.Sym)
n2.Left.Type = l.Type n2.Left.Type = l.Type
if n2.Left.Op == ONAME { if n2.Left.Op == ONAME {
......
...@@ -416,7 +416,7 @@ func Naddr(a *obj.Addr, n *Node) { ...@@ -416,7 +416,7 @@ func Naddr(a *obj.Addr, n *Node) {
// A special case to make write barriers more efficient. // A special case to make write barriers more efficient.
// Taking the address of the first field of a named struct // Taking the address of the first field of a named struct
// is the same as taking the address of the struct. // is the same as taking the address of the struct.
if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Field(0).Sym != n.Right.Sym { if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Field(0).Sym != n.Sym {
Debug['h'] = 1 Debug['h'] = 1
Dump("naddr", n) Dump("naddr", n)
Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a)) Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a))
......
...@@ -220,6 +220,13 @@ func ishairy(n *Node, budget *int) bool { ...@@ -220,6 +220,13 @@ func ishairy(n *Node, budget *int) bool {
ODCLTYPE, // can't print yet ODCLTYPE, // can't print yet
ORETJMP: ORETJMP:
return true return true
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER:
// These used to store the symbol name as an ONAME in
// the Right field, meaning that it cost one budget
// unit. Stay compatible for now.
// TODO(iant): Remove this.
(*budget)--
} }
(*budget)-- (*budget)--
......
...@@ -1793,7 +1793,7 @@ func (p *parser) new_dotname(obj *Node) *Node { ...@@ -1793,7 +1793,7 @@ func (p *parser) new_dotname(obj *Node) *Node {
obj.Used = true obj.Used = true
return oldname(s) return oldname(s)
} }
return Nod(OXDOT, obj, newname(sel)) return NodSym(OXDOT, obj, sel)
} }
func (p *parser) dotname() *Node { func (p *parser) dotname() *Node {
......
...@@ -226,27 +226,27 @@ func walkrange(n *Node) { ...@@ -226,27 +226,27 @@ func walkrange(n *Node) {
hit := prealloc[n] hit := prealloc[n]
hit.Type = th hit.Type = th
n.Left = nil n.Left = nil
keyname := newname(th.Field(0).Sym) // depends on layout of iterator struct. See reflect.go:hiter keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:hiter
valname := newname(th.Field(1).Sym) // ditto valsym := th.Field(1).Sym // ditto
fn := syslook("mapiterinit") fn := syslook("mapiterinit")
substArgTypes(&fn, t.Key(), t.Type, th) substArgTypes(&fn, t.Key(), t.Type, th)
init = append(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil))) init = append(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil()) n.Left = Nod(ONE, NodSym(ODOT, hit, keysym), nodnil())
fn = syslook("mapiternext") fn = syslook("mapiternext")
substArgTypes(&fn, th) substArgTypes(&fn, th)
n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil)) n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
key := Nod(ODOT, hit, keyname) key := NodSym(ODOT, hit, keysym)
key = Nod(OIND, key, nil) key = Nod(OIND, key, nil)
if v1 == nil { if v1 == nil {
body = nil body = nil
} else if v2 == nil { } else if v2 == nil {
body = []*Node{Nod(OAS, v1, key)} body = []*Node{Nod(OAS, v1, key)}
} else { } else {
val := Nod(ODOT, hit, valname) val := NodSym(ODOT, hit, valsym)
val = Nod(OIND, val, nil) val = Nod(OIND, val, nil)
a := Nod(OAS2, nil, nil) a := Nod(OAS2, nil, nil)
a.List.Set([]*Node{v1, v2}) a.List.Set([]*Node{v1, v2})
......
...@@ -574,10 +574,10 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) { ...@@ -574,10 +574,10 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
case OARRAYLIT: case OARRAYLIT:
if value.Type.Bound < 0 { if value.Type.Bound < 0 {
if pass == 1 && ctxt != 0 { if pass == 1 && ctxt != 0 {
a = Nod(ODOT, var_, newname(index.Sym)) a = NodSym(ODOT, var_, index.Sym)
slicelit(ctxt, value, a, init) slicelit(ctxt, value, a, init)
} else if pass == 2 && ctxt == 0 { } else if pass == 2 && ctxt == 0 {
a = Nod(ODOT, var_, newname(index.Sym)) a = NodSym(ODOT, var_, index.Sym)
slicelit(ctxt, value, a, init) slicelit(ctxt, value, a, init)
} else if pass == 3 { } else if pass == 3 {
break break
...@@ -585,12 +585,12 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) { ...@@ -585,12 +585,12 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
continue continue
} }
a = Nod(ODOT, var_, newname(index.Sym)) a = NodSym(ODOT, var_, index.Sym)
arraylit(ctxt, pass, value, a, init) arraylit(ctxt, pass, value, a, init)
continue continue
case OSTRUCTLIT: case OSTRUCTLIT:
a = Nod(ODOT, var_, newname(index.Sym)) a = NodSym(ODOT, var_, index.Sym)
structlit(ctxt, pass, value, a, init) structlit(ctxt, pass, value, a, init)
continue continue
} }
...@@ -605,7 +605,7 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) { ...@@ -605,7 +605,7 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
// build list of var.field = expr // build list of var.field = expr
setlineno(value) setlineno(value)
a = Nod(ODOT, var_, newname(index.Sym)) a = NodSym(ODOT, var_, index.Sym)
a = Nod(OAS, a, value) a = Nod(OAS, a, value)
typecheck(&a, Etop) typecheck(&a, Etop)
...@@ -904,7 +904,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) { ...@@ -904,7 +904,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
a = Nodintconst(b) a = Nodintconst(b)
a = Nod(OINDEX, vstat, a) a = Nod(OINDEX, vstat, a)
a = Nod(ODOT, a, newname(syma)) a = NodSym(ODOT, a, syma)
a = Nod(OAS, a, index) a = Nod(OAS, a, index)
typecheck(&a, Etop) typecheck(&a, Etop)
walkexpr(&a, init) walkexpr(&a, init)
...@@ -916,7 +916,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) { ...@@ -916,7 +916,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
a = Nodintconst(b) a = Nodintconst(b)
a = Nod(OINDEX, vstat, a) a = Nod(OINDEX, vstat, a)
a = Nod(ODOT, a, newname(symb)) a = NodSym(ODOT, a, symb)
a = Nod(OAS, a, value) a = Nod(OAS, a, value)
typecheck(&a, Etop) typecheck(&a, Etop)
walkexpr(&a, init) walkexpr(&a, init)
...@@ -935,11 +935,11 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) { ...@@ -935,11 +935,11 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
a = Nod(OINDEX, vstat, index) a = Nod(OINDEX, vstat, index)
a.Bounded = true a.Bounded = true
a = Nod(ODOT, a, newname(symb)) a = NodSym(ODOT, a, symb)
r := Nod(OINDEX, vstat, index) r := Nod(OINDEX, vstat, index)
r.Bounded = true r.Bounded = true
r = Nod(ODOT, r, newname(syma)) r = NodSym(ODOT, r, syma)
r = Nod(OINDEX, var_, r) r = Nod(OINDEX, var_, r)
r = Nod(OAS, r, a) r = Nod(OAS, r, a)
......
...@@ -2326,16 +2326,14 @@ func (s *state) call(n *Node, k callKind) *ssa.Value { ...@@ -2326,16 +2326,14 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
if fn.Op != ODOTMETH { if fn.Op != ODOTMETH {
Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn) Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
} }
if fn.Right.Op != ONAME {
Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
}
if k == callNormal { if k == callNormal {
sym = fn.Right.Sym sym = fn.Sym
break break
} }
n2 := *fn.Right n2 := newname(fn.Sym)
n2.Class = PFUNC n2.Class = PFUNC
closure = s.expr(&n2) n2.Lineno = fn.Lineno
closure = s.expr(n2)
// Note: receiver is already assigned in n.List, so we don't // Note: receiver is already assigned in n.List, so we don't
// want to set it here. // want to set it here.
case OCALLINTER: case OCALLINTER:
...@@ -3967,14 +3965,14 @@ func AutoVar(v *ssa.Value) (*Node, int64) { ...@@ -3967,14 +3965,14 @@ func AutoVar(v *ssa.Value) (*Node, int64) {
// fieldIdx finds the index of the field referred to by the ODOT node n. // fieldIdx finds the index of the field referred to by the ODOT node n.
func fieldIdx(n *Node) int { func fieldIdx(n *Node) int {
t := n.Left.Type t := n.Left.Type
f := n.Right f := n.Sym
if t.Etype != TSTRUCT { if t.Etype != TSTRUCT {
panic("ODOT's LHS is not a struct") panic("ODOT's LHS is not a struct")
} }
var i int var i int
for _, t1 := range t.Fields().Slice() { for _, t1 := range t.Fields().Slice() {
if t1.Sym != f.Sym { if t1.Sym != f {
i++ i++
continue continue
} }
......
...@@ -339,6 +339,14 @@ func Nod(op Op, nleft *Node, nright *Node) *Node { ...@@ -339,6 +339,14 @@ func Nod(op Op, nleft *Node, nright *Node) *Node {
return n return n
} }
// NodSym makes a Node with Op op and with the Left field set to left
// and the Sym field set to sym. This is for ODOT and friends.
func NodSym(op Op, left *Node, sym *Sym) *Node {
n := Nod(op, left, nil)
n.Sym = sym
return n
}
func saveorignode(n *Node) { func saveorignode(n *Node) {
if n.Orig != nil { if n.Orig != nil {
return return
...@@ -1677,10 +1685,7 @@ func adddot(n *Node) *Node { ...@@ -1677,10 +1685,7 @@ func adddot(n *Node) *Node {
return n return n
} }
if n.Right.Op != ONAME { s := n.Sym
return n
}
s := n.Right.Sym
if s == nil { if s == nil {
return n return n
} }
...@@ -1689,7 +1694,7 @@ func adddot(n *Node) *Node { ...@@ -1689,7 +1694,7 @@ func adddot(n *Node) *Node {
case path != nil: case path != nil:
// rebuild elided dots // rebuild elided dots
for c := len(path) - 1; c >= 0; c-- { for c := len(path) - 1; c >= 0; c-- {
n.Left = Nod(ODOT, n.Left, newname(path[c].field.Sym)) n.Left = NodSym(ODOT, n.Left, path[c].field.Sym)
n.Left.Implicit = true n.Left.Implicit = true
} }
case ambig: case ambig:
...@@ -1960,7 +1965,7 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) { ...@@ -1960,7 +1965,7 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
fn.Nbody.Append(n) fn.Nbody.Append(n)
} }
dot := adddot(Nod(OXDOT, this.Left, newname(method.Sym))) dot := adddot(NodSym(OXDOT, this.Left, method.Sym))
// generate call // generate call
if !instrumenting && Isptr[rcvr.Etype] && Isptr[methodrcvr.Etype] && method.Embedded != 0 && !isifacemethod(method.Type) { if !instrumenting && Isptr[rcvr.Etype] && Isptr[methodrcvr.Etype] && method.Embedded != 0 && !isifacemethod(method.Type) {
......
...@@ -595,14 +595,14 @@ func (s *typeSwitch) walk(sw *Node) { ...@@ -595,14 +595,14 @@ func (s *typeSwitch) walk(sw *Node) {
if !isnilinter(cond.Right.Type) { if !isnilinter(cond.Right.Type) {
// Load type from itab. // Load type from itab.
typ = Nod(ODOTPTR, typ, nil) typ = NodSym(ODOTPTR, typ, nil)
typ.Type = Ptrto(Types[TUINT8]) typ.Type = Ptrto(Types[TUINT8])
typ.Typecheck = 1 typ.Typecheck = 1
typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
typ.Bounded = true // guaranteed not to fault typ.Bounded = true // guaranteed not to fault
} }
// Load hash from type. // Load hash from type.
h := Nod(ODOTPTR, typ, nil) h := NodSym(ODOTPTR, typ, nil)
h.Type = Types[TUINT32] h.Type = Types[TUINT32]
h.Typecheck = 1 h.Typecheck = 1
h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
......
...@@ -249,11 +249,11 @@ const ( ...@@ -249,11 +249,11 @@ const (
ODCLTYPE // type Int int ODCLTYPE // type Int int
ODELETE // delete(Left, Right) ODELETE // delete(Left, Right)
ODOT // Left.Right (Left is of struct type) ODOT // Left.Sym (Left is of struct type)
ODOTPTR // Left.Right (Left is of pointer to struct type) ODOTPTR // Left.Sym (Left is of pointer to struct type)
ODOTMETH // Left.Right (Left is non-interface, Right is method name) ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
ODOTINTER // Left.Right (Left is interface, Right is method name) ODOTINTER // Left.Sym (Left is interface, Right is method name)
OXDOT // Left.Right (before rewrite to one of the preceding) OXDOT // Left.Sym (before rewrite to one of the preceding)
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved) ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved)
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE) ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE)
OEQ // Left == Right OEQ // Left == Right
......
...@@ -252,17 +252,22 @@ func typecheck1(np **Node, top int) { ...@@ -252,17 +252,22 @@ func typecheck1(np **Node, top int) {
*np = n *np = n
}() }()
if n.Sym != nil { switch n.Op {
if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 { case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER:
Yyerror("use of builtin %v not in function call", n.Sym) // n.Sym is a field/method name, not a variable.
n.Type = nil default:
return if n.Sym != nil {
} if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 {
Yyerror("use of builtin %v not in function call", n.Sym)
n.Type = nil
return
}
typecheckdef(n) typecheckdef(n)
if n.Op == ONONAME { if n.Op == ONONAME {
n.Type = nil n.Type = nil
return return
}
} }
} }
...@@ -819,11 +824,6 @@ OpSwitch: ...@@ -819,11 +824,6 @@ OpSwitch:
typecheck(&n.Left, Erv|Etype) typecheck(&n.Left, Erv|Etype)
defaultlit(&n.Left, nil) defaultlit(&n.Left, nil)
if n.Right.Op != ONAME {
Yyerror("rhs of . must be a name") // impossible
n.Type = nil
return
}
t := n.Left.Type t := n.Left.Type
if t == nil { if t == nil {
...@@ -832,14 +832,14 @@ OpSwitch: ...@@ -832,14 +832,14 @@ OpSwitch:
return return
} }
r := n.Right s := n.Sym
if n.Left.Op == OTYPE { if n.Left.Op == OTYPE {
if !looktypedot(n, t, 0) { if !looktypedot(n, t, 0) {
if looktypedot(n, t, 1) { if looktypedot(n, t, 1) {
Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Right.Sym) Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Sym)
} else { } else {
Yyerror("%v undefined (type %v has no method %v)", n, t, n.Right.Sym) Yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
} }
n.Type = nil n.Type = nil
return return
...@@ -856,7 +856,7 @@ OpSwitch: ...@@ -856,7 +856,7 @@ OpSwitch:
if n.Name == nil { if n.Name == nil {
n.Name = new(Name) n.Name = new(Name)
} }
n.Sym = n.Right.Sym n.Right = newname(n.Sym)
n.Type = methodfunc(n.Type, n.Left.Type) n.Type = methodfunc(n.Type, n.Left.Type)
n.Xoffset = 0 n.Xoffset = 0
n.Class = PFUNC n.Class = PFUNC
...@@ -874,7 +874,7 @@ OpSwitch: ...@@ -874,7 +874,7 @@ OpSwitch:
checkwidth(t) checkwidth(t)
} }
if isblank(n.Right) { if isblanksym(n.Sym) {
Yyerror("cannot refer to blank field or method") Yyerror("cannot refer to blank field or method")
n.Type = nil n.Type = nil
return return
...@@ -892,13 +892,13 @@ OpSwitch: ...@@ -892,13 +892,13 @@ OpSwitch:
case lookdot(n, t, 1) != nil: case lookdot(n, t, 1) != nil:
// Field or method matches by name, but it is not exported. // Field or method matches by name, but it is not exported.
Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Right.Sym) Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Sym)
default: default:
if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup. if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup.
Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Right.Sym, mt.Sym) Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Sym, mt.Sym)
} else { } else {
Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Right.Sym) Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Sym)
} }
} }
n.Type = nil n.Type = nil
...@@ -910,7 +910,7 @@ OpSwitch: ...@@ -910,7 +910,7 @@ OpSwitch:
if top&Ecall != 0 { if top&Ecall != 0 {
ok |= Ecall ok |= Ecall
} else { } else {
typecheckpartialcall(n, r) typecheckpartialcall(n, s)
ok |= Erv ok |= Erv
} }
...@@ -2392,7 +2392,7 @@ func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field { ...@@ -2392,7 +2392,7 @@ func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field {
} }
func looktypedot(n *Node, t *Type, dostrcmp int) bool { func looktypedot(n *Node, t *Type, dostrcmp int) bool {
s := n.Right.Sym s := n.Sym
if t.Etype == TINTER { if t.Etype == TINTER {
f1 := lookdot1(n, s, t, t.Fields(), dostrcmp) f1 := lookdot1(n, s, t, t.Fields(), dostrcmp)
...@@ -2400,7 +2400,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool { ...@@ -2400,7 +2400,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
return false return false
} }
n.Right = methodname(n.Right, t) n.Sym = methodsym(n.Sym, t, 0)
n.Xoffset = f1.Width n.Xoffset = f1.Width
n.Type = f1.Type n.Type = f1.Type
n.Op = ODOTINTER n.Op = ODOTINTER
...@@ -2426,7 +2426,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool { ...@@ -2426,7 +2426,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
return false return false
} }
n.Right = methodname(n.Right, t) n.Sym = methodsym(n.Sym, t, 0)
n.Xoffset = f2.Width n.Xoffset = f2.Width
n.Type = f2.Type n.Type = f2.Type
n.Op = ODOTMETH n.Op = ODOTMETH
...@@ -2450,7 +2450,7 @@ type typeSym struct { ...@@ -2450,7 +2450,7 @@ type typeSym struct {
var dotField = map[typeSym]*Field{} var dotField = map[typeSym]*Field{}
func lookdot(n *Node, t *Type, dostrcmp int) *Field { func lookdot(n *Node, t *Type, dostrcmp int) *Field {
s := n.Right.Sym s := n.Sym
dowidth(t) dowidth(t)
var f1 *Field var f1 *Field
...@@ -2474,7 +2474,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field { ...@@ -2474,7 +2474,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
return f1 return f1
} }
if f2 != nil { if f2 != nil {
Yyerror("%v is both field and method", n.Right.Sym) Yyerror("%v is both field and method", n.Sym)
} }
if f1.Width == BADWIDTH { if f1.Width == BADWIDTH {
Fatalf("lookdot badwidth %v %p", f1, f1) Fatalf("lookdot badwidth %v %p", f1, f1)
...@@ -2516,7 +2516,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field { ...@@ -2516,7 +2516,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
n.Left.Implicit = true n.Left.Implicit = true
typecheck(&n.Left, Etype|Erv) typecheck(&n.Left, Etype|Erv)
} else if tt.Etype == Tptr && tt.Type.Etype == Tptr && Eqtype(derefall(tt), derefall(rcvr)) { } else if tt.Etype == Tptr && tt.Type.Etype == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
Yyerror("calling method %v with receiver %v requires explicit dereference", n.Right, Nconv(n.Left, FmtLong)) Yyerror("calling method %v with receiver %v requires explicit dereference", n.Sym, Nconv(n.Left, FmtLong))
for tt.Etype == Tptr { for tt.Etype == Tptr {
// Stop one level early for method with pointer receiver. // Stop one level early for method with pointer receiver.
if rcvr.Etype == Tptr && tt.Type.Etype != Tptr { if rcvr.Etype == Tptr && tt.Type.Etype != Tptr {
...@@ -2545,7 +2545,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field { ...@@ -2545,7 +2545,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
return nil return nil
} }
n.Right = methodname(n.Right, n.Left.Type) n.Sym = methodsym(n.Sym, n.Left.Type, 0)
n.Xoffset = f2.Width n.Xoffset = f2.Width
n.Type = f2.Type n.Type = f2.Type
...@@ -3232,7 +3232,7 @@ func samesafeexpr(l *Node, r *Node) bool { ...@@ -3232,7 +3232,7 @@ func samesafeexpr(l *Node, r *Node) bool {
return l == r return l == r
case ODOT, ODOTPTR: case ODOT, ODOTPTR:
return l.Right != nil && r.Right != nil && l.Right.Sym == r.Right.Sym && samesafeexpr(l.Left, r.Left) return l.Sym != nil && r.Sym != nil && l.Sym == r.Sym && samesafeexpr(l.Left, r.Left)
case OIND: case OIND:
return samesafeexpr(l.Left, r.Left) return samesafeexpr(l.Left, r.Left)
......
...@@ -2480,12 +2480,17 @@ func varexpr(n *Node) bool { ...@@ -2480,12 +2480,17 @@ func varexpr(n *Node) bool {
OPAREN, OPAREN,
OANDAND, OANDAND,
OOROR, OOROR,
ODOT, // but not ODOTPTR
OCONV, OCONV,
OCONVNOP, OCONVNOP,
OCONVIFACE, OCONVIFACE,
ODOTTYPE: ODOTTYPE:
return varexpr(n.Left) && varexpr(n.Right) return varexpr(n.Left) && varexpr(n.Right)
case ODOT: // but not ODOTPTR
// The original code always returned false for ODOT,
// because n.Right would be an ONAME with n.Class not set.
// TODO(iant): Fix this to remove "&& false".
return varexpr(n.Left) && false
} }
// Be conservative. // Be conservative.
...@@ -3234,8 +3239,8 @@ func walkcompare(np **Node, init *Nodes) { ...@@ -3234,8 +3239,8 @@ func walkcompare(np **Node, init *Nodes) {
if isblanksym(t1.Sym) { if isblanksym(t1.Sym) {
continue continue
} }
li = Nod(OXDOT, l, newname(t1.Sym)) li = NodSym(OXDOT, l, t1.Sym)
ri = Nod(OXDOT, r, newname(t1.Sym)) ri = NodSym(OXDOT, r, t1.Sym)
a = Nod(n.Op, li, ri) a = Nod(n.Op, li, ri)
if expr == nil { if expr == nil {
expr = a expr = a
...@@ -3295,9 +3300,7 @@ func samecheap(a *Node, b *Node) bool { ...@@ -3295,9 +3300,7 @@ func samecheap(a *Node, b *Node) bool {
return a == b return a == b
case ODOT, ODOTPTR: case ODOT, ODOTPTR:
ar = a.Right if a.Sym != b.Sym {
br = b.Right
if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
return false return false
} }
...@@ -3815,7 +3818,7 @@ func usefield(n *Node) { ...@@ -3815,7 +3818,7 @@ func usefield(n *Node) {
case ODOT, ODOTPTR: case ODOT, ODOTPTR:
break break
} }
if n.Right == nil { if n.Sym == nil {
// No field name. This DOTPTR was built by the compiler for access // No field name. This DOTPTR was built by the compiler for access
// to runtime data structures. Ignore. // to runtime data structures. Ignore.
return return
...@@ -3825,9 +3828,9 @@ func usefield(n *Node) { ...@@ -3825,9 +3828,9 @@ func usefield(n *Node) {
if Isptr[t.Etype] { if Isptr[t.Etype] {
t = t.Type t = t.Type
} }
field := dotField[typeSym{t.Orig, n.Right.Sym}] field := dotField[typeSym{t.Orig, n.Sym}]
if field == nil { if field == nil {
Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym) Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
} }
if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") { if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
return return
......
...@@ -639,7 +639,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { ...@@ -639,7 +639,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
// A special case to make write barriers more efficient. // A special case to make write barriers more efficient.
// Comparing the first field of a named struct can be done directly. // Comparing the first field of a named struct can be done directly.
base := n1 base := n1
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Right.Sym { if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Sym {
base = n1.Left base = n1.Left
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment