1
0
mirror of https://github.com/golang/go synced 2024-11-16 22:04:50 -07:00

[dev.unified] cmd/compile: avoid reflectType in ssagen

This CL adds alternate code paths for the frontend to plumb through
rtypes to package ssagen, so the latter doesn't have to use
reflectType (which in general will only have access to shape types).

Note: This CL doesn't yet plumb through the rtypes for variables that
escape to the heap. However, those rtypes are only used for calling
runtime.newobject, and the status quo as of Go 1.18 is already to use
shape rtypes for most runtime.newobject calls. (Longer term though, I
would like to get rid of shape rtypes altogether.)

Passes toolstash -cmp.

Updates #53276.

Change-Id: I76a281eca8300de2e701fbac89ead32f8568a5f2
Reviewed-on: https://go-review.googlesource.com/c/go/+/413357
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Matthew Dempsky 2022-06-20 22:28:15 -07:00
parent 93833cd5d8
commit 5e0258c700
2 changed files with 49 additions and 12 deletions

View File

@ -246,6 +246,16 @@ func (n *ConstExpr) Val() constant.Value { return n.val }
type ConvExpr struct {
miniExpr
X Node
// For -d=checkptr instrumentation of conversions from
// unsafe.Pointer to *Elem or *[Len]Elem.
//
// TODO(mdempsky): We only ever need one of these, but currently we
// don't decide which one until walk. Longer term, it probably makes
// sense to have a dedicated IR op for `(*[Len]Elem)(ptr)[:n:m]`
// expressions.
ElemRType Node `mknode:"-"`
ElemElemRType Node `mknode:"-"`
}
func NewConvExpr(pos src.XPos, op Op, typ *types.Type, x Node) *ConvExpr {
@ -650,6 +660,11 @@ type DynamicTypeAssertExpr struct {
miniExpr
X Node
// SrcRType is an expression that yields a *runtime._type value
// representing X's type. It's used in failed assertion panic
// messages.
SrcRType Node
// RType is an expression that yields a *runtime._type value
// representing the asserted type.
//

View File

@ -664,7 +664,7 @@ func (s *state) paramsToHeap() {
// newHeapaddr allocates heap memory for n and sets its heap address.
func (s *state) newHeapaddr(n *ir.Name) {
s.setHeapaddr(n.Pos(), n, s.newObject(n.Type()))
s.setHeapaddr(n.Pos(), n, s.newObject(n.Type(), nil))
}
// setHeapaddr allocates a new PAUTO variable to store ptr (which must be non-nil)
@ -692,23 +692,26 @@ func (s *state) setHeapaddr(pos src.XPos, n *ir.Name, ptr *ssa.Value) {
}
// newObject returns an SSA value denoting new(typ).
func (s *state) newObject(typ *types.Type) *ssa.Value {
func (s *state) newObject(typ *types.Type, rtype *ssa.Value) *ssa.Value {
if typ.Size() == 0 {
return s.newValue1A(ssa.OpAddr, types.NewPtr(typ), ir.Syms.Zerobase, s.sb)
}
return s.rtcall(ir.Syms.Newobject, true, []*types.Type{types.NewPtr(typ)}, s.reflectType(typ))[0]
if rtype == nil {
rtype = s.reflectType(typ)
}
return s.rtcall(ir.Syms.Newobject, true, []*types.Type{types.NewPtr(typ)}, rtype)[0]
}
func (s *state) checkPtrAlignment(n *ir.ConvExpr, v *ssa.Value, count *ssa.Value) {
if !n.Type().IsPtr() {
s.Fatalf("expected pointer type: %v", n.Type())
}
elem := n.Type().Elem()
elem, rtypeExpr := n.Type().Elem(), n.ElemRType
if count != nil {
if !elem.IsArray() {
s.Fatalf("expected array type: %v", elem)
}
elem = elem.Elem()
elem, rtypeExpr = elem.Elem(), n.ElemElemRType
}
size := elem.Size()
// Casting from larger type to smaller one is ok, so for smallest type, do nothing.
@ -721,12 +724,20 @@ func (s *state) checkPtrAlignment(n *ir.ConvExpr, v *ssa.Value, count *ssa.Value
if count.Type.Size() != s.config.PtrSize {
s.Fatalf("expected count fit to an uintptr size, have: %d, want: %d", count.Type.Size(), s.config.PtrSize)
}
s.rtcall(ir.Syms.CheckPtrAlignment, true, nil, v, s.reflectType(elem), count)
var rtype *ssa.Value
if rtypeExpr != nil {
rtype = s.expr(rtypeExpr)
} else {
rtype = s.reflectType(elem)
}
s.rtcall(ir.Syms.CheckPtrAlignment, true, nil, v, rtype, count)
}
// reflectType returns an SSA value representing a pointer to typ's
// reflection type descriptor.
func (s *state) reflectType(typ *types.Type) *ssa.Value {
// TODO(mdempsky): Make this Fatalf under Unified IR; frontend needs
// to supply RType expressions.
lsym := reflectdata.TypeLinksym(typ)
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(types.Types[types.TUINT8]), lsym, s.sb)
}
@ -3290,7 +3301,11 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
case ir.ONEW:
n := n.(*ir.UnaryExpr)
return s.newObject(n.Type().Elem())
var rtype *ssa.Value
if x, ok := n.X.(*ir.DynamicType); ok && x.Op() == ir.ODYNAMICTYPE {
rtype = s.expr(x.RType)
}
return s.newObject(n.Type().Elem(), rtype)
case ir.OUNSAFEADD:
n := n.(*ir.BinaryExpr)
@ -6222,12 +6237,15 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
if n.ITab != nil {
targetItab = s.expr(n.ITab)
}
return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, target, targetItab, commaok)
return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, nil, target, targetItab, commaok)
}
func (s *state) dynamicDottype(n *ir.DynamicTypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
iface := s.expr(n.X)
var target, targetItab *ssa.Value
var source, target, targetItab *ssa.Value
if n.SrcRType != nil {
source = s.expr(n.SrcRType)
}
if !n.X.Type().IsEmptyInterface() && !n.Type().IsInterface() {
byteptr := s.f.Config.Types.BytePtr
targetItab = s.expr(n.ITab)
@ -6237,15 +6255,16 @@ func (s *state) dynamicDottype(n *ir.DynamicTypeAssertExpr, commaok bool) (res,
} else {
target = s.expr(n.RType)
}
return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, target, targetItab, commaok)
return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, source, target, targetItab, commaok)
}
// dottype1 implements a x.(T) operation. iface is the argument (x), dst is the type we're asserting to (T)
// and src is the type we're asserting from.
// source is the *runtime._type of src
// target is the *runtime._type of dst.
// If src is a nonempty interface and dst is not an interface, targetItab is an itab representing (dst, src). Otherwise it is nil.
// commaok is true if the caller wants a boolean success value. Otherwise, the generated code panics if the conversion fails.
func (s *state) dottype1(pos src.XPos, src, dst *types.Type, iface, target, targetItab *ssa.Value, commaok bool) (res, resok *ssa.Value) {
func (s *state) dottype1(pos src.XPos, src, dst *types.Type, iface, source, target, targetItab *ssa.Value, commaok bool) (res, resok *ssa.Value) {
byteptr := s.f.Config.Types.BytePtr
if dst.IsInterface() {
if dst.IsEmptyInterface() {
@ -6381,7 +6400,10 @@ func (s *state) dottype1(pos src.XPos, src, dst *types.Type, iface, target, targ
if !commaok {
// on failure, panic by calling panicdottype
s.startBlock(bFail)
taddr := s.reflectType(src)
taddr := source
if taddr == nil {
taddr = s.reflectType(src)
}
if src.IsEmptyInterface() {
s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr)
} else {