1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef vm_SharedMem_h
8 #define vm_SharedMem_h
9 
10 #include <type_traits>
11 
12 template <typename T>
13 class SharedMem {
14   static_assert(std::is_pointer_v<T>, "SharedMem encapsulates pointer types");
15 
16   enum Sharedness { IsUnshared, IsShared };
17 
18   T ptr_;
19 #ifdef DEBUG
20   Sharedness sharedness_;
21 #endif
22 
SharedMem(T ptr,Sharedness sharedness)23   SharedMem(T ptr, Sharedness sharedness)
24       : ptr_(ptr)
25 #ifdef DEBUG
26         ,
27         sharedness_(sharedness)
28 #endif
29   {
30   }
31 
32  public:
33   // Create a SharedMem<T> that is an unshared nullptr.
SharedMem()34   SharedMem()
35       : ptr_(nullptr)
36 #ifdef DEBUG
37         ,
38         sharedness_(IsUnshared)
39 #endif
40   {
41   }
42 
43   // Create a SharedMem<T> that's shared/unshared in the same way as
44   // "forSharedness".
SharedMem(T ptr,const SharedMem & forSharedness)45   SharedMem(T ptr, const SharedMem& forSharedness)
46       : ptr_(ptr)
47 #ifdef DEBUG
48         ,
49         sharedness_(forSharedness.sharedness_)
50 #endif
51   {
52   }
53 
54   // Create a SharedMem<T> that's marked as shared.
shared(void * p)55   static SharedMem shared(void* p) {
56     return SharedMem(static_cast<T>(p), IsShared);
57   }
58 
59   // Create a SharedMem<T> that's marked as unshared.
unshared(void * p)60   static SharedMem unshared(void* p) {
61     return SharedMem(static_cast<T>(p), IsUnshared);
62   }
63 
64   SharedMem& operator=(const SharedMem& that) {
65     ptr_ = that.ptr_;
66 #ifdef DEBUG
67     sharedness_ = that.sharedness_;
68 #endif
69     return *this;
70   }
71 
72   // Reinterpret-cast the pointer to type U, preserving sharedness.
73   // Eg, "obj->dataPointerEither().cast<uint8_t*>()" yields a
74   // SharedMem<uint8_t*>.
75   template <typename U>
cast()76   inline SharedMem<U> cast() const {
77 #ifdef DEBUG
78     MOZ_ASSERT(
79         asValue() %
80             sizeof(std::conditional_t<std::is_void_v<std::remove_pointer_t<U>>,
81                                       char, std::remove_pointer_t<U>>) ==
82         0);
83     if (sharedness_ == IsUnshared) {
84       return SharedMem<U>::unshared(unwrap());
85     }
86 #endif
87     return SharedMem<U>::shared(unwrap());
88   }
89 
90   explicit operator bool() { return ptr_ != nullptr; }
91 
92   SharedMem operator+(size_t offset) { return SharedMem(ptr_ + offset, *this); }
93 
94   SharedMem operator-(size_t offset) { return SharedMem(ptr_ - offset, *this); }
95 
96   SharedMem operator++() {
97     ptr_++;
98     return *this;
99   }
100 
101   SharedMem operator++(int) {
102     SharedMem<T> result(*this);
103     ptr_++;
104     return result;
105   }
106 
107   SharedMem operator--() {
108     ptr_--;
109     return *this;
110   }
111 
112   SharedMem operator--(int) {
113     SharedMem<T> result(*this);
114     ptr_--;
115     return result;
116   }
117 
asValue()118   uintptr_t asValue() const { return reinterpret_cast<uintptr_t>(ptr_); }
119 
120   // Cast to char*, add nbytes, and cast back to T.  Simplifies code in a few
121   // places.
addBytes(size_t nbytes)122   SharedMem addBytes(size_t nbytes) {
123     MOZ_ASSERT(
124         nbytes %
125             sizeof(std::conditional_t<std::is_void_v<std::remove_pointer_t<T>>,
126                                       char, std::remove_pointer_t<T>>) ==
127         0);
128     return SharedMem(
129         reinterpret_cast<T>(reinterpret_cast<char*>(ptr_) + nbytes), *this);
130   }
131 
unwrap()132   T unwrap() const { return ptr_; }
133 
unwrapUnshared()134   T unwrapUnshared() const {
135     MOZ_ASSERT(sharedness_ == IsUnshared);
136     return ptr_;
137   }
138 
unwrapValue()139   uintptr_t unwrapValue() const { return reinterpret_cast<uintptr_t>(ptr_); }
140 };
141 
142 template <typename T>
143 inline bool operator>=(const SharedMem<T>& a, const SharedMem<T>& b) {
144   return a.unwrap() >= b.unwrap();
145 }
146 
147 template <typename T>
148 inline bool operator>=(const void* a, const SharedMem<T>& b) {
149   return a >= b.unwrap();
150 }
151 
152 template <typename T>
153 inline bool operator==(const void* a, const SharedMem<T>& b) {
154   return a == b.unwrap();
155 }
156 
157 template <typename T>
158 inline bool operator==(const SharedMem<T>& a, decltype(nullptr) b) {
159   return a.unwrap() == b;
160 }
161 
162 template <typename T>
163 inline bool operator==(const SharedMem<T>& a, const SharedMem<T>& b) {
164   return a.unwrap() == b.unwrap();
165 }
166 
167 template <typename T>
168 inline bool operator!=(const SharedMem<T>& a, decltype(nullptr) b) {
169   return a.unwrap() != b;
170 }
171 
172 template <typename T>
173 inline bool operator!=(const SharedMem<T>& a, const SharedMem<T>& b) {
174   return a.unwrap() != b.unwrap();
175 }
176 
177 template <typename T>
178 inline bool operator>(const SharedMem<T>& a, const SharedMem<T>& b) {
179   return a.unwrap() > b.unwrap();
180 }
181 
182 template <typename T>
183 inline bool operator>(const void* a, const SharedMem<T>& b) {
184   return a > b.unwrap();
185 }
186 
187 template <typename T>
188 inline bool operator<=(const SharedMem<T>& a, const SharedMem<T>& b) {
189   return a.unwrap() <= b.unwrap();
190 }
191 
192 template <typename T>
193 inline bool operator<=(const void* a, const SharedMem<T>& b) {
194   return a <= b.unwrap();
195 }
196 
197 template <typename T>
198 inline bool operator<(const void* a, const SharedMem<T>& b) {
199   return a < b.unwrap();
200 }
201 
202 #endif  // vm_SharedMem_h
203