]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.unified] cmd/compile: avoid reflectType in ssagen
authorMatthew Dempsky <mdempsky@google.com>
Tue, 21 Jun 2022 05:28:15 +0000 (22:28 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 21 Jun 2022 23:51:26 +0000 (23:51 +0000)
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>
src/cmd/compile/internal/ir/expr.go
src/cmd/compile/internal/ssagen/ssa.go

index 8ac7e7f4f7797c08fd8f40c7b29205af8edff0c2..27dd390efcc4d9e0c342b603b59cb0b97cd24c6c 100644 (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.
        //
index a7778d37fb39200b00f297d8140dacb38b3b8322..64a30d427fb0d54b800b00b35a57fbc28bc1964c 100644 (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 {