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