1// For the android builds, ignore this file to avoid dependency 2// on yet another package (golang.org/x/sys/unix) 3//+build ignore 4 5package starlark 6 7// This file defines an optimized Int implementation for 64-bit machines 8// running POSIX. It reserves a 4GB portion of the address space using 9// mmap and represents int32 values as addresses within that range. This 10// disambiguates int32 values from *big.Int pointers, letting all Int 11// values be represented as an unsafe.Pointer, so that Int-to-Value 12// interface conversion need not allocate. 13 14// Although iOS (arm64,darwin) claims to be a POSIX-compliant, 15// it limits each process to about 700MB of virtual address space, 16// which defeats the optimization. 17// 18// TODO(golang.org/issue/38485): darwin,arm64 may refer to macOS in the future. 19// Update this when there are distinct GOOS values for macOS, iOS, and other Apple 20// operating systems on arm64. 21 22import ( 23 "log" 24 "math" 25 "math/big" 26 "unsafe" 27 28 "golang.org/x/sys/unix" 29) 30 31// intImpl represents a union of (int32, *big.Int) in a single pointer, 32// so that Int-to-Value conversions need not allocate. 33// 34// The pointer is either a *big.Int, if the value is big, or a pointer into a 35// reserved portion of the address space (smallints), if the value is small. 36// 37// See int_generic.go for the basic representation concepts. 38type intImpl unsafe.Pointer 39 40// get returns the (small, big) arms of the union. 41func (i Int) get() (int64, *big.Int) { 42 ptr := uintptr(i.impl) 43 if ptr >= smallints && ptr < smallints+1<<32 { 44 return math.MinInt32 + int64(ptr-smallints), nil 45 } 46 return 0, (*big.Int)(i.impl) 47} 48 49// Precondition: math.MinInt32 <= x && x <= math.MaxInt32 50func makeSmallInt(x int64) Int { 51 return Int{intImpl(uintptr(x-math.MinInt32) + smallints)} 52} 53 54// Precondition: x cannot be represented as int32. 55func makeBigInt(x *big.Int) Int { return Int{intImpl(x)} } 56 57// smallints is the base address of a 2^32 byte memory region. 58// Pointers to addresses in this region represent int32 values. 59// We assume smallints is not at the very top of the address space. 60var smallints = reserveAddresses(1 << 32) 61 62func reserveAddresses(len int) uintptr { 63 b, err := unix.Mmap(-1, 0, len, unix.PROT_READ, unix.MAP_PRIVATE|unix.MAP_ANON) 64 if err != nil { 65 log.Fatalf("mmap: %v", err) 66 } 67 return uintptr(unsafe.Pointer(&b[0])) 68} 69