1
/****************************************************************************
3
** Copyright (C) 2014 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:LGPL21$
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 or version 3 as published by the Free
20
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22
** following information to ensure the GNU Lesser General Public License
23
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
26
** In addition, as a special exception, Digia gives you certain additional
27
** rights. These rights are described in the Digia Qt LGPL Exception
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
32
****************************************************************************/
34
#include "qv4jsir_p.h"
35
#include "qv4isel_p.h"
36
#include "qv4isel_util_p.h"
37
#include <private/qv4value_inl_p.h>
39
#include <private/qqmlpropertycache_p.h>
45
Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, qout, (stderr, QIODevice::WriteOnly));
47
} // anonymous namespace
50
using namespace QV4::IR;
52
EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
53
: useFastLookups(true)
54
, useTypeInference(true)
55
, executableAllocator(execAllocator)
59
jsGenerator = new QV4::Compiler::JSUnitGenerator(module);
60
ownJSGenerator.reset(jsGenerator);
62
this->jsGenerator = jsGenerator;
64
Q_ASSERT(execAllocator);
69
EvalInstructionSelection::~EvalInstructionSelection()
72
EvalISelFactory::~EvalISelFactory()
75
QQmlRefPointer<CompiledData::CompilationUnit> EvalInstructionSelection::compile(bool generateUnitData)
77
for (int i = 0; i < irModule->functions.size(); ++i)
80
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = backendCompileStep();
82
unit->data = jsGenerator->generateUnit();
86
void IRDecoder::visitMove(IR::Move *s)
88
if (IR::Name *n = s->target->asName()) {
89
if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) {
90
setActivationProperty(s->source, *n->id);
93
} else if (s->target->asTemp() || s->target->asArgLocal()) {
94
if (IR::Name *n = s->source->asName()) {
95
if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
96
loadThisObject(s->target);
97
else if (n->builtin == IR::Name::builtin_qml_id_array)
98
loadQmlIdArray(s->target);
99
else if (n->builtin == IR::Name::builtin_qml_context_object)
100
loadQmlContextObject(s->target);
101
else if (n->builtin == IR::Name::builtin_qml_scope_object)
102
loadQmlScopeObject(s->target);
103
else if (n->builtin == IR::Name::builtin_qml_imported_scripts_object)
104
loadQmlImportedScripts(s->target);
105
else if (n->qmlSingleton)
106
loadQmlSingleton(*n->id, s->target);
108
getActivationProperty(n, s->target);
110
} else if (IR::Const *c = s->source->asConst()) {
111
loadConst(c, s->target);
113
} else if (s->source->asTemp() || s->source->asArgLocal()) {
115
swapValues(s->source, s->target);
117
copyValue(s->source, s->target);
119
} else if (IR::String *str = s->source->asString()) {
120
loadString(*str->value, s->target);
122
} else if (IR::RegExp *re = s->source->asRegExp()) {
123
loadRegexp(re, s->target);
125
} else if (IR::Closure *clos = s->source->asClosure()) {
126
initClosure(clos, s->target);
128
} else if (IR::New *ctor = s->source->asNew()) {
129
if (Name *func = ctor->base->asName()) {
130
constructActivationProperty(func, ctor->args, s->target);
132
} else if (IR::Member *member = ctor->base->asMember()) {
133
constructProperty(member->base, *member->name, ctor->args, s->target);
135
} else if (ctor->base->asTemp() || ctor->base->asArgLocal()) {
136
constructValue(ctor->base, ctor->args, s->target);
139
} else if (IR::Member *m = s->source->asMember()) {
144
bool captureRequired = true;
146
Q_ASSERT(m->kind != IR::Member::MemberOfEnum);
147
const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
148
const bool isSingletonProperty = m->kind == IR::Member::MemberOfSingletonObject;
150
if (_function && attachedPropertiesId == 0 && !m->property->isConstant()) {
151
if (m->kind == IR::Member::MemberOfQmlContextObject) {
152
_function->contextObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
153
captureRequired = false;
154
} else if (m->kind == IR::Member::MemberOfQmlScopeObject) {
155
_function->scopeObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
156
captureRequired = false;
159
getQObjectProperty(m->base, m->property->coreIndex, captureRequired, isSingletonProperty, attachedPropertiesId, s->target);
160
#endif // V4_BOOTSTRAP
162
} else if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) {
163
getProperty(m->base, *m->name, s->target);
166
} else if (IR::Subscript *ss = s->source->asSubscript()) {
167
getElement(ss->base, ss->index, s->target);
169
} else if (IR::Unop *u = s->source->asUnop()) {
170
unop(u->op, u->expr, s->target);
172
} else if (IR::Binop *b = s->source->asBinop()) {
173
binop(b->op, b->left, b->right, s->target);
175
} else if (IR::Call *c = s->source->asCall()) {
176
if (c->base->asName()) {
177
callBuiltin(c, s->target);
179
} else if (Member *member = c->base->asMember()) {
180
callProperty(member->base, *member->name, c->args, s->target);
182
} else if (Subscript *ss = c->base->asSubscript()) {
183
callSubscript(ss->base, ss->index, c->args, s->target);
185
} else if (c->base->asTemp() || c->base->asArgLocal()) {
186
callValue(c->base, c->args, s->target);
189
} else if (IR::Convert *c = s->source->asConvert()) {
190
Q_ASSERT(c->expr->asTemp() || c->expr->asArgLocal());
191
convertType(c->expr, s->target);
194
} else if (IR::Member *m = s->target->asMember()) {
195
if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) {
196
if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) {
197
Q_ASSERT(m->kind != IR::Member::MemberOfEnum);
198
const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
199
if (m->property && attachedPropertiesId == 0) {
203
setQObjectProperty(s->source, m->base, m->property->coreIndex);
207
setProperty(s->source, m->base, *m->name);
212
} else if (IR::Subscript *ss = s->target->asSubscript()) {
213
if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) {
214
setElement(s->source, ss->base, ss->index);
219
// For anything else...:
221
IRPrinter(&qout).print(s);
226
IRDecoder::~IRDecoder()
230
void IRDecoder::visitExp(IR::Exp *s)
232
if (IR::Call *c = s->expr->asCall()) {
233
// These are calls where the result is ignored.
234
if (c->base->asName()) {
236
} else if (c->base->asTemp() || c->base->asArgLocal() || c->base->asConst()) {
237
callValue(c->base, c->args, 0);
238
} else if (Member *member = c->base->asMember()) {
239
Q_ASSERT(member->base->asTemp() || member->base->asArgLocal());
240
callProperty(member->base, *member->name, c->args, 0);
241
} else if (Subscript *s = c->base->asSubscript()) {
242
callSubscript(s->base, s->index, c->args, 0);
251
void IRDecoder::callBuiltin(IR::Call *call, Expr *result)
253
IR::Name *baseName = call->base->asName();
254
Q_ASSERT(baseName != 0);
256
switch (baseName->builtin) {
257
case IR::Name::builtin_invalid:
258
callBuiltinInvalid(baseName, call->args, result);
261
case IR::Name::builtin_typeof: {
262
if (IR::Member *m = call->args->expr->asMember()) {
263
callBuiltinTypeofMember(m->base, *m->name, result);
265
} else if (IR::Subscript *ss = call->args->expr->asSubscript()) {
266
callBuiltinTypeofSubscript(ss->base, ss->index, result);
268
} else if (IR::Name *n = call->args->expr->asName()) {
269
callBuiltinTypeofName(*n->id, result);
271
} else if (call->args->expr->asTemp() ||
272
call->args->expr->asConst() ||
273
call->args->expr->asArgLocal()) {
274
callBuiltinTypeofValue(call->args->expr, result);
279
case IR::Name::builtin_delete: {
280
if (IR::Member *m = call->args->expr->asMember()) {
281
callBuiltinDeleteMember(m->base, *m->name, result);
283
} else if (IR::Subscript *ss = call->args->expr->asSubscript()) {
284
callBuiltinDeleteSubscript(ss->base, ss->index, result);
286
} else if (IR::Name *n = call->args->expr->asName()) {
287
callBuiltinDeleteName(*n->id, result);
289
} else if (call->args->expr->asTemp() ||
290
call->args->expr->asArgLocal()) {
291
// TODO: should throw in strict mode
292
callBuiltinDeleteValue(result);
297
case IR::Name::builtin_throw: {
298
IR::Expr *arg = call->args->expr;
299
Q_ASSERT(arg->asTemp() || arg->asConst() || arg->asArgLocal());
300
callBuiltinThrow(arg);
303
case IR::Name::builtin_rethrow: {
304
callBuiltinReThrow();
307
case IR::Name::builtin_unwind_exception: {
308
callBuiltinUnwindException(result);
311
case IR::Name::builtin_push_catch_scope: {
312
IR::String *s = call->args->expr->asString();
314
callBuiltinPushCatchScope(*s->value);
317
case IR::Name::builtin_foreach_iterator_object: {
318
IR::Expr *arg = call->args->expr;
320
callBuiltinForeachIteratorObject(arg, result);
323
case IR::Name::builtin_foreach_next_property_name: {
324
IR::Expr *arg = call->args->expr;
326
callBuiltinForeachNextPropertyname(arg, result);
328
case IR::Name::builtin_push_with_scope: {
329
if (call->args->expr->asTemp() || call->args->expr->asArgLocal())
330
callBuiltinPushWithScope(call->args->expr);
335
case IR::Name::builtin_pop_scope:
336
callBuiltinPopScope();
339
case IR::Name::builtin_declare_vars: {
342
IR::Const *deletable = call->args->expr->asConst();
343
Q_ASSERT(deletable->type == IR::BoolType);
344
for (IR::ExprList *it = call->args->next; it; it = it->next) {
345
IR::Name *arg = it->expr->asName();
347
callBuiltinDeclareVar(deletable->value != 0, *arg->id);
351
case IR::Name::builtin_define_array:
352
callBuiltinDefineArray(result, call->args);
355
case IR::Name::builtin_define_object_literal: {
356
IR::ExprList *args = call->args;
357
const int keyValuePairsCount = args->expr->asConst()->value;
360
IR::ExprList *keyValuePairs = args;
361
for (int i = 0; i < keyValuePairsCount; ++i) {
362
args = args->next; // name
363
bool isData = args->expr->asConst()->value;
364
args = args->next; // isData flag
365
args = args->next; // value or getter
367
args = args->next; // setter
370
IR::ExprList *arrayEntries = args;
371
bool needSparseArray = false;
372
for (IR::ExprList *it = arrayEntries; it; it = it->next) {
373
uint index = it->expr->asConst()->value;
375
needSparseArray = true;
379
bool isData = it->expr->asConst()->value;
385
callBuiltinDefineObjectLiteral(result, keyValuePairsCount, keyValuePairs, arrayEntries, needSparseArray);
388
case IR::Name::builtin_setup_argument_object:
389
callBuiltinSetupArgumentObject(result);
392
case IR::Name::builtin_convert_this_to_object:
393
callBuiltinConvertThisToObject();
401
IRPrinter(&qout).print(call); qout << endl;