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

« back to all changes in this revision

Viewing changes to Source/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h

  • 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) 2009 University of Szeged
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 * 2. Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in the
 
12
 *    documentation and/or other materials provided with the distribution.
 
13
 *
 
14
 * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
 
15
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
17
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
 
18
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
19
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
20
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
21
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 
22
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
24
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
25
 */
 
26
 
 
27
#ifndef AssemblerBufferWithConstantPool_h
 
28
#define AssemblerBufferWithConstantPool_h
 
29
 
 
30
#if ENABLE(ASSEMBLER)
 
31
 
 
32
#include "AssemblerBuffer.h"
 
33
#include <wtf/SegmentedVector.h>
 
34
 
 
35
#define ASSEMBLER_HAS_CONSTANT_POOL 1
 
36
 
 
37
namespace JSC {
 
38
 
 
39
/*
 
40
    On a constant pool 4 or 8 bytes data can be stored. The values can be
 
41
    constants or addresses. The addresses should be 32 or 64 bits. The constants
 
42
    should be double-precisions float or integer numbers which are hard to be
 
43
    encoded as few machine instructions.
 
44
 
 
45
    TODO: The pool is desinged to handle both 32 and 64 bits values, but
 
46
    currently only the 4 bytes constants are implemented and tested.
 
47
 
 
48
    The AssemblerBuffer can contain multiple constant pools. Each pool is inserted
 
49
    into the instruction stream - protected by a jump instruction from the
 
50
    execution flow.
 
51
 
 
52
    The flush mechanism is called when no space remain to insert the next instruction
 
53
    into the pool. Three values are used to determine when the constant pool itself
 
54
    have to be inserted into the instruction stream (Assembler Buffer):
 
55
 
 
56
    - maxPoolSize: size of the constant pool in bytes, this value cannot be
 
57
        larger than the maximum offset of a PC relative memory load
 
58
 
 
59
    - barrierSize: size of jump instruction in bytes which protects the
 
60
        constant pool from execution
 
61
 
 
62
    - maxInstructionSize: maximum length of a machine instruction in bytes
 
63
 
 
64
    There are some callbacks which solve the target architecture specific
 
65
    address handling:
 
66
 
 
67
    - TYPE patchConstantPoolLoad(TYPE load, int value):
 
68
        patch the 'load' instruction with the index of the constant in the
 
69
        constant pool and return the patched instruction.
 
70
 
 
71
    - void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr):
 
72
        patch the a PC relative load instruction at 'loadAddr' address with the
 
73
        final relative offset. The offset can be computed with help of
 
74
        'constPoolAddr' (the address of the constant pool) and index of the
 
75
        constant (which is stored previously in the load instruction itself).
 
76
 
 
77
    - TYPE placeConstantPoolBarrier(int size):
 
78
        return with a constant pool barrier instruction which jumps over the
 
79
        constant pool.
 
80
 
 
81
    The 'put*WithConstant*' functions should be used to place a data into the
 
82
    constant pool.
 
83
*/
 
84
 
 
85
template <int maxPoolSize, int barrierSize, int maxInstructionSize, class AssemblerType>
 
86
class AssemblerBufferWithConstantPool : public AssemblerBuffer {
 
87
    typedef SegmentedVector<uint32_t, 512> LoadOffsets;
 
88
    using AssemblerBuffer::putIntegral;
 
89
    using AssemblerBuffer::putIntegralUnchecked;
 
90
public:
 
91
    typedef struct {
 
92
        short high;
 
93
        short low;
 
94
    } TwoShorts;
 
95
 
 
96
    enum {
 
97
        UniqueConst,
 
98
        ReusableConst,
 
99
        UnusedEntry,
 
100
    };
 
101
 
 
102
    AssemblerBufferWithConstantPool()
 
103
        : AssemblerBuffer()
 
104
        , m_numConsts(0)
 
105
        , m_maxDistance(maxPoolSize)
 
106
        , m_lastConstDelta(0)
 
107
    {
 
108
        m_pool = static_cast<uint32_t*>(fastMalloc(maxPoolSize));
 
109
        m_mask = static_cast<char*>(fastMalloc(maxPoolSize / sizeof(uint32_t)));
 
110
    }
 
111
 
 
112
    ~AssemblerBufferWithConstantPool()
 
113
    {
 
114
        fastFree(m_mask);
 
115
        fastFree(m_pool);
 
116
    }
 
117
 
 
118
    void ensureSpace(int space)
 
119
    {
 
120
        flushIfNoSpaceFor(space);
 
121
        AssemblerBuffer::ensureSpace(space);
 
122
    }
 
123
 
 
124
    void ensureSpace(int insnSpace, int constSpace)
 
125
    {
 
126
        flushIfNoSpaceFor(insnSpace, constSpace);
 
127
        AssemblerBuffer::ensureSpace(insnSpace);
 
128
    }
 
129
 
 
130
    void ensureSpaceForAnyInstruction(int amount = 1)
 
131
    {
 
132
        flushIfNoSpaceFor(amount * maxInstructionSize, amount * sizeof(uint64_t));
 
133
    }
 
134
 
 
135
    bool isAligned(int alignment)
 
136
    {
 
137
        flushIfNoSpaceFor(alignment);
 
138
        return AssemblerBuffer::isAligned(alignment);
 
139
    }
 
140
 
 
141
    void putByteUnchecked(int value)
 
142
    {
 
143
        AssemblerBuffer::putByteUnchecked(value);
 
144
        correctDeltas(1);
 
145
    }
 
146
 
 
147
    void putByte(int value)
 
148
    {
 
149
        flushIfNoSpaceFor(1);
 
150
        AssemblerBuffer::putByte(value);
 
151
        correctDeltas(1);
 
152
    }
 
153
 
 
154
    void putShortUnchecked(int value)
 
155
    {
 
156
        AssemblerBuffer::putShortUnchecked(value);
 
157
        correctDeltas(2);
 
158
    }
 
159
 
 
160
    void putShort(int value)
 
161
    {
 
162
        flushIfNoSpaceFor(2);
 
163
        AssemblerBuffer::putShort(value);
 
164
        correctDeltas(2);
 
165
    }
 
166
 
 
167
    void putIntUnchecked(int value)
 
168
    {
 
169
        AssemblerBuffer::putIntUnchecked(value);
 
170
        correctDeltas(4);
 
171
    }
 
172
 
 
173
    void putInt(int value)
 
174
    {
 
175
        flushIfNoSpaceFor(4);
 
176
        AssemblerBuffer::putInt(value);
 
177
        correctDeltas(4);
 
178
    }
 
179
 
 
180
    void putInt64Unchecked(int64_t value)
 
181
    {
 
182
        AssemblerBuffer::putInt64Unchecked(value);
 
183
        correctDeltas(8);
 
184
    }
 
185
 
 
186
    void putIntegral(TwoShorts value)
 
187
    {
 
188
        putIntegral(value.high);
 
189
        putIntegral(value.low);
 
190
    }
 
191
 
 
192
    void putIntegralUnchecked(TwoShorts value)
 
193
    {
 
194
        putIntegralUnchecked(value.high);
 
195
        putIntegralUnchecked(value.low);
 
196
    }
 
197
 
 
198
    PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID, JITCompilationEffort effort)
 
199
    {
 
200
        flushConstantPool(false);
 
201
        return AssemblerBuffer::executableCopy(globalData, ownerUID, effort);
 
202
    }
 
203
 
 
204
    void putShortWithConstantInt(uint16_t insn, uint32_t constant, bool isReusable = false)
 
205
    {
 
206
        putIntegralWithConstantInt(insn, constant, isReusable);
 
207
    }
 
208
 
 
209
    void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false)
 
210
    {
 
211
        putIntegralWithConstantInt(insn, constant, isReusable);
 
212
    }
 
213
 
 
214
    // This flushing mechanism can be called after any unconditional jumps.
 
215
    void flushWithoutBarrier(bool isForced = false)
 
216
    {
 
217
        // Flush if constant pool is more than 60% full to avoid overuse of this function.
 
218
        if (isForced || 5 * static_cast<uint32_t>(m_numConsts) > 3 * maxPoolSize / sizeof(uint32_t))
 
219
            flushConstantPool(false);
 
220
    }
 
221
 
 
222
    uint32_t* poolAddress()
 
223
    {
 
224
        return m_pool;
 
225
    }
 
226
 
 
227
    int sizeOfConstantPool()
 
228
    {
 
229
        return m_numConsts;
 
230
    }
 
231
 
 
232
private:
 
233
    void correctDeltas(int insnSize)
 
234
    {
 
235
        m_maxDistance -= insnSize;
 
236
        m_lastConstDelta -= insnSize;
 
237
        if (m_lastConstDelta < 0)
 
238
            m_lastConstDelta = 0;
 
239
    }
 
240
 
 
241
    void correctDeltas(int insnSize, int constSize)
 
242
    {
 
243
        correctDeltas(insnSize);
 
244
 
 
245
        m_maxDistance -= m_lastConstDelta;
 
246
        m_lastConstDelta = constSize;
 
247
    }
 
248
 
 
249
    template<typename IntegralType>
 
250
    void putIntegralWithConstantInt(IntegralType insn, uint32_t constant, bool isReusable)
 
251
    {
 
252
        if (!m_numConsts)
 
253
            m_maxDistance = maxPoolSize;
 
254
        flushIfNoSpaceFor(sizeof(IntegralType), 4);
 
255
 
 
256
        m_loadOffsets.append(codeSize());
 
257
        if (isReusable) {
 
258
            for (int i = 0; i < m_numConsts; ++i) {
 
259
                if (m_mask[i] == ReusableConst && m_pool[i] == constant) {
 
260
                    putIntegral(static_cast<IntegralType>(AssemblerType::patchConstantPoolLoad(insn, i)));
 
261
                    correctDeltas(sizeof(IntegralType));
 
262
                    return;
 
263
                }
 
264
            }
 
265
        }
 
266
 
 
267
        m_pool[m_numConsts] = constant;
 
268
        m_mask[m_numConsts] = static_cast<char>(isReusable ? ReusableConst : UniqueConst);
 
269
 
 
270
        putIntegral(static_cast<IntegralType>(AssemblerType::patchConstantPoolLoad(insn, m_numConsts)));
 
271
        ++m_numConsts;
 
272
 
 
273
        correctDeltas(sizeof(IntegralType), 4);
 
274
    }
 
275
 
 
276
    void flushConstantPool(bool useBarrier = true)
 
277
    {
 
278
        if (m_numConsts == 0)
 
279
            return;
 
280
        int alignPool = (codeSize() + (useBarrier ? barrierSize : 0)) & (sizeof(uint64_t) - 1);
 
281
 
 
282
        if (alignPool)
 
283
            alignPool = sizeof(uint64_t) - alignPool;
 
284
 
 
285
        // Callback to protect the constant pool from execution
 
286
        if (useBarrier)
 
287
            putIntegral(AssemblerType::placeConstantPoolBarrier(m_numConsts * sizeof(uint32_t) + alignPool));
 
288
 
 
289
        if (alignPool) {
 
290
            if (alignPool & 1)
 
291
                AssemblerBuffer::putByte(AssemblerType::padForAlign8);
 
292
            if (alignPool & 2)
 
293
                AssemblerBuffer::putShort(AssemblerType::padForAlign16);
 
294
            if (alignPool & 4)
 
295
                AssemblerBuffer::putInt(AssemblerType::padForAlign32);
 
296
        }
 
297
 
 
298
        int constPoolOffset = codeSize();
 
299
        append(reinterpret_cast<char*>(m_pool), m_numConsts * sizeof(uint32_t));
 
300
 
 
301
        // Patch each PC relative load
 
302
        for (LoadOffsets::Iterator iter = m_loadOffsets.begin(); iter != m_loadOffsets.end(); ++iter) {
 
303
            void* loadAddr = reinterpret_cast<char*>(data()) + *iter;
 
304
            AssemblerType::patchConstantPoolLoad(loadAddr, reinterpret_cast<char*>(data()) + constPoolOffset);
 
305
        }
 
306
 
 
307
        m_loadOffsets.clear();
 
308
        m_numConsts = 0;
 
309
    }
 
310
 
 
311
    void flushIfNoSpaceFor(int nextInsnSize)
 
312
    {
 
313
        if (m_numConsts == 0)
 
314
            return;
 
315
        int lastConstDelta = m_lastConstDelta > nextInsnSize ? m_lastConstDelta - nextInsnSize : 0;
 
316
        if ((m_maxDistance < nextInsnSize + lastConstDelta + barrierSize + (int)sizeof(uint32_t)))
 
317
            flushConstantPool();
 
318
    }
 
319
 
 
320
    void flushIfNoSpaceFor(int nextInsnSize, int nextConstSize)
 
321
    {
 
322
        if (m_numConsts == 0)
 
323
            return;
 
324
        if ((m_maxDistance < nextInsnSize + m_lastConstDelta + nextConstSize + barrierSize + (int)sizeof(uint32_t)) ||
 
325
            (m_numConsts * sizeof(uint32_t) + nextConstSize >= maxPoolSize))
 
326
            flushConstantPool();
 
327
    }
 
328
 
 
329
    uint32_t* m_pool;
 
330
    char* m_mask;
 
331
    LoadOffsets m_loadOffsets;
 
332
 
 
333
    int m_numConsts;
 
334
    int m_maxDistance;
 
335
    int m_lastConstDelta;
 
336
};
 
337
 
 
338
} // namespace JSC
 
339
 
 
340
#endif // ENABLE(ASSEMBLER)
 
341
 
 
342
#endif // AssemblerBufferWithConstantPool_h