aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/v4/qv4compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/qml/v4/qv4compiler.cpp')
-rw-r--r--src/declarative/qml/v4/qv4compiler.cpp1419
1 files changed, 0 insertions, 1419 deletions
diff --git a/src/declarative/qml/v4/qv4compiler.cpp b/src/declarative/qml/v4/qv4compiler.cpp
deleted file mode 100644
index 0a0269d903..0000000000
--- a/src/declarative/qml/v4/qv4compiler.cpp
+++ /dev/null
@@ -1,1419 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4compiler_p.h"
-#include "qv4compiler_p_p.h"
-#include "qv4program_p.h"
-#include "qv4ir_p.h"
-#include "qv4irbuilder_p.h"
-
-#include <private/qdeclarativejsast_p.h>
-#include <private/qdeclarativeaccessors_p.h>
-#include <private/qdeclarativejsengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP)
-DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER)
-DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL)
-DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
-DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST)
-
-static bool qmlBindingsTest = false;
-static bool qmlEnableV4 = true;
-
-using namespace QDeclarativeJS;
-QV4CompilerPrivate::QV4CompilerPrivate()
- : _function(0) , _block(0) , _discarded(false), registerCount(0)
-{
-}
-
-//
-// tracing
-//
-void QV4CompilerPrivate::trace(int line, int column)
-{
- bytecode.clear();
-
- this->currentReg = _function->tempCount;
- this->registerCount = qMax(this->registerCount, this->currentReg);
-
- foreach (IR::BasicBlock *bb, _function->basicBlocks) {
- if (! bb->isTerminated() && (bb->index + 1) < _function->basicBlocks.size())
- bb->JUMP(_function->basicBlocks.at(bb->index + 1));
- }
-
- QVector<IR::BasicBlock *> blocks;
- trace(&blocks);
- currentBlockMask = 0x00000001;
-
-
- for (int i = 0; !_discarded && i < blocks.size(); ++i) {
- IR::BasicBlock *block = blocks.at(i);
- IR::BasicBlock *next = i + 1 < blocks.size() ? blocks.at(i + 1) : 0;
- if (IR::Stmt *terminator = block->terminator()) {
- if (IR::CJump *cj = terminator->asCJump()) {
- if (cj->iffalse != next) {
- IR::Jump *jump = _function->pool->New<IR::Jump>();
- jump->init(cj->iffalse);
- block->statements.append(jump);
- }
- } else if (IR::Jump *j = terminator->asJump()) {
- if (j->target == next) {
- block->statements.resize(block->statements.size() - 1);
- }
- }
- }
-
- block->offset = bytecode.size();
-
- if (bytecode.isEmpty()) {
- if (qmlBindingsTest || bindingsDump()) {
- Instr::BindingId id;
- id.column = column;
- id.line = line;
- gen(id);
- }
-
- if (qmlBindingsTest) {
- QString str = expression->expression.asScript();
- QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
- int offset = data.count();
- data += strdata;
-
- Instr::EnableV4Test test;
- test.reg = 0;
- test.offset = offset;
- test.length = str.length();
- gen(test);
- }
- }
-
- bool usic = false;
- int patchesCount = patches.count();
- qSwap(usedSubscriptionIdsChanged, usic);
-
- int blockopIndex = bytecode.size();
- Instr::Block blockop;
- blockop.block = currentBlockMask;
- gen(blockop);
-
- foreach (IR::Stmt *s, block->statements) {
- if (! _discarded)
- s->accept(this);
- }
-
- qSwap(usedSubscriptionIdsChanged, usic);
-
- if (usic) {
- if (currentBlockMask == 0x80000000) {
- discard();
- return;
- }
- currentBlockMask <<= 1;
- } else if (! _discarded) {
- const int adjust = bytecode.remove(blockopIndex);
- // Correct patches
- for (int ii = patchesCount; ii < patches.count(); ++ii)
- patches[ii].offset -= adjust;
- }
- }
-
-#ifdef DEBUG_IR_STRUCTURE
- IR::IRDump dump;
- for (int i = 0; i < blocks.size(); ++i) {
- dump.basicblock(blocks.at(i));
- }
-#endif
-
-
- if (! _discarded) {
- // back patching
- foreach (const Patch &patch, patches) {
- V4Instr &instr = bytecode[patch.offset];
- int size = V4Instr::size(instructionType(&instr));
- instr.branchop.offset = patch.block->offset - patch.offset - size;
- }
-
- patches.clear();
- }
-}
-
-void QV4CompilerPrivate::trace(QVector<IR::BasicBlock *> *blocks)
-{
- for (int i = 0; i < _function->basicBlocks.size(); ++i) {
- IR::BasicBlock *block = _function->basicBlocks.at(i);
-
- while (! blocks->contains(block)) {
- blocks->append(block);
-
- if (IR::Stmt *terminator = block->terminator()) {
- if (IR::CJump *cj = terminator->asCJump())
- block = cj->iffalse;
- else if (IR::Jump *j = terminator->asJump())
- block = j->target;
- }
- }
- }
-}
-
-void QV4CompilerPrivate::traceExpression(IR::Expr *e, quint8 r)
-{
- if (!e) {
- discard();
- } else {
- qSwap(currentReg, r);
- e->accept(this);
- qSwap(currentReg, r);
- }
-}
-
-//
-// expressions
-//
-void QV4CompilerPrivate::visitConst(IR::Const *e)
-{
- switch (e->type) {
- case IR::BoolType: {
- Instr::LoadBool i;
- i.reg = currentReg;
- i.value = e->value;
- gen(i);
- } break;
-
- case IR::IntType: {
- Instr::LoadInt i;
- i.reg = currentReg;
- i.value = e->value;
- gen(i);
- } break;
-
- case IR::RealType: {
- Instr::LoadReal i;
- i.reg = currentReg;
- i.value = e->value;
- gen(i);
- } break;
-
- default:
- if (qmlVerboseCompiler())
- qWarning() << Q_FUNC_INFO << "unexpected type";
- discard();
- }
-}
-
-void QV4CompilerPrivate::visitString(IR::String *e)
-{
- registerLiteralString(currentReg, e->value);
-}
-
-void QV4CompilerPrivate::visitName(IR::Name *e)
-{
- if (e->base) {
- // fetch the object and store it in reg.
- traceExpression(e->base, currentReg);
- } else {
- _subscribeName.clear();
- }
-
- if (e->storage == IR::Name::RootStorage) {
-
- Instr::LoadRoot instr;
- instr.reg = currentReg;
- gen(instr);
-
- if (e->symbol == IR::Name::IdObject) {
- // The ID is a reference to the root object
- return;
- }
-
- } else if (e->storage == IR::Name::ScopeStorage) {
-
- Instr::LoadScope instr;
- instr.reg = currentReg;
- gen(instr);
-
- _subscribeName << contextName();
-
- } else if (e->storage == IR::Name::IdStorage) {
-
- Instr::LoadId instr;
- instr.reg = currentReg;
- instr.index = e->idObject->idIndex;
- gen(instr);
-
- _subscribeName << QLatin1String("$$$ID_") + *e->id;
-
- if (blockNeedsSubscription(_subscribeName)) {
- Instr::SubscribeId sub;
- sub.reg = currentReg;
- sub.offset = subscriptionIndex(_subscribeName);
- sub.index = instr.index;
- gen(sub);
- }
-
- return;
- } else {
- // No action needed
- }
-
- switch (e->symbol) {
- case IR::Name::Unbound:
- case IR::Name::IdObject:
- case IR::Name::Slot:
- case IR::Name::Object: {
- Q_ASSERT(!"Unreachable");
- discard();
- } break;
-
- case IR::Name::AttachType: {
- _subscribeName << *e->id;
-
- Instr::LoadAttached attached;
- attached.output = currentReg;
- attached.reg = currentReg;
- attached.exceptionId = exceptionId(e->line, e->column);
- if (e->declarativeType->attachedPropertiesId() == -1)
- discard();
- attached.id = e->declarativeType->attachedPropertiesId();
- gen(attached);
- } break;
-
- case IR::Name::Property: {
- _subscribeName << *e->id;
-
- if (e->property->coreIndex == -1) {
- QMetaProperty prop;
- e->property->load(prop, QDeclarativeEnginePrivate::get(engine));
- }
-
- const int propTy = e->property->propType;
- QDeclarativeRegisterType regType;
-
- switch (propTy) {
- case QMetaType::QReal:
- regType = QRealType;
- break;
- case QMetaType::Bool:
- regType = BoolType;
- break;
- case QMetaType::Int:
- regType = IntType;
- break;
- case QMetaType::QString:
- regType = QStringType;
- break;
- case QMetaType::QUrl:
- regType = QUrlType;
- break;
- case QMetaType::QColor:
- regType = QColorType;
- break;
-
- default:
- if (propTy == QDeclarativeMetaType::QQuickAnchorLineMetaTypeId()) {
- regType = PODValueType;
- } else if (QDeclarativeMetaType::isQObject(propTy)) {
- regType = QObjectStarType;
- } else {
- if (qmlVerboseCompiler())
- qWarning() << "Discard unsupported property type:" << QMetaType::typeName(propTy);
- discard(); // Unsupported type
- return;
- }
-
- break;
- } // switch
-
- if (e->property->hasAccessors()) {
- Instr::FetchAndSubscribe fetch;
- fetch.reg = currentReg;
- fetch.subscription = subscriptionIndex(_subscribeName);
- fetch.exceptionId = exceptionId(e->line, e->column);
- fetch.valueType = regType;
- fetch.property = *e->property;
- gen(fetch);
- } else {
- if (blockNeedsSubscription(_subscribeName) && e->property->notifyIndex != -1) {
- Instr::Subscribe sub;
- sub.reg = currentReg;
- sub.offset = subscriptionIndex(_subscribeName);
- sub.index = e->property->notifyIndex;
- gen(sub);
- }
-
- Instr::Fetch fetch;
- fetch.reg = currentReg;
- fetch.index = e->property->coreIndex;
- fetch.exceptionId = exceptionId(e->line, e->column);
- fetch.valueType = regType;
- gen(fetch);
- }
-
- } break;
- } // switch
-}
-
-void QV4CompilerPrivate::visitTemp(IR::Temp *e)
-{
- if (currentReg != e->index) {
- Instr::Copy i;
- i.reg = currentReg;
- i.src = e->index;
- gen(i);
- }
-}
-
-void QV4CompilerPrivate::visitUnop(IR::Unop *e)
-{
- quint8 src = currentReg;
-
- if (IR::Temp *temp = e->expr->asTemp()) {
- src = temp->index;
- } else {
- traceExpression(e->expr, src);
- }
-
- switch (e->op) {
- case IR::OpInvalid:
- Q_ASSERT(!"unreachable");
- break;
-
- case IR::OpIfTrue:
- convertToBool(e->expr, src);
- if (src != currentReg) {
- Instr::Copy i;
- i.reg = currentReg;
- i.src = src;
- gen(i);
- }
- break;
-
- case IR::OpNot: {
- Instr::UnaryNot i;
- convertToBool(e->expr, src);
- i.output = currentReg;
- i.src = src;
- gen(i);
- } break;
-
- case IR::OpUMinus:
- if (e->expr->type == IR::RealType) {
- Instr::UnaryMinusReal i;
- i.output = currentReg;
- i.src = src;
- gen(i);
- } else if (e->expr->type == IR::IntType) {
- convertToReal(e->expr, currentReg);
- Instr::UnaryMinusReal i;
- i.output = currentReg;
- i.src = src;
- gen(i);
- } else {
- discard();
- }
- break;
-
- case IR::OpUPlus:
- if (e->expr->type == IR::RealType) {
- Instr::UnaryPlusReal i;
- i.output = currentReg;
- i.src = src;
- gen(i);
- } else if (e->expr->type == IR::IntType) {
- convertToReal(e->expr, currentReg);
- Instr::UnaryPlusReal i;
- i.output = currentReg;
- i.src = src;
- gen(i);
- } else {
- discard();
- }
- break;
-
- case IR::OpCompl:
- // TODO
- discard();
- break;
-
- case IR::OpBitAnd:
- case IR::OpBitOr:
- case IR::OpBitXor:
- case IR::OpAdd:
- case IR::OpSub:
- case IR::OpMul:
- case IR::OpDiv:
- case IR::OpMod:
- case IR::OpLShift:
- case IR::OpRShift:
- case IR::OpURShift:
- case IR::OpGt:
- case IR::OpLt:
- case IR::OpGe:
- case IR::OpLe:
- case IR::OpEqual:
- case IR::OpNotEqual:
- case IR::OpStrictEqual:
- case IR::OpStrictNotEqual:
- case IR::OpAnd:
- case IR::OpOr:
- Q_ASSERT(!"unreachable");
- break;
- } // switch
-}
-
-void QV4CompilerPrivate::convertToReal(IR::Expr *expr, int reg)
-{
- if (expr->type == IR::RealType)
- return;
-
- switch (expr->type) {
- case IR::BoolType: {
- Instr::ConvertBoolToReal i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- case IR::IntType: {
- Instr::ConvertIntToReal i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- case IR::RealType:
- // nothing to do
- return;
-
- default:
- discard();
- break;
- } // switch
-}
-
-void QV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg)
-{
- if (expr->type == IR::IntType)
- return;
-
- switch (expr->type) {
- case IR::BoolType: {
- Instr::ConvertBoolToInt i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- case IR::IntType:
- // nothing to do
- return;
-
- case IR::RealType: {
- Instr::ConvertRealToInt i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- default:
- discard();
- break;
- } // switch
-}
-
-void QV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
-{
- if (expr->type == IR::BoolType)
- return;
-
- switch (expr->type) {
- case IR::BoolType:
- // nothing to do
- break;
-
- case IR::IntType: {
- Instr::ConvertIntToBool i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- case IR::RealType: {
- Instr::ConvertRealToBool i;
- i.output = i.src = reg;
- gen(i);
- } return;
-
- case IR::StringType: {
- Instr::ConvertStringToBool i;
- i.output = i.src = reg;
- gen(i);
- } return;
-
- case IR::ColorType: {
- Instr::ConvertColorToBool i;
- i.output = i.src = reg;
- gen(i);
- } return;
-
- default:
- discard();
- break;
- } // switch
-}
-
-quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e)
-{
- switch (e->op) {
- case IR::OpInvalid:
- return V4Instr::Noop;
-
- case IR::OpIfTrue:
- case IR::OpNot:
- case IR::OpUMinus:
- case IR::OpUPlus:
- case IR::OpCompl:
- return V4Instr::Noop;
-
- case IR::OpBitAnd:
- return V4Instr::BitAndInt;
-
- case IR::OpBitOr:
- return V4Instr::BitOrInt;
-
- case IR::OpBitXor:
- return V4Instr::BitXorInt;
-
- case IR::OpAdd:
- if (e->type == IR::StringType)
- return V4Instr::AddString;
- return V4Instr::AddReal;
-
- case IR::OpSub:
- return V4Instr::SubReal;
-
- case IR::OpMul:
- return V4Instr::MulReal;
-
- case IR::OpDiv:
- return V4Instr::DivReal;
-
- case IR::OpMod:
- return V4Instr::ModReal;
-
- case IR::OpLShift:
- return V4Instr::LShiftInt;
-
- case IR::OpRShift:
- return V4Instr::RShiftInt;
-
- case IR::OpURShift:
- return V4Instr::URShiftInt;
-
- case IR::OpGt:
- if (e->left->type == IR::StringType)
- return V4Instr::GtString;
- return V4Instr::GtReal;
-
- case IR::OpLt:
- if (e->left->type == IR::StringType)
- return V4Instr::LtString;
- return V4Instr::LtReal;
-
- case IR::OpGe:
- if (e->left->type == IR::StringType)
- return V4Instr::GeString;
- return V4Instr::GeReal;
-
- case IR::OpLe:
- if (e->left->type == IR::StringType)
- return V4Instr::LeString;
- return V4Instr::LeReal;
-
- case IR::OpEqual:
- if (e->left->type == IR::StringType)
- return V4Instr::EqualString;
- return V4Instr::EqualReal;
-
- case IR::OpNotEqual:
- if (e->left->type == IR::StringType)
- return V4Instr::NotEqualString;
- return V4Instr::NotEqualReal;
-
- case IR::OpStrictEqual:
- if (e->left->type == IR::StringType)
- return V4Instr::StrictEqualString;
- return V4Instr::StrictEqualReal;
-
- case IR::OpStrictNotEqual:
- if (e->left->type == IR::StringType)
- return V4Instr::StrictNotEqualString;
- return V4Instr::StrictNotEqualReal;
-
- case IR::OpAnd:
- case IR::OpOr:
- return V4Instr::Noop;
-
- } // switch
-
- return V4Instr::Noop;
-}
-
-void QV4CompilerPrivate::visitBinop(IR::Binop *e)
-{
- int left = currentReg;
- int right = currentReg + 1;
-
- if (e->left->asTemp() && e->type != IR::StringType) // Not sure if the e->type != String test is needed
- left = e->left->asTemp()->index;
- else
- traceExpression(e->left, left);
-
- if (IR::Temp *t = e->right->asTemp())
- right = t->index;
- else
- traceExpression(e->right, right);
-
- if (e->left->type != e->right->type) {
- if (qmlVerboseCompiler())
- qWarning().nospace() << "invalid operands to binary operator " << IR::binaryOperator(e->op)
- << "(`" << IR::binaryOperator(e->left->type)
- << "' and `"
- << IR::binaryOperator(e->right->type)
- << "'";
- discard();
- return;
- }
-
- switch (e->op) {
- case IR::OpInvalid:
- discard();
- break;
-
- // unary
- case IR::OpIfTrue:
- case IR::OpNot:
- case IR::OpUMinus:
- case IR::OpUPlus:
- case IR::OpCompl:
- discard();
- break;
-
- case IR::OpBitAnd:
- case IR::OpBitOr:
- case IR::OpBitXor:
- case IR::OpLShift:
- case IR::OpRShift:
- case IR::OpURShift:
- convertToInt(e->left, left);
- convertToInt(e->right, right);
- break;
-
- case IR::OpAdd:
- if (e->type != IR::StringType) {
- convertToReal(e->left, left);
- convertToReal(e->right, right);
- }
- break;
-
- case IR::OpSub:
- case IR::OpMul:
- case IR::OpDiv:
- case IR::OpMod:
- convertToReal(e->left, left);
- convertToReal(e->right, right);
- break;
-
- case IR::OpGt:
- case IR::OpLt:
- case IR::OpGe:
- case IR::OpLe:
- case IR::OpEqual:
- case IR::OpNotEqual:
- case IR::OpStrictEqual:
- case IR::OpStrictNotEqual:
- if (e->left->type != IR::StringType) {
- convertToReal(e->left, left);
- convertToReal(e->right, right);
- }
- break;
-
- case IR::OpAnd:
- case IR::OpOr:
- discard(); // ### unreachable
- break;
- } // switch
-
- const quint8 opcode = instructionOpcode(e);
- if (opcode != V4Instr::Noop) {
- V4Instr instr;
- instr.binaryop.output = currentReg;
- instr.binaryop.left = left;
- instr.binaryop.right = right;
- gen(static_cast<V4Instr::Type>(opcode), instr);
- }
-}
-
-void QV4CompilerPrivate::visitCall(IR::Call *call)
-{
- if (IR::Name *name = call->base->asName()) {
- IR::Expr *arg = call->onlyArgument();
- if (arg != 0 && arg->type == IR::RealType) {
- traceExpression(arg, currentReg);
-
- switch (name->builtin) {
- case IR::NoBuiltinSymbol:
- break;
-
- case IR::MathSinBultinFunction: {
- Instr::MathSinReal i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathCosBultinFunction: {
- Instr::MathCosReal i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathRoundBultinFunction: {
- Instr::MathRoundReal i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathFloorBultinFunction: {
- Instr::MathFloorReal i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathPIBuiltinConstant:
- break;
- } // switch
- }
- }
-
- if (qmlVerboseCompiler())
- qWarning() << "TODO:" << Q_FUNC_INFO << __LINE__;
- discard();
-}
-
-
-//
-// statements
-//
-void QV4CompilerPrivate::visitExp(IR::Exp *s)
-{
- traceExpression(s->expr, currentReg);
-}
-
-void QV4CompilerPrivate::visitMove(IR::Move *s)
-{
- IR::Temp *target = s->target->asTemp();
- Q_ASSERT(target != 0);
-
- quint8 dest = target->index;
-
- if (target->type != s->source->type) {
- quint8 src = dest;
-
- if (IR::Temp *t = s->source->asTemp())
- src = t->index;
- else
- traceExpression(s->source, dest);
-
- V4Instr::Type opcode = V4Instr::Noop;
- IR::Type targetTy = s->target->type;
- IR::Type sourceTy = s->source->type;
-
- if (sourceTy == IR::UrlType) {
- switch (targetTy) {
- case IR::BoolType:
- case IR::StringType:
- // nothing to do. V4 will generate optimized
- // url-to-xxx conversions.
- break;
- default: {
- // generate a UrlToString conversion and fix
- // the type of the source expression.
- V4Instr conv;
- conv.unaryop.output = V4Instr::ConvertUrlToString;
- conv.unaryop.src = src;
- gen(opcode, conv);
-
- sourceTy = IR::StringType;
- break;
- }
- } // switch
- }
-
- if (targetTy == IR::BoolType) {
- switch (sourceTy) {
- case IR::IntType: opcode = V4Instr::ConvertIntToBool; break;
- case IR::RealType: opcode = V4Instr::ConvertRealToBool; break;
- case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
- case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break;
- case IR::ColorType: opcode = V4Instr::ConvertColorToBool; break;
- default: break;
- } // switch
- } else if (targetTy == IR::IntType) {
- switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToInt; break;
- case IR::RealType: {
- if (s->isMoveForReturn)
- opcode = V4Instr::MathRoundReal;
- else
- opcode = V4Instr::ConvertRealToInt;
- break;
- }
- case IR::StringType: opcode = V4Instr::ConvertStringToInt; break;
- default: break;
- } // switch
- } else if (targetTy == IR::RealType) {
- switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToReal; break;
- case IR::IntType: opcode = V4Instr::ConvertIntToReal; break;
- case IR::StringType: opcode = V4Instr::ConvertStringToReal; break;
- default: break;
- } // switch
- } else if (targetTy == IR::StringType) {
- switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToString; break;
- case IR::IntType: opcode = V4Instr::ConvertIntToString; break;
- case IR::RealType: opcode = V4Instr::ConvertRealToString; break;
- case IR::UrlType: opcode = V4Instr::ConvertUrlToString; break;
- case IR::ColorType: opcode = V4Instr::ConvertColorToString; break;
- default: break;
- } // switch
- } else if (targetTy == IR::UrlType) {
- V4Instr convToString;
- convToString.unaryop.output = dest;
- convToString.unaryop.src = src;
-
- // try to convert the source expression to a string.
- switch (sourceTy) {
- case IR::BoolType: gen(V4Instr::ConvertBoolToString, convToString); sourceTy = IR::StringType; break;
- case IR::IntType: gen(V4Instr::ConvertIntToString, convToString); sourceTy = IR::StringType; break;
- case IR::RealType: gen(V4Instr::ConvertRealToString, convToString); sourceTy = IR::StringType; break;
- case IR::ColorType: gen(V4Instr::ConvertColorToString, convToString); sourceTy = IR::StringType; break;
- default: break;
- } // switch
-
- if (sourceTy == IR::StringType)
- opcode = V4Instr::ConvertStringToUrl;
- } else if (targetTy == IR::ColorType) {
- switch (sourceTy) {
- case IR::StringType: opcode = V4Instr::ConvertStringToColor; break;
- default: break;
- } // switch
- }
- if (opcode != V4Instr::Noop) {
- V4Instr conv;
- conv.unaryop.output = dest;
- conv.unaryop.src = src;
- gen(opcode, conv);
-
- if (s->isMoveForReturn && opcode == V4Instr::ConvertStringToUrl) {
- V4Instr resolveUrl;
- resolveUrl.unaryop.output = dest;
- resolveUrl.unaryop.src = dest;
- gen(V4Instr::ResolveUrl, resolveUrl);
- }
- } else {
- discard();
- }
- } else {
- traceExpression(s->source, dest);
- }
-}
-
-void QV4CompilerPrivate::visitJump(IR::Jump *s)
-{
- patches.append(Patch(s->target, bytecode.size()));
-
- Instr::Branch i;
- i.offset = 0; // ### backpatch
- gen(i);
-}
-
-void QV4CompilerPrivate::visitCJump(IR::CJump *s)
-{
- traceExpression(s->cond, currentReg);
-
- patches.append(Patch(s->iftrue, bytecode.size()));
-
- Instr::BranchTrue i;
- i.reg = currentReg;
- i.offset = 0; // ### backpatch
- gen(i);
-}
-
-void QV4CompilerPrivate::visitRet(IR::Ret *s)
-{
- Q_ASSERT(s->expr != 0);
-
- int storeReg = currentReg;
-
- if (IR::Temp *temp = s->expr->asTemp()) {
- storeReg = temp->index;
- } else {
- traceExpression(s->expr, storeReg);
- }
-
- if (qmlBindingsTest) {
- Instr::TestV4Store test;
- test.reg = storeReg;
- switch (s->type) {
- case IR::StringType:
- test.regType = QMetaType::QString;
- break;
- case IR::UrlType:
- test.regType = QMetaType::QUrl;
- break;
- case IR::ColorType:
- test.regType = QMetaType::QColor;
- break;
- case IR::SGAnchorLineType:
- test.regType = QDeclarativeMetaType::QQuickAnchorLineMetaTypeId();
- break;
- case IR::ObjectType:
- test.regType = QMetaType::QObjectStar;
- break;
- case IR::BoolType:
- test.regType = QMetaType::Bool;
- break;
- case IR::IntType:
- test.regType = QMetaType::Int;
- break;
- case IR::RealType:
- test.regType = QMetaType::QReal;
- break;
- default:
- discard();
- return;
- }
- gen(test);
- }
-
- Instr::Store store;
- store.output = 0;
- store.index = expression->property->index;
- store.reg = storeReg;
- store.exceptionId = exceptionId(s->line, s->column);
- gen(store);
-}
-
-void QV4Compiler::dump(const QByteArray &programData)
-{
- const QV4Program *program = (const QV4Program *)programData.constData();
-
- qWarning() << "Program.bindings:" << program->bindings;
- qWarning() << "Program.dataLength:" << program->dataLength;
- qWarning() << "Program.subscriptions:" << program->subscriptions;
- qWarning() << "Program.indentifiers:" << program->identifiers;
-
- const int programSize = program->instructionCount;
- const char *start = program->instructions();
- const char *end = start + programSize;
- Bytecode bc;
- bc.dump(start, end);
-}
-
-/*!
-Clear the state associated with attempting to compile a specific binding.
-This does not clear the global "committed binding" states.
-*/
-void QV4CompilerPrivate::resetInstanceState()
-{
- data = committed.data;
- exceptions = committed.exceptions;
- usedSubscriptionIds.clear();
- subscriptionIds = committed.subscriptionIds;
- registeredStrings = committed.registeredStrings;
- bytecode.clear();
- patches.clear();
- pool.clear();
- currentReg = 0;
-}
-
-/*!
-Mark the last compile as successful, and add it to the "committed data"
-section.
-
-Returns the index for the committed binding.
-*/
-int QV4CompilerPrivate::commitCompile()
-{
- int rv = committed.count();
- committed.offsets << committed.bytecode.count();
- committed.dependencies << usedSubscriptionIds;
- committed.bytecode.append(bytecode.constData(), bytecode.size());
- committed.data = data;
- committed.exceptions = exceptions;
- committed.subscriptionIds = subscriptionIds;
- committed.registeredStrings = registeredStrings;
- return rv;
-}
-
-bool QV4CompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
-{
- resetInstanceState();
-
- if (expression->property->type == -1)
- return false;
-
- AST::SourceLocation location;
- if (AST::ExpressionNode *astExpression = node->expressionCast()) {
- location = astExpression->firstSourceLocation();
- } else if (AST::Statement *astStatement = node->statementCast()) {
- if (AST::Block *block = AST::cast<AST::Block *>(astStatement))
- location = block->lbraceToken;
- else if (AST::IfStatement *ifStmt = AST::cast<AST::IfStatement *>(astStatement))
- location = ifStmt->ifToken;
- else
- return false;
- } else {
- return false;
- }
-
- IR::Function thisFunction(&pool), *function = &thisFunction;
-
- QV4IRBuilder irBuilder(expression, engine);
- if (!irBuilder(function, node))
- return false;
-
- bool discarded = false;
- qSwap(_discarded, discarded);
- qSwap(_function, function);
- trace(location.startLine, location.startColumn);
- qSwap(_function, function);
- qSwap(_discarded, discarded);
-
- if (qmlVerboseCompiler()) {
- QTextStream qerr(stderr, QIODevice::WriteOnly);
- if (discarded)
- qerr << "======== TODO ====== " << endl;
- else
- qerr << "==================== " << endl;
- qerr << "\tline: " << location.startLine
- << "\tcolumn: " << location.startColumn
- << endl;
- foreach (IR::BasicBlock *bb, function->basicBlocks)
- bb->dump(qerr);
- qerr << endl;
- }
-
- if (discarded || subscriptionIds.count() > 0xFFFF || registeredStrings.count() > 0xFFFF || registerCount > 31)
- return false;
-
- return true;
-}
-
-// Returns a reg
-int QV4CompilerPrivate::registerLiteralString(quint8 reg, const QStringRef &str)
-{
- // ### string cleanup
-
- QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
- int offset = data.count();
- data += strdata;
-
- Instr::LoadString string;
- string.reg = reg;
- string.offset = offset;
- string.length = str.length();
- gen(string);
-
- return reg;
-}
-
-// Returns an identifier offset
-int QV4CompilerPrivate::registerString(const QString &string)
-{
- Q_ASSERT(!string.isEmpty());
-
- QPair<int, int> *iter = registeredStrings.value(string);
-
- if (!iter) {
- quint32 len = string.length();
- QByteArray lendata((const char *)&len, sizeof(quint32));
- QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
- strdata.prepend(lendata);
- int rv = data.count();
- data += strdata;
-
- iter = &registeredStrings[string];
- *iter = qMakePair(registeredStrings.count(), rv);
- }
-
- Instr::InitString reg;
- reg.offset = iter->first;
- reg.dataIdx = iter->second;
- gen(reg);
- return reg.offset;
-}
-
-/*!
-Returns true if the current expression has not already subscribed to \a sub in currentBlockMask.
-*/
-bool QV4CompilerPrivate::blockNeedsSubscription(const QStringList &sub)
-{
- QString str = sub.join(QLatin1String("."));
-
- int *iter = subscriptionIds.value(str);
- if (!iter)
- return true;
-
- quint32 *uiter = usedSubscriptionIds.value(*iter);
- if (!uiter)
- return true;
- else
- return !(*uiter & currentBlockMask);
-}
-
-int QV4CompilerPrivate::subscriptionIndex(const QStringList &sub)
-{
- QString str = sub.join(QLatin1String("."));
- int *iter = subscriptionIds.value(str);
- if (!iter) {
- int count = subscriptionIds.count();
- iter = &subscriptionIds[str];
- *iter = count;
- }
- quint32 &u = usedSubscriptionIds[*iter];
- if (!(u & currentBlockMask)) {
- u |= currentBlockMask;
- usedSubscriptionIdsChanged = true;
- }
- return *iter;
-}
-
-quint32 QV4CompilerPrivate::subscriptionBlockMask(const QStringList &sub)
-{
- QString str = sub.join(QLatin1String("."));
-
- int *iter = subscriptionIds.value(str);
- Q_ASSERT(iter != 0);
-
- quint32 *uiter = usedSubscriptionIds.value(*iter);
- Q_ASSERT(uiter != 0);
-
- return *uiter;
-}
-
-quint8 QV4CompilerPrivate::exceptionId(quint32 line, quint32 column)
-{
- quint8 rv = 0xFF;
- if (exceptions.count() < 0xFF) {
- rv = (quint8)exceptions.count();
- quint64 e = line;
- e <<= 32;
- e |= column;
- exceptions.append(e);
- }
- return rv;
-}
-
-quint8 QV4CompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
-{
- quint8 rv = 0xFF;
- if (n && exceptions.count() < 0xFF) {
- QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
- rv = exceptionId(l.startLine, l.startColumn);
- }
- return rv;
-}
-
-QV4Compiler::QV4Compiler()
-: d(new QV4CompilerPrivate)
-{
- qmlBindingsTest |= qmlBindingsTestEnv();
-}
-
-QV4Compiler::~QV4Compiler()
-{
- delete d; d = 0;
-}
-
-/*
-Returns true if any bindings were compiled.
-*/
-bool QV4Compiler::isValid() const
-{
- return !d->committed.bytecode.isEmpty();
-}
-
-/*
--1 on failure, otherwise the binding index to use.
-*/
-int QV4Compiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
-{
- if (!expression.expression.asAST()) return false;
-
- if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
- return -1;
-
- if (qmlDisableOptimizer() || !qmlEnableV4)
- return -1;
-
- d->expression = &expression;
- d->engine = engine;
-
- if (d->compile(expression.expression.asAST())) {
- return d->commitCompile();
- } else {
- return -1;
- }
-}
-
-QByteArray QV4CompilerPrivate::buildSignalTable() const
-{
- QHash<int, QList<QPair<int, quint32> > > table;
-
- for (int ii = 0; ii < committed.count(); ++ii) {
- const QDeclarativeAssociationList<int, quint32> &deps = committed.dependencies.at(ii);
- for (QDeclarativeAssociationList<int, quint32>::const_iterator iter = deps.begin(); iter != deps.end(); ++iter)
- table[iter->first].append(qMakePair(ii, iter->second));
- }
-
- QVector<quint32> header;
- QVector<quint32> data;
- for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
- header.append(committed.subscriptionIds.count() + data.count());
- const QList<QPair<int, quint32> > &bindings = table[ii];
- data.append(bindings.count());
- for (int jj = 0; jj < bindings.count(); ++jj) {
- data.append(bindings.at(jj).first);
- data.append(bindings.at(jj).second);
- }
- }
- header << data;
-
- return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
-}
-
-QByteArray QV4CompilerPrivate::buildExceptionData() const
-{
- QByteArray rv;
- rv.resize(committed.exceptions.count() * sizeof(quint64));
- ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
- return rv;
-}
-
-/*
-Returns the compiled program.
-*/
-QByteArray QV4Compiler::program() const
-{
- QByteArray programData;
-
- if (isValid()) {
- QV4Program prog;
- prog.bindings = d->committed.count();
-
- Bytecode bc;
- QV4CompilerPrivate::Instr::Jump jump;
- jump.reg = -1;
-
- for (int ii = 0; ii < d->committed.count(); ++ii) {
- jump.count = d->committed.count() - ii - 1;
- jump.count*= V4InstrMeta<V4Instr::Jump>::Size;
- jump.count+= d->committed.offsets.at(ii);
- bc.append(jump);
- }
-
-
- QByteArray bytecode;
- bytecode.reserve(bc.size() + d->committed.bytecode.size());
- bytecode.append(bc.constData(), bc.size());
- bytecode.append(d->committed.bytecode.constData(), d->committed.bytecode.size());
-
- QByteArray data = d->committed.data;
- while (data.count() % 4) data.append('\0');
- prog.signalTableOffset = data.count();
- data += d->buildSignalTable();
- while (data.count() % 4) data.append('\0');
- prog.exceptionDataOffset = data.count();
- data += d->buildExceptionData();
-
- prog.dataLength = 4 * ((data.size() + 3) / 4);
- prog.subscriptions = d->committed.subscriptionIds.count();
- prog.identifiers = d->committed.registeredStrings.count();
- prog.instructionCount = bytecode.count();
- int size = sizeof(QV4Program) + bytecode.count();
- size += prog.dataLength;
-
- programData.resize(size);
- memcpy(programData.data(), &prog, sizeof(QV4Program));
- if (prog.dataLength)
- memcpy((char *)((QV4Program *)programData.data())->data(), data.constData(),
- data.size());
- memcpy((char *)((QV4Program *)programData.data())->instructions(), bytecode.constData(),
- bytecode.count());
- }
-
- if (bindingsDump()) {
- qWarning().nospace() << "Subscription slots:";
-
- for (QDeclarativeAssociationList<QString, int>::ConstIterator iter = d->committed.subscriptionIds.begin();
- iter != d->committed.subscriptionIds.end();
- ++iter) {
- qWarning().nospace() << " " << iter->first << "\t-> " << iter->second;
- }
-
- QV4Compiler::dump(programData);
- }
-
- return programData;
-}
-
-void QV4Compiler::enableBindingsTest(bool e)
-{
- if (e)
- qmlBindingsTest = true;
- else
- qmlBindingsTest = qmlBindingsTestEnv();
-}
-
-void QV4Compiler::enableV4(bool e)
-{
- qmlEnableV4 = e;
-}
-
-QT_END_NAMESPACE