From 385c13cf18815bd165791d42aad8417bc1391644 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 5 Apr 2017 19:38:21 -0700 Subject: [PATCH] cmd/compile/internal/gc: remove a bunch of uses of iterField Passes toolstash-check -all. Change-Id: I9fb91dd78dff149b5e1e1329d00855fd41f12523 Reviewed-on: https://go-review.googlesource.com/39796 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/gc/esc.go | 93 ++++++++++-------------- src/cmd/compile/internal/gc/order.go | 47 ++++++------ src/cmd/compile/internal/gc/subr.go | 57 +++++++++------ src/cmd/compile/internal/gc/type.go | 42 ++++++++--- src/cmd/compile/internal/gc/typecheck.go | 49 ++++++------- src/cmd/compile/internal/gc/walk.go | 25 ++----- 6 files changed, 156 insertions(+), 157 deletions(-) diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index e97b06c8e5..272c83d9d5 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -1608,72 +1608,59 @@ func (e *EscState) esccall(call *Node, parent *Node) { } } - var arg *Node - var note string - param, it := iterFields(fntype.Params()) - i := 0 - for ; i < len(args); i++ { - arg = args[i] - note = param.Note + for i, param := range fntype.Params().FieldSlice() { + note := param.Note + var arg *Node if param.Isddd() && !call.Isddd() { + rest := args[i:] + if len(rest) == 0 { + break + } + // Introduce ODDDARG node to represent ... allocation. arg = nod(ODDDARG, nil, nil) arg.Pos = call.Pos - arr := typArray(param.Type.Elem(), int64(len(args)-i)) + arr := typArray(param.Type.Elem(), int64(len(rest))) arg.Type = typPtr(arr) // make pointer so it will be tracked e.track(arg) call.Right = arg - } - if haspointers(param.Type) { - if e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OPROC { - a := arg - for a.Op == OCONVNOP { - a = a.Left + // Store arguments into slice for ... arg. + for _, a := range rest { + if Debug['m'] > 3 { + fmt.Printf("%v::esccall:: ... <- %S\n", linestr(lineno), a) } - switch a.Op { - // The callee has already been analyzed, so its arguments have esc tags. - // The argument is marked as not escaping at all. - // Record that fact so that any temporary used for - // synthesizing this expression can be reclaimed when - // the function returns. - // This 'noescape' is even stronger than the usual esc == EscNone. - // arg.Esc == EscNone means that arg does not escape the current function. - // arg.SetNoescape(true) here means that arg does not escape this statement - // in the current function. - case OCALLPART, - OCLOSURE, - ODDDARG, - OARRAYLIT, - OSLICELIT, - OPTRLIT, - OSTRUCTLIT: - a.SetNoescape(true) + if note == uintptrEscapesTag { + e.escassignSinkWhyWhere(arg, a, "arg to uintptrescapes ...", call) + } else { + e.escassignWhyWhere(arg, a, "arg to ...", call) } } + } else { + arg = args[i] + if note == uintptrEscapesTag { + e.escassignSinkWhy(arg, arg, "escaping uintptr") + } } - if arg != args[i] { - // This occurs when function parameter field Isddd and call not Isddd - break - } - - if note == uintptrEscapesTag { - e.escassignSinkWhy(arg, arg, "escaping uintptr") - } - - param = it.Next() - } - - // Store arguments into slice for ... arg. - for ; i < len(args); i++ { - if Debug['m'] > 3 { - fmt.Printf("%v::esccall:: ... <- %S\n", linestr(lineno), args[i]) - } - if note == uintptrEscapesTag { - e.escassignSinkWhyWhere(arg, args[i], "arg to uintptrescapes ...", call) - } else { - e.escassignWhyWhere(arg, args[i], "arg to ...", call) + if haspointers(param.Type) && e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OPROC { + a := arg + for a.Op == OCONVNOP { + a = a.Left + } + switch a.Op { + // The callee has already been analyzed, so its arguments have esc tags. + // The argument is marked as not escaping at all. + // Record that fact so that any temporary used for + // synthesizing this expression can be reclaimed when + // the function returns. + // This 'noescape' is even stronger than the usual esc == EscNone. + // arg.Esc == EscNone means that arg does not escape the current function. + // arg.SetNoescape(true) here means that arg does not escape this statement + // in the current function. + case OCALLPART, OCLOSURE, ODDDARG, OARRAYLIT, OSLICELIT, OPTRLIT, OSTRUCTLIT: + a.SetNoescape(true) + } } } } diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index c4c7a9d765..c3e6d59700 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -390,33 +390,36 @@ func ordercall(n *Node, order *Order) { ordercallargs(&n.List, order) if n.Op == OCALLFUNC { - t, it := iterFields(n.Left.Type.Params()) - for i := range n.List.Slice() { - // Check for "unsafe-uintptr" tag provided by escape analysis. - // If present and the argument is really a pointer being converted - // to uintptr, arrange for the pointer to be kept alive until the call - // returns, by copying it into a temp and marking that temp + keepAlive := func(i int) { + // If the argument is really a pointer being converted to uintptr, + // arrange for the pointer to be kept alive until the call returns, + // by copying it into a temp and marking that temp // still alive when we pop the temp stack. - if t == nil { - break + xp := n.List.Addr(i) + for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() { + xp = &(*xp).Left } - if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag { - xp := n.List.Addr(i) - for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() { - xp = &(*xp).Left + x := *xp + if x.Type.IsPtr() { + x = ordercopyexpr(x, x.Type, order, 0) + x.Name.SetKeepalive(true) + *xp = x + } + } + + for i, t := range n.Left.Type.Params().FieldSlice() { + // Check for "unsafe-uintptr" tag provided by escape analysis. + if t.Isddd() && !n.Isddd() { + if t.Note == uintptrEscapesTag { + for ; i < n.List.Len(); i++ { + keepAlive(i) + } } - x := *xp - if x.Type.IsPtr() { - x = ordercopyexpr(x, x.Type, order, 0) - x.Name.SetKeepalive(true) - *xp = x + } else { + if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag { + keepAlive(i) } } - next := it.Next() - if next == nil && t.Isddd() && t.Note == uintptrEscapesTag { - next = t - } - t = next } } } diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index b358db2d0d..23ba48303b 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -655,19 +655,32 @@ func eqtype1(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) boo assumedEqual[typePair{t1, t2}] = struct{}{} switch t1.Etype { - case TINTER, TSTRUCT: - t1, i1 := iterFields(t1) - t2, i2 := iterFields(t2) - for ; t1 != nil && t2 != nil; t1, t2 = i1.Next(), i2.Next() { - if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, cmpTags, assumedEqual) || cmpTags && t1.Note != t2.Note { + case TINTER: + if t1.NumFields() != t2.NumFields() { + return false + } + for i, f1 := range t1.FieldSlice() { + f2 := t2.Field(i) + if f1.Sym != f2.Sym || !eqtype1(f1.Type, f2.Type, cmpTags, assumedEqual) { return false } } + return true - if t1 == nil && t2 == nil { - return true + case TSTRUCT: + if t1.NumFields() != t2.NumFields() { + return false } - return false + for i, f1 := range t1.FieldSlice() { + f2 := t2.Field(i) + if f1.Sym != f2.Sym || f1.Embedded != f2.Embedded || !eqtype1(f1.Type, f2.Type, cmpTags, assumedEqual) { + return false + } + if cmpTags && f1.Note != f2.Note { + return false + } + } + return true case TFUNC: // Check parameters and result parameters for type equality. @@ -675,16 +688,16 @@ func eqtype1(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) boo // equality, because they're never relevant. for _, f := range paramsResults { // Loop over fields in structs, ignoring argument names. - ta, ia := iterFields(f(t1)) - tb, ib := iterFields(f(t2)) - for ; ta != nil && tb != nil; ta, tb = ia.Next(), ib.Next() { - if ta.Isddd() != tb.Isddd() || !eqtype1(ta.Type, tb.Type, cmpTags, assumedEqual) { + fs1, fs2 := f(t1).FieldSlice(), f(t2).FieldSlice() + if len(fs1) != len(fs2) { + return false + } + for i, f1 := range fs1 { + f2 := fs2[i] + if f1.Isddd() != f2.Isddd() || !eqtype1(f1.Type, f2.Type, cmpTags, assumedEqual) { return false } } - if ta != nil || tb != nil { - return false - } } return true @@ -716,18 +729,16 @@ func eqtypenoname(t1 *Type, t2 *Type) bool { return false } - f1, i1 := iterFields(t1) - f2, i2 := iterFields(t2) - for { + if t1.NumFields() != t2.NumFields() { + return false + } + for i, f1 := range t1.FieldSlice() { + f2 := t2.Field(i) if !eqtype(f1.Type, f2.Type) { return false } - if f1 == nil { - return true - } - f1 = i1.Next() - f2 = i2.Next() } + return true } // Is type src assignment compatible to type dst? diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index 61220648cd..442dd752cc 100644 --- a/src/cmd/compile/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -1063,11 +1063,10 @@ func (t *Type) cmp(x *Type) ssa.Cmp { return ssa.CMPgt // bucket maps are least } // If t != t.Map.Bucket, fall through to general case - fallthrough - case TINTER: - t1, ti := iterFields(t) - x1, xi := iterFields(x) - for ; t1 != nil && x1 != nil; t1, x1 = ti.Next(), xi.Next() { + tfs := t.FieldSlice() + xfs := x.FieldSlice() + for i := 0; i < len(tfs) && i < len(xfs); i++ { + t1, x1 := tfs[i], xfs[i] if t1.Embedded != x1.Embedded { return cmpForNe(t1.Embedded < x1.Embedded) } @@ -1081,17 +1080,36 @@ func (t *Type) cmp(x *Type) ssa.Cmp { return c } } - if t1 != x1 { - return cmpForNe(t1 == nil) + if len(tfs) != len(xfs) { + return cmpForNe(len(tfs) < len(xfs)) + } + return ssa.CMPeq + + case TINTER: + tfs := t.FieldSlice() + xfs := x.FieldSlice() + for i := 0; i < len(tfs) && i < len(xfs); i++ { + t1, x1 := tfs[i], xfs[i] + if c := t1.Sym.cmpsym(x1.Sym); c != ssa.CMPeq { + return c + } + if c := t1.Type.cmp(x1.Type); c != ssa.CMPeq { + return c + } + } + if len(tfs) != len(xfs) { + return cmpForNe(len(tfs) < len(xfs)) } return ssa.CMPeq case TFUNC: for _, f := range recvsParamsResults { // Loop over fields in structs, ignoring argument names. - ta, ia := iterFields(f(t)) - tb, ib := iterFields(f(x)) - for ; ta != nil && tb != nil; ta, tb = ia.Next(), ib.Next() { + tfs := f(t).FieldSlice() + xfs := f(x).FieldSlice() + for i := 0; i < len(tfs) && i < len(xfs); i++ { + ta := tfs[i] + tb := xfs[i] if ta.Isddd() != tb.Isddd() { return cmpForNe(!ta.Isddd()) } @@ -1099,8 +1117,8 @@ func (t *Type) cmp(x *Type) ssa.Cmp { return c } } - if ta != tb { - return cmpForNe(ta == nil) + if len(tfs) != len(xfs) { + return cmpForNe(len(tfs) < len(xfs)) } } return ssa.CMPeq diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 17301ea820..f6776994dd 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -1604,8 +1604,7 @@ OpSwitch: } if funarg != nil { - _, it := iterFields(funarg) // Skip first field - for t := it.Next(); t != nil; t = it.Next() { + for _, t := range funarg.FieldSlice()[1:] { if assignop(t.Type, n.Type.Elem(), nil) == 0 { yyerror("cannot append %v value to []%v", t.Type, n.Type.Elem()) } @@ -2591,11 +2590,12 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc } } - tn, it := iterFields(n.Type) + lfs := tstruct.FieldSlice() + rfs := n.Type.FieldSlice() var why string - for _, tl := range tstruct.Fields().Slice() { + for i, tl := range lfs { if tl.Isddd() { - for ; tn != nil; tn = it.Next() { + for _, tn := range rfs[i:] { if assignop(tn.Type, tl.Type.Elem(), &why) == 0 { if call != nil { yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Elem(), call, why) @@ -2604,13 +2604,13 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc } } } - goto out } - if tn == nil { + if i >= len(rfs) { goto notenough } + tn := rfs[i] if assignop(tn.Type, tl.Type, &why) == 0 { if call != nil { yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type, call, why) @@ -2618,11 +2618,9 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type, desc(), why) } } - - tn = it.Next() } - if tn != nil { + if len(rfs) > len(lfs) { goto toomany } goto out @@ -3055,14 +3053,12 @@ func typecheckcomplit(n *Node) *Node { bad := 0 if n.List.Len() != 0 && nokeys(n.List) { // simple list of variables - f, it := iterFields(t) - ls := n.List.Slice() - for i1, n1 := range ls { + for i, n1 := range ls { setlineno(n1) - ls[i1] = typecheck(ls[i1], Erv) - n1 = ls[i1] - if f == nil { + n1 = typecheck(n1, Erv) + ls[i] = n1 + if i >= t.NumFields() { if bad == 0 { yyerror("too many values in struct initializer") } @@ -3070,6 +3066,7 @@ func typecheckcomplit(n *Node) *Node { continue } + f := t.Field(i) s := f.Sym if s != nil && !exportname(s.Name) && s.Pkg != localpkg { yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, t) @@ -3078,11 +3075,9 @@ func typecheckcomplit(n *Node) *Node { n1 = assignconv(n1, f.Type, "field value") n1 = nodSym(OSTRUCTKEY, n1, f.Sym) n1.Xoffset = f.Offset - ls[i1] = n1 - f = it.Next() + ls[i] = n1 } - - if f != nil { + if len(ls) < t.NumFields() { yyerror("too few values in struct initializer") } } else { @@ -3384,17 +3379,15 @@ func typecheckas2(n *Node) { goto mismatch } n.Op = OAS2FUNC - t, s := iterFields(r.Type) - for _, n3 := range n.List.Slice() { - if t.Type != nil && n3.Type != nil { - checkassignto(t.Type, n3) + for i, l := range n.List.Slice() { + f := r.Type.Field(i) + if f.Type != nil && l.Type != nil { + checkassignto(f.Type, l) } - if n3.Name != nil && n3.Name.Defn == n && n3.Name.Param.Ntype == nil { - n3.Type = t.Type + if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil { + l.Type = f.Type } - t = s.Next() } - goto out } } diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index db409900b3..45360f4890 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -1697,20 +1697,16 @@ func fncall(l *Node, rt *Type) bool { // a expression list. called in // expr-list = func() func ascompatet(op Op, nl Nodes, nr *Type) []*Node { - r, saver := iterFields(nr) + if nl.Len() != nr.NumFields() { + Fatalf("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields()) + } var nn, mm Nodes - var ullmanOverflow bool - var i int - for i = 0; i < nl.Len(); i++ { - if r == nil { - break - } - l := nl.Index(i) + for i, l := range nl.Slice() { if isblank(l) { - r = saver.Next() continue } + r := nr.Field(i) // any lv that causes a fn call must be // deferred until all the return arguments @@ -1729,19 +1725,10 @@ func ascompatet(op Op, nl Nodes, nr *Type) []*Node { updateHasCall(a) if a.HasCall() { Dump("ascompatet ucount", a) - ullmanOverflow = true + Fatalf("ascompatet: too many function calls evaluating parameters") } nn.Append(a) - r = saver.Next() - } - - if i < nl.Len() || r != nil { - Fatalf("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields()) - } - - if ullmanOverflow { - Fatalf("ascompatet: too many function calls evaluating parameters") } return append(nn.Slice(), mm.Slice()...) } -- 2.48.1