~ubuntu-branches/ubuntu/wily/qtdeclarative-opensource-src/wily-proposed

« back to all changes in this revision

Viewing changes to src/qml/jit/qv4assembler.cpp

  • Committer: Package Import Robot
  • Author(s): Ricardo Salveti de Araujo, Ricardo Salveti de Araujo, Timo Jyrinki
  • Date: 2014-06-19 02:39:21 UTC
  • mfrom: (0.1.18 experimental)
  • Revision ID: package-import@ubuntu.com-20140619023921-yb2oasnuetz9b0fc
Tags: 5.3.0-3ubuntu4
[ Ricardo Salveti de Araujo ]
* debian/control:
  - Updating dependencies as we now also have libqt5quickwidgets5-gles
* libqt5quickwidgets5.symbols: updating to allow gles variant

[ Timo Jyrinki ]
* Update libqt5quickparticles5.symbols from build logs

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtQml module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** Commercial License Usage
 
10
** Licensees holding valid commercial Qt licenses may use this file in
 
11
** accordance with the commercial license agreement provided with the
 
12
** Software or, alternatively, in accordance with the terms contained in
 
13
** a written agreement between you and Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/contact-us.
 
16
**
 
17
** GNU Lesser General Public License Usage
 
18
** Alternatively, this file may be used under the terms of the GNU Lesser
 
19
** General Public License version 2.1 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "qv4isel_masm_p.h"
 
43
#include "qv4runtime_p.h"
 
44
#include "qv4object_p.h"
 
45
#include "qv4functionobject_p.h"
 
46
#include "qv4regexpobject_p.h"
 
47
#include "qv4lookup_p.h"
 
48
#include "qv4function_p.h"
 
49
#include "qv4ssa_p.h"
 
50
#include "qv4regalloc_p.h"
 
51
#include "qv4assembler_p.h"
 
52
 
 
53
#include <assembler/LinkBuffer.h>
 
54
#include <WTFStubs.h>
 
55
 
 
56
#include <iostream>
 
57
 
 
58
#if ENABLE(ASSEMBLER)
 
59
 
 
60
#if USE(UDIS86)
 
61
#  include <udis86.h>
 
62
#endif
 
63
 
 
64
using namespace QV4;
 
65
using namespace QV4::JIT;
 
66
 
 
67
CompilationUnit::~CompilationUnit()
 
68
{
 
69
}
 
70
 
 
71
void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
 
72
{
 
73
    runtimeFunctions.resize(data->functionTableSize);
 
74
    runtimeFunctions.fill(0);
 
75
    for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
 
76
        const CompiledData::Function *compiledFunction = data->functionAt(i);
 
77
 
 
78
        QV4::Function *runtimeFunction = new QV4::Function(engine, this, compiledFunction,
 
79
                                                           (ReturnedValue (*)(QV4::ExecutionContext *, const uchar *)) codeRefs[i].code().executableAddress());
 
80
        runtimeFunctions[i] = runtimeFunction;
 
81
    }
 
82
}
 
83
 
 
84
QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int functionIndex)
 
85
{
 
86
    if (functionIndex < 0 || functionIndex >= codeRefs.count())
 
87
        return 0;
 
88
    JSC::ExecutableMemoryHandle *handle = codeRefs[functionIndex].executableMemory();
 
89
    if (!handle)
 
90
        return 0;
 
91
    return handle->chunk();
 
92
}
 
93
 
 
94
 
 
95
 
 
96
/* Platform/Calling convention/Architecture specific section */
 
97
 
 
98
#if CPU(X86_64)
 
99
#  if OS(LINUX) || OS(MAC_OS_X)
 
100
static const Assembler::RegisterID calleeSavedRegisters[] = {
 
101
    JSC::X86Registers::ebx,
 
102
    JSC::X86Registers::r12, // LocalsRegister
 
103
    JSC::X86Registers::r13,
 
104
    JSC::X86Registers::r14, // ContextRegister
 
105
    JSC::X86Registers::r15
 
106
};
 
107
#  elif OS(WINDOWS)
 
108
static const Assembler::RegisterID calleeSavedRegisters[] = {
 
109
    JSC::X86Registers::ebx,
 
110
    JSC::X86Registers::esi,
 
111
    JSC::X86Registers::edi,
 
112
    JSC::X86Registers::r12, // LocalsRegister
 
113
    JSC::X86Registers::r13,
 
114
    JSC::X86Registers::r14, // ContextRegister
 
115
    JSC::X86Registers::r15
 
116
};
 
117
#  endif
 
118
#endif
 
119
 
 
120
#if CPU(X86)
 
121
static const Assembler::RegisterID calleeSavedRegisters[] = {
 
122
    JSC::X86Registers::ebx, // temporary register
 
123
    JSC::X86Registers::esi, // ContextRegister
 
124
    JSC::X86Registers::edi  // LocalsRegister
 
125
};
 
126
#endif
 
127
 
 
128
#if CPU(ARM)
 
129
static const Assembler::RegisterID calleeSavedRegisters[] = {
 
130
    JSC::ARMRegisters::r11,
 
131
    JSC::ARMRegisters::r10,
 
132
    JSC::ARMRegisters::r9,
 
133
    JSC::ARMRegisters::r8,
 
134
    JSC::ARMRegisters::r7,
 
135
    JSC::ARMRegisters::r6,
 
136
    JSC::ARMRegisters::r5,
 
137
    JSC::ARMRegisters::r4
 
138
};
 
139
#endif
 
140
 
 
141
const int Assembler::calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / sizeof(calleeSavedRegisters[0]);
 
142
 
 
143
/* End of platform/calling convention/architecture specific section */
 
144
 
 
145
 
 
146
const Assembler::VoidType Assembler::Void;
 
147
 
 
148
Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator,
 
149
                     int maxArgCountForBuiltins)
 
150
    : _stackLayout(function, maxArgCountForBuiltins)
 
151
    , _constTable(this)
 
152
    , _function(function)
 
153
    , _nextBlock(0)
 
154
    , _executableAllocator(executableAllocator)
 
155
    , _isel(isel)
 
156
{
 
157
}
 
158
 
 
159
void Assembler::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock)
 
160
{
 
161
    _addrs[block] = label();
 
162
    catchBlock = block->catchBlock;
 
163
    _nextBlock = nextBlock;
 
164
}
 
165
 
 
166
void Assembler::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
 
167
{
 
168
    Q_UNUSED(current);
 
169
 
 
170
    if (target != _nextBlock)
 
171
        _patches[target].append(jump());
 
172
}
 
173
 
 
174
void Assembler::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
 
175
{
 
176
    _patches[targetBlock].append(targetJump);
 
177
}
 
178
 
 
179
void Assembler::addPatch(DataLabelPtr patch, Label target)
 
180
{
 
181
    DataLabelPatch p;
 
182
    p.dataLabel = patch;
 
183
    p.target = target;
 
184
    _dataLabelPatches.append(p);
 
185
}
 
186
 
 
187
void Assembler::addPatch(DataLabelPtr patch, IR::BasicBlock *target)
 
188
{
 
189
    _labelPatches[target].append(patch);
 
190
}
 
191
 
 
192
void Assembler::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
 
193
                                       IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
 
194
{
 
195
    generateCJumpOnCompare(NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock);
 
196
}
 
197
 
 
198
void Assembler::generateCJumpOnCompare(RelationalCondition cond, RegisterID left,TrustedImm32 right,
 
199
                                       IR::BasicBlock *currentBlock,  IR::BasicBlock *trueBlock,
 
200
                                       IR::BasicBlock *falseBlock)
 
201
{
 
202
    if (trueBlock == _nextBlock) {
 
203
        Jump target = branch32(invert(cond), left, right);
 
204
        addPatch(falseBlock, target);
 
205
    } else {
 
206
        Jump target = branch32(cond, left, right);
 
207
        addPatch(trueBlock, target);
 
208
        jumpToBlock(currentBlock, falseBlock);
 
209
    }
 
210
}
 
211
 
 
212
void Assembler::generateCJumpOnCompare(RelationalCondition cond, RegisterID left, RegisterID right,
 
213
                                       IR::BasicBlock *currentBlock,  IR::BasicBlock *trueBlock,
 
214
                                       IR::BasicBlock *falseBlock)
 
215
{
 
216
    if (trueBlock == _nextBlock) {
 
217
        Jump target = branch32(invert(cond), left, right);
 
218
        addPatch(falseBlock, target);
 
219
    } else {
 
220
        Jump target = branch32(cond, left, right);
 
221
        addPatch(trueBlock, target);
 
222
        jumpToBlock(currentBlock, falseBlock);
 
223
    }
 
224
}
 
225
 
 
226
Assembler::Pointer Assembler::loadTempAddress(RegisterID baseReg, IR::Temp *t)
 
227
{
 
228
    int32_t offset = 0;
 
229
    int scope = t->scope;
 
230
    RegisterID context = ContextRegister;
 
231
    if (scope) {
 
232
        loadPtr(Address(ContextRegister, qOffsetOf(ExecutionContext, outer)), baseReg);
 
233
        --scope;
 
234
        context = baseReg;
 
235
        while (scope) {
 
236
            loadPtr(Address(context, qOffsetOf(ExecutionContext, outer)), context);
 
237
            --scope;
 
238
        }
 
239
    }
 
240
    switch (t->kind) {
 
241
    case IR::Temp::Formal:
 
242
    case IR::Temp::ScopedFormal: {
 
243
        loadPtr(Address(context, qOffsetOf(ExecutionContext, callData)), baseReg);
 
244
        offset = sizeof(CallData) + (t->index - 1) * sizeof(Value);
 
245
    } break;
 
246
    case IR::Temp::Local:
 
247
    case IR::Temp::ScopedLocal: {
 
248
        loadPtr(Address(context, qOffsetOf(CallContext, locals)), baseReg);
 
249
        offset = t->index * sizeof(Value);
 
250
    } break;
 
251
    case IR::Temp::StackSlot: {
 
252
        return stackSlotPointer(t);
 
253
    } break;
 
254
    default:
 
255
        Q_UNREACHABLE();
 
256
    }
 
257
    return Pointer(baseReg, offset);
 
258
}
 
259
 
 
260
Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string)
 
261
{
 
262
    loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, compilationUnit)), Assembler::ScratchRegister);
 
263
    loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg);
 
264
    const int id = _isel->registerString(string);
 
265
    return Pointer(reg, id * sizeof(QV4::StringValue));
 
266
}
 
267
 
 
268
void Assembler::loadStringRef(RegisterID reg, const QString &string)
 
269
{
 
270
    loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, compilationUnit)), reg);
 
271
    loadPtr(Address(reg, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg);
 
272
    const int id = _isel->registerString(string);
 
273
    addPtr(TrustedImmPtr(id * sizeof(QV4::StringValue)), reg);
 
274
}
 
275
 
 
276
void Assembler::storeValue(QV4::Primitive value, IR::Temp* destination)
 
277
{
 
278
    Address addr = loadTempAddress(ScratchRegister, destination);
 
279
    storeValue(value, addr);
 
280
}
 
281
 
 
282
void Assembler::enterStandardStackFrame()
 
283
{
 
284
    platformEnterStandardStackFrame();
 
285
 
 
286
    // ### FIXME: Handle through calleeSavedRegisters mechanism
 
287
    // or eliminate StackFrameRegister altogether.
 
288
    push(StackFrameRegister);
 
289
    move(StackPointerRegister, StackFrameRegister);
 
290
 
 
291
    int frameSize = _stackLayout.calculateStackFrameSize();
 
292
 
 
293
    subPtr(TrustedImm32(frameSize), StackPointerRegister);
 
294
 
 
295
    for (int i = 0; i < calleeSavedRegisterCount; ++i)
 
296
        storePtr(calleeSavedRegisters[i], Address(StackFrameRegister, -(i + 1) * sizeof(void*)));
 
297
 
 
298
}
 
299
 
 
300
void Assembler::leaveStandardStackFrame()
 
301
{
 
302
    // restore the callee saved registers
 
303
    for (int i = calleeSavedRegisterCount - 1; i >= 0; --i)
 
304
        loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i]);
 
305
 
 
306
    int frameSize = _stackLayout.calculateStackFrameSize();
 
307
    // Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
 
308
    // work well for large immediates.
 
309
#if CPU(ARM_THUMB2)
 
310
    move(TrustedImm32(frameSize), JSC::ARMRegisters::r3);
 
311
    add32(JSC::ARMRegisters::r3, StackPointerRegister);
 
312
#else
 
313
    addPtr(TrustedImm32(frameSize), StackPointerRegister);
 
314
#endif
 
315
 
 
316
    pop(StackFrameRegister);
 
317
    platformLeaveStandardStackFrame();
 
318
}
 
319
 
 
320
 
 
321
 
 
322
 
 
323
// Try to load the source expression into the destination FP register. This assumes that two
 
324
// general purpose (integer) registers are available: the ScratchRegister and the
 
325
// ReturnValueRegister. It returns a Jump if no conversion can be performed.
 
326
Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRegisterID dest)
 
327
{
 
328
    switch (src->type) {
 
329
    case IR::DoubleType:
 
330
        moveDouble(toDoubleRegister(src, dest), dest);
 
331
        return Assembler::Jump();
 
332
    case IR::SInt32Type:
 
333
        convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister),
 
334
                                  dest);
 
335
        return Assembler::Jump();
 
336
    case IR::UInt32Type:
 
337
        convertUInt32ToDouble(toUInt32Register(src, Assembler::ScratchRegister),
 
338
                                   dest, Assembler::ReturnValueRegister);
 
339
        return Assembler::Jump();
 
340
    case IR::NullType:
 
341
    case IR::UndefinedType:
 
342
    case IR::BoolType:
 
343
        // TODO?
 
344
    case IR::StringType:
 
345
        return jump();
 
346
    default:
 
347
        break;
 
348
    }
 
349
 
 
350
    IR::Temp *sourceTemp = src->asTemp();
 
351
    Q_ASSERT(sourceTemp);
 
352
 
 
353
    // It's not a number type, so it cannot be in a register.
 
354
    Q_ASSERT(sourceTemp->kind != IR::Temp::PhysicalRegister || sourceTemp->type == IR::BoolType);
 
355
 
 
356
    Assembler::Pointer tagAddr = loadTempAddress(Assembler::ScratchRegister, sourceTemp);
 
357
    tagAddr.offset += 4;
 
358
    load32(tagAddr, Assembler::ScratchRegister);
 
359
 
 
360
    // check if it's an int32:
 
361
    Assembler::Jump isNoInt = branch32(Assembler::NotEqual, Assembler::ScratchRegister,
 
362
                                            Assembler::TrustedImm32(Value::_Integer_Type));
 
363
    convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister), dest);
 
364
    Assembler::Jump intDone = jump();
 
365
 
 
366
    // not an int, check if it's a double:
 
367
    isNoInt.link(this);
 
368
#if QT_POINTER_SIZE == 8
 
369
    and32(Assembler::TrustedImm32(Value::IsDouble_Mask), Assembler::ScratchRegister);
 
370
    Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister,
 
371
                                            Assembler::TrustedImm32(0));
 
372
#else
 
373
    and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister);
 
374
    Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister,
 
375
                                            Assembler::TrustedImm32(Value::NotDouble_Mask));
 
376
#endif
 
377
    toDoubleRegister(src, dest);
 
378
    intDone.link(this);
 
379
 
 
380
    return isNoDbl;
 
381
}
 
382
 
 
383
#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
 
384
namespace {
 
385
inline bool isPregOrConst(IR::Expr *e)
 
386
{
 
387
    if (IR::Temp *t = e->asTemp())
 
388
        return t->kind == IR::Temp::PhysicalRegister;
 
389
    return e->asConst() != 0;
 
390
}
 
391
} // anonymous namespace
 
392
#endif
 
393
 
 
394
Assembler::Jump Assembler::branchDouble(bool invertCondition, IR::AluOp op,
 
395
                                                   IR::Expr *left, IR::Expr *right)
 
396
{
 
397
    Q_ASSERT(isPregOrConst(left));
 
398
    Q_ASSERT(isPregOrConst(right));
 
399
    Q_ASSERT(left->asConst() == 0 || right->asConst() == 0);
 
400
 
 
401
    Assembler::DoubleCondition cond;
 
402
    switch (op) {
 
403
    case IR::OpGt: cond = Assembler::DoubleGreaterThan; break;
 
404
    case IR::OpLt: cond = Assembler::DoubleLessThan; break;
 
405
    case IR::OpGe: cond = Assembler::DoubleGreaterThanOrEqual; break;
 
406
    case IR::OpLe: cond = Assembler::DoubleLessThanOrEqual; break;
 
407
    case IR::OpEqual:
 
408
    case IR::OpStrictEqual: cond = Assembler::DoubleEqual; break;
 
409
    case IR::OpNotEqual:
 
410
    case IR::OpStrictNotEqual: cond = Assembler::DoubleNotEqualOrUnordered; break; // No, the inversion of DoubleEqual is NOT DoubleNotEqual.
 
411
    default:
 
412
        Q_UNREACHABLE();
 
413
    }
 
414
    if (invertCondition)
 
415
        cond = JSC::MacroAssembler::invert(cond);
 
416
 
 
417
    return JSC::MacroAssembler::branchDouble(cond, toDoubleRegister(left), toDoubleRegister(right));
 
418
}
 
419
 
 
420
 
 
421
#endif