1
/****************************************************************************
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtQml module of the Qt Toolkit.
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.
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.
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.
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.
40
****************************************************************************/
42
#include "qv4jsir_p.h"
43
#include "qv4isel_p.h"
44
#include "qv4isel_util_p.h"
45
#include <private/qv4value_inl_p.h>
47
#include <private/qqmlpropertycache_p.h>
53
Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, qout, (stderr, QIODevice::WriteOnly));
55
} // anonymous namespace
58
using namespace QV4::IR;
60
EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
61
: useFastLookups(true)
62
, executableAllocator(execAllocator)
66
jsGenerator = new QV4::Compiler::JSUnitGenerator(module);
67
ownJSGenerator.reset(jsGenerator);
69
this->jsGenerator = jsGenerator;
71
Q_ASSERT(execAllocator);
76
EvalInstructionSelection::~EvalInstructionSelection()
79
EvalISelFactory::~EvalISelFactory()
82
QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool generateUnitData)
84
for (int i = 0; i < irModule->functions.size(); ++i)
87
QV4::CompiledData::CompilationUnit *unit = backendCompileStep();
89
unit->data = jsGenerator->generateUnit();
93
void IRDecoder::visitMove(IR::Move *s)
95
if (IR::Name *n = s->target->asName()) {
96
if (s->source->asTemp() || s->source->asConst()) {
97
setActivationProperty(s->source, *n->id);
100
} else if (IR::Temp *t = s->target->asTemp()) {
101
if (IR::Name *n = s->source->asName()) {
102
if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
104
else if (n->builtin == IR::Name::builtin_qml_id_array)
106
else if (n->builtin == IR::Name::builtin_qml_context_object)
107
loadQmlContextObject(t);
108
else if (n->builtin == IR::Name::builtin_qml_scope_object)
109
loadQmlScopeObject(t);
110
else if (n->builtin == IR::Name::builtin_qml_imported_scripts_object)
111
loadQmlImportedScripts(t);
112
else if (n->qmlSingleton)
113
loadQmlSingleton(*n->id, t);
115
getActivationProperty(n, t);
117
} else if (IR::Const *c = s->source->asConst()) {
120
} else if (IR::Temp *t2 = s->source->asTemp()) {
126
} else if (IR::String *str = s->source->asString()) {
127
loadString(*str->value, t);
129
} else if (IR::RegExp *re = s->source->asRegExp()) {
132
} else if (IR::Closure *clos = s->source->asClosure()) {
133
initClosure(clos, t);
135
} else if (IR::New *ctor = s->source->asNew()) {
136
if (Name *func = ctor->base->asName()) {
137
constructActivationProperty(func, ctor->args, t);
139
} else if (IR::Member *member = ctor->base->asMember()) {
140
constructProperty(member->base->asTemp(), *member->name, ctor->args, t);
142
} else if (IR::Temp *value = ctor->base->asTemp()) {
143
constructValue(value, ctor->args, t);
146
} else if (IR::Member *m = s->source->asMember()) {
151
bool captureRequired = true;
153
Q_ASSERT(m->kind != IR::Member::MemberOfEnum);
154
const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
156
if (_function && attachedPropertiesId == 0 && !m->property->isConstant()) {
157
if (m->kind == IR::Member::MemberOfQmlContextObject) {
158
_function->contextObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
159
captureRequired = false;
160
} else if (m->kind == IR::Member::MemberOfQmlScopeObject) {
161
_function->scopeObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
162
captureRequired = false;
165
getQObjectProperty(m->base, m->property->coreIndex, captureRequired, attachedPropertiesId, t);
166
#endif // V4_BOOTSTRAP
168
} else if (m->base->asTemp() || m->base->asConst()) {
169
getProperty(m->base, *m->name, t);
172
} else if (IR::Subscript *ss = s->source->asSubscript()) {
173
getElement(ss->base, ss->index, t);
175
} else if (IR::Unop *u = s->source->asUnop()) {
176
if (IR::Temp *e = u->expr->asTemp()) {
180
} else if (IR::Binop *b = s->source->asBinop()) {
181
binop(b->op, b->left, b->right, t);
183
} else if (IR::Call *c = s->source->asCall()) {
184
if (c->base->asName()) {
187
} else if (Member *member = c->base->asMember()) {
188
callProperty(member->base, *member->name, c->args, t);
190
} else if (Subscript *ss = c->base->asSubscript()) {
191
callSubscript(ss->base, ss->index, c->args, t);
193
} else if (IR::Temp *value = c->base->asTemp()) {
194
callValue(value, c->args, t);
197
} else if (IR::Convert *c = s->source->asConvert()) {
198
Q_ASSERT(c->expr->asTemp());
199
convertType(c->expr->asTemp(), t);
202
} else if (IR::Member *m = s->target->asMember()) {
203
if (m->base->asTemp() || m->base->asConst()) {
204
if (s->source->asTemp() || s->source->asConst()) {
205
Q_ASSERT(m->kind != IR::Member::MemberOfEnum);
206
const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
207
if (m->property && attachedPropertiesId == 0) {
211
setQObjectProperty(s->source, m->base, m->property->coreIndex);
215
setProperty(s->source, m->base, *m->name);
220
} else if (IR::Subscript *ss = s->target->asSubscript()) {
221
if (s->source->asTemp() || s->source->asConst()) {
222
setElement(s->source, ss->base, ss->index);
227
// For anything else...:
229
s->dump(qout, IR::Stmt::MIR);
234
IRDecoder::~IRDecoder()
238
void IRDecoder::visitExp(IR::Exp *s)
240
if (IR::Call *c = s->expr->asCall()) {
241
// These are calls where the result is ignored.
242
if (c->base->asName()) {
244
} else if (Temp *value = c->base->asTemp()) {
245
callValue(value, c->args, 0);
246
} else if (Member *member = c->base->asMember()) {
247
Q_ASSERT(member->base->asTemp());
248
callProperty(member->base->asTemp(), *member->name, c->args, 0);
249
} else if (Subscript *s = c->base->asSubscript()) {
250
callSubscript(s->base, s->index, c->args, 0);
259
void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
261
IR::Name *baseName = call->base->asName();
262
Q_ASSERT(baseName != 0);
264
switch (baseName->builtin) {
265
case IR::Name::builtin_invalid:
266
callBuiltinInvalid(baseName, call->args, result);
269
case IR::Name::builtin_typeof: {
270
if (IR::Member *m = call->args->expr->asMember()) {
271
callBuiltinTypeofMember(m->base, *m->name, result);
273
} else if (IR::Subscript *ss = call->args->expr->asSubscript()) {
274
callBuiltinTypeofSubscript(ss->base, ss->index, result);
276
} else if (IR::Name *n = call->args->expr->asName()) {
277
callBuiltinTypeofName(*n->id, result);
279
} else if (call->args->expr->asTemp() || call->args->expr->asConst()){
280
callBuiltinTypeofValue(call->args->expr, result);
285
case IR::Name::builtin_delete: {
286
if (IR::Member *m = call->args->expr->asMember()) {
287
callBuiltinDeleteMember(m->base->asTemp(), *m->name, result);
289
} else if (IR::Subscript *ss = call->args->expr->asSubscript()) {
290
callBuiltinDeleteSubscript(ss->base->asTemp(), ss->index, result);
292
} else if (IR::Name *n = call->args->expr->asName()) {
293
callBuiltinDeleteName(*n->id, result);
295
} else if (call->args->expr->asTemp()){
296
// TODO: should throw in strict mode
297
callBuiltinDeleteValue(result);
302
case IR::Name::builtin_throw: {
303
IR::Expr *arg = call->args->expr;
304
Q_ASSERT(arg->asTemp() || arg->asConst());
305
callBuiltinThrow(arg);
308
case IR::Name::builtin_rethrow: {
309
callBuiltinReThrow();
312
case IR::Name::builtin_unwind_exception: {
313
callBuiltinUnwindException(result);
316
case IR::Name::builtin_push_catch_scope: {
317
IR::String *s = call->args->expr->asString();
319
callBuiltinPushCatchScope(*s->value);
322
case IR::Name::builtin_foreach_iterator_object: {
323
IR::Expr *arg = call->args->expr;
325
callBuiltinForeachIteratorObject(arg, result);
328
case IR::Name::builtin_foreach_next_property_name: {
329
IR::Temp *arg = call->args->expr->asTemp();
331
callBuiltinForeachNextPropertyname(arg, result);
333
case IR::Name::builtin_push_with_scope: {
334
IR::Temp *arg = call->args->expr->asTemp();
336
callBuiltinPushWithScope(arg);
339
case IR::Name::builtin_pop_scope:
340
callBuiltinPopScope();
343
case IR::Name::builtin_declare_vars: {
346
IR::Const *deletable = call->args->expr->asConst();
347
Q_ASSERT(deletable->type == IR::BoolType);
348
for (IR::ExprList *it = call->args->next; it; it = it->next) {
349
IR::Name *arg = it->expr->asName();
351
callBuiltinDeclareVar(deletable->value != 0, *arg->id);
355
case IR::Name::builtin_define_array:
356
callBuiltinDefineArray(result, call->args);
359
case IR::Name::builtin_define_object_literal: {
360
IR::ExprList *args = call->args;
361
const int keyValuePairsCount = args->expr->asConst()->value;
364
IR::ExprList *keyValuePairs = args;
365
for (int i = 0; i < keyValuePairsCount; ++i) {
366
args = args->next; // name
367
bool isData = args->expr->asConst()->value;
368
args = args->next; // isData flag
369
args = args->next; // value or getter
371
args = args->next; // setter
374
IR::ExprList *arrayEntries = args;
375
bool needSparseArray = false;
376
for (IR::ExprList *it = arrayEntries; it; it = it->next) {
377
uint index = it->expr->asConst()->value;
379
needSparseArray = true;
383
bool isData = it->expr->asConst()->value;
389
callBuiltinDefineObjectLiteral(result, keyValuePairsCount, keyValuePairs, arrayEntries, needSparseArray);
392
case IR::Name::builtin_setup_argument_object:
393
callBuiltinSetupArgumentObject(result);
396
case IR::Name::builtin_convert_this_to_object:
397
callBuiltinConvertThisToObject();
405
call->dump(qout); qout << endl;