~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/JavaScriptCore/assembler/LinkBuffer.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

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