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_RUNTIME_MEMORY_REGION_H_ 18 #define ART_RUNTIME_MEMORY_REGION_H_ 19 20 #include <stdint.h> 21 #include <type_traits> 22 23 #include <android-base/logging.h> 24 25 #include "arch/instruction_set.h" 26 #include "base/bit_utils.h" 27 #include "base/casts.h" 28 #include "base/macros.h" 29 #include "base/value_object.h" 30 #include "globals.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 // Load a single bit in the region. The bit at offset 0 is the least 113 // significant bit in the first byte. 114 ALWAYS_INLINE bool LoadBit(uintptr_t bit_offset) const { 115 uint8_t bit_mask; 116 uint8_t byte = *ComputeBitPointer(bit_offset, &bit_mask); 117 return byte & bit_mask; 118 } 119 120 ALWAYS_INLINE void StoreBit(uintptr_t bit_offset, bool value) const { 121 uint8_t bit_mask; 122 uint8_t* byte = ComputeBitPointer(bit_offset, &bit_mask); 123 if (value) { 124 *byte |= bit_mask; 125 } else { 126 *byte &= ~bit_mask; 127 } 128 } 129 130 // Load `length` bits from the region starting at bit offset `bit_offset`. 131 // The bit at the smallest offset is the least significant bit in the 132 // loaded value. `length` must not be larger than the number of bits 133 // contained in the return value (32). 134 ALWAYS_INLINE uint32_t LoadBits(uintptr_t bit_offset, size_t length) const { 135 DCHECK_LE(length, BitSizeOf<uint32_t>()); 136 DCHECK_LE(bit_offset + length, size_in_bits()); 137 if (UNLIKELY(length == 0)) { 138 // Do not touch any memory if the range is empty. 139 return 0; 140 } 141 const uint8_t* address = begin() + bit_offset / kBitsPerByte; 142 const uint32_t shift = bit_offset & (kBitsPerByte - 1); 143 // Load the value (reading only the strictly needed bytes). 144 const uint32_t load_bit_count = shift + length; 145 uint32_t value = address[0] >> shift; 146 if (load_bit_count > 8) { 147 value |= static_cast<uint32_t>(address[1]) << (8 - shift); 148 if (load_bit_count > 16) { 149 value |= static_cast<uint32_t>(address[2]) << (16 - shift); 150 if (load_bit_count > 24) { 151 value |= static_cast<uint32_t>(address[3]) << (24 - shift); 152 if (load_bit_count > 32) { 153 value |= static_cast<uint32_t>(address[4]) << (32 - shift); 154 } 155 } 156 } 157 } 158 // Clear unwanted most significant bits. 159 uint32_t clear_bit_count = BitSizeOf(value) - length; 160 value = (value << clear_bit_count) >> clear_bit_count; 161 for (size_t i = 0; i < length; ++i) { 162 DCHECK_EQ((value >> i) & 1, LoadBit(bit_offset + i)); 163 } 164 return value; 165 } 166 167 // Store `value` on `length` bits in the region starting at bit offset 168 // `bit_offset`. The bit at the smallest offset is the least significant 169 // bit of the stored `value`. `value` must not be larger than `length` 170 // bits. 171 void StoreBits(uintptr_t bit_offset, uint32_t value, size_t length); 172 173 void CopyFrom(size_t offset, const MemoryRegion& from) const; 174 175 template<class Vector> 176 void CopyFromVector(size_t offset, Vector& vector) const { 177 if (!vector.empty()) { 178 CopyFrom(offset, MemoryRegion(vector.data(), vector.size())); 179 } 180 } 181 182 // Compute a sub memory region based on an existing one. 183 ALWAYS_INLINE MemoryRegion Subregion(uintptr_t offset, uintptr_t size_in) const { 184 CHECK_GE(this->size(), size_in); 185 CHECK_LE(offset, this->size() - size_in); 186 return MemoryRegion(reinterpret_cast<void*>(begin() + offset), size_in); 187 } 188 189 // Compute an extended memory region based on an existing one. 190 ALWAYS_INLINE void Extend(const MemoryRegion& region, uintptr_t extra) { 191 pointer_ = region.pointer(); 192 size_ = (region.size() + extra); 193 } 194 195 private: 196 template<typename T> 197 ALWAYS_INLINE T* ComputeInternalPointer(size_t offset) const { 198 CHECK_GE(size(), sizeof(T)); 199 CHECK_LE(offset, size() - sizeof(T)); 200 return reinterpret_cast<T*>(begin() + offset); 201 } 202 203 // Locate the bit with the given offset. Returns a pointer to the byte 204 // containing the bit, and sets bit_mask to the bit within that byte. 205 ALWAYS_INLINE uint8_t* ComputeBitPointer(uintptr_t bit_offset, uint8_t* bit_mask) const { 206 uintptr_t bit_remainder = (bit_offset & (kBitsPerByte - 1)); 207 *bit_mask = (1U << bit_remainder); 208 uintptr_t byte_offset = (bit_offset >> kBitsPerByteLog2); 209 return ComputeInternalPointer<uint8_t>(byte_offset); 210 } 211 212 // Is `address` aligned on a machine word? 213 template<typename T> static constexpr bool IsWordAligned(const T* address) { 214 // Word alignment in bytes. 215 size_t kWordAlignment = static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)); 216 return IsAlignedParam(address, kWordAlignment); 217 } 218 219 void* pointer_; 220 size_t size_; 221 }; 222 223 } // namespace art 224 225 #endif // ART_RUNTIME_MEMORY_REGION_H_ 226