]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types: simplify and optimize PtrDataSize
authorMatthew Dempsky <mdempsky@google.com>
Sat, 28 Aug 2021 00:14:00 +0000 (17:14 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Sat, 28 Aug 2021 00:50:13 +0000 (00:50 +0000)
The current implementation of PtrDataSize checks HasPointers each
call, which could lead to exponential blow-up in handling (admittedly
contrived) deeply nested structs.

To avoid the duplicate recursion, this CL incorporates the HasPointers
logic directly int PtrDataSize, and then re-defines HasPointers as
simply "PtrDataSize(t) > 0".

This CL also tightens up HasPointers/PtrDataSize to only be valid on
actual Go types. Fortunately, there was only one instance where this
wasn't already the case (escape analysis), and that's easily fixed
with an extra check for untyped types.

Change-Id: I0044bf9b558a88333aee2ccb137afb6cb4fea1db
Reviewed-on: https://go-review.googlesource.com/c/go/+/345809
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/escape/expr.go
src/cmd/compile/internal/types/size.go
src/cmd/compile/internal/types/type.go

index 62afb5b9288cbe1c007a16ad67a3e126e67b11e8..ced90a47bcb6632a4c8df5a0a1664ab5de409429 100644 (file)
@@ -30,7 +30,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
                base.Pos = lno
        }()
 
-       if k.derefs >= 0 && !n.Type().HasPointers() {
+       if k.derefs >= 0 && !n.Type().IsUntyped() && !n.Type().HasPointers() {
                k.dst = &e.blankLoc
        }
 
index aeeca9074607f19e0e84752379f7660da6bb837f..a47a26da74a84b5ac7c5d47763b89c3e504ef50b 100644 (file)
@@ -630,17 +630,23 @@ func ResumeCheckSize() {
 
 // PtrDataSize returns the length in bytes of the prefix of t
 // containing pointer data. Anything after this offset is scalar data.
+//
+// PtrDataSize is only defined for actual Go types. It's an error to
+// use it on compiler-internal types (e.g., TSSA, TRESULTS).
 func PtrDataSize(t *Type) int64 {
-       if !t.HasPointers() {
+       switch t.Kind() {
+       case TBOOL, TINT8, TUINT8, TINT16, TUINT16, TINT32,
+               TUINT32, TINT64, TUINT64, TINT, TUINT,
+               TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64:
                return 0
-       }
 
-       switch t.Kind() {
-       case TPTR,
-               TUNSAFEPTR,
-               TFUNC,
-               TCHAN,
-               TMAP:
+       case TPTR:
+               if t.Elem().NotInHeap() {
+                       return 0
+               }
+               return int64(PtrSize)
+
+       case TUNSAFEPTR, TFUNC, TCHAN, TMAP:
                return int64(PtrSize)
 
        case TSTRING:
@@ -654,24 +660,32 @@ func PtrDataSize(t *Type) int64 {
                return 2 * int64(PtrSize)
 
        case TSLICE:
+               if t.Elem().NotInHeap() {
+                       return 0
+               }
                // struct { byte *array; uintgo len; uintgo cap; }
                return int64(PtrSize)
 
        case TARRAY:
-               // haspointers already eliminated t.NumElem() == 0.
-               return (t.NumElem()-1)*t.Elem().width + PtrDataSize(t.Elem())
+               if t.NumElem() == 0 {
+                       return 0
+               }
+               // t.NumElem() > 0
+               size := PtrDataSize(t.Elem())
+               if size == 0 {
+                       return 0
+               }
+               return (t.NumElem()-1)*t.Elem().Size() + size
 
        case TSTRUCT:
-               // Find the last field that has pointers.
-               var lastPtrField *Field
+               // Find the last field that has pointers, if any.
                fs := t.Fields().Slice()
                for i := len(fs) - 1; i >= 0; i-- {
-                       if fs[i].Type.HasPointers() {
-                               lastPtrField = fs[i]
-                               break
+                       if size := PtrDataSize(fs[i].Type); size > 0 {
+                               return fs[i].Offset + size
                        }
                }
-               return lastPtrField.Offset + PtrDataSize(lastPtrField.Type)
+               return 0
 
        default:
                base.Fatalf("PtrDataSize: unexpected type, %v", t)
index 6070e158680936da0ec092257ed7492198a618fc..dafd76c79ab81e71906ddec963e8083212d5589b 100644 (file)
@@ -1681,43 +1681,7 @@ func (t *Type) IsUntyped() bool {
 // HasPointers reports whether t contains a heap pointer.
 // Note that this function ignores pointers to go:notinheap types.
 func (t *Type) HasPointers() bool {
-       switch t.kind {
-       case TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64,
-               TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL, TSSA:
-               return false
-
-       case TARRAY:
-               if t.NumElem() == 0 { // empty array has no pointers
-                       return false
-               }
-               return t.Elem().HasPointers()
-
-       case TSTRUCT:
-               for _, t1 := range t.Fields().Slice() {
-                       if t1.Type.HasPointers() {
-                               return true
-                       }
-               }
-               return false
-
-       case TPTR, TSLICE:
-               return !t.Elem().NotInHeap()
-
-       case TTUPLE:
-               ttup := t.extra.(*Tuple)
-               return ttup.first.HasPointers() || ttup.second.HasPointers()
-
-       case TRESULTS:
-               types := t.extra.(*Results).Types
-               for _, et := range types {
-                       if et.HasPointers() {
-                               return true
-                       }
-               }
-               return false
-       }
-
-       return true
+       return PtrDataSize(t) > 0
 }
 
 // Tie returns 'T' if t is a concrete type,