interp: refactor doComposite cases

This commit is contained in:
mpl
2020-09-22 17:26:03 +02:00
committed by GitHub
parent c06f83f34a
commit 3ae01a2af3
6 changed files with 104 additions and 82 deletions

19
_test/composite12.go Normal file
View File

@@ -0,0 +1,19 @@
package main
type A struct {
C D
}
type D struct {
E string
}
func main() {
a := A{}
a.C = D{"bb"}
println(a.C.E)
}
// Output:
// bb

19
_test/composite13.go Normal file
View File

@@ -0,0 +1,19 @@
package main
type A struct {
C D
}
type D struct {
E string
}
func main() {
a := A{}
a.C = D{E: "bb"}
println(a.C.E)
}
// Output:
// bb

16
_test/composite8bis.go Normal file
View File

@@ -0,0 +1,16 @@
package main
type T struct{ I int }
func main() {
t := []*T{}
s := []int{1, 2}
for _, e := range s {
x := &T{I: e}
t = append(t, x)
}
println(t[0].I, t[1].I)
}
// Output:
// 1 2

View File

@@ -543,6 +543,12 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
// which require and additional operation to set the value
break
}
if dest.action == aGetIndex {
// optimization does not work when assigning to a struct field. Maybe we're not
// setting the right frame index or something, and we would end up not writing at
// the right place. So disabling it for now.
break
}
// Skip the assign operation entirely, the source frame index is set
// to destination index, avoiding extra memory alloc and duplication.
n.gen = nop
@@ -2368,9 +2374,9 @@ func compositeGenerator(n *node, typ *itype) (gen bltnGenerator) {
gen = compositeLitNotype
case n.lastChild().kind == keyValueExpr:
if n.nleft == 1 {
gen = compositeSparse
gen = compositeLitKeyed
} else {
gen = compositeSparseNotype
gen = compositeLitKeyedNotype
}
default:
if n.nleft == 1 {

View File

@@ -60,7 +60,7 @@ type receiver struct {
// frame contains values for the current execution level (a function context).
type frame struct {
// id is an atomic counter used for cancellation, only access
// id is an atomic counter used for cancellation, only accessed
// via newFrame/runid/setrunid/clone.
// Located at start of struct to ensure proper aligment.
id uint64

View File

@@ -2060,68 +2060,7 @@ func destType(n *node) *itype {
}
}
// doCompositeLit creates and populates a struct object.
func doCompositeLit(n *node, hasType bool) {
value := valueGenerator(n, n.findex)
next := getExec(n.tnext)
typ := n.typ
if typ.cat == ptrT || typ.cat == aliasT {
typ = typ.val
}
var mu sync.Mutex
typ.mu = &mu
child := n.child
if hasType {
child = n.child[1:]
}
destInterface := destType(n).cat == interfaceT
values := make([]func(*frame) reflect.Value, len(child))
for i, c := range child {
convertLiteralValue(c, typ.field[i].typ.TypeOf())
switch {
case c.typ.cat == funcT:
values[i] = genFunctionWrapper(c)
case isArray(c.typ) && c.typ.val != nil && c.typ.val.cat == interfaceT:
values[i] = genValueInterfaceArray(c)
case isRecursiveType(typ.field[i].typ, typ.field[i].typ.rtype):
values[i] = genValueRecursiveInterface(c, typ.field[i].typ.rtype)
case isInterface(typ.field[i].typ):
values[i] = genInterfaceWrapper(c, typ.field[i].typ.rtype)
default:
values[i] = genValue(c)
}
}
i := n.findex
l := n.level
n.exec = func(f *frame) bltn {
// TODO: it seems fishy that the typ might be modified post-compilation, and
// hence that several goroutines might be using the same typ that they all modify.
// We probably need to revisit that.
typ.mu.Lock()
a := reflect.New(typ.TypeOf()).Elem()
typ.mu.Unlock()
for i, v := range values {
a.Field(i).Set(v(f))
}
switch d := value(f); {
case d.Type().Kind() == reflect.Ptr:
d.Set(a.Addr())
case destInterface:
d.Set(reflect.ValueOf(valueInterface{n, a}))
default:
getFrame(f, l).data[i] = a
}
return next
}
}
func compositeLit(n *node) { doCompositeLit(n, true) }
func compositeLitNotype(n *node) { doCompositeLit(n, false) }
// doCompositeSparse creates a struct Object, filling fields from sparse key-values.
func doCompositeSparse(n *node, hasType bool) {
func doComposite(n *node, hasType bool, keyed bool) {
value := valueGenerator(n, n.findex)
next := getExec(n.tnext)
typ := n.typ
@@ -2137,27 +2076,37 @@ func doCompositeSparse(n *node, hasType bool) {
destInterface := destType(n).cat == interfaceT
values := make(map[int]func(*frame) reflect.Value)
for _, c := range child {
c1 := c.child[1]
field := typ.fieldIndex(c.child[0].ident)
convertLiteralValue(c1, typ.field[field].typ.TypeOf())
for i, c := range child {
var val *node
var fieldIndex int
if keyed {
val = c.child[1]
fieldIndex = typ.fieldIndex(c.child[0].ident)
} else {
val = c
fieldIndex = i
}
convertLiteralValue(val, typ.field[fieldIndex].typ.TypeOf())
switch {
case c1.typ.cat == funcT:
values[field] = genFunctionWrapper(c1)
case isArray(c1.typ) && c1.typ.val != nil && c1.typ.val.cat == interfaceT:
values[field] = genValueInterfaceArray(c1)
case isRecursiveType(typ.field[field].typ, typ.field[field].typ.rtype):
values[field] = genValueRecursiveInterface(c1, typ.field[field].typ.rtype)
case isInterface(typ.field[field].typ):
values[field] = genInterfaceWrapper(c1, typ.field[field].typ.rtype)
case val.typ.cat == funcT:
values[fieldIndex] = genFunctionWrapper(val)
case isArray(val.typ) && val.typ.val != nil && val.typ.val.cat == interfaceT:
values[fieldIndex] = genValueInterfaceArray(val)
case isRecursiveType(typ.field[fieldIndex].typ, typ.field[fieldIndex].typ.rtype):
values[fieldIndex] = genValueRecursiveInterface(val, typ.field[fieldIndex].typ.rtype)
case isInterface(typ.field[fieldIndex].typ):
values[fieldIndex] = genInterfaceWrapper(val, typ.field[fieldIndex].typ.rtype)
default:
values[field] = genValue(c1)
values[fieldIndex] = genValue(val)
}
}
frameIndex := n.findex
l := n.level
n.exec = func(f *frame) bltn {
typ.mu.Lock()
a, _ := typ.zero()
// No need to call zero() as doComposite is only called for a structT
a := reflect.New(typ.TypeOf()).Elem()
typ.mu.Unlock()
for i, v := range values {
a.Field(i).Set(v(f))
@@ -2169,14 +2118,27 @@ func doCompositeSparse(n *node, hasType bool) {
case destInterface:
d.Set(reflect.ValueOf(valueInterface{n, a}))
default:
d.Set(a)
getFrame(f, l).data[frameIndex] = a
}
return next
}
}
func compositeSparse(n *node) { doCompositeSparse(n, true) }
func compositeSparseNotype(n *node) { doCompositeSparse(n, false) }
// doCompositeLit creates and populates a struct object.
func doCompositeLit(n *node, hasType bool) {
doComposite(n, hasType, false)
}
func compositeLit(n *node) { doCompositeLit(n, true) }
func compositeLitNotype(n *node) { doCompositeLit(n, false) }
// doCompositeLitKeyed creates a struct Object, filling fields from sparse key-values.
func doCompositeLitKeyed(n *node, hasType bool) {
doComposite(n, hasType, true)
}
func compositeLitKeyed(n *node) { doCompositeLitKeyed(n, true) }
func compositeLitKeyedNotype(n *node) { doCompositeLitKeyed(n, false) }
func empty(n *node) {}