Skip to content

Commit b40dc30

Browse files
committed
cmd/compile: compute ptrBytes during CalcSize instead of on demand
Compute ptrBytes while computing the size of a type. Requires an extra field on the type, but means that we don't have potentially exponential behavior in the PtrDataSize computation. For #65540. Change-Id: Ia23c72bbd996730baddd32d9ed46cfc00c3472ee Reviewed-on: https://go-review.googlesource.com/c/go/+/571543 Reviewed-by: Keith Randall <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]>
1 parent dda4b17 commit b40dc30

File tree

3 files changed

+65
-68
lines changed

3 files changed

+65
-68
lines changed

src/cmd/compile/internal/types/size.go

Lines changed: 36 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ func isAtomicStdPkg(p *Pkg) bool {
202202
return p.Prefix == "sync/atomic" || p.Prefix == "runtime/internal/atomic"
203203
}
204204

205-
// CalcSize calculates and stores the size, alignment, and eq/hash algorithm for t.
205+
// CalcSize calculates and stores the size, alignment, eq/hash algorithm,
206+
// and ptrBytes for t.
206207
// If CalcSizeDisabled is set, and the size/alignment
207208
// have not already been calculated, it calls Fatal.
208209
// This is used to prevent data races in the back end.
@@ -247,6 +248,7 @@ func CalcSize(t *Type) {
247248
t.width = -2
248249
t.align = 0 // 0 means use t.Width, below
249250
t.alg = AMEM // default
251+
// default t.ptrBytes is 0.
250252
if t.Noalg() {
251253
t.setAlg(ANOALG)
252254
}
@@ -314,10 +316,12 @@ func CalcSize(t *Type) {
314316
w = int64(PtrSize)
315317
t.intRegs = 1
316318
CheckSize(t.Elem())
319+
t.ptrBytes = int64(PtrSize) // See PtrDataSize
317320

318321
case TUNSAFEPTR:
319322
w = int64(PtrSize)
320323
t.intRegs = 1
324+
t.ptrBytes = int64(PtrSize)
321325

322326
case TINTER: // implemented as 2 pointers
323327
w = 2 * int64(PtrSize)
@@ -329,10 +333,12 @@ func CalcSize(t *Type) {
329333
} else {
330334
t.setAlg(AINTER)
331335
}
336+
t.ptrBytes = int64(2 * PtrSize)
332337

333338
case TCHAN: // implemented as pointer
334339
w = int64(PtrSize)
335340
t.intRegs = 1
341+
t.ptrBytes = int64(PtrSize)
336342

337343
CheckSize(t.Elem())
338344

@@ -360,6 +366,7 @@ func CalcSize(t *Type) {
360366
CheckSize(t.Elem())
361367
CheckSize(t.Key())
362368
t.setAlg(ANOEQ)
369+
t.ptrBytes = int64(PtrSize)
363370

364371
case TFORW: // should have been filled in
365372
base.Fatalf("invalid recursive type %v", t)
@@ -375,6 +382,7 @@ func CalcSize(t *Type) {
375382
t.align = uint8(PtrSize)
376383
t.intRegs = 2
377384
t.setAlg(ASTRING)
385+
t.ptrBytes = int64(PtrSize)
378386

379387
case TARRAY:
380388
if t.Elem() == nil {
@@ -420,6 +428,12 @@ func CalcSize(t *Type) {
420428
t.setAlg(ASPECIAL)
421429
}
422430
}
431+
if t.NumElem() > 0 {
432+
x := PtrDataSize(t.Elem())
433+
if x > 0 {
434+
t.ptrBytes = t.Elem().width*(t.NumElem()-1) + x
435+
}
436+
}
423437

424438
case TSLICE:
425439
if t.Elem() == nil {
@@ -430,6 +444,9 @@ func CalcSize(t *Type) {
430444
t.align = uint8(PtrSize)
431445
t.intRegs = 3
432446
t.setAlg(ANOEQ)
447+
if !t.Elem().NotInHeap() {
448+
t.ptrBytes = int64(PtrSize)
449+
}
433450

434451
case TSTRUCT:
435452
if t.IsFuncArgStruct() {
@@ -446,6 +463,7 @@ func CalcSize(t *Type) {
446463
w = int64(PtrSize) // width of func type is pointer
447464
t.intRegs = 1
448465
t.setAlg(ANOEQ)
466+
t.ptrBytes = int64(PtrSize)
449467

450468
// function is 3 cated structures;
451469
// compute their widths as side-effect.
@@ -490,8 +508,6 @@ func CalcStructSize(t *Type) {
490508
switch {
491509
case sym.Name == "align64" && isAtomicStdPkg(sym.Pkg):
492510
maxAlign = 8
493-
case sym.Pkg.Path == "runtime/internal/sys" && sym.Name == "nih":
494-
t.SetNotInHeap(true)
495511
}
496512
}
497513

@@ -560,6 +576,14 @@ func CalcStructSize(t *Type) {
560576
t.setAlg(a)
561577
}
562578
}
579+
// Compute ptrBytes.
580+
for i := len(fields) - 1; i >= 0; i-- {
581+
f := fields[i]
582+
if size := PtrDataSize(f.Type); size > 0 {
583+
t.ptrBytes = f.Offset + size
584+
break
585+
}
586+
}
563587
}
564588

565589
func (t *Type) widthCalculated() bool {
@@ -630,67 +654,13 @@ func ResumeCheckSize() {
630654
// PtrDataSize is only defined for actual Go types. It's an error to
631655
// use it on compiler-internal types (e.g., TSSA, TRESULTS).
632656
func PtrDataSize(t *Type) int64 {
633-
switch t.Kind() {
634-
case TBOOL, TINT8, TUINT8, TINT16, TUINT16, TINT32,
635-
TUINT32, TINT64, TUINT64, TINT, TUINT,
636-
TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64:
637-
return 0
638-
639-
case TPTR:
640-
if t.Elem().NotInHeap() {
641-
return 0
642-
}
643-
return int64(PtrSize)
644-
645-
case TUNSAFEPTR, TFUNC, TCHAN, TMAP:
646-
return int64(PtrSize)
647-
648-
case TSTRING:
649-
// struct { byte *str; intgo len; }
650-
return int64(PtrSize)
651-
652-
case TINTER:
653-
// struct { Itab *tab; void *data; } or
654-
// struct { Type *type; void *data; }
655-
// Note: see comment in typebits.Set
656-
return 2 * int64(PtrSize)
657-
658-
case TSLICE:
659-
if t.Elem().NotInHeap() {
660-
return 0
661-
}
662-
// struct { byte *array; uintgo len; uintgo cap; }
663-
return int64(PtrSize)
664-
665-
case TARRAY:
666-
if t.NumElem() == 0 {
667-
return 0
668-
}
669-
// t.NumElem() > 0
670-
size := PtrDataSize(t.Elem())
671-
if size == 0 {
672-
return 0
673-
}
674-
return (t.NumElem()-1)*t.Elem().Size() + size
675-
676-
case TSTRUCT:
677-
// Find the last field that has pointers, if any.
678-
fs := t.Fields()
679-
for i := len(fs) - 1; i >= 0; i-- {
680-
if size := PtrDataSize(fs[i].Type); size > 0 {
681-
return fs[i].Offset + size
682-
}
683-
}
684-
return 0
685-
686-
case TSSA:
687-
if t != TypeInt128 {
688-
base.Fatalf("PtrDataSize: unexpected ssa type %v", t)
689-
}
690-
return 0
691-
692-
default:
693-
base.Fatalf("PtrDataSize: unexpected type, %v", t)
694-
return 0
695-
}
657+
CalcSize(t)
658+
x := t.ptrBytes
659+
if t.Kind() == TPTR && t.Elem().NotInHeap() {
660+
// Note: this is done here instead of when we're setting
661+
// the ptrBytes field, because at that time (in NewPtr, usually)
662+
// the NotInHeap bit of the element type might not be set yet.
663+
x = 0
664+
}
665+
return x
696666
}

src/cmd/compile/internal/types/sizeof_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
2121
_64bit uintptr // size on 64bit platforms
2222
}{
2323
{Sym{}, 32, 64},
24-
{Type{}, 56, 96},
24+
{Type{}, 64, 104},
2525
{Map{}, 12, 24},
2626
{Forward{}, 20, 32},
2727
{Func{}, 32, 56},

src/cmd/compile/internal/types/type.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ type Type struct {
203203
flags bitset8
204204
alg AlgKind // valid if Align > 0
205205

206+
// size of prefix of object that contains all pointers. valid if Align > 0.
207+
// Note that for pointers, this is always PtrSize even if the element type
208+
// is NotInHeap. See size.go:PtrDataSize for details.
209+
ptrBytes int64
210+
206211
// For defined (named) generic types, a pointer to the list of type params
207212
// (in order) of this type that need to be instantiated. For instantiated
208213
// generic types, this is the targs used to instantiate them. These targs
@@ -549,6 +554,9 @@ func NewArray(elem *Type, bound int64) *Type {
549554
if elem.HasShape() {
550555
t.SetHasShape(true)
551556
}
557+
if elem.NotInHeap() {
558+
t.SetNotInHeap(true)
559+
}
552560
return t
553561
}
554562

@@ -663,6 +671,9 @@ func NewPtr(elem *Type) *Type {
663671
t.SetNoalg(true)
664672
t.alg = ANOALG
665673
}
674+
// Note: we can't check elem.NotInHeap here because it might
675+
// not be set yet. See size.go:PtrDataSize.
676+
t.ptrBytes = int64(PtrSize)
666677
return t
667678
}
668679

@@ -1634,10 +1645,18 @@ func init() {
16341645
func NewNamed(obj Object) *Type {
16351646
t := newType(TFORW)
16361647
t.obj = obj
1637-
if obj.Sym().Pkg == ShapePkg {
1648+
sym := obj.Sym()
1649+
if sym.Pkg == ShapePkg {
16381650
t.SetIsShape(true)
16391651
t.SetHasShape(true)
16401652
}
1653+
if sym.Pkg.Path == "runtime/internal/sys" && sym.Name == "nih" {
1654+
// Recognize the special not-in-heap type. Any type including
1655+
// this type will also be not-in-heap.
1656+
// This logic is duplicated in go/types and
1657+
// cmd/compile/internal/types2.
1658+
t.SetNotInHeap(true)
1659+
}
16411660
return t
16421661
}
16431662

@@ -1664,6 +1683,7 @@ func (t *Type) SetUnderlying(underlying *Type) {
16641683
t.width = underlying.width
16651684
t.align = underlying.align
16661685
t.alg = underlying.alg
1686+
t.ptrBytes = underlying.ptrBytes
16671687
t.intRegs = underlying.intRegs
16681688
t.floatRegs = underlying.floatRegs
16691689
t.underlying = underlying.underlying
@@ -1772,6 +1792,13 @@ func NewStruct(fields []*Field) *Type {
17721792
if fieldsHasShape(fields) {
17731793
t.SetHasShape(true)
17741794
}
1795+
for _, f := range fields {
1796+
if f.Type.NotInHeap() {
1797+
t.SetNotInHeap(true)
1798+
break
1799+
}
1800+
}
1801+
17751802
return t
17761803
}
17771804

0 commit comments

Comments
 (0)