• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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