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