18b57c86886020cf0a5331823be4789ee558764e2Georgia Kouveli// Copyright 2017, VIXL authors 2c68cb64496485710cdb5b8480f8fee287058c93farmvixl// All rights reserved. 3c68cb64496485710cdb5b8480f8fee287058c93farmvixl// 4c68cb64496485710cdb5b8480f8fee287058c93farmvixl// Redistribution and use in source and binary forms, with or without 5c68cb64496485710cdb5b8480f8fee287058c93farmvixl// modification, are permitted provided that the following conditions are met: 6c68cb64496485710cdb5b8480f8fee287058c93farmvixl// 7c68cb64496485710cdb5b8480f8fee287058c93farmvixl// * Redistributions of source code must retain the above copyright notice, 8c68cb64496485710cdb5b8480f8fee287058c93farmvixl// this list of conditions and the following disclaimer. 9c68cb64496485710cdb5b8480f8fee287058c93farmvixl// * Redistributions in binary form must reproduce the above copyright notice, 10c68cb64496485710cdb5b8480f8fee287058c93farmvixl// this list of conditions and the following disclaimer in the documentation 11c68cb64496485710cdb5b8480f8fee287058c93farmvixl// and/or other materials provided with the distribution. 12c68cb64496485710cdb5b8480f8fee287058c93farmvixl// * Neither the name of ARM Limited nor the names of its contributors may be 13c68cb64496485710cdb5b8480f8fee287058c93farmvixl// used to endorse or promote products derived from this software without 14c68cb64496485710cdb5b8480f8fee287058c93farmvixl// specific prior written permission. 15c68cb64496485710cdb5b8480f8fee287058c93farmvixl// 16c68cb64496485710cdb5b8480f8fee287058c93farmvixl// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17c68cb64496485710cdb5b8480f8fee287058c93farmvixl// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18c68cb64496485710cdb5b8480f8fee287058c93farmvixl// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19c68cb64496485710cdb5b8480f8fee287058c93farmvixl// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20c68cb64496485710cdb5b8480f8fee287058c93farmvixl// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21c68cb64496485710cdb5b8480f8fee287058c93farmvixl// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22c68cb64496485710cdb5b8480f8fee287058c93farmvixl// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23c68cb64496485710cdb5b8480f8fee287058c93farmvixl// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24c68cb64496485710cdb5b8480f8fee287058c93farmvixl// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25c68cb64496485710cdb5b8480f8fee287058c93farmvixl// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26c68cb64496485710cdb5b8480f8fee287058c93farmvixl 27c68cb64496485710cdb5b8480f8fee287058c93farmvixl#ifndef VIXL_CODE_BUFFER_H 28c68cb64496485710cdb5b8480f8fee287058c93farmvixl#define VIXL_CODE_BUFFER_H 29c68cb64496485710cdb5b8480f8fee287058c93farmvixl 3078973f258039f6e96eba85f1b5ecdb14b3c51dbbPierre Langlois#include <cstring> 31b68bacb75c1ab265fc539afa93964c7f51f35589Alexandre Rames 321f9074de150536670464a85ef8e0ede60d26e3f9Alexandre Rames#include "globals-vixl.h" 3388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#include "utils-vixl.h" 34c68cb64496485710cdb5b8480f8fee287058c93farmvixl 35c68cb64496485710cdb5b8480f8fee287058c93farmvixlnamespace vixl { 36c68cb64496485710cdb5b8480f8fee287058c93farmvixl 37c68cb64496485710cdb5b8480f8fee287058c93farmvixlclass CodeBuffer { 38c68cb64496485710cdb5b8480f8fee287058c93farmvixl public: 39f2f550c0bfd0f15a4d1c51ff06ec898536f14205Alexandre Rames static const size_t kDefaultCapacity = 4 * KBytes; 40f2f550c0bfd0f15a4d1c51ff06ec898536f14205Alexandre Rames 41f2f550c0bfd0f15a4d1c51ff06ec898536f14205Alexandre Rames explicit CodeBuffer(size_t capacity = kDefaultCapacity); 42919e3fe28a5024c53ede42922092bbc32e89dcb8Alexandre Rames CodeBuffer(byte* buffer, size_t capacity); 43c68cb64496485710cdb5b8480f8fee287058c93farmvixl ~CodeBuffer(); 44c68cb64496485710cdb5b8480f8fee287058c93farmvixl 45c68cb64496485710cdb5b8480f8fee287058c93farmvixl void Reset(); 46c68cb64496485710cdb5b8480f8fee287058c93farmvixl 47745a8558eec037d49b276e040ef18513d7451c36Jacob Bramley#ifdef VIXL_CODE_BUFFER_MMAP 4831dd2ae90d5e82871667fbf3ee2697a155e7c3acAlex Gilday void SetExecutable(); 4931dd2ae90d5e82871667fbf3ee2697a155e7c3acAlex Gilday void SetWritable(); 50745a8558eec037d49b276e040ef18513d7451c36Jacob Bramley#else 51745a8558eec037d49b276e040ef18513d7451c36Jacob Bramley // These require page-aligned memory blocks, which we can only guarantee with 52745a8558eec037d49b276e040ef18513d7451c36Jacob Bramley // mmap. 53390876fd572a28333d843671e30b5cb71c45f6e4Jacob Bramley VIXL_NO_RETURN_IN_DEBUG_MODE void SetExecutable() { VIXL_UNIMPLEMENTED(); } 54390876fd572a28333d843671e30b5cb71c45f6e4Jacob Bramley VIXL_NO_RETURN_IN_DEBUG_MODE void SetWritable() { VIXL_UNIMPLEMENTED(); } 55745a8558eec037d49b276e040ef18513d7451c36Jacob Bramley#endif 5631dd2ae90d5e82871667fbf3ee2697a155e7c3acAlex Gilday 5788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois ptrdiff_t GetOffsetFrom(ptrdiff_t offset) const { 58c68cb64496485710cdb5b8480f8fee287058c93farmvixl ptrdiff_t cursor_offset = cursor_ - buffer_; 59c68cb64496485710cdb5b8480f8fee287058c93farmvixl VIXL_ASSERT((offset >= 0) && (offset <= cursor_offset)); 60c68cb64496485710cdb5b8480f8fee287058c93farmvixl return cursor_offset - offset; 61c68cb64496485710cdb5b8480f8fee287058c93farmvixl } 6288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois VIXL_DEPRECATED("GetOffsetFrom", 6388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois ptrdiff_t OffsetFrom(ptrdiff_t offset) const) { 6488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois return GetOffsetFrom(offset); 6588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois } 66c68cb64496485710cdb5b8480f8fee287058c93farmvixl 6788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois ptrdiff_t GetCursorOffset() const { return GetOffsetFrom(0); } 6888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois VIXL_DEPRECATED("GetCursorOffset", ptrdiff_t CursorOffset() const) { 6988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois return GetCursorOffset(); 7088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois } 7188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois 7288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois void Rewind(ptrdiff_t offset) { 7388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois byte* rewound_cursor = buffer_ + offset; 7488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois VIXL_ASSERT((buffer_ <= rewound_cursor) && (rewound_cursor <= cursor_)); 7588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois cursor_ = rewound_cursor; 7688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois } 77c68cb64496485710cdb5b8480f8fee287058c93farmvixl 78c68cb64496485710cdb5b8480f8fee287058c93farmvixl template <typename T> 79c68cb64496485710cdb5b8480f8fee287058c93farmvixl T GetOffsetAddress(ptrdiff_t offset) const { 806a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); 81c68cb64496485710cdb5b8480f8fee287058c93farmvixl VIXL_ASSERT((offset >= 0) && (offset <= (cursor_ - buffer_))); 82c68cb64496485710cdb5b8480f8fee287058c93farmvixl return reinterpret_cast<T>(buffer_ + offset); 83c68cb64496485710cdb5b8480f8fee287058c93farmvixl } 84c68cb64496485710cdb5b8480f8fee287058c93farmvixl 856a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames // Return the address of the start or end of the buffer. 866a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames template <typename T> 876a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames T GetStartAddress() const { 886a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); 896a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames return GetOffsetAddress<T>(0); 906a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames } 916a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames template <typename T> 926a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames T GetEndAddress() const { 936a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); 946a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames return GetOffsetAddress<T>(GetCapacity()); 956a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames } 966a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames 9788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois size_t GetRemainingBytes() const { 98c68cb64496485710cdb5b8480f8fee287058c93farmvixl VIXL_ASSERT((cursor_ >= buffer_) && (cursor_ <= (buffer_ + capacity_))); 99c68cb64496485710cdb5b8480f8fee287058c93farmvixl return (buffer_ + capacity_) - cursor_; 100c68cb64496485710cdb5b8480f8fee287058c93farmvixl } 10188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois VIXL_DEPRECATED("GetRemainingBytes", size_t RemainingBytes() const) { 10288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois return GetRemainingBytes(); 10388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois } 10488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois 10588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois size_t GetSizeInBytes() const { 10688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois VIXL_ASSERT((cursor_ >= buffer_) && (cursor_ <= (buffer_ + capacity_))); 10788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois return cursor_ - buffer_; 10888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois } 109c68cb64496485710cdb5b8480f8fee287058c93farmvixl 110c68cb64496485710cdb5b8480f8fee287058c93farmvixl // A code buffer can emit: 1115d85018e08776bbf182bcb36edf6fbb764023a5fVincent Belliard // * 8, 16, 32 or 64-bit data: constant. 1125d85018e08776bbf182bcb36edf6fbb764023a5fVincent Belliard // * 16 or 32-bit data: instruction. 113c68cb64496485710cdb5b8480f8fee287058c93farmvixl // * string: debug info. 1145d85018e08776bbf182bcb36edf6fbb764023a5fVincent Belliard void Emit8(uint8_t data) { Emit(data); } 1155d85018e08776bbf182bcb36edf6fbb764023a5fVincent Belliard 11688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois void Emit16(uint16_t data) { Emit(data); } 11788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois 118c68cb64496485710cdb5b8480f8fee287058c93farmvixl void Emit32(uint32_t data) { Emit(data); } 119c68cb64496485710cdb5b8480f8fee287058c93farmvixl 120c68cb64496485710cdb5b8480f8fee287058c93farmvixl void Emit64(uint64_t data) { Emit(data); } 121c68cb64496485710cdb5b8480f8fee287058c93farmvixl 122c68cb64496485710cdb5b8480f8fee287058c93farmvixl void EmitString(const char* string); 123c68cb64496485710cdb5b8480f8fee287058c93farmvixl 12488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois void EmitData(const void* data, size_t size); 12588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois 12686eb8871a7c87e6ef75066c3deaedfc9dbd3c4afAlexandre Rames template <typename T> 12786eb8871a7c87e6ef75066c3deaedfc9dbd3c4afAlexandre Rames void Emit(T value) { 12886eb8871a7c87e6ef75066c3deaedfc9dbd3c4afAlexandre Rames VIXL_ASSERT(HasSpaceFor(sizeof(value))); 12986eb8871a7c87e6ef75066c3deaedfc9dbd3c4afAlexandre Rames dirty_ = true; 13086eb8871a7c87e6ef75066c3deaedfc9dbd3c4afAlexandre Rames memcpy(cursor_, &value, sizeof(value)); 13186eb8871a7c87e6ef75066c3deaedfc9dbd3c4afAlexandre Rames cursor_ += sizeof(value); 13286eb8871a7c87e6ef75066c3deaedfc9dbd3c4afAlexandre Rames } 13386eb8871a7c87e6ef75066c3deaedfc9dbd3c4afAlexandre Rames 1343e1b899f48c1328ac748b1f5fa78f417f7ec6581Vincent Belliard void UpdateData(size_t offset, const void* data, size_t size); 1353e1b899f48c1328ac748b1f5fa78f417f7ec6581Vincent Belliard 13688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois // Align to 32bit. 137c68cb64496485710cdb5b8480f8fee287058c93farmvixl void Align(); 138c68cb64496485710cdb5b8480f8fee287058c93farmvixl 1398b57c86886020cf0a5331823be4789ee558764e2Georgia Kouveli // Ensure there is enough space for and emit 'n' zero bytes. 1408b57c86886020cf0a5331823be4789ee558764e2Georgia Kouveli void EmitZeroedBytes(int n); 1418b57c86886020cf0a5331823be4789ee558764e2Georgia Kouveli 14288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois bool Is16bitAligned() const { return IsAligned<2>(cursor_); } 14388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois 14488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois bool Is32bitAligned() const { return IsAligned<4>(cursor_); } 14588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois 14688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois size_t GetCapacity() const { return capacity_; } 14788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois VIXL_DEPRECATED("GetCapacity", size_t capacity() const) { 14888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois return GetCapacity(); 14988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois } 150c68cb64496485710cdb5b8480f8fee287058c93farmvixl 151c68cb64496485710cdb5b8480f8fee287058c93farmvixl bool IsManaged() const { return managed_; } 152c68cb64496485710cdb5b8480f8fee287058c93farmvixl 153329ccf9105e1f360633f5c6bd229915ad1d1b14bYi Kong void Grow(size_t new_capacity); 154c68cb64496485710cdb5b8480f8fee287058c93farmvixl 155c68cb64496485710cdb5b8480f8fee287058c93farmvixl bool IsDirty() const { return dirty_; } 156c68cb64496485710cdb5b8480f8fee287058c93farmvixl 157c68cb64496485710cdb5b8480f8fee287058c93farmvixl void SetClean() { dirty_ = false; } 158c68cb64496485710cdb5b8480f8fee287058c93farmvixl 15988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois bool HasSpaceFor(size_t amount) const { 16088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois return GetRemainingBytes() >= amount; 16188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois } 16288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois 16388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois void EnsureSpaceFor(size_t amount, bool* has_grown) { 16488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois bool is_full = !HasSpaceFor(amount); 16588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois if (is_full) Grow(capacity_ * 2 + amount); 16688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois VIXL_ASSERT(has_grown != NULL); 16788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois *has_grown = is_full; 16888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois } 16988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois void EnsureSpaceFor(size_t amount) { 17088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois bool dummy; 17188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois EnsureSpaceFor(amount, &dummy); 17288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois } 17388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois 174c68cb64496485710cdb5b8480f8fee287058c93farmvixl private: 175c68cb64496485710cdb5b8480f8fee287058c93farmvixl // Backing store of the buffer. 176c68cb64496485710cdb5b8480f8fee287058c93farmvixl byte* buffer_; 177c68cb64496485710cdb5b8480f8fee287058c93farmvixl // If true the backing store is allocated and deallocated by the buffer. The 178c68cb64496485710cdb5b8480f8fee287058c93farmvixl // backing store can then grow on demand. If false the backing store is 179c68cb64496485710cdb5b8480f8fee287058c93farmvixl // provided by the user and cannot be resized internally. 180c68cb64496485710cdb5b8480f8fee287058c93farmvixl bool managed_; 181c68cb64496485710cdb5b8480f8fee287058c93farmvixl // Pointer to the next location to be written. 182c68cb64496485710cdb5b8480f8fee287058c93farmvixl byte* cursor_; 183c68cb64496485710cdb5b8480f8fee287058c93farmvixl // True if there has been any write since the buffer was created or cleaned. 184c68cb64496485710cdb5b8480f8fee287058c93farmvixl bool dirty_; 185c68cb64496485710cdb5b8480f8fee287058c93farmvixl // Capacity in bytes of the backing store. 186c68cb64496485710cdb5b8480f8fee287058c93farmvixl size_t capacity_; 187c68cb64496485710cdb5b8480f8fee287058c93farmvixl}; 188c68cb64496485710cdb5b8480f8fee287058c93farmvixl 189c68cb64496485710cdb5b8480f8fee287058c93farmvixl} // namespace vixl 190c68cb64496485710cdb5b8480f8fee287058c93farmvixl 191c68cb64496485710cdb5b8480f8fee287058c93farmvixl#endif // VIXL_CODE_BUFFER_H 192