1 /**
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef PANDA_VERIFICATION_UTIL_MEM_H
16 #define PANDA_VERIFICATION_UTIL_MEM_H
17 
18 #include <cstdint>
19 #include "libpandabase/macros.h"
20 
21 namespace ark::verifier {
22 
23 /* We are using the fact that on every operating system some of the process's virtual memory space
24    is unavailable for allocation -- for example, it may be reserved for kernel memory.
25 
26    For Linux:
27        https://linux-kernel-labs.github.io/refs/heads/master/lectures/address-space.html
28 
29        Linux is using a split address space for 32 bit systems, although in the past there
30        were options for supporting 4/4s split or dedicated kernel address space (on those
31        architecture that supports it, e.g. x86). Linux always uses split address space for 64 bit systems.
32 
33        [For 32-bit Linux, the split is usually 3/1, i.e. 0x00000000-0xc0000000 is user space,
34        0xc0000000-0xffffffff is kernel space]
35 
36    For Windows: https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/virtual-address-spaces
37 
38        For a 32-bit process, the virtual address space is usually the 2-gigabyte range 0x00000000
39        through 0x7FFFFFFF.
40        For a 64-bit process on 64-bit Windows, the virtual address space is the 128-terabyte range
41        0x000'00000000 through 0x7FFF'FFFFFFFF.
42 */
43 
44 /* Works on Linux and Windows. Might need adjustment for other OSes */
45 
46 size_t constexpr POINTER_CHECK_SHIFT = sizeof(uintptr_t) * 8 - 4;
47 // NOLINTNEXTLINE(hicpp-signed-bitwise)
48 uintptr_t constexpr POINTER_CHECK_MASK = 0xfL << POINTER_CHECK_SHIFT;
49 uintptr_t constexpr NOT_POINTER = POINTER_CHECK_MASK;
50 
51 size_t constexpr TAG_SHIFT = sizeof(uintptr_t) * 8 - 8;
52 // NOLINTNEXTLINE(hicpp-signed-bitwise)
53 uintptr_t constexpr TAG_MASK = 0xfL << TAG_SHIFT;
54 
55 uintptr_t constexpr PAYLOAD_MASK = ~(POINTER_CHECK_MASK | TAG_MASK);
56 
IsNotPointer(uintptr_t x)57 ALWAYS_INLINE inline bool IsNotPointer(uintptr_t x)
58 {
59     return (x & POINTER_CHECK_MASK) == NOT_POINTER;
60 }
61 
IsPointer(uintptr_t x)62 ALWAYS_INLINE inline bool IsPointer(uintptr_t x)
63 {
64     return !IsNotPointer(x);
65 }
66 
GetTag(uintptr_t x)67 ALWAYS_INLINE inline int GetTag(uintptr_t x)
68 {
69     ASSERT(IsNotPointer(x));
70     return (x & TAG_MASK) >> TAG_SHIFT;
71 }
72 
GetPayload(uintptr_t x)73 ALWAYS_INLINE inline uintptr_t GetPayload(uintptr_t x)
74 {
75     ASSERT(IsNotPointer(x));
76     return x & PAYLOAD_MASK;
77 }
78 
GetPointer(uintptr_t x)79 ALWAYS_INLINE inline uintptr_t GetPointer(uintptr_t x)
80 {
81     ASSERT(IsPointer(x));
82     return x;
83 }
84 
ConstructWithTag(int tag, uintptr_t v)85 ALWAYS_INLINE inline uintptr_t ConstructWithTag(int tag, uintptr_t v)
86 {
87     // NOLINTNEXTLINE(hicpp-signed-bitwise)
88     ASSERT(tag < (1 << 4U));
89     ASSERT(v < (1UL << TAG_SHIFT));
90     return NOT_POINTER | (static_cast<uintptr_t>(tag) << TAG_SHIFT) | v;
91 }
92 
93 }  // namespace ark::verifier
94 
95 #endif /* PANDA_VERIFICATION_UTIL_MEM_H */
96