blob: c677c4f1b6d348f1599bf51f35963119f825bc7b [file] [log] [blame]
ggaren@apple.com58f417e2008-11-17 06:27:06 +00001/*
mark.lam@apple.comd27553f2019-09-18 00:36:19 +00002 * Copyright (C) 2008-2019 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>
sbarati@apple.com80c907f2018-09-28 05:34:38 +000036#if CPU(ARM64E)
37#include <wtf/PtrTag.h>
38#endif
loki@webkit.org7534a3f2010-08-13 10:14:36 +000039#include <wtf/StdLibExtras.h>
yusukesuzuki@slowstart.org68366402018-08-19 22:50:05 +000040#include <wtf/UnalignedAccess.h>
ggaren@apple.com58f417e2008-11-17 06:27:06 +000041
42namespace JSC {
43
sbarati@apple.com80c907f2018-09-28 05:34:38 +000044 class LinkBuffer;
45
barraclough@apple.com4836c7a2011-05-01 22:20:59 +000046 struct AssemblerLabel {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +000047 AssemblerLabel()
48 : m_offset(std::numeric_limits<uint32_t>::max())
49 {
50 }
51
52 explicit AssemblerLabel(uint32_t offset)
barraclough@apple.com4836c7a2011-05-01 22:20:59 +000053 : m_offset(offset)
54 {
55 }
56
57 bool isSet() const { return (m_offset != std::numeric_limits<uint32_t>::max()); }
58
barraclough@apple.comc5390ae2011-05-02 18:30:03 +000059 AssemblerLabel labelAtOffset(int offset) const
60 {
61 return AssemblerLabel(m_offset + offset);
62 }
63
sbarati@apple.comd3d0c002016-01-30 01:11:05 +000064 bool operator==(const AssemblerLabel& other) const { return m_offset == other.m_offset; }
65
barraclough@apple.com4836c7a2011-05-01 22:20:59 +000066 uint32_t m_offset;
67 };
68
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000069 class AssemblerData {
sbarati@apple.comb5bee812016-06-19 19:42:18 +000070 WTF_MAKE_NONCOPYABLE(AssemblerData);
mark.lam@apple.comd27553f2019-09-18 00:36:19 +000071 static constexpr size_t InlineCapacity = 128;
ggaren@apple.com58f417e2008-11-17 06:27:06 +000072 public:
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000073 AssemblerData()
sbarati@apple.comb5bee812016-06-19 19:42:18 +000074 : m_buffer(m_inlineBuffer)
75 , m_capacity(InlineCapacity)
ggaren@apple.com58f417e2008-11-17 06:27:06 +000076 {
77 }
78
sbarati@apple.comb5bee812016-06-19 19:42:18 +000079 AssemblerData(size_t initialCapacity)
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000080 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +000081 if (initialCapacity <= InlineCapacity) {
82 m_capacity = InlineCapacity;
83 m_buffer = m_inlineBuffer;
84 } else {
85 m_capacity = initialCapacity;
86 m_buffer = static_cast<char*>(fastMalloc(m_capacity));
87 }
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000088 }
89
90 AssemblerData(AssemblerData&& other)
91 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +000092 if (other.isInlineBuffer()) {
93 ASSERT(other.m_capacity == InlineCapacity);
94 memcpy(m_inlineBuffer, other.m_inlineBuffer, InlineCapacity);
95 m_buffer = m_inlineBuffer;
96 } else
97 m_buffer = other.m_buffer;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000098 m_capacity = other.m_capacity;
sbarati@apple.comb5bee812016-06-19 19:42:18 +000099
100 other.m_buffer = nullptr;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000101 other.m_capacity = 0;
102 }
103
104 AssemblerData& operator=(AssemblerData&& other)
105 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000106 if (m_buffer && !isInlineBuffer())
107 fastFree(m_buffer);
108
109 if (other.isInlineBuffer()) {
110 ASSERT(other.m_capacity == InlineCapacity);
111 memcpy(m_inlineBuffer, other.m_inlineBuffer, InlineCapacity);
112 m_buffer = m_inlineBuffer;
113 } else
114 m_buffer = other.m_buffer;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000115 m_capacity = other.m_capacity;
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000116
117 other.m_buffer = nullptr;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000118 other.m_capacity = 0;
119 return *this;
120 }
121
122 ~AssemblerData()
123 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000124 if (m_buffer && !isInlineBuffer())
125 fastFree(m_buffer);
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000126 }
127
128 char* buffer() const { return m_buffer; }
129
130 unsigned capacity() const { return m_capacity; }
131
132 void grow(unsigned extraCapacity = 0)
133 {
benjamin@webkit.org26dd4172015-05-18 06:26:10 +0000134 m_capacity = m_capacity + m_capacity / 2 + extraCapacity;
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000135 if (isInlineBuffer()) {
136 m_buffer = static_cast<char*>(fastMalloc(m_capacity));
137 memcpy(m_buffer, m_inlineBuffer, InlineCapacity);
138 } else
139 m_buffer = static_cast<char*>(fastRealloc(m_buffer, m_capacity));
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000140 }
141
142 private:
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000143 bool isInlineBuffer() const { return m_buffer == m_inlineBuffer; }
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000144 char* m_buffer;
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000145 char m_inlineBuffer[InlineCapacity];
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000146 unsigned m_capacity;
147 };
148
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000149#if CPU(ARM64E)
150 class ARM64EHash {
151 public:
sbarati@apple.comfc044cd2018-12-19 02:27:00 +0000152 ARM64EHash() = default;
153 ALWAYS_INLINE void update(uint32_t value)
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000154 {
sbarati@apple.comfc044cd2018-12-19 02:27:00 +0000155 uint64_t input = value ^ m_hash;
156 uint64_t a = static_cast<uint32_t>(tagInt(input, static_cast<PtrTag>(0)) >> 39);
157 uint64_t b = tagInt(input, static_cast<PtrTag>(0xb7e151628aed2a6a)) >> 23;
sbarati@apple.com0f1b4232019-01-24 22:07:33 +0000158 m_hash = a ^ b;
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000159 }
sbarati@apple.comfc044cd2018-12-19 02:27:00 +0000160 uint32_t finalHash() const
161 {
162 uint64_t hash = m_hash;
163 uint64_t a = static_cast<uint32_t>(tagInt(hash, static_cast<PtrTag>(0xbf7158809cf4f3c7)) >> 39);
164 uint64_t b = tagInt(hash, static_cast<PtrTag>(0x62e7160f38b4da56)) >> 23;
sbarati@apple.com0f1b4232019-01-24 22:07:33 +0000165 return static_cast<uint32_t>(a ^ b);
sbarati@apple.comfc044cd2018-12-19 02:27:00 +0000166 }
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000167 private:
sbarati@apple.comfc044cd2018-12-19 02:27:00 +0000168 uint32_t m_hash { 0 };
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000169 };
170#endif
171
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000172 class AssemblerBuffer {
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000173 public:
sbarati@apple.comfc044cd2018-12-19 02:27:00 +0000174 AssemblerBuffer()
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000175 : m_storage()
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000176 , m_index(0)
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000177 {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000178 }
179
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000180 bool isAvailable(unsigned space)
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000181 {
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000182 return m_index + space <= m_storage.capacity();
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000183 }
184
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000185 void ensureSpace(unsigned space)
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000186 {
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000187 while (!isAvailable(space))
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000188 outOfLineGrow();
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000189 }
190
barraclough@apple.com167270d2008-12-15 23:38:19 +0000191 bool isAligned(int alignment) const
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000192 {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000193 return !(m_index & (alignment - 1));
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000194 }
195
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000196#if !CPU(ARM64)
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000197 void putByteUnchecked(int8_t value) { putIntegralUnchecked(value); }
198 void putByte(int8_t value) { putIntegral(value); }
199 void putShortUnchecked(int16_t value) { putIntegralUnchecked(value); }
200 void putShort(int16_t value) { putIntegral(value); }
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000201 void putInt64Unchecked(int64_t value) { putIntegralUnchecked(value); }
202 void putInt64(int64_t value) { putIntegral(value); }
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000203#endif
204 void putIntUnchecked(int32_t value) { putIntegralUnchecked(value); }
205 void putInt(int32_t value) { putIntegral(value); }
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000206
barraclough@apple.come00c8ce2011-04-30 23:59:17 +0000207 size_t codeSize() const
208 {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000209 return m_index;
barraclough@apple.come00c8ce2011-04-30 23:59:17 +0000210 }
211
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000212#if !CPU(ARM64)
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000213 void setCodeSize(size_t index)
214 {
215 // Warning: Only use this if you know exactly what you are doing.
216 // For example, say you want 40 bytes of nops, it's ok to grow
217 // and then fill 40 bytes of nops using bigger instructions.
218 m_index = index;
219 ASSERT(m_index <= m_storage.capacity());
220 }
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000221#endif
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000222
barraclough@apple.com0ec87122011-05-02 01:04:17 +0000223 AssemblerLabel label() const
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000224 {
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000225 return AssemblerLabel(m_index);
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000226 }
227
barraclough@apple.comc5390ae2011-05-02 18:30:03 +0000228 unsigned debugOffset() { return m_index; }
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000229
sbarati@apple.comb5bee812016-06-19 19:42:18 +0000230 AssemblerData&& releaseAssemblerData() { return WTFMove(m_storage); }
barraclough@apple.com9cb663d2011-04-15 00:25:59 +0000231
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000232 // LocalWriter is a trick to keep the storage buffer and the index
233 // in memory while issuing multiple Stores.
234 // It is created in a block scope and its attribute can stay live
235 // between writes.
236 //
237 // LocalWriter *CANNOT* be mixed with other types of access to AssemblerBuffer.
238 // AssemblerBuffer cannot be used until its LocalWriter goes out of scope.
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000239#if !CPU(ARM64) // If we ever need to use this on arm64e, we would need to make the checksum aware of this.
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000240 class LocalWriter {
241 public:
242 LocalWriter(AssemblerBuffer& buffer, unsigned requiredSpace)
243 : m_buffer(buffer)
244 {
245 buffer.ensureSpace(requiredSpace);
246 m_storageBuffer = buffer.m_storage.buffer();
247 m_index = buffer.m_index;
248#if !defined(NDEBUG)
249 m_initialIndex = m_index;
250 m_requiredSpace = requiredSpace;
251#endif
252 }
253
254 ~LocalWriter()
255 {
256 ASSERT(m_index - m_initialIndex <= m_requiredSpace);
257 ASSERT(m_buffer.m_index == m_initialIndex);
258 ASSERT(m_storageBuffer == m_buffer.m_storage.buffer());
259 m_buffer.m_index = m_index;
260 }
261
262 void putByteUnchecked(int8_t value) { putIntegralUnchecked(value); }
263 void putShortUnchecked(int16_t value) { putIntegralUnchecked(value); }
264 void putIntUnchecked(int32_t value) { putIntegralUnchecked(value); }
265 void putInt64Unchecked(int64_t value) { putIntegralUnchecked(value); }
266 private:
267 template<typename IntegralType>
268 void putIntegralUnchecked(IntegralType value)
269 {
270 ASSERT(m_index + sizeof(IntegralType) <= m_buffer.m_storage.capacity());
yusukesuzuki@slowstart.org68366402018-08-19 22:50:05 +0000271 WTF::unalignedStore<IntegralType>(m_storageBuffer + m_index, value);
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000272 m_index += sizeof(IntegralType);
273 }
274 AssemblerBuffer& m_buffer;
275 char* m_storageBuffer;
276 unsigned m_index;
277#if !defined(NDEBUG)
278 unsigned m_initialIndex;
279 unsigned m_requiredSpace;
280#endif
281 };
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000282#endif // !CPU(ARM64)
283
284#if CPU(ARM64E)
285 ARM64EHash hash() const { return m_hash; }
286#endif
287
288#if !CPU(ARM64) // If we were to define this on arm64e, we'd need a way to update the hash as we write directly into the buffer.
289 void* data() const { return m_storage.buffer(); }
290#endif
291
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000292
barraclough@apple.com3fa07df2009-07-17 21:17:45 +0000293 protected:
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000294 template<typename IntegralType>
295 void putIntegral(IntegralType value)
296 {
297 unsigned nextIndex = m_index + sizeof(IntegralType);
298 if (UNLIKELY(nextIndex > m_storage.capacity()))
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000299 outOfLineGrow();
yusukesuzuki@slowstart.org68366402018-08-19 22:50:05 +0000300 putIntegralUnchecked<IntegralType>(value);
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000301 }
302
303 template<typename IntegralType>
304 void putIntegralUnchecked(IntegralType value)
305 {
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000306#if CPU(ARM64)
307 static_assert(sizeof(value) == 4, "");
308#if CPU(ARM64E)
sbarati@apple.comfc044cd2018-12-19 02:27:00 +0000309 m_hash.update(value);
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000310#endif
311#endif
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000312 ASSERT(isAvailable(sizeof(IntegralType)));
yusukesuzuki@slowstart.org68366402018-08-19 22:50:05 +0000313 WTF::unalignedStore<IntegralType>(m_storage.buffer() + m_index, value);
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000314 m_index += sizeof(IntegralType);
315 }
316
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000317 private:
barraclough@apple.com3fa07df2009-07-17 21:17:45 +0000318 void grow(int extraCapacity = 0)
319 {
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000320 m_storage.grow(extraCapacity);
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000321 }
322
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000323 NEVER_INLINE void outOfLineGrow()
324 {
325 m_storage.grow();
326 }
327
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000328#if !CPU(ARM64)
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000329 friend LocalWriter;
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000330#endif
331 friend LinkBuffer;
commit-queue@webkit.org932ba2d2016-03-26 03:47:23 +0000332
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000333 AssemblerData m_storage;
334 unsigned m_index;
sbarati@apple.com80c907f2018-09-28 05:34:38 +0000335#if CPU(ARM64E)
336 ARM64EHash m_hash;
337#endif
ggaren@apple.com58f417e2008-11-17 06:27:06 +0000338 };
339
340} // namespace JSC
341
342#endif // ENABLE(ASSEMBLER)