From bbfae469a1d207a415dd813d799df1ed2dd2d80a Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 30 Mar 2018 12:25:02 -0700 Subject: [PATCH] cmd/compile: handle blank struct fields in NumComponents NumComponents is used by racewalk to decide whether reads and writes might occur to subobjects of an address. For that purpose, blank fields matter. It is also used to decide whether to inline == and != for a type. For that purpose, blank fields may be ignored. Add a parameter to NumComponents to support this distinction. While we're here, document NumComponents, as requested in CL 59334. Change-Id: I8c2021b172edadd6184848a32a74774dde1805c8 Reviewed-on: https://go-review.googlesource.com/103755 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/racewalk.go | 2 +- src/cmd/compile/internal/gc/walk.go | 2 +- src/cmd/compile/internal/types/type.go | 22 +++++++++++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index 9df85adf62..5392d809ae 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -461,7 +461,7 @@ func callinstr(np **Node, init *Nodes, wr, skip bool) { name = "msanwrite" } f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w)) - } else if flag_race && t.NumComponents() > 1 { + } else if flag_race && t.NumComponents(types.CountBlankFields) > 1 { // for composite objects we have to write every address // because a write might happen to any subobject. // composites with only one element don't have subobjects, though. diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index d392d567ca..1f2f5c68c2 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3298,7 +3298,7 @@ func walkcompare(n *Node, init *Nodes) *Node { // We can compare several elements at once with 2/4/8 byte integer compares inline = t.NumElem() <= 1 || (issimple[t.Elem().Etype] && (t.NumElem() <= 4 || t.Elem().Width*t.NumElem() <= maxcmpsize)) case TSTRUCT: - inline = t.NumComponents() <= 4 + inline = t.NumComponents(types.IgnoreBlankFields) <= 4 } cmpl := n.Left diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 87623a2cc3..f5e9237b81 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -1325,7 +1325,20 @@ func (t *Type) SetNumElem(n int64) { at.Bound = n } -func (t *Type) NumComponents() int64 { +type componentsIncludeBlankFields bool + +const ( + IgnoreBlankFields componentsIncludeBlankFields = false + CountBlankFields componentsIncludeBlankFields = true +) + +// NumComponents returns the number of primitive elements that compose t. +// Struct and array types are flattened for the purpose of counting. +// All other types (including string, slice, and interface types) count as one element. +// If countBlank is IgnoreBlankFields, then blank struct fields +// (and their comprised elements) are excluded from the count. +// struct { x, y [3]int } has six components; [10]struct{ x, y string } has twenty. +func (t *Type) NumComponents(countBlank componentsIncludeBlankFields) int64 { switch t.Etype { case TSTRUCT: if t.IsFuncArgStruct() { @@ -1333,11 +1346,14 @@ func (t *Type) NumComponents() int64 { } var n int64 for _, f := range t.FieldSlice() { - n += f.Type.NumComponents() + if countBlank == IgnoreBlankFields && f.Sym.IsBlank() { + continue + } + n += f.Type.NumComponents(countBlank) } return n case TARRAY: - return t.NumElem() * t.Elem().NumComponents() + return t.NumElem() * t.Elem().NumComponents(countBlank) } return 1 } -- 2.50.0