From 9d0320de2574586f3b0610c1b5fd15b8f9c85dec Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 15 Apr 2025 14:55:06 -0700 Subject: [PATCH] runtime: align taggable pointers more so we can use low bits for tag Currently we assume alignment to 8 bytes, so we can steal the low 3 bits. This CL assumes alignment to 512 bytes, so we can steal the low 9 bits. That's 6 extra bits! Aligning to 512 bytes wastes a bit of space but it is not egregious. Most of the objects that we make tagged pointers to are pretty big. Update #49405 Change-Id: I66fc7784ac1be5f12f285de1d7851d5a6871fb75 Reviewed-on: https://go-review.googlesource.com/c/go/+/665815 Reviewed-by: Keith Randall Reviewed-by: Michael Knyszek Auto-Submit: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/runtime/export_test.go | 6 ++++-- src/runtime/lfstack.go | 12 ++---------- src/runtime/lfstack_test.go | 2 +- src/runtime/mgc.go | 8 +++++++- src/runtime/mspanset.go | 13 +++++++++++-- src/runtime/netpoll.go | 8 ++++++-- src/runtime/tagptr.go | 13 +++++++++++-- src/runtime/tagptr_32bit.go | 3 +++ src/runtime/tagptr_64bit.go | 34 ++++++++++++++++++++-------------- 9 files changed, 65 insertions(+), 34 deletions(-) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 572f62c2f9..195a56963d 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -1777,10 +1777,12 @@ func FrameStartLine(f *Frame) int { // PersistentAlloc allocates some memory that lives outside the Go heap. // This memory will never be freed; use sparingly. -func PersistentAlloc(n uintptr) unsafe.Pointer { - return persistentalloc(n, 0, &memstats.other_sys) +func PersistentAlloc(n, align uintptr) unsafe.Pointer { + return persistentalloc(n, align, &memstats.other_sys) } +const TagAlign = tagAlign + // FPCallers works like Callers and uses frame pointer unwinding to populate // pcBuf with the return addresses of the physical frames on the stack. func FPCallers(pcBuf []uintptr) int { diff --git a/src/runtime/lfstack.go b/src/runtime/lfstack.go index cbec6e8447..8946c80348 100644 --- a/src/runtime/lfstack.go +++ b/src/runtime/lfstack.go @@ -24,10 +24,6 @@ type lfstack uint64 func (head *lfstack) push(node *lfnode) { node.pushcnt++ new := lfstackPack(node, node.pushcnt) - if node1 := lfstackUnpack(new); node1 != node { - print("runtime: lfstack.push invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n") - throw("lfstack.push") - } for { old := atomic.Load64((*uint64)(head)) node.next = old @@ -61,15 +57,11 @@ func lfnodeValidate(node *lfnode) { if base, _, _ := findObject(uintptr(unsafe.Pointer(node)), 0, 0); base != 0 { throw("lfstack node allocated from the heap") } - if lfstackUnpack(lfstackPack(node, ^uintptr(0))) != node { - printlock() - println("runtime: bad lfnode address", hex(uintptr(unsafe.Pointer(node)))) - throw("bad lfnode address") - } + lfstackPack(node, ^uintptr(0)) } func lfstackPack(node *lfnode, cnt uintptr) uint64 { - return uint64(taggedPointerPack(unsafe.Pointer(node), cnt)) + return uint64(taggedPointerPack(unsafe.Pointer(node), cnt&(1< ptr=", t.pointer(), " tag=", hex(t.tag()), "\n") + throw("taggedPointerPack") } - return taggedPointer(uint64(uintptr(ptr))<<(64-addrBits) | uint64(tag&(1<> tagBits << 3)) + return unsafe.Pointer(uintptr(int64(tp) >> tagBits << tagAlignBits)) } if GOOS == "aix" { - return unsafe.Pointer(uintptr((tp >> aixTagBits << 3) | 0xa<<56)) + return unsafe.Pointer(uintptr((tp >> aixTagBits << tagAlignBits) | 0xa<<56)) } if GOARCH == "riscv64" { - return unsafe.Pointer(uintptr(tp >> riscv64TagBits << 3)) + return unsafe.Pointer(uintptr(tp >> riscv64TagBits << tagAlignBits)) } - return unsafe.Pointer(uintptr(tp >> tagBits << 3)) + return unsafe.Pointer(uintptr(tp >> tagBits << tagAlignBits)) } // Tag returns the tag from a taggedPointer.