Merge "Save and re-bind previously bounded texture when using cairo_gl_surface_set_bi...
[framework/web/webkit-efl.git] / Source / JavaScriptCore / assembler / LinkBuffer.cpp
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  *
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
31 #include "Options.h"
32
33 namespace JSC {
34
35 LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithoutDisassembly()
36 {
37     performFinalization();
38     
39     return CodeRef(m_executableMemory);
40 }
41
42 LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithDisassembly(const char* format, ...)
43 {
44     ASSERT(Options::showDisassembly() || Options::showDFGDisassembly());
45     
46     CodeRef result = finalizeCodeWithoutDisassembly();
47     
48     dataLog("Generated JIT code for ");
49     va_list argList;
50     va_start(argList, format);
51     WTF::dataLogV(format, argList);
52     va_end(argList);
53     dataLog(":\n");
54     
55     dataLog("    Code at [%p, %p):\n", result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
56     if (!tryToDisassemble(result.code(), m_size, "    ", WTF::dataFile()))
57         dataLog("        <no disassembly available>\n");
58     
59     return result;
60 }
61
62 void LinkBuffer::linkCode(void* ownerUID, JITCompilationEffort effort)
63 {
64     ASSERT(!m_code);
65 #if !ENABLE(BRANCH_COMPACTION)
66     m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort);
67     if (!m_executableMemory)
68         return;
69     m_code = m_executableMemory->start();
70     m_size = m_assembler->m_assembler.codeSize();
71     ASSERT(m_code);
72 #else
73     m_initialSize = m_assembler->m_assembler.codeSize();
74     m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort);
75     if (!m_executableMemory)
76         return;
77     m_code = (uint8_t*)m_executableMemory->start();
78     ASSERT(m_code);
79     ExecutableAllocator::makeWritable(m_code, m_initialSize);
80     uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode();
81     uint8_t* outData = reinterpret_cast<uint8_t*>(m_code);
82     int readPtr = 0;
83     int writePtr = 0;
84     Vector<LinkRecord>& jumpsToLink = m_assembler->jumpsToLink();
85     unsigned jumpCount = jumpsToLink.size();
86     for (unsigned i = 0; i < jumpCount; ++i) {
87         int offset = readPtr - writePtr;
88         ASSERT(!(offset & 1));
89             
90         // Copy the instructions from the last jump to the current one.
91         size_t regionSize = jumpsToLink[i].from() - readPtr;
92         uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr);
93         uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize);
94         uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr);
95         ASSERT(!(regionSize % 2));
96         ASSERT(!(readPtr % 2));
97         ASSERT(!(writePtr % 2));
98         while (copySource != copyEnd)
99             *copyDst++ = *copySource++;
100         m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset);
101         readPtr += regionSize;
102         writePtr += regionSize;
103             
104         // Calculate absolute address of the jump target, in the case of backwards
105         // branches we need to be precise, forward branches we are pessimistic
106         const uint8_t* target;
107         if (jumpsToLink[i].to() >= jumpsToLink[i].from())
108             target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far
109         else
110             target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
111             
112         JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target);
113         // Compact branch if we can...
114         if (m_assembler->canCompact(jumpsToLink[i].type())) {
115             // Step back in the write stream
116             int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType);
117             if (delta) {
118                 writePtr -= delta;
119                 m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr);
120             }
121         }
122         jumpsToLink[i].setFrom(writePtr);
123     }
124     // Copy everything after the last jump
125     memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr);
126     m_assembler->recordLinkOffsets(readPtr, m_initialSize, readPtr - writePtr);
127         
128     for (unsigned i = 0; i < jumpCount; ++i) {
129         uint8_t* location = outData + jumpsToLink[i].from();
130         uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
131         m_assembler->link(jumpsToLink[i], location, target);
132     }
133
134     jumpsToLink.clear();
135     m_size = writePtr + m_initialSize - readPtr;
136     m_executableMemory->shrink(m_size);
137
138 #if DUMP_LINK_STATISTICS
139     dumpLinkStatistics(m_code, m_initialSize, m_size);
140 #endif
141 #if DUMP_CODE
142     dumpCode(m_code, m_size);
143 #endif
144 #endif
145 }
146
147 void LinkBuffer::performFinalization()
148 {
149 #ifndef NDEBUG
150     ASSERT(!m_completed);
151     ASSERT(isValid());
152     m_completed = true;
153 #endif
154     
155 #if ENABLE(BRANCH_COMPACTION)
156     ExecutableAllocator::makeExecutable(code(), m_initialSize);
157 #else
158     ExecutableAllocator::makeExecutable(code(), m_size);
159 #endif
160     MacroAssembler::cacheFlush(code(), m_size);
161 }
162
163 #if DUMP_LINK_STATISTICS
164 void LinkBuffer::dumpLinkStatistics(void* code, size_t initializeSize, size_t finalSize)
165 {
166     static unsigned linkCount = 0;
167     static unsigned totalInitialSize = 0;
168     static unsigned totalFinalSize = 0;
169     linkCount++;
170     totalInitialSize += initialSize;
171     totalFinalSize += finalSize;
172     dataLog("link %p: orig %u, compact %u (delta %u, %.2f%%)\n", 
173             code, static_cast<unsigned>(initialSize), static_cast<unsigned>(finalSize),
174             static_cast<unsigned>(initialSize - finalSize),
175             100.0 * (initialSize - finalSize) / initialSize);
176     dataLog("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n", 
177             linkCount, totalInitialSize, totalFinalSize, totalInitialSize - totalFinalSize,
178             100.0 * (totalInitialSize - totalFinalSize) / totalInitialSize);
179 }
180 #endif
181
182 #if DUMP_CODE
183 void LinkBuffer::dumpCode(void* code, size_t size)
184 {
185 #if CPU(ARM_THUMB2)
186     // Dump the generated code in an asm file format that can be assembled and then disassembled
187     // for debugging purposes. For example, save this output as jit.s:
188     //   gcc -arch armv7 -c jit.s
189     //   otool -tv jit.o
190     static unsigned codeCount = 0;
191     unsigned short* tcode = static_cast<unsigned short*>(code);
192     size_t tsize = size / sizeof(short);
193     char nameBuf[128];
194     snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++);
195     dataLog("\t.syntax unified\n"
196             "\t.section\t__TEXT,__text,regular,pure_instructions\n"
197             "\t.globl\t%s\n"
198             "\t.align 2\n"
199             "\t.code 16\n"
200             "\t.thumb_func\t%s\n"
201             "# %p\n"
202             "%s:\n", nameBuf, nameBuf, code, nameBuf);
203         
204     for (unsigned i = 0; i < tsize; i++)
205         dataLog("\t.short\t0x%x\n", tcode[i]);
206 #elif CPU(ARM_TRADITIONAL)
207     //   gcc -c jit.s
208     //   objdump -D jit.o
209     static unsigned codeCount = 0;
210     unsigned int* tcode = static_cast<unsigned int*>(code);
211     size_t tsize = size / sizeof(unsigned int);
212     char nameBuf[128];
213     snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++);
214     dataLog("\t.globl\t%s\n"
215             "\t.align 4\n"
216             "\t.code 32\n"
217             "\t.text\n"
218             "# %p\n"
219             "%s:\n", nameBuf, code, nameBuf);
220
221     for (unsigned i = 0; i < tsize; i++)
222         dataLog("\t.long\t0x%x\n", tcode[i]);
223 #endif
224 }
225 #endif
226
227 } // namespace JSC
228
229 #endif // ENABLE(ASSEMBLER)
230
231