From: Matthew Dempsky Date: Sat, 28 Aug 2021 00:14:00 +0000 (-0700) Subject: cmd/compile/internal/types: simplify and optimize PtrDataSize X-Git-Tag: go1.18beta1~1594 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c81fa001a7;p=gostls13.git cmd/compile/internal/types: simplify and optimize PtrDataSize 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 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go index 62afb5b928..ced90a47bc 100644 --- a/src/cmd/compile/internal/escape/expr.go +++ b/src/cmd/compile/internal/escape/expr.go @@ -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 } diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index aeeca90746..a47a26da74 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -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) diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 6070e15868..dafd76c79a 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -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,