cmd/compile: change Node.Nbody, Func.Inl from *NodeList to Nodes
Passes toolstash -cmp.
Casual timings show about a 3% improvement in compile times.
Update #14473.
Change-Id: I584add2e8f1a52486ba418b25ba6122b7347b643
Reviewed-on: https://go-review.googlesource.com/19989
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index c993737..a0ff489 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -232,9 +232,9 @@
na.Etype = 1 // no escape to heap
call.List = list(call.List, na)
call.List = list(call.List, nh)
- n.Nbody = list(n.Nbody, Nod(OAS, nh, call))
+ n.Nbody.Append(Nod(OAS, nh, call))
- fn.Nbody = list(fn.Nbody, n)
+ fn.Nbody.Append(n)
// Walk the struct using memhash for runs of AMEM
// and calling specific hash functions for the others.
@@ -262,7 +262,7 @@
call.List = list(call.List, na)
call.List = list(call.List, nh)
call.List = list(call.List, Nodintconst(size))
- fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
+ fn.Nbody.Append(Nod(OAS, nh, call))
}
if t1 == nil {
@@ -285,7 +285,7 @@
na.Etype = 1 // no escape to heap
call.List = list(call.List, na)
call.List = list(call.List, nh)
- fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
+ fn.Nbody.Append(Nod(OAS, nh, call))
t1 = t1.Down
}
@@ -293,17 +293,17 @@
r := Nod(ORETURN, nil, nil)
r.List = list(r.List, nh)
- fn.Nbody = list(fn.Nbody, r)
+ fn.Nbody.Append(r)
if Debug['r'] != 0 {
- dumplist("genhash body", fn.Nbody)
+ dumpslice("genhash body", fn.Nbody.Slice())
}
funcbody(fn)
Curfn = fn
fn.Func.Dupok = true
typecheck(&fn, Etop)
- typechecklist(fn.Nbody, Etop)
+ typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil
// Disable safemode while compiling this code: the code we
@@ -429,14 +429,14 @@
nif.Left = Nod(ONE, nx, ny)
r := Nod(ORETURN, nil, nil)
r.List = list(r.List, Nodbool(false))
- nif.Nbody = list(nif.Nbody, r)
- nrange.Nbody = list(nrange.Nbody, nif)
- fn.Nbody = list(fn.Nbody, nrange)
+ nif.Nbody.Append(r)
+ nrange.Nbody.Append(nif)
+ fn.Nbody.Append(nrange)
// return true
ret := Nod(ORETURN, nil, nil)
ret.List = list(ret.List, Nodbool(true))
- fn.Nbody = list(fn.Nbody, ret)
+ fn.Nbody.Append(ret)
// Walk the struct using memequal for runs of AMEM
// and calling specific equality tests for the others.
@@ -500,18 +500,18 @@
ret := Nod(ORETURN, nil, nil)
ret.List = list(ret.List, and)
- fn.Nbody = list(fn.Nbody, ret)
+ fn.Nbody.Append(ret)
}
if Debug['r'] != 0 {
- dumplist("geneq body", fn.Nbody)
+ dumpslice("geneq body", fn.Nbody.Slice())
}
funcbody(fn)
Curfn = fn
fn.Func.Dupok = true
typecheck(&fn, Etop)
- typechecklist(fn.Nbody, Etop)
+ typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil
// Disable safemode while compiling this code: the code we
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index dc55bb0..49793bf 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -748,7 +748,7 @@
// is written out for exported functions with inlined function bodies.
func (p *exporter) collectInlined(n *Node) int {
- if n != nil && n.Func != nil && n.Func.Inl != nil {
+ if n != nil && n.Func != nil && len(n.Func.Inl.Slice()) != 0 {
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug['l'] < 2 {
@@ -762,13 +762,13 @@
func (p *exporter) body(i int, f *Func) {
p.int(i)
- p.block(f.Inl)
+ p.block(f.Inl.Slice())
}
-func (p *exporter) block(list *NodeList) {
- p.int(count(list))
- for q := list; q != nil; q = q.Next {
- p.stmt(q.N)
+func (p *exporter) block(list []*Node) {
+ p.int(len(list))
+ for _, n := range list {
+ p.stmt(n)
}
}
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index f330f1b..5c2ffa6 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -95,7 +95,7 @@
funchdr(n)
// go.y:hidden_import
- n.Func.Inl = nil
+ n.Func.Inl.Set(nil)
funcbody(n)
importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
}
@@ -253,7 +253,7 @@
n.Type.Nname = n
// go.y:hidden_import
- n.Func.Inl = nil
+ n.Func.Inl.Set(nil)
funcbody(n)
importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
}
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 9a7a5c0..d8ec059 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -59,7 +59,7 @@
}
func_ := Curfn
- func_.Nbody = body
+ func_.Nbody.SetToNodeList(body)
func_.Func.Endlineno = lineno
funcbody(func_)
@@ -111,7 +111,7 @@
Curfn = func_
olddd := decldepth
decldepth = 1
- typechecklist(func_.Nbody, Etop)
+ typecheckslice(func_.Nbody.Slice(), Etop)
decldepth = olddd
Curfn = oldfn
}
@@ -193,10 +193,10 @@
xfunc.Func.Endlineno = func_.Func.Endlineno
makefuncsym(xfunc.Func.Nname.Sym)
- xfunc.Nbody = func_.Nbody
+ xfunc.Nbody.Set(func_.Nbody.Slice())
xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
func_.Func.Dcl = nil
- if xfunc.Nbody == nil {
+ if len(xfunc.Nbody.Slice()) == 0 {
Fatalf("empty body - won't generate any code")
}
typecheck(&xfunc, Etop)
@@ -204,7 +204,7 @@
xfunc.Func.Closure = func_
func_.Func.Closure = xfunc
- func_.Nbody = nil
+ func_.Nbody.Set(nil)
func_.List = nil
func_.Rlist = nil
@@ -589,30 +589,30 @@
ptr.Used = true
ptr.Name.Curfn = xfunc
xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr)
- var body *NodeList
+ var body []*Node
if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
ptr.Name.Param.Ntype = typenod(rcvrtype)
- body = list(body, Nod(OAS, ptr, cv))
+ body = append(body, Nod(OAS, ptr, cv))
} else {
ptr.Name.Param.Ntype = typenod(Ptrto(rcvrtype))
- body = list(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.List = callargs
call.Isddd = ddd
if t0.Outtuple == 0 {
- body = list(body, call)
+ body = append(body, call)
} else {
n := Nod(OAS2, nil, nil)
n.List = retargs
n.Rlist = list1(call)
- body = list(body, n)
+ body = append(body, n)
n = Nod(ORETURN, nil, nil)
- body = list(body, n)
+ body = append(body, n)
}
- xfunc.Nbody = body
+ xfunc.Nbody.Set(body)
typecheck(&xfunc, Etop)
sym.Def = xfunc
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index 33c04c5..52ada12 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -1520,7 +1520,7 @@
for _, n := range list {
if n.Func.WBLineno == 0 {
c.curfn = n
- c.visitcodelist(n.Nbody)
+ c.visitcodeslice(n.Nbody.Slice())
}
}
if c.stable {
@@ -1557,6 +1557,12 @@
}
}
+func (c *nowritebarrierrecChecker) visitcodeslice(l []*Node) {
+ for _, n := range l {
+ c.visitcode(n)
+ }
+}
+
func (c *nowritebarrierrecChecker) visitcode(n *Node) {
if n == nil {
return
@@ -1570,7 +1576,7 @@
c.visitcode(n.Left)
c.visitcode(n.Right)
c.visitcodelist(n.List)
- c.visitcodelist(n.Nbody)
+ c.visitcodeslice(n.Nbody.Slice())
c.visitcodelist(n.Rlist)
}
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 5745994..e26cbb3 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -78,7 +78,7 @@
min := v.visitgen
v.stack = append(v.stack, n)
- min = v.visitcodelist(n.Nbody, min)
+ min = v.visitcodeslice(n.Nbody.Slice(), min)
if (min == id || min == id+1) && n.Func.FCurfn == nil {
// This node is the root of a strongly connected component.
@@ -117,6 +117,13 @@
return min
}
+func (v *bottomUpVisitor) visitcodeslice(l []*Node, min uint32) uint32 {
+ for _, n := range l {
+ min = v.visitcode(n, min)
+ }
+ return min
+}
+
func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
if n == nil {
return min
@@ -126,7 +133,7 @@
min = v.visitcode(n.Left, min)
min = v.visitcode(n.Right, min)
min = v.visitcodelist(n.List, min)
- min = v.visitcodelist(n.Nbody, min)
+ min = v.visitcodeslice(n.Nbody.Slice(), min)
min = v.visitcodelist(n.Rlist, min)
if n.Op == OCALLFUNC || n.Op == OCALLMETH {
@@ -491,7 +498,7 @@
if ln.Type != nil && !haspointers(ln.Type) {
break
}
- if Curfn.Nbody == nil && !Curfn.Noescape {
+ if len(Curfn.Nbody.Slice()) == 0 && !Curfn.Noescape {
ln.Esc = EscHeap
} else {
ln.Esc = EscNone // prime for escflood later
@@ -509,8 +516,8 @@
}
}
- escloopdepthlist(e, Curfn.Nbody)
- esclist(e, Curfn.Nbody, Curfn)
+ escloopdepthslice(e, Curfn.Nbody.Slice())
+ escslice(e, Curfn.Nbody.Slice(), Curfn)
Curfn = savefn
e.loopdepth = saveld
}
@@ -528,6 +535,12 @@
}
}
+func escloopdepthslice(e *EscState, l []*Node) {
+ for _, n := range l {
+ escloopdepth(e, n)
+ }
+}
+
func escloopdepth(e *EscState, n *Node) {
if n == nil {
return
@@ -562,7 +575,7 @@
escloopdepth(e, n.Left)
escloopdepth(e, n.Right)
escloopdepthlist(e, n.List)
- escloopdepthlist(e, n.Nbody)
+ escloopdepthslice(e, n.Nbody.Slice())
escloopdepthlist(e, n.Rlist)
}
@@ -572,6 +585,12 @@
}
}
+func escslice(e *EscState, l []*Node, up *Node) {
+ for _, n := range l {
+ esc(e, n, up)
+ }
+}
+
func esc(e *EscState, n *Node, up *Node) {
if n == nil {
return
@@ -622,7 +641,7 @@
esc(e, n.Left, n)
esc(e, n.Right, n)
- esclist(e, n.Nbody, n)
+ escslice(e, n.Nbody.Slice(), n)
esclist(e, n.List, n)
esclist(e, n.Rlist, n)
@@ -1395,7 +1414,7 @@
nE := e.nodeEscState(n)
if fn != nil && fn.Op == ONAME && fn.Class == PFUNC &&
- fn.Name.Defn != nil && fn.Name.Defn.Nbody != nil && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged {
+ fn.Name.Defn != nil && len(fn.Name.Defn.Nbody.Slice()) != 0 && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged {
if Debug['m'] > 2 {
fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
}
@@ -1833,7 +1852,7 @@
// External functions are assumed unsafe,
// unless //go:noescape is given before the declaration.
- if func_.Nbody == nil {
+ if len(func_.Nbody.Slice()) == 0 {
if func_.Noescape {
for t := getinargx(func_.Type).Type; t != nil; t = t.Down {
if haspointers(t.Type) {
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index 1b61d7f..b36fe7b 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -112,6 +112,12 @@
}
}
+func reexportdepslice(ll []*Node) {
+ for _, n := range ll {
+ reexportdep(n)
+ }
+}
+
func reexportdep(n *Node) {
if n == nil {
return
@@ -217,7 +223,7 @@
reexportdeplist(n.List)
reexportdeplist(n.Rlist)
reexportdeplist(n.Ninit)
- reexportdeplist(n.Nbody)
+ reexportdepslice(n.Nbody.Slice())
}
func dumpexportconst(s *Sym) {
@@ -249,7 +255,7 @@
dumpexporttype(t)
if t.Etype == TFUNC && n.Class == PFUNC {
- if n.Func != nil && n.Func.Inl != nil {
+ if n.Func != nil && len(n.Func.Inl.Slice()) != 0 {
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug['l'] < 2 {
@@ -257,9 +263,9 @@
}
// NOTE: The space after %#S here is necessary for ld's export data parser.
- exportf("\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Func.Inl, obj.FmtSharp|obj.FmtBody))
+ exportf("\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconvslice(n.Func.Inl.Slice(), obj.FmtSharp|obj.FmtBody))
- reexportdeplist(n.Func.Inl)
+ reexportdepslice(n.Func.Inl.Slice())
} else {
exportf("\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
}
@@ -307,15 +313,15 @@
if f.Nointerface {
exportf("\t//go:nointerface\n")
}
- if f.Type.Nname != nil && f.Type.Nname.Func.Inl != nil { // nname was set by caninl
+ if f.Type.Nname != nil && len(f.Type.Nname.Func.Inl.Slice()) != 0 { // nname was set by caninl
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug['l'] < 2 {
typecheckinl(f.Type.Nname)
}
- exportf("\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp))
- reexportdeplist(f.Type.Nname.Func.Inl)
+ exportf("\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconvslice(f.Type.Nname.Func.Inl.Slice(), obj.FmtSharp))
+ reexportdepslice(f.Type.Nname.Func.Inl.Slice())
} else {
exportf("\tfunc (%v) %v %v\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
}
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 9327a13..39b74f6 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -1216,7 +1216,7 @@
if fmtmode == FErr {
return "func literal"
}
- if n.Nbody != nil {
+ if len(n.Nbody.Slice()) != 0 {
return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
}
return fmt.Sprintf("%v { %v }", n.Type, n.Name.Param.Closure.Nbody)
@@ -1583,7 +1583,7 @@
fmt.Fprintf(&buf, "%v-rlist%v", Oconv(int(n.Op), 0), n.Rlist)
}
- if n.Nbody != nil {
+ if len(n.Nbody.Slice()) != 0 {
indent(&buf)
fmt.Fprintf(&buf, "%v-body%v", Oconv(int(n.Op), 0), n.Nbody)
}
@@ -1699,6 +1699,10 @@
return Hconv(l, 0)
}
+func (n Nodes) String() string {
+ return Hconvslice(n.Slice(), 0)
+}
+
// Fmt '%H': NodeList.
// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
func Hconv(l *NodeList, flag int) string {
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index 4edef2b..2292a56 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -777,7 +777,7 @@
gen(n.Right) // contin: incr
Patch(p1, Pc) // test:
Bgen(n.Left, false, -1, breakpc) // if(!test) goto break
- Genlist(n.Nbody) // body
+ Genslice(n.Nbody.Slice()) // body
gjmp(continpc)
Patch(breakpc, Pc) // done:
continpc = scontin
@@ -792,7 +792,7 @@
p2 := gjmp(nil) // p2: goto else
Patch(p1, Pc) // test:
Bgen(n.Left, false, int(-n.Likely), p2) // if(!test) goto p2
- Genlist(n.Nbody) // then
+ Genslice(n.Nbody.Slice()) // then
p3 := gjmp(nil) // goto done
Patch(p2, Pc) // else:
Genlist(n.Rlist) // else
@@ -809,9 +809,9 @@
lab.Breakpc = breakpc
}
- Patch(p1, Pc) // test:
- Genlist(n.Nbody) // switch(test) body
- Patch(breakpc, Pc) // done:
+ Patch(p1, Pc) // test:
+ Genslice(n.Nbody.Slice()) // switch(test) body
+ Patch(breakpc, Pc) // done:
breakpc = sbreak
if lab != nil {
lab.Breakpc = nil
@@ -828,9 +828,9 @@
lab.Breakpc = breakpc
}
- Patch(p1, Pc) // test:
- Genlist(n.Nbody) // select() body
- Patch(breakpc, Pc) // done:
+ Patch(p1, Pc) // test:
+ Genslice(n.Nbody.Slice()) // select() body
+ Patch(breakpc, Pc) // done:
breakpc = sbreak
if lab != nil {
lab.Breakpc = nil
diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go
index 6071ab4..d7db786 100644
--- a/src/cmd/compile/internal/gc/init.go
+++ b/src/cmd/compile/internal/gc/init.go
@@ -46,15 +46,15 @@
// initdoneĀ· = 2; (10)
// return (11)
// }
-func anyinit(n *NodeList) bool {
+func anyinit(n []*Node) bool {
// are there any interesting init statements
- for l := n; l != nil; l = l.Next {
- switch l.N.Op {
+ for _, ln := range n {
+ switch ln.Op {
case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
break
case OAS, OASWB:
- if isblank(l.N.Left) && candiscard(l.N.Right) {
+ if isblank(ln.Left) && candiscard(ln.Right) {
break
}
fallthrough
@@ -94,12 +94,12 @@
return
}
- n = initfix(n)
- if !anyinit(n) {
+ nf := initfix(n)
+ if !anyinit(nf) {
return
}
- var r *NodeList
+ var r []*Node
// (1)
gatevar := newname(Lookup("initdoneĀ·"))
@@ -120,37 +120,37 @@
a := Nod(OIF, nil, nil)
a.Left = Nod(ONE, gatevar, Nodintconst(0))
- r = list(r, a)
+ r = append(r, a)
// (4)
b := Nod(OIF, nil, nil)
b.Left = Nod(OEQ, gatevar, Nodintconst(2))
- b.Nbody = list1(Nod(ORETURN, nil, nil))
- a.Nbody = list1(b)
+ b.Nbody.Set([]*Node{Nod(ORETURN, nil, nil)})
+ a.Nbody.Set([]*Node{b})
// (5)
b = syslook("throwinit", 0)
b = Nod(OCALL, b, nil)
- a.Nbody = list(a.Nbody, b)
+ a.Nbody.Append(b)
// (6)
a = Nod(OAS, gatevar, Nodintconst(1))
- r = list(r, a)
+ r = append(r, a)
// (7)
for _, s := range initSyms {
if s.Def != nil && s != initsym {
// could check that it is fn of no args/returns
a = Nod(OCALL, s.Def, nil)
- r = list(r, a)
+ r = append(r, a)
}
}
// (8)
- r = concat(r, n)
+ r = append(r, nf...)
// (9)
// could check that it is fn of no args/returns
@@ -160,26 +160,26 @@
break
}
a = Nod(OCALL, s.Def, nil)
- r = list(r, a)
+ r = append(r, a)
}
// (10)
a = Nod(OAS, gatevar, Nodintconst(2))
- r = list(r, a)
+ r = append(r, a)
// (11)
a = Nod(ORETURN, nil, nil)
- r = list(r, a)
+ r = append(r, a)
exportsym(fn.Func.Nname)
- fn.Nbody = r
+ fn.Nbody.Set(r)
funcbody(fn)
Curfn = fn
typecheck(&fn, Etop)
- typechecklist(r, Etop)
+ typecheckslice(r, Etop)
Curfn = nil
funccompile(fn)
}
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index f5c3265..8406565 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -79,7 +79,7 @@
}
if Debug['m'] > 2 {
- fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, obj.FmtLong), Hconv(fn.Func.Inl, obj.FmtSharp))
+ fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, obj.FmtLong), Hconvslice(fn.Func.Inl.Slice(), obj.FmtSharp))
}
save_safemode := safemode
@@ -87,7 +87,7 @@
savefn := Curfn
Curfn = fn
- typechecklist(fn.Func.Inl, Etop)
+ typecheckslice(fn.Func.Inl.Slice(), Etop)
Curfn = savefn
safemode = save_safemode
@@ -112,7 +112,7 @@
}
// If fn has no body (is defined outside of Go), cannot inline it.
- if fn.Nbody == nil {
+ if len(fn.Nbody.Slice()) == 0 {
return
}
@@ -141,15 +141,15 @@
const maxBudget = 80
budget := maxBudget // allowed hairyness
- if ishairylist(fn.Nbody, &budget) || budget < 0 {
+ if ishairyslice(fn.Nbody.Slice(), &budget) || budget < 0 {
return
}
savefn := Curfn
Curfn = fn
- fn.Func.Nname.Func.Inl = fn.Nbody
- fn.Nbody = inlcopylist(fn.Func.Nname.Func.Inl)
+ fn.Func.Nname.Func.Inl.Set(fn.Nbody.Slice())
+ fn.Nbody.Set(inlcopyslice(fn.Func.Nname.Func.Inl.Slice()))
inldcl := inlcopyslice(fn.Func.Nname.Name.Defn.Func.Dcl)
if len(inldcl) > 0 {
fn.Func.Nname.Func.Inldcl = &inldcl
@@ -161,7 +161,7 @@
fn.Type.Nname = fn.Func.Nname
if Debug['m'] > 1 {
- fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Func.Nname, obj.FmtSharp), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Nname.Func.Inl, obj.FmtSharp))
+ fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Func.Nname, obj.FmtSharp), Tconv(fn.Type, obj.FmtSharp), Hconvslice(fn.Func.Nname.Func.Inl.Slice(), obj.FmtSharp))
} else if Debug['m'] != 0 {
fmt.Printf("%v: can inline %v\n", fn.Line(), fn.Func.Nname)
}
@@ -179,6 +179,15 @@
return false
}
+func ishairyslice(ll []*Node, budget *int) bool {
+ for _, n := range ll {
+ if ishairy(n, budget) {
+ return true
+ }
+ }
+ return false
+}
+
func ishairy(n *Node, budget *int) bool {
if n == nil {
return false
@@ -187,12 +196,12 @@
switch n.Op {
// Call is okay if inlinable and we have the budget for the body.
case OCALLFUNC:
- if n.Left.Func != nil && n.Left.Func.Inl != nil {
+ if n.Left.Func != nil && len(n.Left.Func.Inl.Slice()) != 0 {
*budget -= int(n.Left.Func.InlCost)
break
}
if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
- if n.Left.Sym.Def != nil && n.Left.Sym.Def.Func.Inl != nil {
+ if n.Left.Sym.Def != nil && len(n.Left.Sym.Def.Func.Inl.Slice()) != 0 {
*budget -= int(n.Left.Sym.Def.Func.InlCost)
break
}
@@ -209,7 +218,7 @@
if n.Left.Type.Nname == nil {
Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign))
}
- if n.Left.Type.Nname.Func.Inl != nil {
+ if len(n.Left.Type.Nname.Func.Inl.Slice()) != 0 {
*budget -= int(n.Left.Type.Nname.Func.InlCost)
break
}
@@ -239,7 +248,7 @@
(*budget)--
- return *budget < 0 || ishairy(n.Left, budget) || ishairy(n.Right, budget) || ishairylist(n.List, budget) || ishairylist(n.Rlist, budget) || ishairylist(n.Ninit, budget) || ishairylist(n.Nbody, budget)
+ return *budget < 0 || ishairy(n.Left, budget) || ishairy(n.Right, budget) || ishairylist(n.List, budget) || ishairylist(n.Rlist, budget) || ishairylist(n.Ninit, budget) || ishairyslice(n.Nbody.Slice(), budget)
}
// Inlcopy and inlcopylist recursively copy the body of a function.
@@ -266,14 +275,14 @@
m := Nod(OXXX, nil, nil)
*m = *n
if m.Func != nil {
- m.Func.Inl = nil
+ m.Func.Inl.Set(nil)
}
m.Left = inlcopy(n.Left)
m.Right = inlcopy(n.Right)
m.List = inlcopylist(n.List)
m.Rlist = inlcopylist(n.Rlist)
m.Ninit = inlcopylist(n.Ninit)
- m.Nbody = inlcopylist(n.Nbody)
+ m.Nbody.Set(inlcopyslice(n.Nbody.Slice()))
return m
}
@@ -307,9 +316,9 @@
n.Op = OBLOCK
// n->ninit stays
- n.List = n.Nbody
+ n.List = n.Nbody.NodeList()
- n.Nbody = nil
+ n.Nbody.Set(nil)
n.Rlist = nil
}
@@ -317,7 +326,7 @@
func inlconv2expr(np **Node) {
n := *np
r := n.Rlist.N
- addinit(&r, concat(n.Ninit, n.Nbody))
+ addinit(&r, concat(n.Ninit, n.Nbody.NodeList()))
*np = r
}
@@ -332,7 +341,7 @@
}
l := n.Rlist
- addinit(&l.N, concat(n.Ninit, n.Nbody))
+ addinit(&l.N, concat(n.Ninit, n.Nbody.NodeList()))
return l
}
@@ -342,6 +351,12 @@
}
}
+func inlnodeslice(l []*Node) {
+ for i := range l {
+ inlnode(&l[i])
+ }
+}
+
// inlnode recurses over the tree to find inlineable calls, which will
// be turned into OINLCALLs by mkinlcall. When the recursion comes
// back up will examine left, right, list, rlist, ninit, ntest, nincr,
@@ -454,10 +469,10 @@
}
}
- inlnodelist(n.Nbody)
- for l := n.Nbody; l != nil; l = l.Next {
- if l.N.Op == OINLCALL {
- inlconv2stmt(l.N)
+ inlnodeslice(n.Nbody.Slice())
+ for _, n := range n.Nbody.Slice() {
+ if n.Op == OINLCALL {
+ inlconv2stmt(n)
}
}
@@ -477,7 +492,7 @@
if Debug['m'] > 3 {
fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, obj.FmtSign))
}
- if n.Left.Func != nil && n.Left.Func.Inl != nil { // normal case
+ if n.Left.Func != nil && len(n.Left.Func.Inl.Slice()) != 0 { // normal case
mkinlcall(np, n.Left, n.Isddd)
} else if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
if n.Left.Sym.Def != nil {
@@ -539,7 +554,7 @@
// parameters.
func mkinlcall1(np **Node, fn *Node, isddd bool) {
// For variadic fn.
- if fn.Func.Inl == nil {
+ if len(fn.Func.Inl.Slice()) == 0 {
return
}
@@ -555,7 +570,7 @@
// Bingo, we have a function node, and it has an inlineable body
if Debug['m'] > 1 {
- fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), fn.Sym, Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Inl, obj.FmtSharp))
+ fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), fn.Sym, Tconv(fn.Type, obj.FmtSharp), Hconvslice(fn.Func.Inl.Slice(), obj.FmtSharp))
} else if Debug['m'] != 0 {
fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
}
@@ -796,19 +811,19 @@
inlretlabel = newlabel_inl()
inlgen++
- body := inlsubstlist(fn.Func.Inl)
+ body := inlsubstslice(fn.Func.Inl.Slice())
- body = list(body, Nod(OGOTO, inlretlabel, nil)) // avoid 'not used' when function doesn't have return
- body = list(body, Nod(OLABEL, inlretlabel, nil))
+ body = append(body, Nod(OGOTO, inlretlabel, nil)) // avoid 'not used' when function doesn't have return
+ body = append(body, Nod(OLABEL, inlretlabel, nil))
- typechecklist(body, Etop)
+ typecheckslice(body, Etop)
//dumplist("ninit post", ninit);
call := Nod(OINLCALL, nil, nil)
call.Ninit = ninit
- call.Nbody = body
+ call.Nbody.Set(body)
call.Rlist = inlretvars
call.Type = n.Type
call.Typecheck = 1
@@ -834,15 +849,15 @@
// instead we emit the things that the body needs
// and each use must redo the inlining.
// luckily these are small.
- body = fn.Func.Inl
- fn.Func.Inl = nil // prevent infinite recursion (shouldn't happen anyway)
- inlnodelist(call.Nbody)
- for ll := call.Nbody; ll != nil; ll = ll.Next {
- if ll.N.Op == OINLCALL {
- inlconv2stmt(ll.N)
+ body = fn.Func.Inl.Slice()
+ fn.Func.Inl.Set(nil) // prevent infinite recursion (shouldn't happen anyway)
+ inlnodeslice(call.Nbody.Slice())
+ for _, n := range call.Nbody.Slice() {
+ if n.Op == OINLCALL {
+ inlconv2stmt(n)
}
}
- fn.Func.Inl = body
+ fn.Func.Inl.Set(body)
if Debug['m'] > 2 {
fmt.Printf("%v: After inlining %v\n\n", n.Line(), Nconv(*np, obj.FmtSign))
@@ -907,8 +922,8 @@
return n
}
-// inlsubst and inlsubstlist recursively copy the body of the saved
-// pristine ->inl body of the function while substituting references
+// inlsubst, inlsubstlist, and inlsubstslice recursively copy the body of the
+// saved pristine ->inl body of the function while substituting references
// to input/output parameters with ones to the tmpnames, and
// substituting returns with assignments to the output.
func inlsubstlist(ll *NodeList) *NodeList {
@@ -919,6 +934,14 @@
return l
}
+func inlsubstslice(ll []*Node) []*Node {
+ l := make([]*Node, 0, len(ll))
+ for _, n := range ll {
+ l = append(l, inlsubst(n))
+ }
+ return l
+}
+
func inlsubst(n *Node) *Node {
if n == nil {
return nil
@@ -990,7 +1013,7 @@
m.List = inlsubstlist(n.List)
m.Rlist = inlsubstlist(n.Rlist)
m.Ninit = concat(m.Ninit, inlsubstlist(n.Ninit))
- m.Nbody = inlsubstlist(n.Nbody)
+ m.Nbody.Set(inlsubstslice(n.Nbody.Slice()))
return m
}
@@ -1002,6 +1025,12 @@
}
}
+func setlnoslice(ll []*Node, lno int) {
+ for _, n := range ll {
+ setlno(n, lno)
+ }
+}
+
func setlno(n *Node, lno int) {
if n == nil {
return
@@ -1017,5 +1046,5 @@
setlnolist(n.List, lno)
setlnolist(n.Rlist, lno)
setlnolist(n.Ninit, lno)
- setlnolist(n.Nbody, lno)
+ setlnoslice(n.Nbody.Slice(), lno)
}
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index 62cdded..995fd13 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -388,10 +388,10 @@
Curfn = l.N
decldepth = 1
saveerrors()
- typechecklist(l.N.Nbody, Etop)
+ typecheckslice(l.N.Nbody.Slice(), Etop)
checkreturn(l.N)
if nerrors != 0 {
- l.N.Nbody = nil // type errors; do not compile
+ l.N.Nbody.Set(nil) // type errors; do not compile
}
}
}
@@ -417,7 +417,7 @@
// Typecheck imported function bodies if debug['l'] > 1,
// otherwise lazily when used or re-exported.
for _, n := range importlist {
- if n.Func.Inl != nil {
+ if len(n.Func.Inl.Slice()) != 0 {
saveerrors()
typecheckinl(n)
}
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index cc74ea5..e94ff21 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -41,8 +41,8 @@
// Order holds state during the ordering process.
type Order struct {
- out *NodeList // list of generated statements
- temp []*Node // stack of temporary variables
+ out []*Node // list of generated statements
+ temp []*Node // stack of temporary variables
}
// Order rewrites fn->nbody to apply the ordering constraints
@@ -50,10 +50,10 @@
func order(fn *Node) {
if Debug['W'] > 1 {
s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
- dumplist(s, fn.Nbody)
+ dumpslice(s, fn.Nbody.Slice())
}
- orderblock(&fn.Nbody)
+ orderblockNodes(&fn.Nbody)
}
// Ordertemp allocates a new temporary with the given type,
@@ -64,7 +64,7 @@
if clear {
a := Nod(OAS, var_, nil)
typecheck(&a, Etop)
- order.out = list(order.out, a)
+ order.out = append(order.out, a)
}
order.temp = append(order.temp, var_)
@@ -87,7 +87,7 @@
var_ := ordertemp(t, order, clear != 0)
a := Nod(OAS, var_, n)
typecheck(&a, Etop)
- order.out = list(order.out, a)
+ order.out = append(order.out, a)
return var_
}
@@ -223,7 +223,7 @@
// Cleantempnopop emits to *out VARKILL instructions for each temporary
// above the mark on the temporary stack, but it does not pop them
// from the stack.
-func cleantempnopop(mark ordermarker, order *Order, out **NodeList) {
+func cleantempnopop(mark ordermarker, order *Order, out *[]*Node) {
var kill *Node
for i := len(order.temp) - 1; i >= int(mark); i-- {
@@ -232,11 +232,11 @@
n.Name.Keepalive = false
kill = Nod(OVARLIVE, n, nil)
typecheck(&kill, Etop)
- *out = list(*out, kill)
+ *out = append(*out, kill)
}
kill = Nod(OVARKILL, n, nil)
typecheck(&kill, Etop)
- *out = list(*out, kill)
+ *out = append(*out, kill)
}
}
@@ -254,6 +254,13 @@
}
}
+// Orderstmtslice orders each of the statements in the slice.
+func orderstmtslice(l []*Node, order *Order) {
+ for _, n := range l {
+ orderstmt(n, order)
+ }
+}
+
// Orderblock orders the block of statements *l onto a new list,
// and then replaces *l with that list.
func orderblock(l **NodeList) {
@@ -261,7 +268,21 @@
mark := marktemp(&order)
orderstmtlist(*l, &order)
cleantemp(mark, &order)
- *l = order.out
+ var ll *NodeList
+ for _, n := range order.out {
+ ll = list(ll, n)
+ }
+ *l = ll
+}
+
+// OrderblockNodes orders the block of statements in n into a new slice,
+// and then replaces the old slice in n with the new slice.
+func orderblockNodes(n *Nodes) {
+ var order Order
+ mark := marktemp(&order)
+ orderstmtslice(n.Slice(), &order)
+ cleantemp(mark, &order)
+ n.Set(order.out)
}
// Orderexprinplace orders the side effects in *np and
@@ -270,7 +291,7 @@
n := *np
var order Order
orderexpr(&n, &order, nil)
- addinit(&n, order.out)
+ addinitslice(&n, order.out)
// insert new temporaries from order
// at head of outer list.
@@ -287,7 +308,7 @@
mark := marktemp(&order)
orderstmt(n, &order)
cleantemp(mark, &order)
- *np = liststmt(order.out)
+ *np = liststmtslice(order.out)
}
// Orderinit moves n's init list to order->out.
@@ -413,7 +434,7 @@
Fatalf("ordermapassign %v", Oconv(int(n.Op), 0))
case OAS:
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
// We call writebarrierfat only for values > 4 pointers long. See walk.go.
if (n.Left.Op == OINDEXMAP || (needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr))) && !isaddrokay(n.Right) {
@@ -421,11 +442,11 @@
n.Left = ordertemp(m.Type, order, false)
a := Nod(OAS, m, n.Left)
typecheck(&a, Etop)
- order.out = list(order.out, a)
+ order.out = append(order.out, a)
}
case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
- var post *NodeList
+ var post []*Node
var m *Node
var a *Node
for l := n.List; l != nil; l = l.Next {
@@ -440,18 +461,18 @@
l.N = ordertemp(m.Type, order, false)
a = Nod(OAS, m, l.N)
typecheck(&a, Etop)
- post = list(post, a)
+ post = append(post, a)
} else if instrumenting && n.Op == OAS2FUNC && !isblank(l.N) {
m = l.N
l.N = ordertemp(m.Type, order, false)
a = Nod(OAS, m, l.N)
typecheck(&a, Etop)
- post = list(post, a)
+ post = append(post, a)
}
}
- order.out = list(order.out, n)
- order.out = concat(order.out, post)
+ order.out = append(order.out, n)
+ order.out = append(order.out, post...)
}
}
@@ -472,7 +493,7 @@
Fatalf("orderstmt %v", Oconv(int(n.Op), 0))
case OVARKILL, OVARLIVE:
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
case OAS:
t := marktemp(order)
@@ -497,7 +518,7 @@
case OAS2, OAS2DOTTYPE:
ordermapassign(n, order)
default:
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
}
cleantemp(t, order)
@@ -561,11 +582,11 @@
orderexprlist(n.List, order)
orderexpr(&n.Rlist.N.Left, order, nil) // i in i.(T)
if isblank(n.List.N) {
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
} else {
typ := n.Rlist.N.Type
tmp1 := ordertemp(typ, order, haspointers(typ))
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
r := Nod(OAS, n.List.N, tmp1)
typecheck(&r, Etop)
ordermapassign(r, order)
@@ -589,7 +610,7 @@
} else {
tmp2 = ordertemp(Types[TBOOL], order, false)
}
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
r := Nod(OAS, n.List.N, tmp1)
typecheck(&r, Etop)
ordermapassign(r, order)
@@ -614,14 +635,14 @@
OGOTO,
OLABEL,
ORETJMP:
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
// Special: handle call arguments.
case OCALLFUNC, OCALLINTER, OCALLMETH:
t := marktemp(order)
ordercall(n, order)
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
cleantemp(t, order)
// Special: order arguments to inner call but not call itself.
@@ -644,7 +665,7 @@
ordercall(n.Left, order)
}
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
cleantemp(t, order)
case ODELETE:
@@ -652,7 +673,7 @@
orderexpr(&n.List.N, order, nil)
orderexpr(&n.List.Next.N, order, nil)
orderaddrtemp(&n.List.Next.N, order) // map key
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
cleantemp(t, order)
// Clean temporaries from condition evaluation at
@@ -661,12 +682,12 @@
t := marktemp(order)
orderexprinplace(&n.Left, order)
- var l *NodeList
+ var l []*Node
cleantempnopop(t, order, &l)
- n.Nbody = concat(l, n.Nbody)
- orderblock(&n.Nbody)
+ n.Nbody.Set(append(l, n.Nbody.Slice()...))
+ orderblockNodes(&n.Nbody)
orderstmtinplace(&n.Right)
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
cleantemp(t, order)
// Clean temporaries from condition at
@@ -675,16 +696,20 @@
t := marktemp(order)
orderexprinplace(&n.Left, order)
- var l *NodeList
+ var l []*Node
cleantempnopop(t, order, &l)
- n.Nbody = concat(l, n.Nbody)
+ n.Nbody.Set(append(l, n.Nbody.Slice()...))
l = nil
cleantempnopop(t, order, &l)
- n.Rlist = concat(l, n.Rlist)
+ var ll *NodeList
+ for _, n := range l {
+ ll = list(ll, n)
+ }
+ n.Rlist = concat(ll, n.Rlist)
poptemp(t, order)
- orderblock(&n.Nbody)
+ orderblockNodes(&n.Nbody)
orderblock(&n.Rlist)
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
// Special: argument will be converted to interface using convT2E
// so make sure it is an addressable temporary.
@@ -695,7 +720,7 @@
if !Isinter(n.Left.Type) {
orderaddrtemp(&n.Left, order)
}
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
cleantemp(t, order)
// n->right is the expression being ranged over.
@@ -756,13 +781,13 @@
for l := n.List; l != nil; l = l.Next {
orderexprinplace(&l.N, order)
}
- orderblock(&n.Nbody)
- order.out = list(order.out, n)
+ orderblockNodes(&n.Nbody)
+ order.out = append(order.out, n)
cleantemp(t, order)
case ORETURN:
ordercallargs(&n.List, order)
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
// Special: clean case temporaries in each block entry.
// Select must enter one of its blocks, so there is no
@@ -897,19 +922,23 @@
}
}
- orderblock(&l.N.Nbody)
+ orderblockNodes(&l.N.Nbody)
}
// Now that we have accumulated all the temporaries, clean them.
// Also insert any ninit queued during the previous loop.
// (The temporary cleaning must follow that ninit work.)
for l := n.List; l != nil; l = l.Next {
- cleantempnopop(t, order, &l.N.Ninit)
- l.N.Nbody = concat(l.N.Ninit, l.N.Nbody)
+ s := make([]*Node, 0, count(l.N.Ninit))
+ for ll := l.N.Ninit; ll != nil; ll = ll.Next {
+ s = append(s, ll.N)
+ }
+ cleantempnopop(t, order, &s)
+ l.N.Nbody.Set(append(s, l.N.Nbody.Slice()...))
l.N.Ninit = nil
}
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
poptemp(t, order)
// Special: value being sent is passed as a pointer; make it addressable.
@@ -919,7 +948,7 @@
orderexpr(&n.Left, order, nil)
orderexpr(&n.Right, order, nil)
orderaddrtemp(&n.Right, order)
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
cleantemp(t, order)
// TODO(rsc): Clean temporaries more aggressively.
@@ -938,10 +967,10 @@
Fatalf("order switch case %v", Oconv(int(l.N.Op), 0))
}
orderexprlistinplace(l.N.List, order)
- orderblock(&l.N.Nbody)
+ orderblockNodes(&l.N.Nbody)
}
- order.out = list(order.out, n)
+ order.out = append(order.out, n)
cleantemp(t, order)
}
@@ -1080,9 +1109,13 @@
// Clean temporaries from first branch at beginning of second.
// Leave them on the stack so that they can be killed in the outer
// context in case the short circuit is taken.
- var l *NodeList
+ var s []*Node
- cleantempnopop(mark, order, &l)
+ cleantempnopop(mark, order, &s)
+ var l *NodeList
+ for _, n := range s {
+ l = list(l, n)
+ }
n.Right.Ninit = concat(l, n.Right.Ninit)
orderexprinplace(&n.Right, order)
diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go
index 621be57..c8dbcc5 100644
--- a/src/cmd/compile/internal/gc/parser.go
+++ b/src/cmd/compile/internal/gc/parser.go
@@ -858,7 +858,7 @@
stmt := p.case_(tswitch) // does markdcl
stmt.Xoffset = int64(block)
- stmt.Nbody = p.stmt_list()
+ stmt.Nbody.SetToNodeList(p.stmt_list())
popdcl()
@@ -946,7 +946,7 @@
stmt := p.for_header()
body := p.loop_body("for clause")
- stmt.Nbody = concat(stmt.Nbody, body)
+ stmt.Nbody.AppendNodeList(body)
return stmt
}
@@ -1043,7 +1043,7 @@
Yyerror("missing condition in if statement")
}
- stmt.Nbody = p.loop_body("if clause")
+ stmt.Nbody.SetToNodeList(p.loop_body("if clause"))
if p.got(LELSE) {
if p.tok == LIF {
@@ -1858,7 +1858,7 @@
return nil
}
- f.Nbody = body
+ f.Nbody.SetToNodeList(body)
f.Noescape = p.pragma&Noescape != 0
if f.Noescape && body != nil {
Yyerror("can only use //go:noescape with external func implementations")
@@ -2079,7 +2079,7 @@
l = list(l, p.xfndcl())
default:
- if p.tok == '{' && l != nil && l.End.N.Op == ODCLFUNC && l.End.N.Nbody == nil {
+ if p.tok == '{' && l != nil && l.End.N.Op == ODCLFUNC && len(l.End.N.Nbody.Slice()) == 0 {
// opening { of function declaration on next line
p.syntax_error("unexpected semicolon or newline before {")
} else {
@@ -2835,14 +2835,14 @@
return
}
- s2.Func.Inl = s3
+ s2.Func.Inl.SetToNodeList(s3)
funcbody(s2)
importlist = append(importlist, s2)
if Debug['E'] > 0 {
fmt.Printf("import [%q] func %v \n", importpkg.Path, s2)
- if Debug['m'] > 2 && s2.Func.Inl != nil {
+ if Debug['m'] > 2 && len(s2.Func.Inl.Slice()) != 0 {
fmt.Printf("inl body:%v\n", s2.Func.Inl)
}
}
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index 6c5fb2d..31cc3bc 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -358,7 +358,7 @@
var nam *Node
var gcargs *Sym
var gclocals *Sym
- if fn.Nbody == nil {
+ if len(fn.Nbody.Slice()) == 0 {
if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
goto ret
@@ -385,7 +385,7 @@
if t.Nname != nil {
n = Nod(OAS, t.Nname, nil)
typecheck(&n, Etop)
- Curfn.Nbody = concat(list1(n), Curfn.Nbody)
+ Curfn.Nbody.Set(append([]*Node{n}, Curfn.Nbody.Slice()...))
}
t = structnext(&save)
@@ -472,7 +472,7 @@
}
Genslice(Curfn.Func.Enter.Slice())
- Genlist(Curfn.Nbody)
+ Genslice(Curfn.Nbody.Slice())
gclean()
checklabels()
if nerrors != 0 {
diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
index d1f6cef..352a399 100644
--- a/src/cmd/compile/internal/gc/racewalk.go
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -55,7 +55,7 @@
}
if flag_race == 0 || !ispkgin(norace_inst_pkgs) {
- instrumentlist(fn.Nbody, nil)
+ instrumentslice(fn.Nbody.Slice(), nil)
// nothing interesting for race detector in fn->enter
instrumentslice(fn.Func.Exit.Slice(), nil)
@@ -78,7 +78,7 @@
if Debug['W'] != 0 {
s := fmt.Sprintf("after instrument %v", fn.Func.Nname.Sym)
- dumplist(s, fn.Nbody)
+ dumpslice(s, fn.Nbody.Slice())
s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
dumpslice(s, fn.Func.Enter.Slice())
s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
@@ -439,7 +439,7 @@
if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
instrumentlist(n.List, init)
}
- instrumentlist(n.Nbody, nil)
+ instrumentslice(n.Nbody.Slice(), nil)
instrumentlist(n.Rlist, nil)
*np = n
}
@@ -612,12 +612,18 @@
}
}
+func foreachslice(l []*Node, f func(*Node, interface{}), c interface{}) {
+ for _, n := range l {
+ foreachnode(n, f, c)
+ }
+}
+
func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
foreachlist(n.Ninit, f, c)
foreachnode(n.Left, f, c)
foreachnode(n.Right, f, c)
foreachlist(n.List, f, c)
- foreachlist(n.Nbody, f, c)
+ foreachslice(n.Nbody.Slice(), f, c)
foreachlist(n.Rlist, f, c)
}
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 4386bcf..2270d71 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -128,7 +128,7 @@
}
decldepth++
- typechecklist(n.Nbody, Etop)
+ typecheckslice(n.Nbody.Slice(), Etop)
decldepth--
}
@@ -159,7 +159,7 @@
// to avoid erroneous processing by racewalk.
n.List = nil
- var body *NodeList
+ var body []*Node
var init *NodeList
switch t.Etype {
default:
@@ -192,12 +192,12 @@
if v1 == nil {
body = nil
} else if v2 == nil {
- body = list1(Nod(OAS, v1, hv1))
+ body = []*Node{Nod(OAS, v1, hv1)}
} else {
a := Nod(OAS2, nil, nil)
a.List = list(list1(v1), v2)
a.Rlist = list(list1(hv1), Nod(OIND, hp, nil))
- body = list1(a)
+ body = []*Node{a}
// Advance pointer as part of increment.
// We used to advance the pointer before executing the loop body,
@@ -245,14 +245,14 @@
if v1 == nil {
body = nil
} else if v2 == nil {
- body = list1(Nod(OAS, v1, key))
+ body = []*Node{Nod(OAS, v1, key)}
} else {
val := Nod(ODOT, hit, valname)
val = Nod(OIND, val, nil)
a := Nod(OAS2, nil, nil)
a.List = list(list1(v1), v2)
a.Rlist = list(list1(key), val)
- body = list1(a)
+ body = []*Node{a}
}
// orderstmt arranged for a copy of the channel variable.
@@ -277,7 +277,7 @@
if v1 == nil {
body = nil
} else {
- body = list1(Nod(OAS, v1, hv1))
+ body = []*Node{Nod(OAS, v1, hv1)}
}
// orderstmt arranged for a copy of the string variable.
@@ -306,10 +306,10 @@
body = nil
if v1 != nil {
- body = list1(Nod(OAS, v1, ohv1))
+ body = []*Node{Nod(OAS, v1, ohv1)}
}
if v2 != nil {
- body = list(body, Nod(OAS, v2, hv2))
+ body = append(body, Nod(OAS, v2, hv2))
}
}
@@ -319,8 +319,8 @@
typechecklist(n.Left.Ninit, Etop)
typecheck(&n.Left, Erv)
typecheck(&n.Right, Etop)
- typechecklist(body, Etop)
- n.Nbody = concat(body, n.Nbody)
+ typecheckslice(body, Etop)
+ n.Nbody.Set(append(body, n.Nbody.Slice()...))
walkstmt(&n)
lineno = int32(lno)
@@ -344,10 +344,10 @@
if v1 == nil || v2 != nil {
return false
}
- if n.Nbody == nil || n.Nbody.N == nil || n.Nbody.Next != nil {
+ if len(n.Nbody.Slice()) == 0 || n.Nbody.Slice()[0] == nil || len(n.Nbody.Slice()) > 1 {
return false
}
- stmt := n.Nbody.N // only stmt in body
+ stmt := n.Nbody.Slice()[0] // only stmt in body
if stmt.Op != OAS || stmt.Left.Op != OINDEX {
return false
}
@@ -368,7 +368,7 @@
// }
n.Op = OIF
- n.Nbody = nil
+ n.Nbody.Set(nil)
n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0))
// hp = &a[0]
@@ -379,7 +379,7 @@
tmp = Nod(OADDR, tmp, nil)
tmp = Nod(OCONVNOP, tmp, nil)
tmp.Type = Ptrto(Types[TUINT8])
- n.Nbody = list(n.Nbody, Nod(OAS, hp, tmp))
+ n.Nbody.Append(Nod(OAS, hp, tmp))
// hn = len(a) * sizeof(elem(a))
hn := temp(Types[TUINTPTR])
@@ -387,20 +387,20 @@
tmp = Nod(OLEN, a, nil)
tmp = Nod(OMUL, tmp, Nodintconst(elemsize))
tmp = conv(tmp, Types[TUINTPTR])
- n.Nbody = list(n.Nbody, Nod(OAS, hn, tmp))
+ n.Nbody.Append(Nod(OAS, hn, tmp))
// memclr(hp, hn)
fn := mkcall("memclr", nil, nil, hp, hn)
- n.Nbody = list(n.Nbody, fn)
+ n.Nbody.Append(fn)
// i = len(a) - 1
v1 = Nod(OAS, v1, Nod(OSUB, Nod(OLEN, a, nil), Nodintconst(1)))
- n.Nbody = list(n.Nbody, v1)
+ n.Nbody.Append(v1)
typecheck(&n.Left, Erv)
- typechecklist(n.Nbody, Etop)
+ typecheckslice(n.Nbody.Slice(), Etop)
walkstmt(&n)
return true
}
diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
index e770c8f..0243947 100644
--- a/src/cmd/compile/internal/gc/select.go
+++ b/src/cmd/compile/internal/gc/select.go
@@ -79,7 +79,7 @@
}
}
- typechecklist(ncase.Nbody, Etop)
+ typecheckslice(ncase.Nbody.Slice(), Etop)
}
sel.Xoffset = int64(count)
@@ -95,14 +95,14 @@
i := count(sel.List)
// optimization: zero-case select
- var init *NodeList
+ var init []*Node
var r *Node
var n *Node
var var_ *Node
var selv *Node
var cas *Node
if i == 0 {
- sel.Nbody = list1(mkcall("block", nil, nil))
+ sel.Nbody.Set([]*Node{mkcall("block", nil, nil)})
goto out
}
@@ -155,14 +155,18 @@
a := Nod(OIF, nil, nil)
a.Left = Nod(OEQ, ch, nodnil())
- a.Nbody = list1(mkcall("block", nil, &l))
+ a.Nbody.Set([]*Node{mkcall("block", nil, &l)})
typecheck(&a, Etop)
l = list(l, a)
l = list(l, n)
}
- l = concat(l, cas.Nbody)
- sel.Nbody = l
+ s := make([]*Node, 0, count(l))
+ for ll := l; ll != nil; ll = ll.Next {
+ s = append(s, ll.N)
+ }
+ s = append(s, cas.Nbody.Slice()...)
+ sel.Nbody.Set(s)
goto out
}
@@ -242,13 +246,16 @@
}
typecheck(&r.Left, Erv)
- r.Nbody = cas.Nbody
- r.Rlist = concat(dflt.Ninit, dflt.Nbody)
- sel.Nbody = list1(r)
+ r.Nbody.Set(cas.Nbody.Slice())
+ r.Rlist = concat(dflt.Ninit, dflt.Nbody.NodeList())
+ sel.Nbody.Set([]*Node{r})
goto out
}
- init = sel.Ninit
+ init = make([]*Node, 0, count(sel.Ninit))
+ for ll := sel.Ninit; ll != nil; ll = ll.Next {
+ init = append(init, ll.N)
+ }
sel.Ninit = nil
// generate sel-struct
@@ -257,11 +264,11 @@
selv = temp(selecttype(int32(sel.Xoffset)))
r = Nod(OAS, selv, nil)
typecheck(&r, Etop)
- init = list(init, r)
+ init = append(init, r)
var_ = conv(conv(Nod(OADDR, selv, nil), Types[TUNSAFEPTR]), Ptrto(Types[TUINT8]))
r = mkcall("newselect", nil, nil, var_, Nodintconst(selv.Type.Width), Nodintconst(sel.Xoffset))
typecheck(&r, Etop)
- init = list(init, r)
+ init = append(init, r)
// register cases
for l := sel.List; l != nil; l = l.Next {
@@ -299,22 +306,22 @@
}
// selv is no longer alive after use.
- r.Nbody = list(r.Nbody, Nod(OVARKILL, selv, nil))
+ r.Nbody.Append(Nod(OVARKILL, selv, nil))
- r.Nbody = concat(r.Nbody, cas.Nbody)
- r.Nbody = list(r.Nbody, Nod(OBREAK, nil, nil))
- init = list(init, r)
+ r.Nbody.Append(cas.Nbody.Slice()...)
+ r.Nbody.Append(Nod(OBREAK, nil, nil))
+ init = append(init, r)
}
// run the select
setlineno(sel)
- init = list(init, mkcall("selectgo", nil, nil, var_))
- sel.Nbody = init
+ init = append(init, mkcall("selectgo", nil, nil, var_))
+ sel.Nbody.Set(init)
out:
sel.List = nil
- walkstmtlist(sel.Nbody)
+ walkstmtslice(sel.Nbody.Slice())
lineno = int32(lno)
}
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index f149c2c..c6647cc 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -24,7 +24,7 @@
// init1 walks the AST starting at n, and accumulates in out
// the list of definitions needing init code in dependency order.
-func init1(n *Node, out **NodeList) {
+func init1(n *Node, out *[]*Node) {
if n == nil {
return
}
@@ -98,7 +98,7 @@
Fatalf("init1: bad defn")
case ODCLFUNC:
- init2list(defn.Nbody, out)
+ init2slice(defn.Nbody.Slice(), out)
case OAS:
if defn.Left != n {
@@ -120,7 +120,7 @@
if Debug['%'] != 0 {
Dump("nonstatic", defn)
}
- *out = list(*out, defn)
+ *out = append(*out, defn)
}
case OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
@@ -134,7 +134,7 @@
if Debug['%'] != 0 {
Dump("nonstatic", defn)
}
- *out = list(*out, defn)
+ *out = append(*out, defn)
defn.Initorder = InitDone
}
}
@@ -187,7 +187,7 @@
}
// recurse over n, doing init1 everywhere.
-func init2(n *Node, out **NodeList) {
+func init2(n *Node, out *[]*Node) {
if n == nil || n.Initorder == InitDone {
return
}
@@ -202,23 +202,29 @@
init2list(n.Ninit, out)
init2list(n.List, out)
init2list(n.Rlist, out)
- init2list(n.Nbody, out)
+ init2slice(n.Nbody.Slice(), out)
if n.Op == OCLOSURE {
- init2list(n.Func.Closure.Nbody, out)
+ init2slice(n.Func.Closure.Nbody.Slice(), out)
}
if n.Op == ODOTMETH || n.Op == OCALLPART {
init2(n.Type.Nname, out)
}
}
-func init2list(l *NodeList, out **NodeList) {
+func init2list(l *NodeList, out *[]*Node) {
for ; l != nil; l = l.Next {
init2(l.N, out)
}
}
-func initreorder(l *NodeList, out **NodeList) {
+func init2slice(l []*Node, out *[]*Node) {
+ for _, n := range l {
+ init2(n, out)
+ }
+}
+
+func initreorder(l *NodeList, out *[]*Node) {
var n *Node
for ; l != nil; l = l.Next {
@@ -237,8 +243,8 @@
// initfix computes initialization order for a list l of top-level
// declarations and outputs the corresponding list of statements
// to include in the init() function body.
-func initfix(l *NodeList) *NodeList {
- var lout *NodeList
+func initfix(l *NodeList) []*Node {
+ var lout []*Node
initplans = make(map[*Node]*InitPlan)
lno := int(lineno)
initreorder(l, &lout)
@@ -249,7 +255,7 @@
// compilation of top-level (static) assignments
// into DATA statements if at all possible.
-func staticinit(n *Node, out **NodeList) bool {
+func staticinit(n *Node, out *[]*Node) bool {
if n.Op != ONAME || n.Class != PEXTERN || n.Name.Defn == nil || n.Name.Defn.Op != OAS {
Fatalf("staticinit")
}
@@ -262,7 +268,7 @@
// like staticassign but we are copying an already
// initialized value r.
-func staticcopy(l *Node, r *Node, out **NodeList) bool {
+func staticcopy(l *Node, r *Node, out *[]*Node) bool {
if r.Op != ONAME {
return false
}
@@ -291,7 +297,7 @@
if staticcopy(l, r, out) {
return true
}
- *out = list(*out, Nod(OAS, l, r))
+ *out = append(*out, Nod(OAS, l, r))
return true
case OLITERAL:
@@ -362,7 +368,7 @@
rr.Type = ll.Type
rr.Xoffset += e.Xoffset
setlineno(rr)
- *out = list(*out, Nod(OAS, ll, rr))
+ *out = append(*out, Nod(OAS, ll, rr))
}
}
}
@@ -373,7 +379,7 @@
return false
}
-func staticassign(l *Node, r *Node, out **NodeList) bool {
+func staticassign(l *Node, r *Node, out *[]*Node) bool {
for r.Op == OCONVNOP {
r = r.Left
}
@@ -410,7 +416,7 @@
// Init underlying literal.
if !staticassign(a, r.Left, out) {
- *out = list(*out, Nod(OAS, a, r.Left))
+ *out = append(*out, Nod(OAS, a, r.Left))
}
return true
}
@@ -463,7 +469,7 @@
*a = n
a.Orig = a // completely separate copy
if !staticassign(a, e.Expr, out) {
- *out = list(*out, Nod(OAS, a, e.Expr))
+ *out = append(*out, Nod(OAS, a, e.Expr))
}
}
}
@@ -967,7 +973,7 @@
r = Nod(OAS, r, a)
a = Nod(OFOR, nil, nil)
- a.Nbody = list1(r)
+ a.Nbody.Set([]*Node{r})
a.Ninit = list1(Nod(OAS, index, Nodintconst(0)))
a.Left = Nod(OLT, index, Nodintconst(t.Bound))
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 6c55820..204962c 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -2170,8 +2170,8 @@
l = list(l, nodlit(v)) // method name
call := Nod(OCALL, syslook("panicwrap", 0), nil)
call.List = l
- n.Nbody = list1(call)
- fn.Nbody = list(fn.Nbody, n)
+ n.Nbody.Set([]*Node{call})
+ fn.Nbody.Append(n)
}
dot := adddot(Nod(OXDOT, this.Left, newname(method.Sym)))
@@ -2185,10 +2185,10 @@
}
as := Nod(OAS, this.Left, Nod(OCONVNOP, dot, nil))
as.Right.Type = rcvr
- fn.Nbody = list(fn.Nbody, as)
+ fn.Nbody.Append(as)
n := Nod(ORETJMP, nil, nil)
n.Left = newname(methodsym(method.Sym, methodrcvr, 0))
- fn.Nbody = list(fn.Nbody, n)
+ fn.Nbody.Append(n)
} else {
fn.Func.Wrapper = true // ignore frame for panic+recover matching
call := Nod(OCALL, dot, nil)
@@ -2200,11 +2200,11 @@
call = n
}
- fn.Nbody = list(fn.Nbody, call)
+ fn.Nbody.Append(call)
}
if false && Debug['r'] != 0 {
- dumplist("genwrapper body", fn.Nbody)
+ dumpslice("genwrapper body", fn.Nbody.Slice())
}
funcbody(fn)
@@ -2215,7 +2215,7 @@
fn.Func.Dupok = true
}
typecheck(&fn, Etop)
- typechecklist(fn.Nbody, Etop)
+ typecheckslice(fn.Nbody.Slice(), Etop)
inlcalls(fn)
escAnalyze([]*Node{fn}, false)
@@ -2394,6 +2394,14 @@
return n
}
+func liststmtslice(l []*Node) *Node {
+ var ll *NodeList
+ for _, n := range l {
+ ll = list(ll, n)
+ }
+ return liststmt(ll)
+}
+
// return nelem of list
func structcount(t *Type) int {
var s Iter
@@ -2740,6 +2748,14 @@
n.Ullman = UINF
}
+func addinitslice(np **Node, init []*Node) {
+ var l *NodeList
+ for _, n := range init {
+ l = list(l, n)
+ }
+ addinit(np, l)
+}
+
var reservedimports = []string{
"go",
"type",
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 661b3ee..6e74349 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -181,7 +181,7 @@
}
}
- typechecklist(ncase.Nbody, Etop)
+ typecheckslice(ncase.Nbody.Slice(), Etop)
}
lineno = int32(lno)
@@ -230,7 +230,7 @@
}
// convert the switch into OIF statements
- var cas *NodeList
+ var cas []*Node
if s.kind == switchKindTrue || s.kind == switchKindFalse {
s.exprname = Nodbool(s.kind == switchKindTrue)
} else if consttype(cond) >= 0 {
@@ -238,8 +238,8 @@
s.exprname = cond
} else {
s.exprname = temp(cond.Type)
- cas = list1(Nod(OAS, s.exprname, cond))
- typechecklist(cas, Etop)
+ cas = []*Node{Nod(OAS, s.exprname, cond)}
+ typecheckslice(cas, Etop)
}
// enumerate the cases, and lop off the default case
@@ -258,7 +258,7 @@
// deal with expressions one at a time
if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst {
a := s.walkCases(cc[:1])
- cas = list(cas, a)
+ cas = append(cas, a)
cc = cc[1:]
continue
}
@@ -271,15 +271,15 @@
// sort and compile constants
sort.Sort(caseClauseByExpr(cc[:run]))
a := s.walkCases(cc[:run])
- cas = list(cas, a)
+ cas = append(cas, a)
cc = cc[run:]
}
// handle default case
if nerrors == 0 {
- cas = list(cas, def)
- sw.Nbody = concat(cas, sw.Nbody)
- walkstmtlist(sw.Nbody)
+ cas = append(cas, def)
+ sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
+ walkstmtslice(sw.Nbody.Slice())
}
}
@@ -303,7 +303,7 @@
a.Left = Nod(ONOT, n.Left, nil) // if !val
typecheck(&a.Left, Erv)
}
- a.Nbody = list1(n.Right) // goto l
+ a.Nbody.Set([]*Node{n.Right}) // goto l
cas = list(cas, a)
lineno = int32(lno)
@@ -325,7 +325,7 @@
a.Left = le
}
typecheck(&a.Left, Erv)
- a.Nbody = list1(s.walkCases(cc[:half]))
+ a.Nbody.Set([]*Node{s.walkCases(cc[:half])})
a.Rlist = list1(s.walkCases(cc[half:]))
return a
}
@@ -340,9 +340,9 @@
lno := setlineno(sw)
- var cas *NodeList // cases
- var stat *NodeList // statements
- var def *Node // defaults
+ var cas *NodeList // cases
+ var stat []*Node // statements
+ var def *Node // defaults
br := Nod(OBREAK, nil, nil)
for l := sw.List; l != nil; l = l.Next {
@@ -377,17 +377,19 @@
}
}
- stat = list(stat, Nod(OLABEL, jmp.Left, nil))
+ stat = append(stat, Nod(OLABEL, jmp.Left, nil))
if typeswvar != nil && needvar && n.Rlist != nil {
- l := list1(Nod(ODCL, n.Rlist.N, nil))
- l = list(l, Nod(OAS, n.Rlist.N, typeswvar))
- typechecklist(l, Etop)
- stat = concat(stat, l)
+ l := []*Node{
+ Nod(ODCL, n.Rlist.N, nil),
+ Nod(OAS, n.Rlist.N, typeswvar),
+ }
+ typecheckslice(l, Etop)
+ stat = append(stat, l...)
}
- stat = concat(stat, n.Nbody)
+ stat = append(stat, n.Nbody.Slice()...)
// botch - shouldn't fall thru declaration
- last := stat.End.N
+ last := stat[len(stat)-1]
if last.Xoffset == n.Xoffset && last.Op == OXFALL {
if typeswvar != nil {
setlineno(last)
@@ -401,17 +403,17 @@
last.Op = OFALL
} else {
- stat = list(stat, br)
+ stat = append(stat, br)
}
}
- stat = list(stat, br)
+ stat = append(stat, br)
if def != nil {
cas = list(cas, def)
}
sw.List = cas
- sw.Nbody = stat
+ sw.Nbody.Set(stat)
lineno = lno
}
@@ -531,14 +533,14 @@
return
}
- var cas *NodeList
+ var cas []*Node
// predeclare temporary variables and the boolean var
s.facename = temp(cond.Right.Type)
a := Nod(OAS, s.facename, cond.Right)
typecheck(&a, Etop)
- cas = list(cas, a)
+ cas = append(cas, a)
s.okname = temp(Types[TBOOL])
typecheck(&s.okname, Erv)
@@ -579,18 +581,18 @@
i.Left = Nod(OEQ, typ, nodnil())
if typenil != nil {
// Do explicit nil case right here.
- i.Nbody = list1(typenil)
+ i.Nbody.Set([]*Node{typenil})
} else {
// Jump to default case.
lbl := newCaseLabel()
- i.Nbody = list1(Nod(OGOTO, lbl, nil))
+ i.Nbody.Set([]*Node{Nod(OGOTO, lbl, nil)})
// Wrap default case with label.
blk := Nod(OBLOCK, nil, nil)
blk.List = list(list1(Nod(OLABEL, lbl, nil)), def)
def = blk
}
typecheck(&i.Left, Erv)
- cas = list(cas, i)
+ cas = append(cas, i)
if !isnilinter(cond.Right.Type) {
// Load type from itab.
@@ -608,7 +610,7 @@
h.Bounded = true // guaranteed not to fault
a = Nod(OAS, s.hashname, h)
typecheck(&a, Etop)
- cas = list(cas, a)
+ cas = append(cas, a)
// insert type equality check into each case block
for _, c := range cc {
@@ -625,7 +627,7 @@
for len(cc) > 0 {
if cc[0].typ != caseKindTypeConst {
n := cc[0].node
- cas = list(cas, n.Right)
+ cas = append(cas, n.Right)
cc = cc[1:]
continue
}
@@ -642,7 +644,7 @@
if false {
for i := 0; i < run; i++ {
n := cc[i].node
- cas = list(cas, n.Right)
+ cas = append(cas, n.Right)
}
continue
}
@@ -659,16 +661,16 @@
}
// binary search among cases to narrow by hash
- cas = list(cas, s.walkCases(cc[:ncase]))
+ cas = append(cas, s.walkCases(cc[:ncase]))
cc = cc[ncase:]
}
// handle default case
if nerrors == 0 {
- cas = list(cas, def)
- sw.Nbody = concat(cas, sw.Nbody)
+ cas = append(cas, def)
+ sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
sw.List = nil
- walkstmtlist(sw.Nbody)
+ walkstmtslice(sw.Nbody.Slice())
}
}
@@ -698,7 +700,7 @@
c := Nod(OIF, nil, nil)
c.Left = s.okname
- c.Nbody = list1(t.Right) // if ok { goto l }
+ c.Nbody.Set([]*Node{t.Right}) // if ok { goto l }
return liststmt(list(init, c))
}
@@ -715,7 +717,7 @@
a := Nod(OIF, nil, nil)
a.Left = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
typecheck(&a.Left, Erv)
- a.Nbody = list1(n.Right)
+ a.Nbody.Set([]*Node{n.Right})
cas = list(cas, a)
}
return liststmt(cas)
@@ -726,7 +728,7 @@
a := Nod(OIF, nil, nil)
a.Left = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
typecheck(&a.Left, Erv)
- a.Nbody = list1(s.walkCases(cc[:half]))
+ a.Nbody.Set([]*Node{s.walkCases(cc[:half])})
a.Rlist = list1(s.walkCases(cc[half:]))
return a
}
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index 7c34862..72944a7 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -16,7 +16,7 @@
Left *Node
Right *Node
Ninit *NodeList
- Nbody *NodeList
+ Nbody Nodes
List *NodeList
Rlist *NodeList
@@ -164,7 +164,7 @@
FCurfn *Node
Nname *Node
- Inl *NodeList // copy of the body for use in inlining
+ Inl Nodes // copy of the body for use in inlining
InlCost int32
Depth int32
@@ -503,7 +503,7 @@
// NodeList returns the entries in Nodes as a NodeList.
// Changes to the NodeList entries (as in l.N = n) will *not* be
-// reflect in the Nodes.
+// reflected in the Nodes.
// This wastes memory and should be used as little as possible.
func (n *Nodes) NodeList() *NodeList {
if n.slice == nil {
@@ -537,3 +537,23 @@
*n.slice = append(*n.slice, a...)
}
}
+
+// SetToNodeList sets Nodes to the contents of a NodeList.
+func (n *Nodes) SetToNodeList(l *NodeList) {
+ s := make([]*Node, 0, count(l))
+ for ; l != nil; l = l.Next {
+ s = append(s, l.N)
+ }
+ n.Set(s)
+}
+
+// AppendNodeList appends the contents of a NodeList.
+func (n *Nodes) AppendNodeList(l *NodeList) {
+ if n.slice == nil {
+ n.SetToNodeList(l)
+ } else {
+ for ; l != nil; l = l.Next {
+ *n.slice = append(*n.slice, l.N)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 0445551..3288599 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -217,7 +217,7 @@
return true
}
- return callrecv(n.Left) || callrecv(n.Right) || callrecvlist(n.Ninit) || callrecvlist(n.Nbody) || callrecvlist(n.List) || callrecvlist(n.Rlist)
+ return callrecv(n.Left) || callrecv(n.Right) || callrecvlist(n.Ninit) || callrecvslice(n.Nbody.Slice()) || callrecvlist(n.List) || callrecvlist(n.Rlist)
}
func callrecvlist(l *NodeList) bool {
@@ -229,6 +229,15 @@
return false
}
+func callrecvslice(l []*Node) bool {
+ for _, n := range l {
+ if callrecv(n) {
+ return true
+ }
+ }
+ return false
+}
+
// indexlit implements typechecking of untyped values as
// array/slice indexes. It is equivalent to defaultlit
// except for constants of numerical kind, which are acceptable
@@ -2064,7 +2073,7 @@
}
}
typecheck(&n.Right, Etop)
- typechecklist(n.Nbody, Etop)
+ typecheckslice(n.Nbody.Slice(), Etop)
decldepth--
break OpSwitch
@@ -2078,7 +2087,7 @@
Yyerror("non-bool %v used as if condition", Nconv(n.Left, obj.FmtLong))
}
}
- typechecklist(n.Nbody, Etop)
+ typecheckslice(n.Nbody.Slice(), Etop)
typechecklist(n.Rlist, Etop)
break OpSwitch
@@ -2128,7 +2137,7 @@
case OXCASE:
ok |= Etop
typechecklist(n.List, Erv)
- typechecklist(n.Nbody, Etop)
+ typecheckslice(n.Nbody.Slice(), Etop)
break OpSwitch
case ODCLFUNC:
@@ -3871,7 +3880,7 @@
markbreak(n.Right, implicit)
markbreaklist(n.Ninit, implicit)
- markbreaklist(n.Nbody, implicit)
+ markbreakslice(n.Nbody.Slice(), implicit)
markbreaklist(n.List, implicit)
markbreaklist(n.Rlist, implicit)
}
@@ -3904,26 +3913,51 @@
}
}
-func isterminating(l *NodeList, top int) bool {
+func markbreakslice(l []*Node, implicit *Node) {
+ for i := 0; i < len(l); i++ {
+ n := l[i]
+ if n.Op == OLABEL && i+1 < len(l) && n.Name.Defn == l[i+1] {
+ switch n.Name.Defn.Op {
+ case OFOR, OSWITCH, OTYPESW, OSELECT, ORANGE:
+ lab := new(Label)
+ lab.Def = n.Name.Defn
+ n.Left.Sym.Label = lab
+ markbreak(n.Name.Defn, n.Name.Defn)
+ n.Left.Sym.Label = nil
+ i++
+ continue
+ }
+ }
+
+ markbreak(n, implicit)
+ }
+}
+
+// Isterminating returns whether the NodeList l ends with a
+// terminating statement.
+func (l *NodeList) isterminating() bool {
if l == nil {
return false
}
- if top != 0 {
- for l.Next != nil && l.N.Op != OLABEL {
- l = l.Next
- }
- markbreaklist(l, nil)
- }
-
for l.Next != nil {
l = l.Next
}
- n := l.N
+ return l.N.isterminating()
+}
- if n == nil {
+// Isterminating whether the Nodes list ends with a terminating
+// statement.
+func (l Nodes) isterminating() bool {
+ c := len(l.Slice())
+ if c == 0 {
return false
}
+ return l.Slice()[c-1].isterminating()
+}
+// Isterminating returns whether the node n, the last one in a
+// statement list, is a terminating statement.
+func (n *Node) isterminating() bool {
switch n.Op {
// NOTE: OLABEL is treated as a separate statement,
// not a separate prefix, so skipping to the last statement
@@ -3931,7 +3965,7 @@
// skipping over the label. No case OLABEL here.
case OBLOCK:
- return isterminating(n.List, 0)
+ return n.List.isterminating()
case OGOTO,
ORETURN,
@@ -3950,15 +3984,15 @@
return true
case OIF:
- return isterminating(n.Nbody, 0) && isterminating(n.Rlist, 0)
+ return n.Nbody.isterminating() && n.Rlist.isterminating()
case OSWITCH, OTYPESW, OSELECT:
if n.Hasbreak {
return false
}
def := 0
- for l = n.List; l != nil; l = l.Next {
- if !isterminating(l.N.Nbody, 0) {
+ for l := n.List; l != nil; l = l.Next {
+ if !l.N.Nbody.isterminating() {
return false
}
if l.N.List == nil { // default
@@ -3976,8 +4010,9 @@
}
func checkreturn(fn *Node) {
- if fn.Type.Outtuple != 0 && fn.Nbody != nil {
- if !isterminating(fn.Nbody, 1) {
+ if fn.Type.Outtuple != 0 && len(fn.Nbody.Slice()) != 0 {
+ markbreakslice(fn.Nbody.Slice(), nil)
+ if !fn.Nbody.isterminating() {
yyerrorl(int(fn.Func.Endlineno), "missing return at end of function")
}
}
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 5e1db64..d0f942d 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -22,7 +22,7 @@
if Debug['W'] != 0 {
s := fmt.Sprintf("\nbefore %v", Curfn.Func.Nname.Sym)
- dumplist(s, Curfn.Nbody)
+ dumpslice(s, Curfn.Nbody.Slice())
}
lno := int(lineno)
@@ -64,10 +64,10 @@
if nerrors != 0 {
return
}
- walkstmtlist(Curfn.Nbody)
+ walkstmtslice(Curfn.Nbody.Slice())
if Debug['W'] != 0 {
s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
- dumplist(s, Curfn.Nbody)
+ dumpslice(s, Curfn.Nbody.Slice())
}
heapmoves()
@@ -264,11 +264,11 @@
}
walkstmt(&n.Right)
- walkstmtlist(n.Nbody)
+ walkstmtslice(n.Nbody.Slice())
case OIF:
walkexpr(&n.Left, &n.Ninit)
- walkstmtlist(n.Nbody)
+ walkstmtslice(n.Nbody.Slice())
walkstmtlist(n.Rlist)
case OPROC:
@@ -1009,7 +1009,7 @@
n2 := Nod(OIF, nil, nil)
n2.Left = Nod(OEQ, l, nodnil())
- n2.Nbody = list1(Nod(OAS, l, n1))
+ n2.Nbody.Set([]*Node{Nod(OAS, l, n1)})
n2.Likely = -1
typecheck(&n2, Etop)
*init = list(*init, n2)
@@ -2814,7 +2814,7 @@
substArgTypes(fn, s.Type.Type, s.Type.Type)
// s = growslice_n(T, s, n)
- nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt)))
+ nif.Nbody.Set([]*Node{Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt))})
l = list(l, nif)
@@ -2944,7 +2944,7 @@
fn := syslook("growslice", 1) // growslice(<type>, old []T, mincap int) (ret []T)
substArgTypes(fn, ns.Type.Type, ns.Type.Type)
- nx.Nbody = list1(Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, Nod(OADD, Nod(OLEN, ns, nil), na))))
+ nx.Nbody.Set([]*Node{Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, Nod(OADD, Nod(OLEN, ns, nil), na)))})
l = list(l, nx)
@@ -3018,7 +3018,7 @@
nif := Nod(OIF, nil, nil)
nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
- nif.Nbody = list(nif.Nbody, Nod(OAS, nlen, Nod(OLEN, nr, nil)))
+ nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
l = list(l, nif)
// Call memmove.
@@ -3804,6 +3804,15 @@
return true
}
+func candiscardslice(l []*Node) bool {
+ for _, n := range l {
+ if !candiscard(n) {
+ return false
+ }
+ }
+ return true
+}
+
func candiscard(n *Node) bool {
if n == nil {
return true
@@ -3890,7 +3899,7 @@
return false
}
- if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {
+ if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardslice(n.Nbody.Slice()) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {
return false
}
@@ -3946,12 +3955,12 @@
typecheck(&a, Etop)
walkstmt(&a)
- fn.Nbody = list1(a)
+ fn.Nbody.Set([]*Node{a})
funcbody(fn)
typecheck(&fn, Etop)
- typechecklist(fn.Nbody, Etop)
+ typecheckslice(fn.Nbody.Slice(), Etop)
xtop = list(xtop, fn)
Curfn = oldfn