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