2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "LinkBuffer.h"
35 LinkBuffer::CodeRef
LinkBuffer::finalizeCodeWithoutDisassembly()
37 performFinalization();
39 return CodeRef(m_executableMemory
);
42 LinkBuffer::CodeRef
LinkBuffer::finalizeCodeWithDisassembly(const char* format
, ...)
44 ASSERT(Options::showDisassembly() || Options::showDFGDisassembly());
46 CodeRef result
= finalizeCodeWithoutDisassembly();
48 dataLogF("Generated JIT code for ");
50 va_start(argList
, format
);
51 WTF::dataLogFV(format
, argList
);
55 dataLogF(" Code at [%p, %p):\n", result
.code().executableAddress(), static_cast<char*>(result
.code().executableAddress()) + result
.size());
56 disassemble(result
.code(), m_size
, " ", WTF::dataFile());
61 #if ENABLE(BRANCH_COMPACTION)
62 template <typename InstructionType
>
63 void LinkBuffer::copyCompactAndLinkCode(void* ownerUID
, JITCompilationEffort effort
)
65 m_initialSize
= m_assembler
->m_assembler
.codeSize();
66 m_executableMemory
= m_vm
->executableAllocator
.allocate(*m_vm
, m_initialSize
, ownerUID
, effort
);
67 if (!m_executableMemory
)
69 m_code
= (uint8_t*)m_executableMemory
->start();
71 ExecutableAllocator::makeWritable(m_code
, m_initialSize
);
72 uint8_t* inData
= (uint8_t*)m_assembler
->unlinkedCode();
73 uint8_t* outData
= reinterpret_cast<uint8_t*>(m_code
);
76 Vector
<LinkRecord
, 0, UnsafeVectorOverflow
>& jumpsToLink
= m_assembler
->jumpsToLink();
77 unsigned jumpCount
= jumpsToLink
.size();
78 for (unsigned i
= 0; i
< jumpCount
; ++i
) {
79 int offset
= readPtr
- writePtr
;
80 ASSERT(!(offset
& 1));
82 // Copy the instructions from the last jump to the current one.
83 size_t regionSize
= jumpsToLink
[i
].from() - readPtr
;
84 InstructionType
* copySource
= reinterpret_cast_ptr
<InstructionType
*>(inData
+ readPtr
);
85 InstructionType
* copyEnd
= reinterpret_cast_ptr
<InstructionType
*>(inData
+ readPtr
+ regionSize
);
86 InstructionType
* copyDst
= reinterpret_cast_ptr
<InstructionType
*>(outData
+ writePtr
);
87 ASSERT(!(regionSize
% 2));
88 ASSERT(!(readPtr
% 2));
89 ASSERT(!(writePtr
% 2));
90 while (copySource
!= copyEnd
)
91 *copyDst
++ = *copySource
++;
92 m_assembler
->recordLinkOffsets(readPtr
, jumpsToLink
[i
].from(), offset
);
93 readPtr
+= regionSize
;
94 writePtr
+= regionSize
;
96 // Calculate absolute address of the jump target, in the case of backwards
97 // branches we need to be precise, forward branches we are pessimistic
98 const uint8_t* target
;
99 if (jumpsToLink
[i
].to() >= jumpsToLink
[i
].from())
100 target
= outData
+ jumpsToLink
[i
].to() - offset
; // Compensate for what we have collapsed so far
102 target
= outData
+ jumpsToLink
[i
].to() - m_assembler
->executableOffsetFor(jumpsToLink
[i
].to());
104 JumpLinkType jumpLinkType
= m_assembler
->computeJumpType(jumpsToLink
[i
], outData
+ writePtr
, target
);
105 // Compact branch if we can...
106 if (m_assembler
->canCompact(jumpsToLink
[i
].type())) {
107 // Step back in the write stream
108 int32_t delta
= m_assembler
->jumpSizeDelta(jumpsToLink
[i
].type(), jumpLinkType
);
111 m_assembler
->recordLinkOffsets(jumpsToLink
[i
].from() - delta
, readPtr
, readPtr
- writePtr
);
114 jumpsToLink
[i
].setFrom(writePtr
);
116 // Copy everything after the last jump
117 memcpy(outData
+ writePtr
, inData
+ readPtr
, m_initialSize
- readPtr
);
118 m_assembler
->recordLinkOffsets(readPtr
, m_initialSize
, readPtr
- writePtr
);
120 for (unsigned i
= 0; i
< jumpCount
; ++i
) {
121 uint8_t* location
= outData
+ jumpsToLink
[i
].from();
122 uint8_t* target
= outData
+ jumpsToLink
[i
].to() - m_assembler
->executableOffsetFor(jumpsToLink
[i
].to());
123 m_assembler
->link(jumpsToLink
[i
], location
, target
);
127 m_size
= writePtr
+ m_initialSize
- readPtr
;
128 m_executableMemory
->shrink(m_size
);
130 #if DUMP_LINK_STATISTICS
131 dumpLinkStatistics(m_code
, m_initialSize
, m_size
);
134 dumpCode(m_code
, m_size
);
140 void LinkBuffer::linkCode(void* ownerUID
, JITCompilationEffort effort
)
143 #if !ENABLE(BRANCH_COMPACTION)
144 m_executableMemory
= m_assembler
->m_assembler
.executableCopy(*m_vm
, ownerUID
, effort
);
145 if (!m_executableMemory
)
147 m_code
= m_executableMemory
->start();
148 m_size
= m_assembler
->m_assembler
.codeSize();
150 #elif CPU(ARM_THUMB2)
151 copyCompactAndLinkCode
<uint16_t>(ownerUID
, effort
);
153 copyCompactAndLinkCode
<uint32_t>(ownerUID
, effort
);
157 void LinkBuffer::performFinalization()
160 ASSERT(!m_completed
);
165 #if ENABLE(BRANCH_COMPACTION)
166 ExecutableAllocator::makeExecutable(code(), m_initialSize
);
168 ExecutableAllocator::makeExecutable(code(), m_size
);
170 MacroAssembler::cacheFlush(code(), m_size
);
173 #if DUMP_LINK_STATISTICS
174 void LinkBuffer::dumpLinkStatistics(void* code
, size_t initializeSize
, size_t finalSize
)
176 static unsigned linkCount
= 0;
177 static unsigned totalInitialSize
= 0;
178 static unsigned totalFinalSize
= 0;
180 totalInitialSize
+= initialSize
;
181 totalFinalSize
+= finalSize
;
182 dataLogF("link %p: orig %u, compact %u (delta %u, %.2f%%)\n",
183 code
, static_cast<unsigned>(initialSize
), static_cast<unsigned>(finalSize
),
184 static_cast<unsigned>(initialSize
- finalSize
),
185 100.0 * (initialSize
- finalSize
) / initialSize
);
186 dataLogF("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n",
187 linkCount
, totalInitialSize
, totalFinalSize
, totalInitialSize
- totalFinalSize
,
188 100.0 * (totalInitialSize
- totalFinalSize
) / totalInitialSize
);
193 void LinkBuffer::dumpCode(void* code
, size_t size
)
196 // Dump the generated code in an asm file format that can be assembled and then disassembled
197 // for debugging purposes. For example, save this output as jit.s:
198 // gcc -arch armv7 -c jit.s
200 static unsigned codeCount
= 0;
201 unsigned short* tcode
= static_cast<unsigned short*>(code
);
202 size_t tsize
= size
/ sizeof(short);
204 snprintf(nameBuf
, sizeof(nameBuf
), "_jsc_jit%u", codeCount
++);
205 dataLogF("\t.syntax unified\n"
206 "\t.section\t__TEXT,__text,regular,pure_instructions\n"
210 "\t.thumb_func\t%s\n"
212 "%s:\n", nameBuf
, nameBuf
, code
, nameBuf
);
214 for (unsigned i
= 0; i
< tsize
; i
++)
215 dataLogF("\t.short\t0x%x\n", tcode
[i
]);
216 #elif CPU(ARM_TRADITIONAL)
219 static unsigned codeCount
= 0;
220 unsigned int* tcode
= static_cast<unsigned int*>(code
);
221 size_t tsize
= size
/ sizeof(unsigned int);
223 snprintf(nameBuf
, sizeof(nameBuf
), "_jsc_jit%u", codeCount
++);
224 dataLogF("\t.globl\t%s\n"
229 "%s:\n", nameBuf
, code
, nameBuf
);
231 for (unsigned i
= 0; i
< tsize
; i
++)
232 dataLogF("\t.long\t0x%x\n", tcode
[i
]);
239 #endif // ENABLE(ASSEMBLER)