1
0
mirror of https://github.com/golang/go synced 2024-11-26 04:07:59 -07:00

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 <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2021-08-27 17:14:00 -07:00
parent a9377183d0
commit c81fa001a7
3 changed files with 33 additions and 55 deletions

View 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
}

View 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() {
return 0
}
switch t.Kind() {
case TPTR,
TUNSAFEPTR,
TFUNC,
TCHAN,
TMAP:
case TBOOL, TINT8, TUINT8, TINT16, TUINT16, TINT32,
TUINT32, TINT64, TUINT64, TINT, TUINT,
TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64:
return 0
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)

View 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,