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