mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: allow multi-field structs to be stored directly in interfaces
If the struct is a bunch of 0-sized fields and one pointer field. Fixes #74092 Change-Id: I87c5d162c8c9fdba812420d7f9d21de97295b62c Reviewed-on: https://go-review.googlesource.com/c/go/+/681937 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
parent
21ab0128b6
commit
cd55f86b8d
7 changed files with 33 additions and 36 deletions
|
|
@ -921,8 +921,8 @@
|
||||||
@x.Block (Load <v.Type> (OffPtr <v.Type.PtrTo()> [t.FieldOff(int(i))] ptr) mem)
|
@x.Block (Load <v.Type> (OffPtr <v.Type.PtrTo()> [t.FieldOff(int(i))] ptr) mem)
|
||||||
|
|
||||||
// Putting struct{*byte} and similar into direct interfaces.
|
// Putting struct{*byte} and similar into direct interfaces.
|
||||||
(IMake _typ (StructMake val)) => (IMake _typ val)
|
(IMake _typ (StructMake val)) => imakeOfStructMake(v)
|
||||||
(StructSelect [0] (IData x)) => (IData x)
|
(StructSelect [_] (IData x)) => (IData x)
|
||||||
|
|
||||||
// un-SSAable values use mem->mem copies
|
// un-SSAable values use mem->mem copies
|
||||||
(Store {t} dst (Load src mem) mem) && !CanSSA(t) =>
|
(Store {t} dst (Load src mem) mem) && !CanSSA(t) =>
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,14 @@ func (x *expandState) decomposeAsNecessary(pos src.XPos, b *Block, a, m0 *Value,
|
||||||
if a.Op == OpIMake {
|
if a.Op == OpIMake {
|
||||||
data := a.Args[1]
|
data := a.Args[1]
|
||||||
for data.Op == OpStructMake || data.Op == OpArrayMake1 {
|
for data.Op == OpStructMake || data.Op == OpArrayMake1 {
|
||||||
data = data.Args[0]
|
// A struct make might have a few zero-sized fields.
|
||||||
|
// Use the pointer-y one we know is there.
|
||||||
|
for _, a := range data.Args {
|
||||||
|
if a.Type.Size() > 0 {
|
||||||
|
data = a
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return x.decomposeAsNecessary(pos, b, data, mem, rc.next(data.Type))
|
return x.decomposeAsNecessary(pos, b, data, mem, rc.next(data.Type))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2689,3 +2689,17 @@ func panicBoundsCToAux(p PanicBoundsC) Aux {
|
||||||
func panicBoundsCCToAux(p PanicBoundsCC) Aux {
|
func panicBoundsCCToAux(p PanicBoundsCC) Aux {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When v is (IMake typ (StructMake ...)), convert to
|
||||||
|
// (IMake typ arg) where arg is the pointer-y argument to
|
||||||
|
// the StructMake (there must be exactly one).
|
||||||
|
func imakeOfStructMake(v *Value) *Value {
|
||||||
|
var arg *Value
|
||||||
|
for _, a := range v.Args[1].Args {
|
||||||
|
if a.Type.Size() > 0 {
|
||||||
|
arg = a
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v.Block.NewValue2(v.Pos, OpIMake, v.Type, v.Args[0], arg)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11201,15 +11201,12 @@ func rewriteValuegeneric_OpIMake(v *Value) bool {
|
||||||
v_1 := v.Args[1]
|
v_1 := v.Args[1]
|
||||||
v_0 := v.Args[0]
|
v_0 := v.Args[0]
|
||||||
// match: (IMake _typ (StructMake val))
|
// match: (IMake _typ (StructMake val))
|
||||||
// result: (IMake _typ val)
|
// result: imakeOfStructMake(v)
|
||||||
for {
|
for {
|
||||||
_typ := v_0
|
|
||||||
if v_1.Op != OpStructMake || len(v_1.Args) != 1 {
|
if v_1.Op != OpStructMake || len(v_1.Args) != 1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
val := v_1.Args[0]
|
v.copyOf(imakeOfStructMake(v))
|
||||||
v.reset(OpIMake)
|
|
||||||
v.AddArg2(_typ, val)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (IMake _typ (ArrayMake1 val))
|
// match: (IMake _typ (ArrayMake1 val))
|
||||||
|
|
@ -32045,10 +32042,10 @@ func rewriteValuegeneric_OpStructSelect(v *Value) bool {
|
||||||
v0.AddArg2(v1, mem)
|
v0.AddArg2(v1, mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (StructSelect [0] (IData x))
|
// match: (StructSelect [_] (IData x))
|
||||||
// result: (IData x)
|
// result: (IData x)
|
||||||
for {
|
for {
|
||||||
if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpIData {
|
if v_0.Op != OpIData {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
x := v_0.Args[0]
|
x := v_0.Args[0]
|
||||||
|
|
|
||||||
|
|
@ -1829,26 +1829,7 @@ func IsReflexive(t *Type) bool {
|
||||||
// Can this type be stored directly in an interface word?
|
// Can this type be stored directly in an interface word?
|
||||||
// Yes, if the representation is a single pointer.
|
// Yes, if the representation is a single pointer.
|
||||||
func IsDirectIface(t *Type) bool {
|
func IsDirectIface(t *Type) bool {
|
||||||
switch t.Kind() {
|
return t.Size() == int64(PtrSize) && PtrDataSize(t) == int64(PtrSize)
|
||||||
case TPTR:
|
|
||||||
// Pointers to notinheap types must be stored indirectly. See issue 42076.
|
|
||||||
return !t.Elem().NotInHeap()
|
|
||||||
case TCHAN,
|
|
||||||
TMAP,
|
|
||||||
TFUNC,
|
|
||||||
TUNSAFEPTR:
|
|
||||||
return true
|
|
||||||
|
|
||||||
case TARRAY:
|
|
||||||
// Array of 1 direct iface type can be direct.
|
|
||||||
return t.NumElem() == 1 && IsDirectIface(t.Elem())
|
|
||||||
|
|
||||||
case TSTRUCT:
|
|
||||||
// Struct with 1 field of direct iface type can be direct.
|
|
||||||
return t.NumFields() == 1 && IsDirectIface(t.Field(0).Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsInterfaceMethod reports whether (field) m is
|
// IsInterfaceMethod reports whether (field) m is
|
||||||
|
|
|
||||||
|
|
@ -121,8 +121,8 @@ const (
|
||||||
TFlagGCMaskOnDemand TFlag = 1 << 4
|
TFlagGCMaskOnDemand TFlag = 1 << 4
|
||||||
|
|
||||||
// TFlagDirectIface means that a value of this type is stored directly
|
// TFlagDirectIface means that a value of this type is stored directly
|
||||||
// in the data field of an interface, instead of indirectly. Normally
|
// in the data field of an interface, instead of indirectly.
|
||||||
// this means the type is pointer-ish.
|
// This flag is just a cached computation of Size_ == PtrBytes == goarch.PtrSize.
|
||||||
TFlagDirectIface TFlag = 1 << 5
|
TFlagDirectIface TFlag = 1 << 5
|
||||||
|
|
||||||
// Leaving this breadcrumb behind for dlv. It should not be used, and no
|
// Leaving this breadcrumb behind for dlv. It should not be used, and no
|
||||||
|
|
|
||||||
|
|
@ -2524,8 +2524,7 @@ func StructOf(fields []StructField) Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case len(fs) == 1 && fs[0].Typ.IsDirectIface():
|
case typ.Size_ == goarch.PtrSize && typ.PtrBytes == goarch.PtrSize:
|
||||||
// structs of 1 direct iface type can be direct
|
|
||||||
typ.TFlag |= abi.TFlagDirectIface
|
typ.TFlag |= abi.TFlagDirectIface
|
||||||
default:
|
default:
|
||||||
typ.TFlag &^= abi.TFlagDirectIface
|
typ.TFlag &^= abi.TFlagDirectIface
|
||||||
|
|
@ -2694,8 +2693,7 @@ func ArrayOf(length int, elem Type) Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case length == 1 && typ.IsDirectIface():
|
case array.Size_ == goarch.PtrSize && array.PtrBytes == goarch.PtrSize:
|
||||||
// array of 1 direct iface type can be direct
|
|
||||||
array.TFlag |= abi.TFlagDirectIface
|
array.TFlag |= abi.TFlagDirectIface
|
||||||
default:
|
default:
|
||||||
array.TFlag &^= abi.TFlagDirectIface
|
array.TFlag &^= abi.TFlagDirectIface
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue