1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build amd64 arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x wasm
6
7package runtime
8
9import "unsafe"
10
11const (
12	// addrBits is the number of bits needed to represent a virtual address.
13	//
14	// See heapAddrBits for a table of address space sizes on
15	// various architectures. 48 bits is enough for all
16	// architectures except s390x.
17	//
18	// On AMD64, virtual addresses are 48-bit (or 57-bit) numbers sign extended to 64.
19	// We shift the address left 16 to eliminate the sign extended part and make
20	// room in the bottom for the count.
21	//
22	// On s390x, virtual addresses are 64-bit. There's not much we
23	// can do about this, so we just hope that the kernel doesn't
24	// get to really high addresses and panic if it does.
25	addrBits = 48
26
27	// In addition to the 16 bits taken from the top, we can take 3 from the
28	// bottom, because node must be pointer-aligned, giving a total of 19 bits
29	// of count.
30	cntBits = 64 - addrBits + 3
31
32	// On AIX, 64-bit addresses are split into 36-bit segment number and 28-bit
33	// offset in segment.  Segment numbers in the range 0x0A0000000-0x0AFFFFFFF(LSA)
34	// are available for mmap.
35	// We assume all lfnode addresses are from memory allocated with mmap.
36	// We use one bit to distinguish between the two ranges.
37	aixAddrBits = 57
38	aixCntBits  = 64 - aixAddrBits + 3
39)
40
41func lfstackPack(node *lfnode, cnt uintptr) uint64 {
42	if GOARCH == "ppc64" && GOOS == "aix" {
43		return uint64(uintptr(unsafe.Pointer(node)))<<(64-aixAddrBits) | uint64(cnt&(1<<aixCntBits-1))
44	}
45	return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
46}
47
48func lfstackUnpack(val uint64) *lfnode {
49	if GOARCH == "amd64" {
50		// amd64 systems can place the stack above the VA hole, so we need to sign extend
51		// val before unpacking.
52		return (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> cntBits << 3)))
53	}
54	if GOARCH == "ppc64" && GOOS == "aix" {
55		return (*lfnode)(unsafe.Pointer(uintptr((val >> aixCntBits << 3) | 0xa<<56)))
56	}
57	return (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
58}
59