blob: 7340952d53c4f5d4f58855feac7511324e5ef9dd [file] [log] [blame]
ggaren@apple.com58f417e2008-11-17 06:27:06 +00001/*
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +00002 * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved.
ggaren@apple.com58f417e2008-11-17 06:27:06 +00003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
ryanhaddad@apple.com22104f52016-09-28 17:08:17 +000026#pragma once
ggaren@apple.com58f417e2008-11-17 06:27:06 +000027
ggaren@apple.com58f417e2008-11-17 06:27:06 +000028#if ENABLE(ASSEMBLER)
29
fpizlo@apple.comb75911b2012-06-13 20:53:52 +000030#include "ExecutableAllocator.h"
fpizlo@apple.com0f25ee82012-03-01 05:46:20 +000031#include "JITCompilationEffort.h"
barraclough@apple.com780b75b2008-12-17 01:27:13 +000032#include "stdint.h"
ggaren@apple.com3e9d4132008-11-18 03:25:03 +000033#include <string.h>
ggaren@apple.com58f417e2008-11-17 06:27:06 +000034#include <wtf/Assertions.h>
35#include <wtf/FastMalloc.h>
loki@webkit.org7534a3f2010-08-13 10:14:36 +000036#include <wtf/StdLibExtras.h>
ggaren@apple.com58f417e2008-11-17 06:27:06 +000037
38namespace JSC {
39
barraclough@apple.com4836c7a2011-05-01 22:20:59 +000040 struct AssemblerLabel {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +000041 AssemblerLabel()
42 : m_offset(std::numeric_limits<uint32_t>::max())
43 {
44 }
45
46 explicit AssemblerLabel(uint32_t offset)
barraclough@apple.com4836c7a2011-05-01 22:20:59 +000047 : m_offset(offset)
48 {
49 }
50
51 bool isSet() const { return (m_offset != std::numeric_limits<uint32_t>::max()); }
52
barraclough@apple.comc5390ae2011-05-02 18:30:03 +000053 AssemblerLabel labelAtOffset(int offset) const
54 {
55 return AssemblerLabel(m_offset + offset);
56 }
57
sbarati@apple.comd3d0c002016-01-30 01:11:05 +000058 bool operator==(const AssemblerLabel& other) const { return m_offset == other.m_offset; }
59
barraclough@apple.com4836c7a2011-05-01 22:20:59 +000060 uint32_t m_offset;
61 };
62
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000063 class AssemblerData {
sbarati@apple.comb5bee812016-06-19 19:42:18 +000064 WTF_MAKE_NONCOPYABLE(AssemblerData);
65 static const size_t InlineCapacity = 128;
ggaren@apple.com58f417e2008-11-17 06:27:06 +000066 public:
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000067 AssemblerData()
sbarati@apple.comb5bee812016-06-19 19:42:18 +000068 : m_buffer(m_inlineBuffer)
69 , m_capacity(InlineCapacity)
ggaren@apple.com58f417e2008-11-17 06:27:06 +000070 {
71 }
72
sbarati@apple.comb5bee812016-06-19 19:42:18 +000073 AssemblerData(size_t initialCapacity)
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000074 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +000075 if (initialCapacity <= InlineCapacity) {
76 m_capacity = InlineCapacity;
77 m_buffer = m_inlineBuffer;
78 } else {
79 m_capacity = initialCapacity;
80 m_buffer = static_cast<char*>(fastMalloc(m_capacity));
81 }
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000082 }
83
84 AssemblerData(AssemblerData&& other)
85 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +000086 if (other.isInlineBuffer()) {
87 ASSERT(other.m_capacity == InlineCapacity);
88 memcpy(m_inlineBuffer, other.m_inlineBuffer, InlineCapacity);
89 m_buffer = m_inlineBuffer;
90 } else
91 m_buffer = other.m_buffer;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000092 m_capacity = other.m_capacity;
sbarati@apple.comb5bee812016-06-19 19:42:18 +000093
94 other.m_buffer = nullptr;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000095 other.m_capacity = 0;
96 }
97
98 AssemblerData& operator=(AssemblerData&& other)
99 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000100 if (m_buffer && !isInlineBuffer())
101 fastFree(m_buffer);
102
103 if (other.isInlineBuffer()) {
104 ASSERT(other.m_capacity == InlineCapacity);
105 memcpy(m_inlineBuffer, other.m_inlineBuffer, InlineCapacity);
106 m_buffer = m_inlineBuffer;
107 } else
108 m_buffer = other.m_buffer;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000109 m_capacity = other.m_capacity;
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000110
111 other.m_buffer = nullptr;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000112 other.m_capacity = 0;
113 return *this;
114 }
115
116 ~AssemblerData()
117 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000118 if (m_buffer && !isInlineBuffer())
119 fastFree(m_buffer);
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000120 }
121
122 char* buffer() const { return m_buffer; }
123
124 unsigned capacity() const { return m_capacity; }
125
126 void grow(unsigned extraCapacity = 0)
127 {
benjamin@webkit.org26dd4172015-05-18 06:26:10 +0000128 m_capacity = m_capacity + m_capacity / 2 + extraCapacity;
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000129 if (isInlineBuffer()) {
130 m_buffer = static_cast<char*>(fastMalloc(m_capacity));
131 memcpy(m_buffer, m_inlineBuffer, InlineCapacity);
132 } else
133 m_buffer = static_cast<char*>(fastRealloc(m_buffer, m_capacity));
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000134 }
135
136 private:
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000137 bool isInlineBuffer() const { return m_buffer == m_inlineBuffer; }
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000138 char* m_buffer;
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000139 char m_inlineBuffer[InlineCapacity];
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000140 unsigned m_capacity;
141 };
142
143 class AssemblerBuffer {
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000144 public:
145 AssemblerBuffer()
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000146 : m_storage()
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000147 , m_index(0)
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000148 {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000149 }
150
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000151 bool isAvailable(unsigned space)
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000152 {
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000153 return m_index + space <= m_storage.capacity();
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000154 }
155
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000156 void ensureSpace(unsigned space)
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000157 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000158 while (!isAvailable(space))
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000159 outOfLineGrow();
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000160 }
161
barraclough@apple.com167270d2008-12-15 23:38:19 +0000162 bool isAligned(int alignment) const
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000163 {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000164 return !(m_index & (alignment - 1));
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000165 }
166
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000167 void putByteUnchecked(int8_t value) { putIntegralUnchecked(value); }
168 void putByte(int8_t value) { putIntegral(value); }
169 void putShortUnchecked(int16_t value) { putIntegralUnchecked(value); }
170 void putShort(int16_t value) { putIntegral(value); }
171 void putIntUnchecked(int32_t value) { putIntegralUnchecked(value); }
172 void putInt(int32_t value) { putIntegral(value); }
173 void putInt64Unchecked(int64_t value) { putIntegralUnchecked(value); }
174 void putInt64(int64_t value) { putIntegral(value); }
175
barraclough@apple.com167270d2008-12-15 23:38:19 +0000176 void* data() const
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000177 {
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000178 return m_storage.buffer();
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000179 }
180
barraclough@apple.come00c8ce2011-04-30 23:59:17 +0000181 size_t codeSize() const
182 {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000183 return m_index;
barraclough@apple.come00c8ce2011-04-30 23:59:17 +0000184 }
185
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000186 void setCodeSize(size_t index)
187 {
188 // Warning: Only use this if you know exactly what you are doing.
189 // For example, say you want 40 bytes of nops, it's ok to grow
190 // and then fill 40 bytes of nops using bigger instructions.
191 m_index = index;
192 ASSERT(m_index <= m_storage.capacity());
193 }
194
barraclough@apple.com0ec87122011-05-02 01:04:17 +0000195 AssemblerLabel label() const
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000196 {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000197 return AssemblerLabel(m_index);
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000198 }
199
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000200 unsigned debugOffset() { return m_index; }
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000201
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000202 AssemblerData&& releaseAssemblerData() { return WTFMove(m_storage); }
barraclough@apple.com9cb663d2011-04-15 00:25:59 +0000203
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000204 // LocalWriter is a trick to keep the storage buffer and the index
205 // in memory while issuing multiple Stores.
206 // It is created in a block scope and its attribute can stay live
207 // between writes.
208 //
209 // LocalWriter *CANNOT* be mixed with other types of access to AssemblerBuffer.
210 // AssemblerBuffer cannot be used until its LocalWriter goes out of scope.
211 class LocalWriter {
212 public:
213 LocalWriter(AssemblerBuffer& buffer, unsigned requiredSpace)
214 : m_buffer(buffer)
215 {
216 buffer.ensureSpace(requiredSpace);
217 m_storageBuffer = buffer.m_storage.buffer();
218 m_index = buffer.m_index;
219#if !defined(NDEBUG)
220 m_initialIndex = m_index;
221 m_requiredSpace = requiredSpace;
222#endif
223 }
224
225 ~LocalWriter()
226 {
227 ASSERT(m_index - m_initialIndex <= m_requiredSpace);
228 ASSERT(m_buffer.m_index == m_initialIndex);
229 ASSERT(m_storageBuffer == m_buffer.m_storage.buffer());
230 m_buffer.m_index = m_index;
231 }
232
233 void putByteUnchecked(int8_t value) { putIntegralUnchecked(value); }
234 void putShortUnchecked(int16_t value) { putIntegralUnchecked(value); }
235 void putIntUnchecked(int32_t value) { putIntegralUnchecked(value); }
236 void putInt64Unchecked(int64_t value) { putIntegralUnchecked(value); }
237 private:
238 template<typename IntegralType>
239 void putIntegralUnchecked(IntegralType value)
240 {
241 ASSERT(m_index + sizeof(IntegralType) <= m_buffer.m_storage.capacity());
242 *reinterpret_cast_ptr<IntegralType*>(m_storageBuffer + m_index) = value;
243 m_index += sizeof(IntegralType);
244 }
245 AssemblerBuffer& m_buffer;
246 char* m_storageBuffer;
247 unsigned m_index;
248#if !defined(NDEBUG)
249 unsigned m_initialIndex;
250 unsigned m_requiredSpace;
251#endif
252 };
253
barraclough@apple.com3fa07df2009-07-17 21:17:45 +0000254 protected:
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000255 template<typename IntegralType>
256 void putIntegral(IntegralType value)
257 {
258 unsigned nextIndex = m_index + sizeof(IntegralType);
259 if (UNLIKELY(nextIndex > m_storage.capacity()))
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000260 outOfLineGrow();
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000261 ASSERT(isAvailable(sizeof(IntegralType)));
262 *reinterpret_cast_ptr<IntegralType*>(m_storage.buffer() + m_index) = value;
263 m_index = nextIndex;
264 }
265
266 template<typename IntegralType>
267 void putIntegralUnchecked(IntegralType value)
268 {
269 ASSERT(isAvailable(sizeof(IntegralType)));
270 *reinterpret_cast_ptr<IntegralType*>(m_storage.buffer() + m_index) = value;
271 m_index += sizeof(IntegralType);
272 }
273
barraclough@apple.com3fa07df2009-07-17 21:17:45 +0000274 void append(const char* data, int size)
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000275 {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000276 if (!isAvailable(size))
barraclough@apple.com3fa07df2009-07-17 21:17:45 +0000277 grow(size);
278
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000279 memcpy(m_storage.buffer() + m_index, data, size);
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000280 m_index += size;
barraclough@apple.com3fa07df2009-07-17 21:17:45 +0000281 }
282
283 void grow(int extraCapacity = 0)
284 {
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000285 m_storage.grow(extraCapacity);
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000286 }
287
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000288 private:
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000289 NEVER_INLINE void outOfLineGrow()
290 {
291 m_storage.grow();
292 }
293
294 friend LocalWriter;
295
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000296 AssemblerData m_storage;
297 unsigned m_index;
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000298 };
299
300} // namespace JSC
301
302#endif // ENABLE(ASSEMBLER)