1b8021494Sopenharmony_ci// Copyright 2017, VIXL authors 2b8021494Sopenharmony_ci// All rights reserved. 3b8021494Sopenharmony_ci// 4b8021494Sopenharmony_ci// Redistribution and use in source and binary forms, with or without 5b8021494Sopenharmony_ci// modification, are permitted provided that the following conditions are met: 6b8021494Sopenharmony_ci// 7b8021494Sopenharmony_ci// * Redistributions of source code must retain the above copyright notice, 8b8021494Sopenharmony_ci// this list of conditions and the following disclaimer. 9b8021494Sopenharmony_ci// * Redistributions in binary form must reproduce the above copyright notice, 10b8021494Sopenharmony_ci// this list of conditions and the following disclaimer in the documentation 11b8021494Sopenharmony_ci// and/or other materials provided with the distribution. 12b8021494Sopenharmony_ci// * Neither the name of ARM Limited nor the names of its contributors may be 13b8021494Sopenharmony_ci// used to endorse or promote products derived from this software without 14b8021494Sopenharmony_ci// specific prior written permission. 15b8021494Sopenharmony_ci// 16b8021494Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17b8021494Sopenharmony_ci// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18b8021494Sopenharmony_ci// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19b8021494Sopenharmony_ci// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20b8021494Sopenharmony_ci// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21b8021494Sopenharmony_ci// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22b8021494Sopenharmony_ci// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23b8021494Sopenharmony_ci// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24b8021494Sopenharmony_ci// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25b8021494Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26b8021494Sopenharmony_ci 27b8021494Sopenharmony_ci#ifndef VIXL_CODE_BUFFER_H 28b8021494Sopenharmony_ci#define VIXL_CODE_BUFFER_H 29b8021494Sopenharmony_ci 30b8021494Sopenharmony_ci#ifdef VIXL_CODE_BUFFER_MMAP 31b8021494Sopenharmony_ciextern "C" { 32b8021494Sopenharmony_ci#include <sys/mman.h> 33b8021494Sopenharmony_ci} 34b8021494Sopenharmony_ci#endif 35b8021494Sopenharmony_ci 36b8021494Sopenharmony_ci#include <cstring> 37b8021494Sopenharmony_ci 38b8021494Sopenharmony_ci#include "globals-vixl.h" 39b8021494Sopenharmony_ci#include "utils-vixl.h" 40b8021494Sopenharmony_ci 41b8021494Sopenharmony_cinamespace vixl { 42b8021494Sopenharmony_ci 43b8021494Sopenharmony_ciclass CodeBuffer { 44b8021494Sopenharmony_ci public: 45b8021494Sopenharmony_ci static const size_t kDefaultCapacity = 4 * MBytes; 46b8021494Sopenharmony_ci 47b8021494Sopenharmony_ci explicit CodeBuffer(size_t capacity = kDefaultCapacity); 48b8021494Sopenharmony_ci CodeBuffer(byte* buffer, size_t capacity); 49b8021494Sopenharmony_ci ~CodeBuffer() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION; 50b8021494Sopenharmony_ci 51b8021494Sopenharmony_ci void Reset(); 52b8021494Sopenharmony_ci 53b8021494Sopenharmony_ci#ifdef VIXL_CODE_BUFFER_MMAP 54b8021494Sopenharmony_ci // Make the buffer executable or writable. These states are mutually 55b8021494Sopenharmony_ci // exclusive. 56b8021494Sopenharmony_ci // Note that these require page-aligned memory blocks, which we can only 57b8021494Sopenharmony_ci // guarantee with VIXL_CODE_BUFFER_MMAP. 58b8021494Sopenharmony_ci void SetExecutable(); 59b8021494Sopenharmony_ci void SetWritable(); 60b8021494Sopenharmony_ci 61b8021494Sopenharmony_ci void SetMmapMaxBytes(size_t size) { 62b8021494Sopenharmony_ci mmap_max_ = size; 63b8021494Sopenharmony_ci } 64b8021494Sopenharmony_ci#else 65b8021494Sopenharmony_ci // These require page-aligned memory blocks, which we can only guarantee with 66b8021494Sopenharmony_ci // mmap. 67b8021494Sopenharmony_ci VIXL_NO_RETURN_IN_DEBUG_MODE void SetExecutable() { VIXL_UNIMPLEMENTED(); } 68b8021494Sopenharmony_ci VIXL_NO_RETURN_IN_DEBUG_MODE void SetWritable() { VIXL_UNIMPLEMENTED(); } 69b8021494Sopenharmony_ci#endif 70b8021494Sopenharmony_ci 71b8021494Sopenharmony_ci bool IsValid() const { 72b8021494Sopenharmony_ci return (buffer_ != MAP_FAILED); 73b8021494Sopenharmony_ci } 74b8021494Sopenharmony_ci 75b8021494Sopenharmony_ci ptrdiff_t GetOffsetFrom(ptrdiff_t offset) const { 76b8021494Sopenharmony_ci ptrdiff_t cursor_offset = cursor_ - buffer_; 77b8021494Sopenharmony_ci VIXL_ASSERT((offset >= 0) && (offset <= cursor_offset)); 78b8021494Sopenharmony_ci return cursor_offset - offset; 79b8021494Sopenharmony_ci } 80b8021494Sopenharmony_ci VIXL_DEPRECATED("GetOffsetFrom", 81b8021494Sopenharmony_ci ptrdiff_t OffsetFrom(ptrdiff_t offset) const) { 82b8021494Sopenharmony_ci return GetOffsetFrom(offset); 83b8021494Sopenharmony_ci } 84b8021494Sopenharmony_ci 85b8021494Sopenharmony_ci ptrdiff_t GetCursorOffset() const { return GetOffsetFrom(0); } 86b8021494Sopenharmony_ci VIXL_DEPRECATED("GetCursorOffset", ptrdiff_t CursorOffset() const) { 87b8021494Sopenharmony_ci return GetCursorOffset(); 88b8021494Sopenharmony_ci } 89b8021494Sopenharmony_ci 90b8021494Sopenharmony_ci void Rewind(ptrdiff_t offset) { 91b8021494Sopenharmony_ci byte* rewound_cursor = buffer_ + offset; 92b8021494Sopenharmony_ci VIXL_ASSERT((buffer_ <= rewound_cursor) && (rewound_cursor <= cursor_)); 93b8021494Sopenharmony_ci cursor_ = rewound_cursor; 94b8021494Sopenharmony_ci } 95b8021494Sopenharmony_ci 96b8021494Sopenharmony_ci template <typename T> 97b8021494Sopenharmony_ci T GetOffsetAddress(ptrdiff_t offset) const { 98b8021494Sopenharmony_ci VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); 99b8021494Sopenharmony_ci VIXL_ASSERT((offset >= 0) && (offset <= (cursor_ - buffer_))); 100b8021494Sopenharmony_ci return reinterpret_cast<T>(buffer_ + offset); 101b8021494Sopenharmony_ci } 102b8021494Sopenharmony_ci 103b8021494Sopenharmony_ci // Return the address of the start or end of the emitted code. 104b8021494Sopenharmony_ci template <typename T> 105b8021494Sopenharmony_ci T GetStartAddress() const { 106b8021494Sopenharmony_ci VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); 107b8021494Sopenharmony_ci return GetOffsetAddress<T>(0); 108b8021494Sopenharmony_ci } 109b8021494Sopenharmony_ci template <typename T> 110b8021494Sopenharmony_ci T GetEndAddress() const { 111b8021494Sopenharmony_ci VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); 112b8021494Sopenharmony_ci return GetOffsetAddress<T>(GetSizeInBytes()); 113b8021494Sopenharmony_ci } 114b8021494Sopenharmony_ci 115b8021494Sopenharmony_ci size_t GetRemainingBytes() const { 116b8021494Sopenharmony_ci VIXL_ASSERT((cursor_ >= buffer_) && (cursor_ <= (buffer_ + capacity_))); 117b8021494Sopenharmony_ci return (buffer_ + capacity_) - cursor_; 118b8021494Sopenharmony_ci } 119b8021494Sopenharmony_ci VIXL_DEPRECATED("GetRemainingBytes", size_t RemainingBytes() const) { 120b8021494Sopenharmony_ci return GetRemainingBytes(); 121b8021494Sopenharmony_ci } 122b8021494Sopenharmony_ci 123b8021494Sopenharmony_ci size_t GetSizeInBytes() const { 124b8021494Sopenharmony_ci VIXL_ASSERT((cursor_ >= buffer_) && (cursor_ <= (buffer_ + capacity_))); 125b8021494Sopenharmony_ci return cursor_ - buffer_; 126b8021494Sopenharmony_ci } 127b8021494Sopenharmony_ci 128b8021494Sopenharmony_ci // A code buffer can emit: 129b8021494Sopenharmony_ci // * 8, 16, 32 or 64-bit data: constant. 130b8021494Sopenharmony_ci // * 16 or 32-bit data: instruction. 131b8021494Sopenharmony_ci // * string: debug info. 132b8021494Sopenharmony_ci void Emit8(uint8_t data) { Emit(data); } 133b8021494Sopenharmony_ci 134b8021494Sopenharmony_ci void Emit16(uint16_t data) { Emit(data); } 135b8021494Sopenharmony_ci 136b8021494Sopenharmony_ci void Emit32(uint32_t data) { Emit(data); } 137b8021494Sopenharmony_ci 138b8021494Sopenharmony_ci void Emit64(uint64_t data) { Emit(data); } 139b8021494Sopenharmony_ci 140b8021494Sopenharmony_ci void EmitString(const char* string); 141b8021494Sopenharmony_ci 142b8021494Sopenharmony_ci void EmitData(const void* data, size_t size); 143b8021494Sopenharmony_ci 144b8021494Sopenharmony_ci template <typename T> 145b8021494Sopenharmony_ci void Emit(T value) { 146b8021494Sopenharmony_ci VIXL_ASSERT(HasSpaceFor(sizeof(value))); 147b8021494Sopenharmony_ci dirty_ = true; 148b8021494Sopenharmony_ci byte* c = cursor_; 149b8021494Sopenharmony_ci memcpy(c, &value, sizeof(value)); 150b8021494Sopenharmony_ci cursor_ = c + sizeof(value); 151b8021494Sopenharmony_ci } 152b8021494Sopenharmony_ci 153b8021494Sopenharmony_ci void UpdateData(size_t offset, const void* data, size_t size); 154b8021494Sopenharmony_ci 155b8021494Sopenharmony_ci // Align to 32bit. 156b8021494Sopenharmony_ci void Align(); 157b8021494Sopenharmony_ci 158b8021494Sopenharmony_ci // Ensure there is enough space for and emit 'n' zero bytes. 159b8021494Sopenharmony_ci void EmitZeroedBytes(int n); 160b8021494Sopenharmony_ci 161b8021494Sopenharmony_ci bool Is16bitAligned() const { return IsAligned<2>(cursor_); } 162b8021494Sopenharmony_ci 163b8021494Sopenharmony_ci bool Is32bitAligned() const { return IsAligned<4>(cursor_); } 164b8021494Sopenharmony_ci 165b8021494Sopenharmony_ci size_t GetCapacity() const { return capacity_; } 166b8021494Sopenharmony_ci VIXL_DEPRECATED("GetCapacity", size_t capacity() const) { 167b8021494Sopenharmony_ci return GetCapacity(); 168b8021494Sopenharmony_ci } 169b8021494Sopenharmony_ci 170b8021494Sopenharmony_ci bool IsManaged() const { return managed_; } 171b8021494Sopenharmony_ci void Grow(size_t new_capacity); 172b8021494Sopenharmony_ci 173b8021494Sopenharmony_ci bool IsDirty() const { return dirty_; } 174b8021494Sopenharmony_ci 175b8021494Sopenharmony_ci void SetClean() { dirty_ = false; } 176b8021494Sopenharmony_ci 177b8021494Sopenharmony_ci bool HasSpaceFor(size_t amount) const { 178b8021494Sopenharmony_ci return GetRemainingBytes() >= amount; 179b8021494Sopenharmony_ci } 180b8021494Sopenharmony_ci 181b8021494Sopenharmony_ci void EnsureSpaceFor(size_t amount, bool* has_grown) { 182b8021494Sopenharmony_ci bool is_full = !HasSpaceFor(amount); 183b8021494Sopenharmony_ci if (is_full) Grow(capacity_ * 2 + amount); 184b8021494Sopenharmony_ci VIXL_ASSERT(has_grown != NULL); 185b8021494Sopenharmony_ci *has_grown = is_full; 186b8021494Sopenharmony_ci } 187b8021494Sopenharmony_ci void EnsureSpaceFor(size_t amount) { 188b8021494Sopenharmony_ci bool placeholder; 189b8021494Sopenharmony_ci EnsureSpaceFor(amount, &placeholder); 190b8021494Sopenharmony_ci } 191b8021494Sopenharmony_ci 192b8021494Sopenharmony_ci private: 193b8021494Sopenharmony_ci // Backing store of the buffer. 194b8021494Sopenharmony_ci byte* buffer_; 195b8021494Sopenharmony_ci // If true the backing store is allocated and deallocated by the buffer. The 196b8021494Sopenharmony_ci // backing store can then grow on demand. If false the backing store is 197b8021494Sopenharmony_ci // provided by the user and cannot be resized internally. 198b8021494Sopenharmony_ci bool managed_; 199b8021494Sopenharmony_ci // Pointer to the next location to be written. 200b8021494Sopenharmony_ci byte* cursor_; 201b8021494Sopenharmony_ci // True if there has been any write since the buffer was created or cleaned. 202b8021494Sopenharmony_ci bool dirty_; 203b8021494Sopenharmony_ci // Capacity in bytes of the backing store. 204b8021494Sopenharmony_ci size_t capacity_; 205b8021494Sopenharmony_ci#ifdef VIXL_CODE_BUFFER_MMAP 206b8021494Sopenharmony_ci size_t mmap_max_{0}; 207b8021494Sopenharmony_ci#endif 208b8021494Sopenharmony_ci}; 209b8021494Sopenharmony_ci 210b8021494Sopenharmony_ci} // namespace vixl 211b8021494Sopenharmony_ci 212b8021494Sopenharmony_ci#endif // VIXL_CODE_BUFFER_H 213