mirror of
https://github.com/golang/go
synced 2024-11-26 06:27:58 -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:
parent
a9377183d0
commit
c81fa001a7
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user