1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 Copyright (c) 2008-2017, Petr Kobalicek
3 
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7 
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11 
12 1. The origin of this software must not be misrepresented; you must not
13    claim that you wrote the original software. If you use this software
14    in a product, an acknowledgment in the product documentation would be
15    appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17    misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 #ifdef __PLUMED_HAS_ASMJIT
21 #pragma GCC diagnostic push
22 #pragma GCC diagnostic ignored "-Wpedantic"
23 // [AsmJit]
24 // Complete x86/x64 JIT and Remote Assembler for C++.
25 //
26 // [License]
27 // Zlib - See LICENSE.md file in the package.
28 
29 // [Export]
30 #define ASMJIT_EXPORTS
31 
32 // [Dependencies]
33 #include "./moved_string.h"
34 #include "./utils.h"
35 
36 // [Api-Begin]
37 #include "./asmjit_apibegin.h"
38 
39 namespace PLMD {
40 namespace asmjit {
41 
42 // ============================================================================
43 // [asmjit::StringBuilder - Construction / Destruction]
44 // ============================================================================
45 
46 // Should be placed in read-only memory.
47 static const char StringBuilder_empty[4] = { 0 };
48 
StringBuilder()49 StringBuilder::StringBuilder() noexcept
50   : _data(const_cast<char*>(StringBuilder_empty)),
51     _length(0),
52     _capacity(0),
53     _canFree(false) {}
54 
~StringBuilder()55 StringBuilder::~StringBuilder() noexcept {
56   if (_canFree)
57     Internal::releaseMemory(_data);
58 }
59 
60 // ============================================================================
61 // [asmjit::StringBuilder - Prepare / Reserve]
62 // ============================================================================
63 
prepare(uint32_t op,size_t len)64 ASMJIT_FAVOR_SIZE char* StringBuilder::prepare(uint32_t op, size_t len) noexcept {
65   if (op == kStringOpSet) {
66     // We don't care here, but we can't return a null pointer since it indicates
67     // failure in memory allocation.
68     if (len == 0) {
69       if (_data != StringBuilder_empty)
70         _data[0] = 0;
71 
72       _length = 0;
73       return _data;
74     }
75 
76     if (_capacity < len) {
77       if (len >= IntTraits<size_t>::maxValue() - sizeof(intptr_t) * 2)
78         return nullptr;
79 
80       size_t to = Utils::alignTo<size_t>(len, sizeof(intptr_t));
81       if (to < 256 - sizeof(intptr_t))
82         to = 256 - sizeof(intptr_t);
83 
84       char* newData = static_cast<char*>(Internal::allocMemory(to + sizeof(intptr_t)));
85       if (!newData) {
86         clear();
87         return nullptr;
88       }
89 
90       if (_canFree)
91         Internal::releaseMemory(_data);
92 
93       _data = newData;
94       _capacity = to + sizeof(intptr_t) - 1;
95       _canFree = true;
96     }
97 
98     _data[len] = 0;
99     _length = len;
100 
101     ASMJIT_ASSERT(_length <= _capacity);
102     return _data;
103   }
104   else {
105     // We don't care here, but we can't return a null pointer since it indicates
106     // failure of memory allocation.
107     if (len == 0)
108       return _data + _length;
109 
110     // Overflow.
111     if (IntTraits<size_t>::maxValue() - sizeof(intptr_t) * 2 - _length < len)
112       return nullptr;
113 
114     size_t after = _length + len;
115     if (_capacity < after) {
116       size_t to = _capacity;
117 
118       if (to < 256)
119         to = 256;
120 
121       while (to < 1024 * 1024 && to < after)
122         to *= 2;
123 
124       if (to < after) {
125         to = after;
126         if (to < (IntTraits<size_t>::maxValue() - 1024 * 32))
127           to = Utils::alignTo<size_t>(to, 1024 * 32);
128       }
129 
130       to = Utils::alignTo<size_t>(to, sizeof(intptr_t));
131       char* newData = static_cast<char*>(Internal::allocMemory(to + sizeof(intptr_t)));
132       if (!newData) return nullptr;
133 
134       ::memcpy(newData, _data, _length);
135       if (_canFree)
136         Internal::releaseMemory(_data);
137 
138       _data = newData;
139       _capacity = to + sizeof(intptr_t) - 1;
140       _canFree = true;
141     }
142 
143     char* ret = _data + _length;
144     _data[after] = 0;
145     _length = after;
146 
147     ASMJIT_ASSERT(_length <= _capacity);
148     return ret;
149   }
150 }
151 
reserve(size_t to)152 ASMJIT_FAVOR_SIZE Error StringBuilder::reserve(size_t to) noexcept {
153   if (_capacity >= to)
154     return kErrorOk;
155 
156   if (to >= IntTraits<size_t>::maxValue() - sizeof(intptr_t) * 2)
157     return DebugUtils::errored(kErrorNoHeapMemory);
158 
159   to = Utils::alignTo<size_t>(to, sizeof(intptr_t));
160   char* newData = static_cast<char*>(Internal::allocMemory(to + sizeof(intptr_t)));
161 
162   if (!newData)
163     return DebugUtils::errored(kErrorNoHeapMemory);
164 
165   ::memcpy(newData, _data, _length + 1);
166   if (_canFree)
167     Internal::releaseMemory(_data);
168 
169   _data = newData;
170   _capacity = to + sizeof(intptr_t) - 1;
171   _canFree = true;
172   return kErrorOk;
173 }
174 
175 // ============================================================================
176 // [asmjit::StringBuilder - Clear]
177 // ============================================================================
178 
clear()179 void StringBuilder::clear() noexcept {
180   if (_data != StringBuilder_empty)
181     _data[0] = 0;
182   _length = 0;
183 }
184 
185 // ============================================================================
186 // [asmjit::StringBuilder - Methods]
187 // ============================================================================
188 
_opString(uint32_t op,const char * str,size_t len)189 Error StringBuilder::_opString(uint32_t op, const char* str, size_t len) noexcept {
190   if (len == Globals::kInvalidIndex)
191     len = str ? ::strlen(str) : static_cast<size_t>(0);
192 
193   char* p = prepare(op, len);
194   if (!p) return DebugUtils::errored(kErrorNoHeapMemory);
195 
196   ::memcpy(p, str, len);
197   return kErrorOk;
198 }
199 
_opChar(uint32_t op,char c)200 Error StringBuilder::_opChar(uint32_t op, char c) noexcept {
201   char* p = prepare(op, 1);
202   if (!p) return DebugUtils::errored(kErrorNoHeapMemory);
203 
204   *p = c;
205   return kErrorOk;
206 }
207 
_opChars(uint32_t op,char c,size_t n)208 Error StringBuilder::_opChars(uint32_t op, char c, size_t n) noexcept {
209   char* p = prepare(op, n);
210   if (!p) return DebugUtils::errored(kErrorNoHeapMemory);
211 
212   ::memset(p, c, n);
213   return kErrorOk;
214 }
215 
216 static const char StringBuilder_numbers[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
217 
_opNumber(uint32_t op,uint64_t i,uint32_t base,size_t width,uint32_t flags)218 Error StringBuilder::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) noexcept {
219   if (base < 2 || base > 36)
220     base = 10;
221 
222   char buf[128];
223   char* p = buf + ASMJIT_ARRAY_SIZE(buf);
224 
225   uint64_t orig = i;
226   char sign = '\0';
227 
228   // --------------------------------------------------------------------------
229   // [Sign]
230   // --------------------------------------------------------------------------
231 
232   if ((flags & kStringFormatSigned) != 0 && static_cast<int64_t>(i) < 0) {
233     i = static_cast<uint64_t>(-static_cast<int64_t>(i));
234     sign = '-';
235   }
236   else if ((flags & kStringFormatShowSign) != 0) {
237     sign = '+';
238   }
239   else if ((flags & kStringFormatShowSpace) != 0) {
240     sign = ' ';
241   }
242 
243   // --------------------------------------------------------------------------
244   // [Number]
245   // --------------------------------------------------------------------------
246 
247   do {
248     uint64_t d = i / base;
249     uint64_t r = i % base;
250 
251     *--p = StringBuilder_numbers[r];
252     i = d;
253   } while (i);
254 
255   size_t numberLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p);
256 
257   // --------------------------------------------------------------------------
258   // [Alternate Form]
259   // --------------------------------------------------------------------------
260 
261   if ((flags & kStringFormatAlternate) != 0) {
262     if (base == 8) {
263       if (orig != 0)
264         *--p = '0';
265     }
266     if (base == 16) {
267       *--p = 'x';
268       *--p = '0';
269     }
270   }
271 
272   // --------------------------------------------------------------------------
273   // [Width]
274   // --------------------------------------------------------------------------
275 
276   if (sign != 0)
277     *--p = sign;
278 
279   if (width > 256)
280     width = 256;
281 
282   if (width <= numberLength)
283     width = 0;
284   else
285     width -= numberLength;
286 
287   // --------------------------------------------------------------------------
288   // Write]
289   // --------------------------------------------------------------------------
290 
291   size_t prefixLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberLength;
292   char* data = prepare(op, prefixLength + width + numberLength);
293 
294   if (!data)
295     return DebugUtils::errored(kErrorNoHeapMemory);
296 
297   ::memcpy(data, p, prefixLength);
298   data += prefixLength;
299 
300   ::memset(data, '0', width);
301   data += width;
302 
303   ::memcpy(data, p + prefixLength, numberLength);
304   return kErrorOk;
305 }
306 
_opHex(uint32_t op,const void * data,size_t len)307 Error StringBuilder::_opHex(uint32_t op, const void* data, size_t len) noexcept {
308   char* dst;
309 
310   if (len >= IntTraits<size_t>::maxValue() / 2 || !(dst = prepare(op, len * 2)))
311     return DebugUtils::errored(kErrorNoHeapMemory);;
312 
313   const char* src = static_cast<const char*>(data);
314   for (size_t i = 0; i < len; i++, dst += 2, src++) {
315     dst[0] = StringBuilder_numbers[(src[0] >> 4) & 0xF];
316     dst[1] = StringBuilder_numbers[(src[0]     ) & 0xF];
317   }
318   return kErrorOk;
319 }
320 
_opVFormat(uint32_t op,const char * fmt,va_list ap)321 Error StringBuilder::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept {
322   char buf[1024];
323 
324   vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
325   buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0';
326 
327   return _opString(op, buf);
328 }
329 
setFormat(const char * fmt,...)330 Error StringBuilder::setFormat(const char* fmt, ...) noexcept {
331   bool result;
332 
333   va_list ap;
334   va_start(ap, fmt);
335   result = _opVFormat(kStringOpSet, fmt, ap);
336   va_end(ap);
337 
338   return result;
339 }
340 
appendFormat(const char * fmt,...)341 Error StringBuilder::appendFormat(const char* fmt, ...) noexcept {
342   bool result;
343 
344   va_list ap;
345   va_start(ap, fmt);
346   result = _opVFormat(kStringOpAppend, fmt, ap);
347   va_end(ap);
348 
349   return result;
350 }
351 
eq(const char * str,size_t len) const352 bool StringBuilder::eq(const char* str, size_t len) const noexcept {
353   const char* aData = _data;
354   const char* bData = str;
355 
356   size_t aLength = _length;
357   size_t bLength = len;
358 
359   if (bLength == Globals::kInvalidIndex) {
360     size_t i;
361     for (i = 0; i < aLength; i++)
362       if (aData[i] != bData[i] || bData[i] == 0)
363         return false;
364     return bData[i] == 0;
365   }
366   else {
367     if (aLength != bLength)
368       return false;
369     return ::memcmp(aData, bData, aLength) == 0;
370   }
371 }
372 
373 } // asmjit namespace
374 } // namespace PLMD
375 
376 // [Api-End]
377 #include "./asmjit_apiend.h"
378 #pragma GCC diagnostic pop
379 #endif // __PLUMED_HAS_ASMJIT
380