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