interp: refactor doComposite cases
This commit is contained in:
19
_test/composite12.go
Normal file
19
_test/composite12.go
Normal 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
19
_test/composite13.go
Normal 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
16
_test/composite8bis.go
Normal 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
|
||||||
@@ -543,6 +543,12 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
|||||||
// which require and additional operation to set the value
|
// which require and additional operation to set the value
|
||||||
break
|
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
|
// Skip the assign operation entirely, the source frame index is set
|
||||||
// to destination index, avoiding extra memory alloc and duplication.
|
// to destination index, avoiding extra memory alloc and duplication.
|
||||||
n.gen = nop
|
n.gen = nop
|
||||||
@@ -2368,9 +2374,9 @@ func compositeGenerator(n *node, typ *itype) (gen bltnGenerator) {
|
|||||||
gen = compositeLitNotype
|
gen = compositeLitNotype
|
||||||
case n.lastChild().kind == keyValueExpr:
|
case n.lastChild().kind == keyValueExpr:
|
||||||
if n.nleft == 1 {
|
if n.nleft == 1 {
|
||||||
gen = compositeSparse
|
gen = compositeLitKeyed
|
||||||
} else {
|
} else {
|
||||||
gen = compositeSparseNotype
|
gen = compositeLitKeyedNotype
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if n.nleft == 1 {
|
if n.nleft == 1 {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ type receiver struct {
|
|||||||
|
|
||||||
// frame contains values for the current execution level (a function context).
|
// frame contains values for the current execution level (a function context).
|
||||||
type frame struct {
|
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.
|
// via newFrame/runid/setrunid/clone.
|
||||||
// Located at start of struct to ensure proper aligment.
|
// Located at start of struct to ensure proper aligment.
|
||||||
id uint64
|
id uint64
|
||||||
|
|||||||
120
interp/run.go
120
interp/run.go
@@ -2060,68 +2060,7 @@ func destType(n *node) *itype {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// doCompositeLit creates and populates a struct object.
|
func doComposite(n *node, hasType bool, keyed bool) {
|
||||||
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) {
|
|
||||||
value := valueGenerator(n, n.findex)
|
value := valueGenerator(n, n.findex)
|
||||||
next := getExec(n.tnext)
|
next := getExec(n.tnext)
|
||||||
typ := n.typ
|
typ := n.typ
|
||||||
@@ -2137,27 +2076,37 @@ func doCompositeSparse(n *node, hasType bool) {
|
|||||||
destInterface := destType(n).cat == interfaceT
|
destInterface := destType(n).cat == interfaceT
|
||||||
|
|
||||||
values := make(map[int]func(*frame) reflect.Value)
|
values := make(map[int]func(*frame) reflect.Value)
|
||||||
for _, c := range child {
|
for i, c := range child {
|
||||||
c1 := c.child[1]
|
var val *node
|
||||||
field := typ.fieldIndex(c.child[0].ident)
|
var fieldIndex int
|
||||||
convertLiteralValue(c1, typ.field[field].typ.TypeOf())
|
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 {
|
switch {
|
||||||
case c1.typ.cat == funcT:
|
case val.typ.cat == funcT:
|
||||||
values[field] = genFunctionWrapper(c1)
|
values[fieldIndex] = genFunctionWrapper(val)
|
||||||
case isArray(c1.typ) && c1.typ.val != nil && c1.typ.val.cat == interfaceT:
|
case isArray(val.typ) && val.typ.val != nil && val.typ.val.cat == interfaceT:
|
||||||
values[field] = genValueInterfaceArray(c1)
|
values[fieldIndex] = genValueInterfaceArray(val)
|
||||||
case isRecursiveType(typ.field[field].typ, typ.field[field].typ.rtype):
|
case isRecursiveType(typ.field[fieldIndex].typ, typ.field[fieldIndex].typ.rtype):
|
||||||
values[field] = genValueRecursiveInterface(c1, typ.field[field].typ.rtype)
|
values[fieldIndex] = genValueRecursiveInterface(val, typ.field[fieldIndex].typ.rtype)
|
||||||
case isInterface(typ.field[field].typ):
|
case isInterface(typ.field[fieldIndex].typ):
|
||||||
values[field] = genInterfaceWrapper(c1, typ.field[field].typ.rtype)
|
values[fieldIndex] = genInterfaceWrapper(val, typ.field[fieldIndex].typ.rtype)
|
||||||
default:
|
default:
|
||||||
values[field] = genValue(c1)
|
values[fieldIndex] = genValue(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frameIndex := n.findex
|
||||||
|
l := n.level
|
||||||
n.exec = func(f *frame) bltn {
|
n.exec = func(f *frame) bltn {
|
||||||
typ.mu.Lock()
|
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()
|
typ.mu.Unlock()
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
a.Field(i).Set(v(f))
|
a.Field(i).Set(v(f))
|
||||||
@@ -2169,14 +2118,27 @@ func doCompositeSparse(n *node, hasType bool) {
|
|||||||
case destInterface:
|
case destInterface:
|
||||||
d.Set(reflect.ValueOf(valueInterface{n, a}))
|
d.Set(reflect.ValueOf(valueInterface{n, a}))
|
||||||
default:
|
default:
|
||||||
d.Set(a)
|
getFrame(f, l).data[frameIndex] = a
|
||||||
}
|
}
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compositeSparse(n *node) { doCompositeSparse(n, true) }
|
// doCompositeLit creates and populates a struct object.
|
||||||
func compositeSparseNotype(n *node) { doCompositeSparse(n, false) }
|
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) {}
|
func empty(n *node) {}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user