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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qv4compiler_p.h"
43 #include "qv4compiler_p_p.h"
44 #include "qv4program_p.h"
46 #include "qv4irbuilder_p.h"
48 #include <private/qdeclarativejsast_p.h>
49 #include <private/qdeclarativeaccessors_p.h>
50 #include <private/qdeclarativejsengine_p.h>
54 DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP)
55 DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER)
56 DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL)
57 DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
58 DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST)
60 static bool qmlBindingsTest = false;
61 static bool qmlEnableV4 = true;
63 using namespace QDeclarativeJS;
64 QV4CompilerPrivate::QV4CompilerPrivate()
65 : _function(0) , _block(0) , _discarded(false)
72 void QV4CompilerPrivate::trace(int line, int column)
76 this->currentReg = _function->tempCount;
78 foreach (IR::BasicBlock *bb, _function->basicBlocks) {
79 if (! bb->isTerminated() && (bb->index + 1) < _function->basicBlocks.size())
80 bb->JUMP(_function->basicBlocks.at(bb->index + 1));
83 QVector<IR::BasicBlock *> blocks;
85 currentBlockMask = 0x00000001;
88 for (int i = 0; !_discarded && i < blocks.size(); ++i) {
89 IR::BasicBlock *block = blocks.at(i);
90 IR::BasicBlock *next = i + 1 < blocks.size() ? blocks.at(i + 1) : 0;
91 if (IR::Stmt *terminator = block->terminator()) {
92 if (IR::CJump *cj = terminator->asCJump()) {
93 if (cj->iffalse != next) {
94 IR::Jump *jump = _function->pool->New<IR::Jump>();
95 jump->init(cj->iffalse);
96 block->statements.append(jump);
98 } else if (IR::Jump *j = terminator->asJump()) {
99 if (j->target == next) {
100 block->statements.resize(block->statements.size() - 1);
105 block->offset = bytecode.size();
107 if (bytecode.isEmpty()) {
108 if (qmlBindingsTest || bindingsDump()) {
115 if (qmlBindingsTest) {
116 QString str = expression->expression.asScript();
117 QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
118 int offset = data.count();
121 Instr::EnableV4Test test;
123 test.offset = offset;
124 test.length = str.length();
130 int patchesCount = patches.count();
131 qSwap(usedSubscriptionIdsChanged, usic);
133 int blockopIndex = bytecode.size();
134 Instr::Block blockop;
135 blockop.block = currentBlockMask;
138 foreach (IR::Stmt *s, block->statements) {
143 qSwap(usedSubscriptionIdsChanged, usic);
146 if (currentBlockMask == 0x80000000) {
150 currentBlockMask <<= 1;
151 } else if (! _discarded) {
152 const int adjust = bytecode.remove(blockopIndex);
154 for (int ii = patchesCount; ii < patches.count(); ++ii)
155 patches[ii].offset -= adjust;
159 #ifdef DEBUG_IR_STRUCTURE
161 for (int i = 0; i < blocks.size(); ++i) {
162 dump.basicblock(blocks.at(i));
169 foreach (const Patch &patch, patches) {
170 V4Instr &instr = bytecode[patch.offset];
171 int size = V4Instr::size(instructionType(&instr));
172 instr.branchop.offset = patch.block->offset - patch.offset - size;
179 void QV4CompilerPrivate::trace(QVector<IR::BasicBlock *> *blocks)
181 for (int i = 0; i < _function->basicBlocks.size(); ++i) {
182 IR::BasicBlock *block = _function->basicBlocks.at(i);
184 while (! blocks->contains(block)) {
185 blocks->append(block);
187 if (IR::Stmt *terminator = block->terminator()) {
188 if (IR::CJump *cj = terminator->asCJump())
190 else if (IR::Jump *j = terminator->asJump())
197 void QV4CompilerPrivate::traceExpression(IR::Expr *e, quint8 r)
202 qSwap(currentReg, r);
204 qSwap(currentReg, r);
211 void QV4CompilerPrivate::visitConst(IR::Const *e)
236 if (qmlVerboseCompiler())
237 qWarning() << Q_FUNC_INFO << "unexpected type";
242 void QV4CompilerPrivate::visitString(IR::String *e)
244 registerLiteralString(currentReg, e->value);
247 void QV4CompilerPrivate::visitName(IR::Name *e)
250 // fetch the object and store it in reg.
251 traceExpression(e->base, currentReg);
253 _subscribeName.clear();
256 if (e->storage == IR::Name::RootStorage) {
258 Instr::LoadRoot instr;
259 instr.reg = currentReg;
262 if (e->symbol == IR::Name::IdObject) {
263 // The ID is a reference to the root object
267 } else if (e->storage == IR::Name::ScopeStorage) {
269 Instr::LoadScope instr;
270 instr.reg = currentReg;
273 _subscribeName << contextName();
275 } else if (e->storage == IR::Name::IdStorage) {
278 instr.reg = currentReg;
279 instr.index = e->idObject->idIndex;
282 _subscribeName << QLatin1String("$$$ID_") + *e->id;
284 if (blockNeedsSubscription(_subscribeName)) {
285 Instr::SubscribeId sub;
286 sub.reg = currentReg;
287 sub.offset = subscriptionIndex(_subscribeName);
288 sub.index = instr.index;
298 case IR::Name::Unbound:
299 case IR::Name::IdObject:
301 case IR::Name::Object: {
302 Q_ASSERT(!"Unreachable");
306 case IR::Name::AttachType: {
307 _subscribeName << *e->id;
309 Instr::LoadAttached attached;
310 attached.output = currentReg;
311 attached.reg = currentReg;
312 attached.exceptionId = exceptionId(e->line, e->column);
313 if (e->declarativeType->attachedPropertiesId() == -1)
315 attached.id = e->declarativeType->attachedPropertiesId();
319 case IR::Name::Property: {
320 _subscribeName << *e->id;
322 if (e->property->coreIndex == -1) {
324 e->property->load(prop, QDeclarativeEnginePrivate::get(engine));
327 const int propTy = e->property->propType;
328 QDeclarativeRegisterType regType;
331 case QMetaType::QReal:
334 case QMetaType::Bool:
340 case QMetaType::QString:
341 regType = QStringType;
345 if (propTy == qMetaTypeId<QDeclarative1AnchorLine>()) {
346 regType = PODValueType;
347 } else if (propTy == QDeclarativeMetaType::QQuickAnchorLineMetaTypeId()) {
348 regType = PODValueType;
349 } else if (QDeclarativeMetaType::isQObject(propTy)) {
350 regType = QObjectStarType;
352 if (qmlVerboseCompiler())
353 qWarning() << "Discard unsupported property type:" << QMetaType::typeName(propTy);
354 discard(); // Unsupported type
361 if (e->property->hasAccessors()) {
362 Instr::FetchAndSubscribe fetch;
363 fetch.reg = currentReg;
364 fetch.subscription = subscriptionIndex(_subscribeName);
365 fetch.exceptionId = exceptionId(e->line, e->column);
366 fetch.valueType = regType;
367 fetch.property = *e->property;
370 if (blockNeedsSubscription(_subscribeName) && e->property->notifyIndex != -1) {
371 Instr::Subscribe sub;
372 sub.reg = currentReg;
373 sub.offset = subscriptionIndex(_subscribeName);
374 sub.index = e->property->notifyIndex;
379 fetch.reg = currentReg;
380 fetch.index = e->property->coreIndex;
381 fetch.exceptionId = exceptionId(e->line, e->column);
382 fetch.valueType = regType;
390 void QV4CompilerPrivate::visitTemp(IR::Temp *e)
392 if (currentReg != e->index) {
400 void QV4CompilerPrivate::visitUnop(IR::Unop *e)
402 quint8 src = currentReg;
404 if (IR::Temp *temp = e->expr->asTemp()) {
407 traceExpression(e->expr, src);
412 Q_ASSERT(!"unreachable");
416 convertToBool(e->expr, src);
417 if (src != currentReg) {
427 convertToBool(e->expr, src);
428 i.output = currentReg;
434 if (e->expr->type == IR::RealType) {
435 Instr::UnaryMinusReal i;
436 i.output = currentReg;
439 } else if (e->expr->type == IR::IntType) {
440 convertToReal(e->expr, currentReg);
441 Instr::UnaryMinusReal i;
442 i.output = currentReg;
451 if (e->expr->type == IR::RealType) {
452 Instr::UnaryPlusReal i;
453 i.output = currentReg;
456 } else if (e->expr->type == IR::IntType) {
457 convertToReal(e->expr, currentReg);
458 Instr::UnaryPlusReal i;
459 i.output = currentReg;
489 case IR::OpStrictEqual:
490 case IR::OpStrictNotEqual:
493 Q_ASSERT(!"unreachable");
498 void QV4CompilerPrivate::convertToReal(IR::Expr *expr, int reg)
500 if (expr->type == IR::RealType)
503 switch (expr->type) {
505 Instr::ConvertBoolToReal i;
506 i.output = i.src = reg;
511 Instr::ConvertIntToReal i;
512 i.output = i.src = reg;
526 void QV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg)
528 if (expr->type == IR::IntType)
531 switch (expr->type) {
533 Instr::ConvertBoolToInt i;
534 i.output = i.src = reg;
543 Instr::ConvertRealToInt i;
544 i.output = i.src = reg;
554 void QV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
556 if (expr->type == IR::BoolType)
559 switch (expr->type) {
565 Instr::ConvertIntToBool i;
566 i.output = i.src = reg;
571 Instr::ConvertRealToBool i;
572 i.output = i.src = reg;
576 case IR::StringType: {
577 Instr::ConvertStringToBool i;
578 i.output = i.src = reg;
588 quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e)
592 return V4Instr::Noop;
599 return V4Instr::Noop;
602 return V4Instr::BitAndInt;
605 return V4Instr::BitOrInt;
608 return V4Instr::BitXorInt;
611 if (e->type == IR::StringType)
612 return V4Instr::AddString;
613 return V4Instr::AddReal;
616 return V4Instr::SubReal;
619 return V4Instr::MulReal;
622 return V4Instr::DivReal;
625 return V4Instr::ModReal;
628 return V4Instr::LShiftInt;
631 return V4Instr::RShiftInt;
634 return V4Instr::URShiftInt;
637 if (e->left->type == IR::StringType)
638 return V4Instr::GtString;
639 return V4Instr::GtReal;
642 if (e->left->type == IR::StringType)
643 return V4Instr::LtString;
644 return V4Instr::LtReal;
647 if (e->left->type == IR::StringType)
648 return V4Instr::GeString;
649 return V4Instr::GeReal;
652 if (e->left->type == IR::StringType)
653 return V4Instr::LeString;
654 return V4Instr::LeReal;
657 if (e->left->type == IR::StringType)
658 return V4Instr::EqualString;
659 return V4Instr::EqualReal;
662 if (e->left->type == IR::StringType)
663 return V4Instr::NotEqualString;
664 return V4Instr::NotEqualReal;
666 case IR::OpStrictEqual:
667 if (e->left->type == IR::StringType)
668 return V4Instr::StrictEqualString;
669 return V4Instr::StrictEqualReal;
671 case IR::OpStrictNotEqual:
672 if (e->left->type == IR::StringType)
673 return V4Instr::StrictNotEqualString;
674 return V4Instr::StrictNotEqualReal;
678 return V4Instr::Noop;
682 return V4Instr::Noop;
685 void QV4CompilerPrivate::visitBinop(IR::Binop *e)
687 int left = currentReg;
688 int right = currentReg + 1;
690 if (e->left->asTemp() && e->type != IR::StringType) // Not sure if the e->type != String test is needed
691 left = e->left->asTemp()->index;
693 traceExpression(e->left, left);
695 if (IR::Temp *t = e->right->asTemp())
698 traceExpression(e->right, right);
700 if (e->left->type != e->right->type) {
701 if (qmlVerboseCompiler())
702 qWarning().nospace() << "invalid operands to binary operator " << IR::binaryOperator(e->op)
703 << "(`" << IR::binaryOperator(e->left->type)
705 << IR::binaryOperator(e->right->type)
731 convertToInt(e->left, left);
732 convertToInt(e->right, right);
736 if (e->type != IR::StringType) {
737 convertToReal(e->left, left);
738 convertToReal(e->right, right);
746 convertToReal(e->left, left);
747 convertToReal(e->right, right);
756 case IR::OpStrictEqual:
757 case IR::OpStrictNotEqual:
758 if (e->left->type != IR::StringType) {
759 convertToReal(e->left, left);
760 convertToReal(e->right, right);
766 discard(); // ### unreachable
770 const quint8 opcode = instructionOpcode(e);
771 if (opcode != V4Instr::Noop) {
773 instr.binaryop.output = currentReg;
774 instr.binaryop.left = left;
775 instr.binaryop.right = right;
776 gen(static_cast<V4Instr::Type>(opcode), instr);
780 void QV4CompilerPrivate::visitCall(IR::Call *call)
782 if (IR::Name *name = call->base->asName()) {
783 IR::Expr *arg = call->onlyArgument();
784 if (arg != 0 && arg->type == IR::RealType) {
785 traceExpression(arg, currentReg);
787 switch (name->builtin) {
788 case IR::NoBuiltinSymbol:
791 case IR::MathSinBultinFunction: {
792 Instr::MathSinReal i;
793 i.output = i.src = currentReg;
797 case IR::MathCosBultinFunction: {
798 Instr::MathCosReal i;
799 i.output = i.src = currentReg;
803 case IR::MathRoundBultinFunction: {
804 Instr::MathRoundReal i;
805 i.output = i.src = currentReg;
809 case IR::MathFloorBultinFunction: {
810 Instr::MathFloorReal i;
811 i.output = i.src = currentReg;
815 case IR::MathPIBuiltinConstant:
821 if (qmlVerboseCompiler())
822 qWarning() << "TODO:" << Q_FUNC_INFO << __LINE__;
830 void QV4CompilerPrivate::visitExp(IR::Exp *s)
832 traceExpression(s->expr, currentReg);
835 void QV4CompilerPrivate::visitMove(IR::Move *s)
837 IR::Temp *target = s->target->asTemp();
838 Q_ASSERT(target != 0);
840 quint8 dest = target->index;
842 if (target->type != s->source->type) {
845 if (IR::Temp *t = s->source->asTemp())
848 traceExpression(s->source, dest);
850 V4Instr::Type opcode = V4Instr::Noop;
851 if (target->type == IR::BoolType) {
852 switch (s->source->type) {
853 case IR::IntType: opcode = V4Instr::ConvertIntToBool; break;
854 case IR::RealType: opcode = V4Instr::ConvertRealToBool; break;
855 case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
858 } else if (target->type == IR::IntType) {
859 switch (s->source->type) {
860 case IR::BoolType: opcode = V4Instr::ConvertBoolToInt; break;
862 if (s->isMoveForReturn)
863 opcode = V4Instr::MathRoundReal;
865 opcode = V4Instr::ConvertRealToInt;
868 case IR::StringType: opcode = V4Instr::ConvertStringToInt; break;
871 } else if (target->type == IR::RealType) {
872 switch (s->source->type) {
873 case IR::BoolType: opcode = V4Instr::ConvertBoolToReal; break;
874 case IR::IntType: opcode = V4Instr::ConvertIntToReal; break;
875 case IR::StringType: opcode = V4Instr::ConvertStringToReal; break;
878 } else if (target->type == IR::StringType) {
879 switch (s->source->type) {
880 case IR::BoolType: opcode = V4Instr::ConvertBoolToString; break;
881 case IR::IntType: opcode = V4Instr::ConvertIntToString; break;
882 case IR::RealType: opcode = V4Instr::ConvertRealToString; break;
886 if (opcode != V4Instr::Noop) {
888 conv.unaryop.output = dest;
889 conv.unaryop.src = src;
895 traceExpression(s->source, dest);
899 void QV4CompilerPrivate::visitJump(IR::Jump *s)
901 patches.append(Patch(s->target, bytecode.size()));
904 i.offset = 0; // ### backpatch
908 void QV4CompilerPrivate::visitCJump(IR::CJump *s)
910 traceExpression(s->cond, currentReg);
912 patches.append(Patch(s->iftrue, bytecode.size()));
916 i.offset = 0; // ### backpatch
920 void QV4CompilerPrivate::visitRet(IR::Ret *s)
922 Q_ASSERT(s->expr != 0);
924 int storeReg = currentReg;
926 if (IR::Temp *temp = s->expr->asTemp()) {
927 storeReg = temp->index;
929 traceExpression(s->expr, storeReg);
932 if (qmlBindingsTest) {
933 Instr::TestV4Store test;
937 test.regType = QMetaType::QString;
940 test.regType = QMetaType::QUrl;
942 case IR::AnchorLineType:
943 test.regType = qMetaTypeId<QDeclarative1AnchorLine>();
945 case IR::SGAnchorLineType:
946 test.regType = QDeclarativeMetaType::QQuickAnchorLineMetaTypeId();
949 test.regType = QMetaType::QObjectStar;
952 test.regType = QMetaType::Bool;
955 test.regType = QMetaType::Int;
958 test.regType = QMetaType::QReal;
969 store.index = expression->property->index;
970 store.reg = storeReg;
971 store.exceptionId = exceptionId(s->line, s->column);
975 void QV4Compiler::dump(const QByteArray &programData)
977 const QV4Program *program = (const QV4Program *)programData.constData();
979 qWarning() << "Program.bindings:" << program->bindings;
980 qWarning() << "Program.dataLength:" << program->dataLength;
981 qWarning() << "Program.subscriptions:" << program->subscriptions;
982 qWarning() << "Program.indentifiers:" << program->identifiers;
984 const int programSize = program->instructionCount;
985 const char *start = program->instructions();
986 const char *end = start + programSize;
992 Clear the state associated with attempting to compile a specific binding.
993 This does not clear the global "committed binding" states.
995 void QV4CompilerPrivate::resetInstanceState()
997 data = committed.data;
998 exceptions = committed.exceptions;
999 usedSubscriptionIds.clear();
1000 subscriptionIds = committed.subscriptionIds;
1001 registeredStrings = committed.registeredStrings;
1009 Mark the last compile as successful, and add it to the "committed data"
1012 Returns the index for the committed binding.
1014 int QV4CompilerPrivate::commitCompile()
1016 int rv = committed.count();
1017 committed.offsets << committed.bytecode.count();
1018 committed.dependencies << usedSubscriptionIds;
1019 committed.bytecode.append(bytecode.constData(), bytecode.size());
1020 committed.data = data;
1021 committed.exceptions = exceptions;
1022 committed.subscriptionIds = subscriptionIds;
1023 committed.registeredStrings = registeredStrings;
1027 bool QV4CompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
1029 resetInstanceState();
1031 if (expression->property->type == -1)
1034 AST::SourceLocation location;
1035 if (AST::ExpressionNode *astExpression = node->expressionCast()) {
1036 location = astExpression->firstSourceLocation();
1037 } else if (AST::Statement *astStatement = node->statementCast()) {
1038 if (AST::Block *block = AST::cast<AST::Block *>(astStatement))
1039 location = block->lbraceToken;
1040 else if (AST::IfStatement *ifStmt = AST::cast<AST::IfStatement *>(astStatement))
1041 location = ifStmt->ifToken;
1048 IR::Function thisFunction(&pool), *function = &thisFunction;
1050 QV4IRBuilder irBuilder(expression, engine);
1051 if (!irBuilder(function, node))
1054 bool discarded = false;
1055 qSwap(_discarded, discarded);
1056 qSwap(_function, function);
1057 trace(location.startLine, location.startColumn);
1058 qSwap(_function, function);
1059 qSwap(_discarded, discarded);
1061 if (qmlVerboseCompiler()) {
1062 QTextStream qerr(stderr, QIODevice::WriteOnly);
1064 qerr << "======== TODO ====== " << endl;
1066 qerr << "==================== " << endl;
1067 qerr << "\tline: " << location.startLine
1068 << "\tcolumn: " << location.startColumn
1070 foreach (IR::BasicBlock *bb, function->basicBlocks)
1075 if (discarded || subscriptionIds.count() > 0xFFFF || registeredStrings.count() > 0xFFFF)
1082 int QV4CompilerPrivate::registerLiteralString(quint8 reg, const QStringRef &str)
1084 // ### string cleanup
1086 QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
1087 int offset = data.count();
1090 Instr::LoadString string;
1092 string.offset = offset;
1093 string.length = str.length();
1099 // Returns an identifier offset
1100 int QV4CompilerPrivate::registerString(const QString &string)
1102 Q_ASSERT(!string.isEmpty());
1104 QPair<int, int> *iter = registeredStrings.value(string);
1107 quint32 len = string.length();
1108 QByteArray lendata((const char *)&len, sizeof(quint32));
1109 QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
1110 strdata.prepend(lendata);
1111 int rv = data.count();
1114 iter = ®isteredStrings[string];
1115 *iter = qMakePair(registeredStrings.count(), rv);
1118 Instr::InitString reg;
1119 reg.offset = iter->first;
1120 reg.dataIdx = iter->second;
1126 Returns true if the current expression has not already subscribed to \a sub in currentBlockMask.
1128 bool QV4CompilerPrivate::blockNeedsSubscription(const QStringList &sub)
1130 QString str = sub.join(QLatin1String("."));
1132 int *iter = subscriptionIds.value(str);
1136 quint32 *uiter = usedSubscriptionIds.value(*iter);
1140 return !(*uiter & currentBlockMask);
1143 int QV4CompilerPrivate::subscriptionIndex(const QStringList &sub)
1145 QString str = sub.join(QLatin1String("."));
1146 int *iter = subscriptionIds.value(str);
1148 int count = subscriptionIds.count();
1149 iter = &subscriptionIds[str];
1152 quint32 &u = usedSubscriptionIds[*iter];
1153 if (!(u & currentBlockMask)) {
1154 u |= currentBlockMask;
1155 usedSubscriptionIdsChanged = true;
1160 quint32 QV4CompilerPrivate::subscriptionBlockMask(const QStringList &sub)
1162 QString str = sub.join(QLatin1String("."));
1164 int *iter = subscriptionIds.value(str);
1165 Q_ASSERT(iter != 0);
1167 quint32 *uiter = usedSubscriptionIds.value(*iter);
1168 Q_ASSERT(uiter != 0);
1173 quint8 QV4CompilerPrivate::exceptionId(quint32 line, quint32 column)
1176 if (exceptions.count() < 0xFF) {
1177 rv = (quint8)exceptions.count();
1181 exceptions.append(e);
1186 quint8 QV4CompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
1189 if (n && exceptions.count() < 0xFF) {
1190 QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
1191 rv = exceptionId(l.startLine, l.startColumn);
1196 QV4Compiler::QV4Compiler()
1197 : d(new QV4CompilerPrivate)
1199 qmlBindingsTest |= qmlBindingsTestEnv();
1202 QV4Compiler::~QV4Compiler()
1208 Returns true if any bindings were compiled.
1210 bool QV4Compiler::isValid() const
1212 return !d->committed.bytecode.isEmpty();
1216 -1 on failure, otherwise the binding index to use.
1218 int QV4Compiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
1220 if (!expression.expression.asAST()) return false;
1222 if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
1225 if (qmlDisableOptimizer() || !qmlEnableV4)
1228 d->expression = &expression;
1231 if (d->compile(expression.expression.asAST())) {
1232 return d->commitCompile();
1238 QByteArray QV4CompilerPrivate::buildSignalTable() const
1240 QHash<int, QList<QPair<int, quint32> > > table;
1242 for (int ii = 0; ii < committed.count(); ++ii) {
1243 const QDeclarativeAssociationList<int, quint32> &deps = committed.dependencies.at(ii);
1244 for (QDeclarativeAssociationList<int, quint32>::const_iterator iter = deps.begin(); iter != deps.end(); ++iter)
1245 table[iter->first].append(qMakePair(ii, iter->second));
1248 QVector<quint32> header;
1249 QVector<quint32> data;
1250 for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
1251 header.append(committed.subscriptionIds.count() + data.count());
1252 const QList<QPair<int, quint32> > &bindings = table[ii];
1253 data.append(bindings.count());
1254 for (int jj = 0; jj < bindings.count(); ++jj) {
1255 data.append(bindings.at(jj).first);
1256 data.append(bindings.at(jj).second);
1261 return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
1264 QByteArray QV4CompilerPrivate::buildExceptionData() const
1267 rv.resize(committed.exceptions.count() * sizeof(quint64));
1268 ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
1273 Returns the compiled program.
1275 QByteArray QV4Compiler::program() const
1277 QByteArray programData;
1281 prog.bindings = d->committed.count();
1284 QV4CompilerPrivate::Instr::Jump jump;
1287 for (int ii = 0; ii < d->committed.count(); ++ii) {
1288 jump.count = d->committed.count() - ii - 1;
1289 jump.count*= V4InstrMeta<V4Instr::Jump>::Size;
1290 jump.count+= d->committed.offsets.at(ii);
1295 QByteArray bytecode;
1296 bytecode.reserve(bc.size() + d->committed.bytecode.size());
1297 bytecode.append(bc.constData(), bc.size());
1298 bytecode.append(d->committed.bytecode.constData(), d->committed.bytecode.size());
1300 QByteArray data = d->committed.data;
1301 while (data.count() % 4) data.append('\0');
1302 prog.signalTableOffset = data.count();
1303 data += d->buildSignalTable();
1304 while (data.count() % 4) data.append('\0');
1305 prog.exceptionDataOffset = data.count();
1306 data += d->buildExceptionData();
1308 prog.dataLength = 4 * ((data.size() + 3) / 4);
1309 prog.subscriptions = d->committed.subscriptionIds.count();
1310 prog.identifiers = d->committed.registeredStrings.count();
1311 prog.instructionCount = bytecode.count();
1312 int size = sizeof(QV4Program) + bytecode.count();
1313 size += prog.dataLength;
1315 programData.resize(size);
1316 memcpy(programData.data(), &prog, sizeof(QV4Program));
1317 if (prog.dataLength)
1318 memcpy((char *)((QV4Program *)programData.data())->data(), data.constData(),
1320 memcpy((char *)((QV4Program *)programData.data())->instructions(), bytecode.constData(),
1324 if (bindingsDump()) {
1325 qWarning().nospace() << "Subscription slots:";
1327 for (QDeclarativeAssociationList<QString, int>::ConstIterator iter = d->committed.subscriptionIds.begin();
1328 iter != d->committed.subscriptionIds.end();
1330 qWarning().nospace() << " " << iter->first << "\t-> " << iter->second;
1333 QV4Compiler::dump(programData);
1339 void QV4Compiler::enableBindingsTest(bool e)
1342 qmlBindingsTest = true;
1344 qmlBindingsTest = qmlBindingsTestEnv();
1347 void QV4Compiler::enableV4(bool e)