1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_LIBARTBASE_BASE_MEMORY_REGION_H_ 18 #define ART_LIBARTBASE_BASE_MEMORY_REGION_H_ 19 20 #include <stdint.h> 21 #include <type_traits> 22 23 #include <android-base/logging.h> 24 25 #include "bit_utils.h" 26 #include "casts.h" 27 #include "enums.h" 28 #include "globals.h" 29 #include "macros.h" 30 #include "value_object.h" 31 32 namespace art { 33 34 // Memory regions are useful for accessing memory with bounds check in 35 // debug mode. They can be safely passed by value and do not assume ownership 36 // of the region. 37 class MemoryRegion final : public ValueObject { 38 public: 39 struct ContentEquals { 40 constexpr bool operator()(const MemoryRegion& lhs, const MemoryRegion& rhs) const { 41 return lhs.size() == rhs.size() && memcmp(lhs.begin(), rhs.begin(), lhs.size()) == 0; 42 } 43 }; 44 45 MemoryRegion() : pointer_(nullptr), size_(0) {} 46 MemoryRegion(void* pointer_in, uintptr_t size_in) : pointer_(pointer_in), size_(size_in) {} 47 48 void* pointer() const { return pointer_; } 49 size_t size() const { return size_; } 50 size_t size_in_bits() const { return size_ * kBitsPerByte; } 51 52 static size_t pointer_offset() { 53 return OFFSETOF_MEMBER(MemoryRegion, pointer_); 54 } 55 56 uint8_t* begin() const { return reinterpret_cast<uint8_t*>(pointer_); } 57 uint8_t* end() const { return begin() + size_; } 58 59 // Load value of type `T` at `offset`. The memory address corresponding 60 // to `offset` should be word-aligned (on ARM, this is a requirement). 61 template<typename T> 62 ALWAYS_INLINE T Load(uintptr_t offset) const { 63 T* address = ComputeInternalPointer<T>(offset); 64 DCHECK(IsWordAligned(address)); 65 return *address; 66 } 67 68 // Store `value` (of type `T`) at `offset`. The memory address 69 // corresponding to `offset` should be word-aligned (on ARM, this is 70 // a requirement). 71 template<typename T> 72 ALWAYS_INLINE void Store(uintptr_t offset, T value) const { 73 T* address = ComputeInternalPointer<T>(offset); 74 DCHECK(IsWordAligned(address)); 75 *address = value; 76 } 77 78 // Load value of type `T` at `offset`. The memory address corresponding 79 // to `offset` does not need to be word-aligned. 80 template<typename T> 81 ALWAYS_INLINE T LoadUnaligned(uintptr_t offset) const { 82 // Equivalent unsigned integer type corresponding to T. 83 typedef typename std::make_unsigned<T>::type U; 84 U equivalent_unsigned_integer_value = 0; 85 // Read the value byte by byte in a little-endian fashion. 86 for (size_t i = 0; i < sizeof(U); ++i) { 87 equivalent_unsigned_integer_value += 88 *ComputeInternalPointer<uint8_t>(offset + i) << (i * kBitsPerByte); 89 } 90 return bit_cast<T, U>(equivalent_unsigned_integer_value); 91 } 92 93 // Store `value` (of type `T`) at `offset`. The memory address 94 // corresponding to `offset` does not need to be word-aligned. 95 template<typename T> 96 ALWAYS_INLINE void StoreUnaligned(uintptr_t offset, T value) const { 97 // Equivalent unsigned integer type corresponding to T. 98 typedef typename std::make_unsigned<T>::type U; 99 U equivalent_unsigned_integer_value = bit_cast<U, T>(value); 100 // Write the value byte by byte in a little-endian fashion. 101 for (size_t i = 0; i < sizeof(U); ++i) { 102 *ComputeInternalPointer<uint8_t>(offset + i) = 103 (equivalent_unsigned_integer_value >> (i * kBitsPerByte)) & 0xFF; 104 } 105 } 106 107 template<typename T> 108 ALWAYS_INLINE T* PointerTo(uintptr_t offset) const { 109 return ComputeInternalPointer<T>(offset); 110 } 111 112 void CopyFrom(size_t offset, const MemoryRegion& from) const; 113 114 template<class Vector> 115 void CopyFromVector(size_t offset, Vector& vector) const { 116 if (!vector.empty()) { 117 CopyFrom(offset, MemoryRegion(vector.data(), vector.size())); 118 } 119 } 120 121 // Compute a sub memory region based on an existing one. 122 ALWAYS_INLINE MemoryRegion Subregion(uintptr_t offset, uintptr_t size_in) const { 123 CHECK_GE(this->size(), size_in); 124 CHECK_LE(offset, this->size() - size_in); 125 return MemoryRegion(reinterpret_cast<void*>(begin() + offset), size_in); 126 } 127 128 // Compute an extended memory region based on an existing one. 129 ALWAYS_INLINE void Extend(const MemoryRegion& region, uintptr_t extra) { 130 pointer_ = region.pointer(); 131 size_ = (region.size() + extra); 132 } 133 134 private: 135 template<typename T> 136 ALWAYS_INLINE T* ComputeInternalPointer(size_t offset) const { 137 CHECK_GE(size(), sizeof(T)); 138 CHECK_LE(offset, size() - sizeof(T)); 139 return reinterpret_cast<T*>(begin() + offset); 140 } 141 142 // Locate the bit with the given offset. Returns a pointer to the byte 143 // containing the bit, and sets bit_mask to the bit within that byte. 144 ALWAYS_INLINE uint8_t* ComputeBitPointer(uintptr_t bit_offset, uint8_t* bit_mask) const { 145 uintptr_t bit_remainder = (bit_offset & (kBitsPerByte - 1)); 146 *bit_mask = (1U << bit_remainder); 147 uintptr_t byte_offset = (bit_offset >> kBitsPerByteLog2); 148 return ComputeInternalPointer<uint8_t>(byte_offset); 149 } 150 151 // Is `address` aligned on a machine word? 152 template<typename T> static constexpr bool IsWordAligned(const T* address) { 153 // Word alignment in bytes. Determined from pointer size. 154 return IsAligned<kRuntimePointerSize>(address); 155 } 156 157 void* pointer_; 158 size_t size_; 159 }; 160 161 } // namespace art 162 163 #endif // ART_LIBARTBASE_BASE_MEMORY_REGION_H_ 164