1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ 6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ 7 8 #include <new> 9 #include <vector> 10 11 #include "mojo/public/cpp/bindings/lib/bindings_internal.h" 12 #include "mojo/public/cpp/bindings/lib/bindings_serialization.h" 13 #include "mojo/public/cpp/bindings/lib/bounds_checker.h" 14 #include "mojo/public/cpp/bindings/lib/buffer.h" 15 #include "mojo/public/cpp/bindings/lib/validation_errors.h" 16 17 namespace mojo { 18 template <typename T> class Array; 19 class String; 20 21 namespace internal { 22 23 template <typename T> 24 struct ArrayDataTraits { 25 typedef T StorageType; 26 typedef T& Ref; 27 typedef T const& ConstRef; 28 29 static size_t GetStorageSize(size_t num_elements) { 30 return sizeof(StorageType) * num_elements; 31 } 32 static Ref ToRef(StorageType* storage, size_t offset) { 33 return storage[offset]; 34 } 35 static ConstRef ToConstRef(const StorageType* storage, size_t offset) { 36 return storage[offset]; 37 } 38 }; 39 40 template <typename P> 41 struct ArrayDataTraits<P*> { 42 typedef StructPointer<P> StorageType; 43 typedef P*& Ref; 44 typedef P* const& ConstRef; 45 46 static size_t GetStorageSize(size_t num_elements) { 47 return sizeof(StorageType) * num_elements; 48 } 49 static Ref ToRef(StorageType* storage, size_t offset) { 50 return storage[offset].ptr; 51 } 52 static ConstRef ToConstRef(const StorageType* storage, size_t offset) { 53 return storage[offset].ptr; 54 } 55 }; 56 57 template <typename T> 58 struct ArrayDataTraits<Array_Data<T>*> { 59 typedef ArrayPointer<T> StorageType; 60 typedef Array_Data<T>*& Ref; 61 typedef Array_Data<T>* const& ConstRef; 62 63 static size_t GetStorageSize(size_t num_elements) { 64 return sizeof(StorageType) * num_elements; 65 } 66 static Ref ToRef(StorageType* storage, size_t offset) { 67 return storage[offset].ptr; 68 } 69 static ConstRef ToConstRef(const StorageType* storage, size_t offset) { 70 return storage[offset].ptr; 71 } 72 }; 73 74 // Specialization of Arrays for bools, optimized for space. It has the 75 // following differences from a generalized Array: 76 // * Each element takes up a single bit of memory. 77 // * Accessing a non-const single element uses a helper class |BitRef|, which 78 // emulates a reference to a bool. 79 template <> 80 struct ArrayDataTraits<bool> { 81 // Helper class to emulate a reference to a bool, used for direct element 82 // access. 83 class BitRef { 84 public: 85 ~BitRef(); 86 BitRef& operator=(bool value); 87 BitRef& operator=(const BitRef& value); 88 operator bool() const; 89 private: 90 friend struct ArrayDataTraits<bool>; 91 BitRef(uint8_t* storage, uint8_t mask); 92 BitRef(); 93 uint8_t* storage_; 94 uint8_t mask_; 95 }; 96 97 typedef uint8_t StorageType; 98 typedef BitRef Ref; 99 typedef bool ConstRef; 100 101 static size_t GetStorageSize(size_t num_elements) { 102 return ((num_elements + 7) / 8); 103 } 104 static BitRef ToRef(StorageType* storage, size_t offset) { 105 return BitRef(&storage[offset / 8], 1 << (offset % 8)); 106 } 107 static bool ToConstRef(const StorageType* storage, size_t offset) { 108 return (storage[offset / 8] & (1 << (offset % 8))) != 0; 109 } 110 }; 111 112 // What follows is code to support the serialization of Array_Data<T>. There 113 // are two interesting cases: arrays of primitives and arrays of objects. 114 // Arrays of objects are represented as arrays of pointers to objects. 115 116 template <typename T, bool kIsHandle> struct ArraySerializationHelper; 117 118 template <typename T> 119 struct ArraySerializationHelper<T, false> { 120 typedef typename ArrayDataTraits<T>::StorageType ElementType; 121 122 static void EncodePointersAndHandles(const ArrayHeader* header, 123 ElementType* elements, 124 std::vector<Handle>* handles) { 125 } 126 127 static void DecodePointersAndHandles(const ArrayHeader* header, 128 ElementType* elements, 129 std::vector<Handle>* handles) { 130 } 131 132 static bool ValidateElements(const ArrayHeader* header, 133 const ElementType* elements, 134 BoundsChecker* bounds_checker) { 135 return true; 136 } 137 }; 138 139 template <> 140 struct ArraySerializationHelper<Handle, true> { 141 typedef ArrayDataTraits<Handle>::StorageType ElementType; 142 143 static void EncodePointersAndHandles(const ArrayHeader* header, 144 ElementType* elements, 145 std::vector<Handle>* handles); 146 147 static void DecodePointersAndHandles(const ArrayHeader* header, 148 ElementType* elements, 149 std::vector<Handle>* handles); 150 151 static bool ValidateElements(const ArrayHeader* header, 152 const ElementType* elements, 153 BoundsChecker* bounds_checker); 154 }; 155 156 template <typename H> 157 struct ArraySerializationHelper<H, true> { 158 typedef typename ArrayDataTraits<H>::StorageType ElementType; 159 160 static void EncodePointersAndHandles(const ArrayHeader* header, 161 ElementType* elements, 162 std::vector<Handle>* handles) { 163 ArraySerializationHelper<Handle, true>::EncodePointersAndHandles( 164 header, elements, handles); 165 } 166 167 static void DecodePointersAndHandles(const ArrayHeader* header, 168 ElementType* elements, 169 std::vector<Handle>* handles) { 170 ArraySerializationHelper<Handle, true>::DecodePointersAndHandles( 171 header, elements, handles); 172 } 173 174 static bool ValidateElements(const ArrayHeader* header, 175 const ElementType* elements, 176 BoundsChecker* bounds_checker) { 177 return ArraySerializationHelper<Handle, true>::ValidateElements( 178 header, elements, bounds_checker); 179 } 180 }; 181 182 template <typename P> 183 struct ArraySerializationHelper<P*, false> { 184 typedef typename ArrayDataTraits<P*>::StorageType ElementType; 185 186 static void EncodePointersAndHandles(const ArrayHeader* header, 187 ElementType* elements, 188 std::vector<Handle>* handles) { 189 for (uint32_t i = 0; i < header->num_elements; ++i) 190 Encode(&elements[i], handles); 191 } 192 193 static void DecodePointersAndHandles(const ArrayHeader* header, 194 ElementType* elements, 195 std::vector<Handle>* handles) { 196 for (uint32_t i = 0; i < header->num_elements; ++i) 197 Decode(&elements[i], handles); 198 } 199 200 static bool ValidateElements(const ArrayHeader* header, 201 const ElementType* elements, 202 BoundsChecker* bounds_checker) { 203 for (uint32_t i = 0; i < header->num_elements; ++i) { 204 if (!ValidateEncodedPointer(&elements[i].offset)) { 205 ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER); 206 return false; 207 } 208 if (!P::Validate(DecodePointerRaw(&elements[i].offset), bounds_checker)) 209 return false; 210 } 211 return true; 212 } 213 }; 214 215 template <typename T> 216 class Array_Data { 217 public: 218 typedef ArrayDataTraits<T> Traits; 219 typedef typename Traits::StorageType StorageType; 220 typedef typename Traits::Ref Ref; 221 typedef typename Traits::ConstRef ConstRef; 222 typedef ArraySerializationHelper<T, IsHandle<T>::value> Helper; 223 224 static Array_Data<T>* New(size_t num_elements, Buffer* buf) { 225 size_t num_bytes = sizeof(Array_Data<T>) + 226 Traits::GetStorageSize(num_elements); 227 return new (buf->Allocate(num_bytes)) Array_Data<T>(num_bytes, 228 num_elements); 229 } 230 231 static bool Validate(const void* data, BoundsChecker* bounds_checker) { 232 if (!data) 233 return true; 234 if (!IsAligned(data)) { 235 ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); 236 return false; 237 } 238 if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) { 239 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); 240 return false; 241 } 242 const ArrayHeader* header = static_cast<const ArrayHeader*>(data); 243 if (header->num_bytes < (sizeof(Array_Data<T>) + 244 Traits::GetStorageSize(header->num_elements))) { 245 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER); 246 return false; 247 } 248 if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { 249 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); 250 return false; 251 } 252 253 const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data); 254 return Helper::ValidateElements(&object->header_, object->storage(), 255 bounds_checker); 256 } 257 258 size_t size() const { return header_.num_elements; } 259 260 Ref at(size_t offset) { 261 assert(offset < static_cast<size_t>(header_.num_elements)); 262 return Traits::ToRef(storage(), offset); 263 } 264 265 ConstRef at(size_t offset) const { 266 assert(offset < static_cast<size_t>(header_.num_elements)); 267 return Traits::ToConstRef(storage(), offset); 268 } 269 270 StorageType* storage() { 271 return reinterpret_cast<StorageType*>( 272 reinterpret_cast<char*>(this) + sizeof(*this)); 273 } 274 275 const StorageType* storage() const { 276 return reinterpret_cast<const StorageType*>( 277 reinterpret_cast<const char*>(this) + sizeof(*this)); 278 } 279 280 void EncodePointersAndHandles(std::vector<Handle>* handles) { 281 Helper::EncodePointersAndHandles(&header_, storage(), handles); 282 } 283 284 void DecodePointersAndHandles(std::vector<Handle>* handles) { 285 Helper::DecodePointersAndHandles(&header_, storage(), handles); 286 } 287 288 private: 289 Array_Data(size_t num_bytes, size_t num_elements) { 290 header_.num_bytes = static_cast<uint32_t>(num_bytes); 291 header_.num_elements = static_cast<uint32_t>(num_elements); 292 } 293 ~Array_Data() {} 294 295 internal::ArrayHeader header_; 296 297 // Elements of type internal::ArrayDataTraits<T>::StorageType follow. 298 }; 299 MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data); 300 301 // UTF-8 encoded 302 typedef Array_Data<char> String_Data; 303 304 template <typename T, bool kIsMoveOnlyType> struct ArrayTraits {}; 305 306 template <typename T> struct ArrayTraits<T, false> { 307 typedef T StorageType; 308 typedef typename std::vector<T>::reference RefType; 309 typedef typename std::vector<T>::const_reference ConstRefType; 310 typedef ConstRefType ForwardType; 311 static inline void Initialize(std::vector<T>* vec) { 312 } 313 static inline void Finalize(std::vector<T>* vec) { 314 } 315 static inline ConstRefType at(const std::vector<T>* vec, size_t offset) { 316 return vec->at(offset); 317 } 318 static inline RefType at(std::vector<T>* vec, size_t offset) { 319 return vec->at(offset); 320 } 321 static inline void Resize(std::vector<T>* vec, size_t size) { 322 vec->resize(size); 323 } 324 static inline void PushBack(std::vector<T>* vec, ForwardType value) { 325 vec->push_back(value); 326 } 327 }; 328 329 template <typename T> struct ArrayTraits<T, true> { 330 struct StorageType { 331 char buf[sizeof(T) + (8 - (sizeof(T) % 8)) % 8]; // Make 8-byte aligned. 332 }; 333 typedef T& RefType; 334 typedef const T& ConstRefType; 335 typedef T ForwardType; 336 static inline void Initialize(std::vector<StorageType>* vec) { 337 for (size_t i = 0; i < vec->size(); ++i) 338 new (vec->at(i).buf) T(); 339 } 340 static inline void Finalize(std::vector<StorageType>* vec) { 341 for (size_t i = 0; i < vec->size(); ++i) 342 reinterpret_cast<T*>(vec->at(i).buf)->~T(); 343 } 344 static inline ConstRefType at(const std::vector<StorageType>* vec, 345 size_t offset) { 346 return *reinterpret_cast<const T*>(vec->at(offset).buf); 347 } 348 static inline RefType at(std::vector<StorageType>* vec, size_t offset) { 349 return *reinterpret_cast<T*>(vec->at(offset).buf); 350 } 351 static inline void Resize(std::vector<StorageType>* vec, size_t size) { 352 size_t old_size = vec->size(); 353 for (size_t i = size; i < old_size; i++) 354 reinterpret_cast<T*>(vec->at(i).buf)->~T(); 355 ResizeStorage(vec, size); 356 for (size_t i = old_size; i < vec->size(); i++) 357 new (vec->at(i).buf) T(); 358 } 359 static inline void PushBack(std::vector<StorageType>* vec, RefType value) { 360 size_t old_size = vec->size(); 361 ResizeStorage(vec, old_size + 1); 362 new (vec->at(old_size).buf) T(value.Pass()); 363 } 364 static inline void ResizeStorage(std::vector<StorageType>* vec, size_t size) { 365 if (size <= vec->capacity()) { 366 vec->resize(size); 367 return; 368 } 369 std::vector<StorageType> new_storage(size); 370 for (size_t i = 0; i < vec->size(); i++) 371 new (new_storage.at(i).buf) T(at(vec, i).Pass()); 372 vec->swap(new_storage); 373 Finalize(&new_storage); 374 } 375 }; 376 377 template <> struct WrapperTraits<String, false> { 378 typedef String_Data* DataType; 379 }; 380 381 } // namespace internal 382 } // namespace mojo 383 384 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ 385