github.com/primecitizens/pcz/std@v0.2.1/builtin/ptr/tptr_64bit.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 // 4 // Copyright 2014 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 //go:build amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x || wasm 9 10 package stdptr 11 12 import ( 13 "unsafe" 14 15 "github.com/primecitizens/pcz/std/core/arch" 16 "github.com/primecitizens/pcz/std/core/os" 17 ) 18 19 const ( 20 // addrBits is the number of bits needed to represent a virtual address. 21 // 22 // See heapAddrBits for a table of address space sizes on 23 // various architectures. 48 bits is enough for all 24 // architectures except s390x. 25 // 26 // On AMD64, virtual addresses are 48-bit (or 57-bit) numbers sign extended to 64. 27 // We shift the address left 16 to eliminate the sign extended part and make 28 // room in the bottom for the count. 29 // 30 // On s390x, virtual addresses are 64-bit. There's not much we 31 // can do about this, so we just hope that the kernel doesn't 32 // get to really high addresses and panic if it does. 33 addrBits = 48 34 35 // In addition to the 16 bits taken from the top, we can take 3 from the 36 // bottom, because node must be pointer-aligned, giving a total of 19 bits 37 // of count. 38 tagBits = 64 - addrBits + 3 39 40 // On AIX, 64-bit addresses are split into 36-bit segment number and 28-bit 41 // offset in segment. Segment numbers in the range 0x0A0000000-0x0AFFFFFFF(LSA) 42 // are available for mmap. 43 // We assume all tagged addresses are from memory allocated with mmap. 44 // We use one bit to distinguish between the two ranges. 45 aixAddrBits = 57 46 aixTagBits = 64 - aixAddrBits + 3 47 48 // riscv64 SV57 mode gives 56 bits of userspace VA. 49 // tagged pointer code supports it, 50 // but broader support for SV57 mode is incomplete, 51 // and there may be other issues (see #54104). 52 riscv64AddrBits = 56 53 riscv64TagBits = 64 - riscv64AddrBits + 3 54 ) 55 56 // The number of bits stored in the numeric tag of a TaggedPointer 57 const TaggedPointerBits = (os.IsAix * aixTagBits) + (arch.IsRiscv64 * riscv64TagBits) + ((1 - os.IsAix) * (1 - arch.IsRiscv64) * tagBits) 58 59 // TaggedPointerPack created a TaggedPointer from a pointer and a tag. 60 // Tag bits that don't fit in the result are discarded. 61 func TaggedPointerPack(ptr unsafe.Pointer, tag uintptr) TaggedPointer { 62 if os.IsAix == 1 { 63 if arch.IsPpc64 == 0 { 64 panic("check this code for aix on non-ppc64") 65 } 66 return TaggedPointer(uint64(uintptr(ptr))<<(64-aixAddrBits) | uint64(tag&(1<<aixTagBits-1))) 67 } 68 if arch.IsRiscv64 == 1 { 69 return TaggedPointer(uint64(uintptr(ptr))<<(64-riscv64AddrBits) | uint64(tag&(1<<riscv64TagBits-1))) 70 } 71 return TaggedPointer(uint64(uintptr(ptr))<<(64-addrBits) | uint64(tag&(1<<tagBits-1))) 72 } 73 74 // Pointer returns the pointer from a TaggedPointer. 75 func (tp TaggedPointer) pointer() unsafe.Pointer { 76 if arch.IsAmd64 == 1 { 77 // amd64 systems can place the stack above the VA hole, so we need to sign extend 78 // val before unpacking. 79 return unsafe.Pointer(uintptr(int64(tp) >> tagBits << 3)) 80 } 81 if os.IsAix == 1 { 82 return unsafe.Pointer(uintptr((tp >> aixTagBits << 3) | 0xa<<56)) 83 } 84 if arch.IsRiscv64 == 1 { 85 return unsafe.Pointer(uintptr(tp >> riscv64TagBits << 3)) 86 } 87 return unsafe.Pointer(uintptr(tp >> tagBits << 3)) 88 } 89 90 // Tag returns the tag from a TaggedPointer. 91 func (tp TaggedPointer) tag() uintptr { 92 return uintptr(tp & (1<<TaggedPointerBits - 1)) 93 }