blob: 5fcaea493129702cc39a43b6a77d451ae93e7eea [file] [log] [blame]
fpizlo@apple.com2adf5272012-06-20 01:33:30 +00001/*
fpizlo@apple.com32622c92015-03-24 05:37:19 +00002 * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
fpizlo@apple.com2adf5272012-06-20 01:33:30 +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
26#include "config.h"
27#include "LinkBuffer.h"
28
29#if ENABLE(ASSEMBLER)
30
msaboff@apple.com95894332014-01-29 19:18:54 +000031#include "CodeBlock.h"
32#include "JITCode.h"
fpizlo@apple.comfb7eff22014-02-11 01:45:50 +000033#include "JSCInlines.h"
fpizlo@apple.com2adf5272012-06-20 01:33:30 +000034#include "Options.h"
mhahnenberg@apple.com50a0ca12013-12-17 01:33:05 +000035#include "VM.h"
oliver@apple.com90fce822013-07-25 04:00:13 +000036#include <wtf/CompilationThread.h>
fpizlo@apple.com2adf5272012-06-20 01:33:30 +000037
38namespace JSC {
39
mark.lam@apple.comee3c4102015-10-14 18:57:07 +000040bool shouldDumpDisassemblyFor(CodeBlock* codeBlock)
msaboff@apple.com95894332014-01-29 19:18:54 +000041{
mark.lam@apple.comee3c4102015-10-14 18:57:07 +000042 if (JITCode::isOptimizingJIT(codeBlock->jitType()) && Options::dumpDFGDisassembly())
msaboff@apple.com95894332014-01-29 19:18:54 +000043 return true;
mark.lam@apple.comee3c4102015-10-14 18:57:07 +000044 return Options::dumpDisassembly();
msaboff@apple.com95894332014-01-29 19:18:54 +000045}
46
fpizlo@apple.com2adf5272012-06-20 01:33:30 +000047LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithoutDisassembly()
48{
49 performFinalization();
50
fpizlo@apple.com2e7ada02013-10-23 18:22:09 +000051 ASSERT(m_didAllocate);
52 if (m_executableMemory)
53 return CodeRef(m_executableMemory);
54
55 return CodeRef::createSelfManagedCodeRef(MacroAssemblerCodePtr(m_code));
fpizlo@apple.com2adf5272012-06-20 01:33:30 +000056}
57
58LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithDisassembly(const char* format, ...)
59{
fpizlo@apple.com2adf5272012-06-20 01:33:30 +000060 CodeRef result = finalizeCodeWithoutDisassembly();
mark.lam@apple.com10190c42013-12-03 01:32:43 +000061
fpizlo@apple.com32622c92015-03-24 05:37:19 +000062 if (m_alreadyDisassembled)
63 return result;
64
65 StringPrintStream out;
66 out.printf("Generated JIT code for ");
fpizlo@apple.com2adf5272012-06-20 01:33:30 +000067 va_list argList;
68 va_start(argList, format);
fpizlo@apple.com32622c92015-03-24 05:37:19 +000069 out.vprintf(format, argList);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +000070 va_end(argList);
fpizlo@apple.com32622c92015-03-24 05:37:19 +000071 out.printf(":\n");
72
73 out.printf(" Code at [%p, %p):\n", result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
fpizlo@apple.com2adf5272012-06-20 01:33:30 +000074
fpizlo@apple.com32622c92015-03-24 05:37:19 +000075 CString header = out.toCString();
76
77 if (Options::asyncDisassembly()) {
78 disassembleAsynchronously(header, result, m_size, " ");
79 return result;
80 }
81
82 dataLog(header);
fpizlo@apple.com2860dbe2012-11-22 03:47:23 +000083 disassemble(result.code(), m_size, " ", WTF::dataFile());
fpizlo@apple.com2adf5272012-06-20 01:33:30 +000084
85 return result;
86}
87
dbates@webkit.org98f0de02013-10-15 22:16:39 +000088#if ENABLE(BRANCH_COMPACTION)
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +000089static ALWAYS_INLINE void recordLinkOffsets(AssemblerData& assemblerData, int32_t regionStart, int32_t regionEnd, int32_t offset)
90{
91 int32_t ptr = regionStart / sizeof(int32_t);
92 const int32_t end = regionEnd / sizeof(int32_t);
93 int32_t* offsets = reinterpret_cast<int32_t*>(assemblerData.buffer());
94 while (ptr < end)
95 offsets[ptr++] = offset;
96}
97
dbates@webkit.org98f0de02013-10-15 22:16:39 +000098template <typename InstructionType>
benjamin@webkit.orgf766fd92014-07-08 04:23:30 +000099void LinkBuffer::copyCompactAndLinkCode(MacroAssembler& macroAssembler, void* ownerUID, JITCompilationEffort effort)
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000100{
benjamin@webkit.orgf766fd92014-07-08 04:23:30 +0000101 m_initialSize = macroAssembler.m_assembler.codeSize();
fpizlo@apple.coma26c9042013-10-20 02:07:39 +0000102 allocate(m_initialSize, ownerUID, effort);
fpizlo@apple.com41bed902014-02-25 22:18:21 +0000103 if (didFailToAllocate())
104 return;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000105 Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink = macroAssembler.jumpsToLink();
106 m_assemblerStorage = macroAssembler.m_assembler.buffer().releaseAssemblerData();
107 uint8_t* inData = reinterpret_cast<uint8_t*>(m_assemblerStorage.buffer());
oliver@apple.com3243ddf2016-04-11 19:00:48 +0000108
oliver@apple.com89b03a62016-03-09 00:08:53 +0000109 AssemblerData outBuffer(m_size);
110 uint8_t* outData = reinterpret_cast<uint8_t*>(outBuffer.buffer());
oliver@apple.com3243ddf2016-04-11 19:00:48 +0000111 uint8_t* codeOutData = reinterpret_cast<uint8_t*>(m_code);
112
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000113 int readPtr = 0;
114 int writePtr = 0;
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000115 unsigned jumpCount = jumpsToLink.size();
116 for (unsigned i = 0; i < jumpCount; ++i) {
117 int offset = readPtr - writePtr;
118 ASSERT(!(offset & 1));
119
120 // Copy the instructions from the last jump to the current one.
121 size_t regionSize = jumpsToLink[i].from() - readPtr;
dbates@webkit.org98f0de02013-10-15 22:16:39 +0000122 InstructionType* copySource = reinterpret_cast_ptr<InstructionType*>(inData + readPtr);
123 InstructionType* copyEnd = reinterpret_cast_ptr<InstructionType*>(inData + readPtr + regionSize);
124 InstructionType* copyDst = reinterpret_cast_ptr<InstructionType*>(outData + writePtr);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000125 ASSERT(!(regionSize % 2));
126 ASSERT(!(readPtr % 2));
127 ASSERT(!(writePtr % 2));
128 while (copySource != copyEnd)
129 *copyDst++ = *copySource++;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000130 recordLinkOffsets(m_assemblerStorage, readPtr, jumpsToLink[i].from(), offset);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000131 readPtr += regionSize;
132 writePtr += regionSize;
133
134 // Calculate absolute address of the jump target, in the case of backwards
135 // branches we need to be precise, forward branches we are pessimistic
136 const uint8_t* target;
137 if (jumpsToLink[i].to() >= jumpsToLink[i].from())
oliver@apple.com3243ddf2016-04-11 19:00:48 +0000138 target = codeOutData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000139 else
oliver@apple.com3243ddf2016-04-11 19:00:48 +0000140 target = codeOutData + jumpsToLink[i].to() - executableOffsetFor(jumpsToLink[i].to());
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000141
oliver@apple.com3243ddf2016-04-11 19:00:48 +0000142 JumpLinkType jumpLinkType = MacroAssembler::computeJumpType(jumpsToLink[i], codeOutData + writePtr, target);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000143 // Compact branch if we can...
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000144 if (MacroAssembler::canCompact(jumpsToLink[i].type())) {
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000145 // Step back in the write stream
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000146 int32_t delta = MacroAssembler::jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000147 if (delta) {
148 writePtr -= delta;
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000149 recordLinkOffsets(m_assemblerStorage, jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000150 }
151 }
152 jumpsToLink[i].setFrom(writePtr);
153 }
154 // Copy everything after the last jump
155 memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr);
benjamin@webkit.orgf6de0772014-07-15 23:59:14 +0000156 recordLinkOffsets(m_assemblerStorage, readPtr, m_initialSize, readPtr - writePtr);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000157
158 for (unsigned i = 0; i < jumpCount; ++i) {
oliver@apple.com3243ddf2016-04-11 19:00:48 +0000159 uint8_t* location = codeOutData + jumpsToLink[i].from();
160 uint8_t* target = codeOutData + jumpsToLink[i].to() - executableOffsetFor(jumpsToLink[i].to());
161 MacroAssembler::link(jumpsToLink[i], outData + jumpsToLink[i].from(), location, target);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000162 }
163
164 jumpsToLink.clear();
fpizlo@apple.coma26c9042013-10-20 02:07:39 +0000165 shrink(writePtr + m_initialSize - readPtr);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000166
cdumez@apple.com35ccc142016-03-16 19:33:47 +0000167 performJITMemcpy(m_code, outBuffer.buffer(), m_size);
oliver@apple.com89b03a62016-03-09 00:08:53 +0000168
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000169#if DUMP_LINK_STATISTICS
170 dumpLinkStatistics(m_code, m_initialSize, m_size);
171#endif
172#if DUMP_CODE
173 dumpCode(m_code, m_size);
174#endif
dbates@webkit.org98f0de02013-10-15 22:16:39 +0000175}
176#endif
177
178
benjamin@webkit.orgf766fd92014-07-08 04:23:30 +0000179void LinkBuffer::linkCode(MacroAssembler& macroAssembler, void* ownerUID, JITCompilationEffort effort)
dbates@webkit.org98f0de02013-10-15 22:16:39 +0000180{
dbates@webkit.org98f0de02013-10-15 22:16:39 +0000181#if !ENABLE(BRANCH_COMPACTION)
commit-queue@webkit.org30a6a702013-10-22 15:51:51 +0000182#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
benjamin@webkit.orgf766fd92014-07-08 04:23:30 +0000183 macroAssembler.m_assembler.buffer().flushConstantPool(false);
commit-queue@webkit.org30a6a702013-10-22 15:51:51 +0000184#endif
benjamin@webkit.orgf766fd92014-07-08 04:23:30 +0000185 AssemblerBuffer& buffer = macroAssembler.m_assembler.buffer();
fpizlo@apple.coma26c9042013-10-20 02:07:39 +0000186 allocate(buffer.codeSize(), ownerUID, effort);
187 if (!m_didAllocate)
dbates@webkit.org98f0de02013-10-15 22:16:39 +0000188 return;
dbates@webkit.org98f0de02013-10-15 22:16:39 +0000189 ASSERT(m_code);
commit-queue@webkit.org65391052013-10-29 19:02:46 +0000190#if CPU(ARM_TRADITIONAL)
benjamin@webkit.orgf766fd92014-07-08 04:23:30 +0000191 macroAssembler.m_assembler.prepareExecutableCopy(m_code);
commit-queue@webkit.org65391052013-10-29 19:02:46 +0000192#endif
oliver@apple.com3243ddf2016-04-11 19:00:48 +0000193 performJITMemcpy(m_code, buffer.data(), buffer.codeSize());
commit-queue@webkit.org40a5dbd2013-11-05 15:32:27 +0000194#if CPU(MIPS)
benjamin@webkit.orgf766fd92014-07-08 04:23:30 +0000195 macroAssembler.m_assembler.relocateJumps(buffer.data(), m_code);
commit-queue@webkit.org40a5dbd2013-11-05 15:32:27 +0000196#endif
dbates@webkit.org98f0de02013-10-15 22:16:39 +0000197#elif CPU(ARM_THUMB2)
benjamin@webkit.org719b7572014-07-08 04:35:42 +0000198 copyCompactAndLinkCode<uint16_t>(macroAssembler, ownerUID, effort);
dbates@webkit.org98f0de02013-10-15 22:16:39 +0000199#elif CPU(ARM64)
benjamin@webkit.org719b7572014-07-08 04:35:42 +0000200 copyCompactAndLinkCode<uint32_t>(macroAssembler, ownerUID, effort);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000201#endif
fpizlo@apple.com6e697962015-10-12 17:56:26 +0000202
aestes@apple.com13aae082016-01-02 08:03:08 +0000203 m_linkTasks = WTFMove(macroAssembler.m_linkTasks);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000204}
205
fpizlo@apple.coma26c9042013-10-20 02:07:39 +0000206void LinkBuffer::allocate(size_t initialSize, void* ownerUID, JITCompilationEffort effort)
207{
fpizlo@apple.com2e7ada02013-10-23 18:22:09 +0000208 if (m_code) {
209 if (initialSize > m_size)
210 return;
211
212 m_didAllocate = true;
213 m_size = initialSize;
214 return;
215 }
216
oliver@apple.com89b03a62016-03-09 00:08:53 +0000217 ASSERT(m_vm != nullptr);
fpizlo@apple.coma26c9042013-10-20 02:07:39 +0000218 m_executableMemory = m_vm->executableAllocator.allocate(*m_vm, initialSize, ownerUID, effort);
219 if (!m_executableMemory)
220 return;
fpizlo@apple.coma26c9042013-10-20 02:07:39 +0000221 m_code = m_executableMemory->start();
222 m_size = initialSize;
223 m_didAllocate = true;
224}
225
226void LinkBuffer::shrink(size_t newSize)
227{
fpizlo@apple.com41bed902014-02-25 22:18:21 +0000228 if (!m_executableMemory)
229 return;
fpizlo@apple.coma26c9042013-10-20 02:07:39 +0000230 m_size = newSize;
231 m_executableMemory->shrink(m_size);
232}
233
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000234void LinkBuffer::performFinalization()
235{
fpizlo@apple.com6e697962015-10-12 17:56:26 +0000236 for (auto& task : m_linkTasks)
237 task->run(*this);
238
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000239#ifndef NDEBUG
oliver@apple.com90fce822013-07-25 04:00:13 +0000240 ASSERT(!isCompilationThread());
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000241 ASSERT(!m_completed);
242 ASSERT(isValid());
243 m_completed = true;
244#endif
245
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000246 MacroAssembler::cacheFlush(code(), m_size);
247}
248
249#if DUMP_LINK_STATISTICS
250void LinkBuffer::dumpLinkStatistics(void* code, size_t initializeSize, size_t finalSize)
251{
252 static unsigned linkCount = 0;
253 static unsigned totalInitialSize = 0;
254 static unsigned totalFinalSize = 0;
255 linkCount++;
256 totalInitialSize += initialSize;
257 totalFinalSize += finalSize;
fpizlo@apple.com01902c82012-11-22 04:23:36 +0000258 dataLogF("link %p: orig %u, compact %u (delta %u, %.2f%%)\n",
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000259 code, static_cast<unsigned>(initialSize), static_cast<unsigned>(finalSize),
260 static_cast<unsigned>(initialSize - finalSize),
261 100.0 * (initialSize - finalSize) / initialSize);
fpizlo@apple.com01902c82012-11-22 04:23:36 +0000262 dataLogF("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n",
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000263 linkCount, totalInitialSize, totalFinalSize, totalInitialSize - totalFinalSize,
264 100.0 * (totalInitialSize - totalFinalSize) / totalInitialSize);
265}
266#endif
267
268#if DUMP_CODE
269void LinkBuffer::dumpCode(void* code, size_t size)
270{
271#if CPU(ARM_THUMB2)
272 // Dump the generated code in an asm file format that can be assembled and then disassembled
273 // for debugging purposes. For example, save this output as jit.s:
274 // gcc -arch armv7 -c jit.s
275 // otool -tv jit.o
276 static unsigned codeCount = 0;
277 unsigned short* tcode = static_cast<unsigned short*>(code);
278 size_t tsize = size / sizeof(short);
279 char nameBuf[128];
280 snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++);
fpizlo@apple.com01902c82012-11-22 04:23:36 +0000281 dataLogF("\t.syntax unified\n"
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000282 "\t.section\t__TEXT,__text,regular,pure_instructions\n"
283 "\t.globl\t%s\n"
284 "\t.align 2\n"
285 "\t.code 16\n"
286 "\t.thumb_func\t%s\n"
287 "# %p\n"
288 "%s:\n", nameBuf, nameBuf, code, nameBuf);
289
290 for (unsigned i = 0; i < tsize; i++)
fpizlo@apple.com01902c82012-11-22 04:23:36 +0000291 dataLogF("\t.short\t0x%x\n", tcode[i]);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000292#elif CPU(ARM_TRADITIONAL)
293 // gcc -c jit.s
294 // objdump -D jit.o
295 static unsigned codeCount = 0;
296 unsigned int* tcode = static_cast<unsigned int*>(code);
297 size_t tsize = size / sizeof(unsigned int);
298 char nameBuf[128];
299 snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++);
fpizlo@apple.com01902c82012-11-22 04:23:36 +0000300 dataLogF("\t.globl\t%s\n"
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000301 "\t.align 4\n"
302 "\t.code 32\n"
303 "\t.text\n"
304 "# %p\n"
305 "%s:\n", nameBuf, code, nameBuf);
306
307 for (unsigned i = 0; i < tsize; i++)
fpizlo@apple.com01902c82012-11-22 04:23:36 +0000308 dataLogF("\t.long\t0x%x\n", tcode[i]);
fpizlo@apple.com2adf5272012-06-20 01:33:30 +0000309#endif
310}
311#endif
312
313} // namespace JSC
314
315#endif // ENABLE(ASSEMBLER)
316
317