1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qdeclarativev4instruction_p.h"
43 #include "qdeclarativev4bindings_p.h"
45 #include <QtCore/qdebug.h>
46 #include <private/qdeclarativeglobal_p.h>
48 // Define this to do a test dump of all the instructions at startup. This is
49 // helpful to test that each instruction's Instr::dump() case uses the correct
50 // number of tabs etc and otherwise looks correct.
51 // #define DEBUG_INSTR_DUMP
55 DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
57 namespace QDeclarativeJS {
59 #ifdef DEBUG_INSTR_DUMP
60 static struct DumpInstrAtStartup {
61 DumpInstrAtStartup() {
62 #define DUMP_INSTR_AT_STARTUP(Type, FMT) { Instr i; i.common.type = Instr::Type; i.dump(0); }
63 FOR_EACH_V4_INSTR(DUMP_INSTR_AT_STARTUP);
65 } dump_instr_at_startup;
68 int Instr::size() const
70 #define V4_RETURN_INSTR_SIZE(I, FMT) case I: return QML_V4_INSTR_SIZE(I, FMT);
71 switch (common.type) {
72 FOR_EACH_V4_INSTR(V4_RETURN_INSTR_SIZE)
74 #undef V4_RETURN_INSTR_SIZE
78 void Instr::dump(int address) const
82 leading = QByteArray::number(address);
83 leading.prepend(QByteArray(8 - leading.count(), ' '));
87 #define INSTR_DUMP qWarning().nospace() << leading.constData()
89 switch (common.type) {
91 INSTR_DUMP << "\t" << "Noop";
93 case Instr::BindingId:
94 INSTR_DUMP << id.line << ":" << id.column << ":";
96 case Instr::Subscribe:
97 INSTR_DUMP << "\t" << "Subscribe" << "\t\t" << "Object_Reg(" << subscribeop.reg << ") Notify_Signal(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
99 case Instr::SubscribeId:
100 INSTR_DUMP << "\t" << "SubscribeId" << "\t\t" << "Id_Offset(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
102 case Instr::FetchAndSubscribe:
103 INSTR_DUMP << "\t" << "FetchAndSubscribe" << "\t" << "Object_Reg(" << fetchAndSubscribe.reg << ") Fast_Accessor(" << fetchAndSubscribe.function << ") -> Output_Reg(" << fetchAndSubscribe.reg << ") Subscription_Slot(" << fetchAndSubscribe.subscription << ")";
106 INSTR_DUMP << "\t" << "LoadId" << "\t\t\t" << "Id_Offset(" << load.index << ") -> Output_Reg(" << load.reg << ")";
108 case Instr::LoadScope:
109 INSTR_DUMP << "\t" << "LoadScope" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
111 case Instr::LoadRoot:
112 INSTR_DUMP << "\t" << "LoadRoot" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
114 case Instr::LoadAttached:
115 INSTR_DUMP << "\t" << "LoadAttached" << "\t\t" << "Object_Reg(" << attached.reg << ") Attached_Index(" << attached.id << ") -> Output_Reg(" << attached.output << ")";
117 case Instr::UnaryNot:
118 INSTR_DUMP << "\t" << "UnaryNot" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
120 case Instr::UnaryMinusReal:
121 INSTR_DUMP << "\t" << "UnaryMinusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
123 case Instr::UnaryMinusInt:
124 INSTR_DUMP << "\t" << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
126 case Instr::UnaryPlusReal:
127 INSTR_DUMP << "\t" << "UnaryPlusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
129 case Instr::UnaryPlusInt:
130 INSTR_DUMP << "\t" << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
132 case Instr::ConvertBoolToInt:
133 INSTR_DUMP << "\t" << "ConvertBoolToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
135 case Instr::ConvertBoolToReal:
136 INSTR_DUMP << "\t" << "ConvertBoolToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
138 case Instr::ConvertBoolToString:
139 INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
141 case Instr::ConvertIntToBool:
142 INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
144 case Instr::ConvertIntToReal:
145 INSTR_DUMP << "\t" << "ConvertIntToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
147 case Instr::ConvertIntToString:
148 INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
150 case Instr::ConvertRealToBool:
151 INSTR_DUMP << "\t" << "ConvertRealToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
153 case Instr::ConvertRealToInt:
154 INSTR_DUMP << "\t" << "ConvertRealToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
156 case Instr::ConvertRealToString:
157 INSTR_DUMP << "\t" << "ConvertRealToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
159 case Instr::ConvertStringToBool:
160 INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
162 case Instr::ConvertStringToInt:
163 INSTR_DUMP << "\t" << "ConvertStringToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
165 case Instr::ConvertStringToReal:
166 INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
168 case Instr::MathSinReal:
169 INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
171 case Instr::MathCosReal:
172 INSTR_DUMP << "\t" << "MathCosReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
174 case Instr::MathRoundReal:
175 INSTR_DUMP << "\t" << "MathRoundReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
177 case Instr::MathFloorReal:
178 INSTR_DUMP << "\t" << "MathFloorReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
180 case Instr::MathPIReal:
181 INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
184 INSTR_DUMP << "\t" << "Real" << "\t\t\t" << "Constant(" << real_value.value << ") -> Output_Reg(" << real_value.reg << ")";
187 INSTR_DUMP << "\t" << "Int" << "\t\t\t" << "Constant(" << int_value.value << ") -> Output_Reg(" << int_value.reg << ")";
190 INSTR_DUMP << "\t" << "Bool" << "\t\t\t" << "Constant(" << bool_value.value << ") -> Output_Reg(" << bool_value.reg << ")";
193 INSTR_DUMP << "\t" << "String" << "\t\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ") -> Output_Register(" << string_value.reg << ")";
195 case Instr::EnableV4Test:
196 INSTR_DUMP << "\t" << "EnableV4Test" << "\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ")";
198 case Instr::TestV4Store:
199 INSTR_DUMP << "\t" << "TestV4Store" << "\t\t" << "Input_Reg(" << storetest.reg << ") Reg_Type(" << storetest.regType << ")";
201 case Instr::BitAndInt:
202 INSTR_DUMP << "\t" << "BitAndInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
204 case Instr::BitOrInt:
205 INSTR_DUMP << "\t" << "BitOrInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
207 case Instr::BitXorInt:
208 INSTR_DUMP << "\t" << "BitXorInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
211 INSTR_DUMP << "\t" << "AddReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
213 case Instr::AddString:
214 INSTR_DUMP << "\t" << "AddString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
217 INSTR_DUMP << "\t" << "SubReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
220 INSTR_DUMP << "\t" << "MulReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
223 INSTR_DUMP << "\t" << "DivReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
226 INSTR_DUMP << "\t" << "ModReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
228 case Instr::LShiftInt:
229 INSTR_DUMP << "\t" << "LShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
231 case Instr::RShiftInt:
232 INSTR_DUMP << "\t" << "RShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
234 case Instr::URShiftInt:
235 INSTR_DUMP << "\t" << "URShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
238 INSTR_DUMP << "\t" << "GtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
241 INSTR_DUMP << "\t" << "LtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
244 INSTR_DUMP << "\t" << "GeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
247 INSTR_DUMP << "\t" << "LeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
249 case Instr::EqualReal:
250 INSTR_DUMP << "\t" << "EqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
252 case Instr::NotEqualReal:
253 INSTR_DUMP << "\t" << "NotEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
255 case Instr::StrictEqualReal:
256 INSTR_DUMP << "\t" << "StrictEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
258 case Instr::StrictNotEqualReal:
259 INSTR_DUMP << "\t" << "StrictNotEqualReal" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
261 case Instr::GtString:
262 INSTR_DUMP << "\t" << "GtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
264 case Instr::LtString:
265 INSTR_DUMP << "\t" << "LtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
267 case Instr::GeString:
268 INSTR_DUMP << "\t" << "GeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
270 case Instr::LeString:
271 INSTR_DUMP << "\t" << "LeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
273 case Instr::EqualString:
274 INSTR_DUMP << "\t" << "EqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
276 case Instr::NotEqualString:
277 INSTR_DUMP << "\t" << "NotEqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
279 case Instr::StrictEqualString:
280 INSTR_DUMP << "\t" << "StrictEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
282 case Instr::StrictNotEqualString:
283 INSTR_DUMP << "\t" << "StrictNotEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
285 case Instr::NewString:
286 INSTR_DUMP << "\t" << "NewString" << "\t\t" << "Register(" << construct.reg << ")";
289 INSTR_DUMP << "\t" << "NewUrl" << "\t\t\t" << "Register(" << construct.reg << ")";
291 case Instr::CleanupRegister:
292 INSTR_DUMP << "\t" << "CleanupRegister" << "\t\t" << "Register(" << cleanup.reg << ")";
295 INSTR_DUMP << "\t" << "Fetch" << "\t\t\t" << "Object_Reg(" << fetch.reg << ") Property_Index(" << fetch.index << ") -> Output_Reg(" << fetch.reg << ")";
298 INSTR_DUMP << "\t" << "Store" << "\t\t\t" << "Input_Reg(" << store.reg << ") -> Object_Reg(" << store.output << ") Property_Index(" << store.index << ")";
301 INSTR_DUMP << "\t" << "Copy" << "\t\t\t" << "Input_Reg(" << copy.src << ") -> Output_Reg(" << copy.reg << ")";
304 if (jump.reg != -1) {
305 INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ") [if false == Input_Reg(" << jump.reg << ")]";
307 INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ")";
310 case Instr::BranchFalse:
311 INSTR_DUMP << "\t" << "BranchFalse" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if false == Input_Reg(" << branchop.reg << ")]";
313 case Instr::BranchTrue:
314 INSTR_DUMP << "\t" << "BranchTrue" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if true == Input_Reg(" << branchop.reg << ")]";
317 INSTR_DUMP << "\t" << "Branch" << "\t\t\t" << "Address(" << (address + size() + branchop.offset) << ")";
319 case Instr::InitString:
320 INSTR_DUMP << "\t" << "InitString" << "\t\t" << "String_DataIndex(" << initstring.dataIdx << ") -> String_Slot(" << initstring.offset << ")";
323 INSTR_DUMP << "\t" << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(blockop.block, 16).constData() << ")";
326 INSTR_DUMP << "\t" << "Unknown";
336 void Instr::load_root(quint8 reg)
338 common.type = LoadRoot;
343 void Instr::load_scope(quint8 reg)
345 common.type = LoadScope;
350 void Instr::load_id(quint8 reg, quint32 idIndex)
352 common.type = LoadId;
354 load.index = idIndex;
357 void Instr::subscribe(qint8 reg, quint16 subscribeSlot, quint32 notifyIndex)
359 common.type = Instr::Subscribe;
360 subscribeop.reg = reg;
361 subscribeop.offset = subscribeSlot;
362 subscribeop.index = notifyIndex;
365 void Instr::subscribeId(qint8 reg, quint16 subscribeSlot, quint32 idIndex)
367 common.type = Instr::SubscribeId;
368 subscribeop.reg = reg;
369 subscribeop.offset = subscribeSlot;
370 subscribeop.index = idIndex;
373 void Instr::move_reg_bool(quint8 reg, bool value)
376 bool_value.reg = reg;
377 bool_value.value = value;
380 void Instr::move_reg_int(quint8 reg, int value)
384 int_value.value = value;
387 void Instr::move_reg_qreal(quint8 reg, qreal value)
390 real_value.reg = reg;
391 real_value.value = value;
394 void Instr::move_reg_reg(quint8 reg, quint8 src)
401 void Instr::unary_not(quint8 dest, quint8 src)
403 common.type = UnaryNot;
405 unaryop.output = dest;
408 void Instr::uminus_real(quint8 dest, quint8 src)
410 common.type = UnaryMinusReal;
412 unaryop.output = dest;
415 void Instr::uminus_int(quint8 dest, quint8 src)
417 common.type = UnaryMinusInt;
419 unaryop.output = dest;
422 void Instr::uplus_real(quint8 dest, quint8 src)
424 common.type = UnaryPlusReal;
426 unaryop.output = dest;
429 void Instr::uplus_int(quint8 dest, quint8 src)
431 common.type = UnaryPlusInt;
433 unaryop.output = dest;
436 void Instr::ucompl_real(quint8 dest, quint8 src)
440 if (qmlVerboseCompiler())
441 qWarning() << "TODO" << Q_FUNC_INFO;
444 void Instr::ucompl_int(quint8 dest, quint8 src)
448 if (qmlVerboseCompiler())
449 qWarning() << "TODO" << Q_FUNC_INFO;
452 void Instr::math_sin_real(quint8 reg)
454 common.type = MathSinReal;
456 unaryop.output = reg;
459 void Instr::math_cos_real(quint8 reg)
461 common.type = MathCosReal;
463 unaryop.output = reg;
466 void Instr::math_round_real(quint8 reg)
468 common.type = MathRoundReal;
470 unaryop.output = reg;
473 void Instr::math_floor_real(quint8 reg)
475 common.type = MathFloorReal;
477 unaryop.output = reg;
480 void Instr::math_pi_real(quint8 reg)
482 common.type = MathPIReal;
484 unaryop.output = reg;
487 void Instr::branch_true(quint8 reg, qint16 offset)
489 common.type = BranchTrue;
491 branchop.offset = offset;
494 void Instr::branch_false(quint8 reg, qint16 offset)
496 common.type = BranchFalse;
498 branchop.offset = offset;
501 void Instr::branch(qint16 offset)
503 common.type = Branch;
504 branchop.offset = offset;
507 void Instr::block(quint32 mask)
510 blockop.block = mask;
515 #ifdef QML_THREADED_INTERPRETER
516 decodeInstr = QDeclarativeV4Bindings::getDecodeInstrTable();
520 void Bytecode::append(const Instr &instr)
523 #ifdef QML_THREADED_INTERPRETER
525 i.common.code = decodeInstr[i.common.type];
526 it = (const char *) &i;
528 it = (const char *) &instr;
530 d.append(it, instr.size());
533 void Bytecode::append(const QVector<Instr> &instrs)
535 foreach (const Instr &i, instrs)
539 int Bytecode::remove(int offset)
541 const Instr *instr = (const Instr *) (d.begin() + offset);
542 const int instrSize = instr->size();
543 d.remove(offset, instrSize);
547 const Instr &Bytecode::operator[](int offset) const
549 return *((const Instr *) (d.begin() + offset));
552 Instr &Bytecode::operator[](int offset)
554 return *((Instr *) (d.begin() + offset));