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:
parent
93833cd5d8
commit
5e0258c700
@ -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.
|
||||
//
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user