constpool.h 8.28 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.

// [Guard]
#ifndef _ASMJIT_BASE_CONSTPOOL_H
#define _ASMJIT_BASE_CONSTPOOL_H

11
// [Dependencies]
12
13
14
#include "../base/zone.h"

// [Api-Begin]
15
#include "../asmjit_apibegin.h"
16
17
18

namespace asmjit {

19
//! \addtogroup asmjit_base
20
21
22
//! \{

// ============================================================================
23
// [asmjit::ConstPool]
24
25
// ============================================================================

26
27
28
29
//! Constant pool.
class ConstPool {
public:
  ASMJIT_NONCOPYABLE(ConstPool)
30
31

  enum {
32
33
34
35
36
37
38
    kIndex1 = 0,
    kIndex2 = 1,
    kIndex4 = 2,
    kIndex8 = 3,
    kIndex16 = 4,
    kIndex32 = 5,
    kIndexCount = 6
39
40
41
  };

  // --------------------------------------------------------------------------
42
  // [Gap]
43
44
  // --------------------------------------------------------------------------

45
46
47
48
49
50
51
52
  //! \internal
  //!
  //! Zone-allocated const-pool gap.
  struct Gap {
    Gap* _next;                          //!< Pointer to the next gap
    size_t _offset;                      //!< Offset of the gap.
    size_t _length;                      //!< Remaining bytes of the gap (basically a gap size).
  };
53
54

  // --------------------------------------------------------------------------
55
  // [Node]
56
57
  // --------------------------------------------------------------------------

58
59
60
61
62
63
64
65
66
67
68
69
70
  //! \internal
  //!
  //! Zone-allocated const-pool node.
  struct Node {
    ASMJIT_INLINE void* getData() const noexcept {
      return static_cast<void*>(const_cast<ConstPool::Node*>(this) + 1);
    }

    Node* _link[2];                      //!< Left/Right nodes.
    uint32_t _level : 31;                //!< Horizontal level for balance.
    uint32_t _shared : 1;                //!< If this constant is shared with another.
    uint32_t _offset;                    //!< Data offset from the beginning of the pool.
  };
71
72

  // --------------------------------------------------------------------------
73
  // [Tree]
74
75
  // --------------------------------------------------------------------------

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  //! \internal
  //!
  //! Zone-allocated const-pool tree.
  struct Tree {
    enum {
      //! Maximum tree height == log2(1 << 64).
      kHeightLimit = 64
    };

    // --------------------------------------------------------------------------
    // [Construction / Destruction]
    // --------------------------------------------------------------------------

    ASMJIT_INLINE Tree(size_t dataSize = 0) noexcept
      : _root(nullptr),
        _length(0),
        _dataSize(dataSize) {}
    ASMJIT_INLINE ~Tree() {}

    // --------------------------------------------------------------------------
    // [Reset]
    // --------------------------------------------------------------------------

    ASMJIT_INLINE void reset() noexcept {
      _root = nullptr;
      _length = 0;
    }
103

104
105
106
    // --------------------------------------------------------------------------
    // [Accessors]
    // --------------------------------------------------------------------------
107

108
109
    ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; }
    ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
110

111
112
113
114
    ASMJIT_INLINE void setDataSize(size_t dataSize) noexcept {
      ASMJIT_ASSERT(isEmpty());
      _dataSize = dataSize;
    }
115

116
117
118
    // --------------------------------------------------------------------------
    // [Ops]
    // --------------------------------------------------------------------------
119

120
121
    ASMJIT_API Node* get(const void* data) noexcept;
    ASMJIT_API void put(Node* node) noexcept;
122

123
124
125
    // --------------------------------------------------------------------------
    // [Iterate]
    // --------------------------------------------------------------------------
126

127
128
129
130
    template<typename Visitor>
    ASMJIT_INLINE void iterate(Visitor& visitor) const noexcept {
      Node* node = const_cast<Node*>(_root);
      if (!node) return;
131

132
133
      Node* stack[kHeightLimit];
      size_t top = 0;
134

135
136
137
138
139
      for (;;) {
        Node* left = node->_link[0];
        if (left != nullptr) {
          ASMJIT_ASSERT(top != kHeightLimit);
          stack[top++] = node;
140

141
142
143
          node = left;
          continue;
        }
144

145
146
147
148
149
Visit:
        visitor.visit(node);
        node = node->_link[1];
        if (node != nullptr)
          continue;
150

151
152
        if (top == 0)
          return;
153

154
155
        node = stack[--top];
        goto Visit;
156
157
158
      }
    }

159
160
161
    // --------------------------------------------------------------------------
    // [Helpers]
    // --------------------------------------------------------------------------
162

163
164
165
    static ASMJIT_INLINE Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) noexcept {
      Node* node = zone->allocT<Node>(sizeof(Node) + size);
      if (ASMJIT_UNLIKELY(!node)) return nullptr;
166

167
168
169
170
171
      node->_link[0] = nullptr;
      node->_link[1] = nullptr;
      node->_level = 1;
      node->_shared = shared;
      node->_offset = static_cast<uint32_t>(offset);
172

173
174
175
      ::memcpy(node->getData(), data, size);
      return node;
    }
176

177
178
179
    // --------------------------------------------------------------------------
    // [Members]
    // --------------------------------------------------------------------------
180

181
182
183
    Node* _root;                         //!< Root of the tree
    size_t _length;                      //!< Length of the tree (count of nodes).
    size_t _dataSize;                    //!< Size of the data.
184
185
186
187
188
189
  };

  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

190
191
  ASMJIT_API ConstPool(Zone* zone) noexcept;
  ASMJIT_API ~ConstPool() noexcept;
192
193
194
195
196

  // --------------------------------------------------------------------------
  // [Reset]
  // --------------------------------------------------------------------------

197
  ASMJIT_API void reset(Zone* zone) noexcept;
198
199
200
201
202
203

  // --------------------------------------------------------------------------
  // [Ops]
  // --------------------------------------------------------------------------

  //! Get whether the constant-pool is empty.
204
  ASMJIT_INLINE bool isEmpty() const noexcept { return _size == 0; }
205
  //! Get the size of the constant-pool in bytes.
206
  ASMJIT_INLINE size_t getSize() const noexcept { return _size; }
207
  //! Get minimum alignment.
208
  ASMJIT_INLINE size_t getAlignment() const noexcept { return _alignment; }
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226

  //! Add a constant to the constant pool.
  //!
  //! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes.
  //! The constant is added to the pool only if it doesn't not exist, otherwise
  //! cached value is returned.
  //!
  //! AsmJit is able to subdivide added constants, so for example if you add
  //! 8-byte constant 0x1122334455667788 it will create the following slots:
  //!
  //!   8-byte: 0x1122334455667788
  //!   4-byte: 0x11223344, 0x55667788
  //!
  //! The reason is that when combining MMX/SSE/AVX code some patterns are used
  //! frequently. However, AsmJit is not able to reallocate a constant that has
  //! been already added. For example if you try to add 4-byte constant and then
  //! 8-byte constant having the same 4-byte pattern as the previous one, two
  //! independent slots will be generated by the pool.
227
  ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept;
228
229
230
231
232
233

  // --------------------------------------------------------------------------
  // [Fill]
  // --------------------------------------------------------------------------

  //! Fill the destination with the constants from the pool.
234
  ASMJIT_API void fill(void* dst) const noexcept;
235
236
237
238
239

  // --------------------------------------------------------------------------
  // [Members]
  // --------------------------------------------------------------------------

240
241
242
243
244
245
246
  Zone* _zone;                           //!< Zone allocator.
  Tree _tree[kIndexCount];               //!< Tree per size.
  Gap* _gaps[kIndexCount];               //!< Gaps per size.
  Gap* _gapPool;                         //!< Gaps pool

  size_t _size;                          //!< Size of the pool (in bytes).
  size_t _alignment;                     //!< Required pool alignment.
247
248
249
250
251
252
253
};

//! \}

} // asmjit namespace

// [Api-End]
254
#include "../asmjit_apiend.h"
255
256
257

// [Guard]
#endif // _ASMJIT_BASE_CONSTPOOL_H