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