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