aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp8
-rw-r--r--src/imports/localstorage/plugin.cpp3
-rw-r--r--src/imports/xmllistmodel/qqmlxmllistmodel.cpp2
-rw-r--r--src/particles/qquickv4particledata_p.h2
-rw-r--r--src/plugins/accessible/quick/qaccessiblequickitem.cpp54
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp436
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h138
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp770
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h41
-rw-r--r--src/qml/compiler/qv4compileddata.cpp21
-rw-r--r--src/qml/compiler/qv4compileddata_p.h97
-rw-r--r--src/qml/compiler/qv4compiler.cpp11
-rw-r--r--src/qml/compiler/qv4compiler_p.h1
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h101
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp114
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h32
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp329
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h4
-rw-r--r--src/qml/compiler/qv4isel_p.h1
-rw-r--r--src/qml/compiler/qv4isel_util_p.h36
-rw-r--r--src/qml/compiler/qv4regalloc.cpp2
-rw-r--r--src/qml/compiler/qv4ssa.cpp26
-rw-r--r--src/qml/compiler/qv4ssa_p.h9
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp370
-rw-r--r--src/qml/debugger/qqmldebugserver_p.h3
-rw-r--r--src/qml/debugger/qqmldebugservice.cpp16
-rw-r--r--src/qml/debugger/qqmldebugservice_p.h6
-rw-r--r--src/qml/debugger/qqmlenginedebugservice.cpp4
-rw-r--r--src/qml/debugger/qqmlenginedebugservice_p.h4
-rw-r--r--src/qml/debugger/qqmlprofilerservice.cpp9
-rw-r--r--src/qml/debugger/qqmlprofilerservice_p.h69
-rw-r--r--src/qml/debugger/qv4debugservice.cpp7
-rw-r--r--src/qml/debugger/qv4debugservice_p.h4
-rw-r--r--src/qml/debugger/qv4profilerservice.cpp6
-rw-r--r--src/qml/debugger/qv4profilerservice_p.h1
-rw-r--r--src/qml/jsapi/qjsvalue.cpp2
-rw-r--r--src/qml/jsapi/qjsvalue_p.h2
-rw-r--r--src/qml/jsapi/qjsvalueiterator_p.h4
-rw-r--r--src/qml/jsruntime/jsruntime.pri4
-rw-r--r--src/qml/jsruntime/qv4alloca_p.h4
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp65
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h14
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4context.cpp6
-rw-r--r--src/qml/jsruntime/qv4context_p.h21
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp10
-rw-r--r--src/qml/jsruntime/qv4engine.cpp14
-rw-r--r--src/qml/jsruntime/qv4engine_p.h121
-rw-r--r--src/qml/jsruntime/qv4function.cpp2
-rw-r--r--src/qml/jsruntime/qv4function_p.h4
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h10
-rw-r--r--src/qml/jsruntime/qv4global_p.h16
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4include_p.h2
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp57
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h5
-rw-r--r--src/qml/jsruntime/qv4managed_p.h67
-rw-r--r--src/qml/jsruntime/qv4mm.cpp6
-rw-r--r--src/qml/jsruntime/qv4mm_p.h2
-rw-r--r--src/qml/jsruntime/qv4object.cpp11
-rw-r--r--src/qml/jsruntime/qv4object_p.h29
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp20
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h7
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp255
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h167
-rw-r--r--src/qml/jsruntime/qv4property_p.h6
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp5
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h6
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h7
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp24
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h21
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h327
-rw-r--r--src/qml/jsruntime/qv4script.cpp4
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp2
-rw-r--r--src/qml/jsruntime/qv4serialize_p.h2
-rw-r--r--src/qml/jsruntime/qv4sparsearray.cpp26
-rw-r--r--src/qml/jsruntime/qv4sparsearray_p.h21
-rw-r--r--src/qml/jsruntime/qv4string_p.h10
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4value.cpp215
-rw-r--r--src/qml/jsruntime/qv4value_def_p.h476
-rw-r--r--src/qml/jsruntime/qv4value_inl_p.h283
-rw-r--r--src/qml/jsruntime/qv4value_p.h718
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp133
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h3
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h2
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp2
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp2
-rw-r--r--src/qml/qml/qqmlcompiler.cpp6
-rw-r--r--src/qml/qml/qqmlcompiler_p.h3
-rw-r--r--src/qml/qml/qqmlcomponent.cpp15
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp2
-rw-r--r--src/qml/qml/qqmlcontextwrapper_p.h2
-rw-r--r--src/qml/qml/qqmldata_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp16
-rw-r--r--src/qml/qml/qqmlimport.cpp21
-rw-r--r--src/qml/qml/qqmlincubator.cpp24
-rw-r--r--src/qml/qml/qqmlincubator_p.h4
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp2
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp3
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp663
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h24
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp4
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h4
-rw-r--r--src/qml/qml/qqmltypeloader.cpp10
-rw-r--r--src/qml/qml/qqmltypeloader_p.h5
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvme.cpp20
-rw-r--r--src/qml/qml/qqmlvme_p.h53
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp3
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h2
-rw-r--r--src/qml/qml/v8/qv8engine.cpp2
-rw-r--r--src/qml/qml/v8/qv8engine_p.h2
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp35
-rw-r--r--src/qml/types/qquickworkerscript.cpp2
-rw-r--r--src/qml/util/qqmladaptormodel.cpp8
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp45
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h2
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp51
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h80
-rw-r--r--src/quick/items/qquickitem.h2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp3
-rw-r--r--src/quick/items/qquickloader_p_p.h2
-rw-r--r--src/quick/items/qquickscreen.cpp2
-rw-r--r--src/quick/items/qquicktext.cpp24
-rw-r--r--src/quick/items/qquicktext_p.h2
-rw-r--r--src/quick/items/qquicktextedit.cpp24
-rw-r--r--src/quick/items/qquicktextedit_p.h2
-rw-r--r--src/quick/items/qquicktextinput.cpp5
-rw-r--r--src/quick/items/qquicktextnode.cpp8
-rw-r--r--src/quick/items/qquickwindow.cpp2
-rw-r--r--src/quick/items/qquickwindow_p.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp336
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h24
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h2
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp24
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h3
-rw-r--r--src/quick/scenegraph/scenegraph.pri4
-rw-r--r--src/quick/scenegraph/scenegraph.qrc2
-rw-r--r--src/quick/scenegraph/shaders/visualization.frag11
-rw-r--r--src/quick/scenegraph/shaders/visualization.vert22
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp7
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp7
-rw-r--r--src/quick/util/qquickanimatorjob.cpp2
155 files changed, 4813 insertions, 2834 deletions
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index f425eaa220..5ed38db3d7 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -96,10 +96,10 @@ void QQuickFolderListModelPrivate::init()
{
Q_Q(QQuickFolderListModel);
qRegisterMetaType<QList<FileProperty> >("QList<FileProperty>");
- q->connect(&fileInfoThread, SIGNAL(directoryChanged(QString, QList<FileProperty>)),
- q, SLOT(_q_directoryChanged(QString, QList<FileProperty>)));
- q->connect(&fileInfoThread, SIGNAL(directoryUpdated(QString, QList<FileProperty>, int, int)),
- q, SLOT(_q_directoryUpdated(QString, QList<FileProperty>, int, int)));
+ q->connect(&fileInfoThread, SIGNAL(directoryChanged(QString,QList<FileProperty>)),
+ q, SLOT(_q_directoryChanged(QString,QList<FileProperty>)));
+ q->connect(&fileInfoThread, SIGNAL(directoryUpdated(QString,QList<FileProperty>,int,int)),
+ q, SLOT(_q_directoryUpdated(QString,QList<FileProperty>,int,int)));
q->connect(&fileInfoThread, SIGNAL(sortFinished(QList<FileProperty>)),
q, SLOT(_q_sortFinished(QList<FileProperty>)));
q->connect(q, SIGNAL(rowCountChanged()), q, SIGNAL(countChanged()));
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 6b2242d00b..7a7649c6f1 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -131,6 +131,7 @@ public:
bool forwardOnly; // type == Rows
};
+DEFINE_REF(QQmlSqlDatabaseWrapper, Object);
DEFINE_OBJECT_VTABLE(QQmlSqlDatabaseWrapper);
static ReturnedValue qmlsqldatabase_version(CallContext *ctx)
@@ -206,7 +207,7 @@ static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Eng
return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName;
}
-static ReturnedValue qmlsqldatabase_rows_index(QV4::Referenced<QQmlSqlDatabaseWrapper> r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0)
+static ReturnedValue qmlsqldatabase_rows_index(QQmlSqlDatabaseWrapperRef r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0)
{
Scope scope(v4);
QV8Engine *v8 = v4->v8Engine;
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
index ebfdad5cbf..0b9be3105b 100644
--- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
+++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
@@ -44,7 +44,7 @@
#include <qqmlcontext.h>
#include <private/qqmlengine_p.h>
#include <private/qv8engine_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4object_p.h>
diff --git a/src/particles/qquickv4particledata_p.h b/src/particles/qquickv4particledata_p.h
index b3614f94ff..10e9ecacc5 100644
--- a/src/particles/qquickv4particledata_p.h
+++ b/src/particles/qquickv4particledata_p.h
@@ -44,7 +44,7 @@
#include <private/qv8engine_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/accessible/quick/qaccessiblequickitem.cpp b/src/plugins/accessible/quick/qaccessiblequickitem.cpp
index 3521d4f98e..4b68574149 100644
--- a/src/plugins/accessible/quick/qaccessiblequickitem.cpp
+++ b/src/plugins/accessible/quick/qaccessiblequickitem.cpp
@@ -152,52 +152,24 @@ QList<QQuickItem *> QAccessibleQuickItem::childItems() const
QAccessible::State QAccessibleQuickItem::state() const
{
- QAccessible::State state;
+ QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(item());
+ if (!attached)
+ return QAccessible::State();
- if (item()->hasActiveFocus()) {
- state.focusable = true;
- state.focused = true;
- }
-
- if (item()->activeFocusOnTab())
- state.focusable = true;
+ QAccessible::State st = attached->state();
if (!item()->window() || !item()->window()->isVisible() ||!item()->isVisible() || qFuzzyIsNull(item()->opacity()))
- state.invisible = true;
+ st.invisible = true;
- QAccessible::Role r = role();
- switch (r) {
- case QAccessible::Button: {
- state.focusable = true;
- QVariant checkable = item()->property("checkable");
- if (!checkable.toBool())
- break;
- // fall through
- }
- case QAccessible::CheckBox:
- case QAccessible::RadioButton: {
- state.focusable = true;
- state.checkable = true;
- state.checked = item()->property("checked").toBool();
- break;
- }
- case QAccessible::MenuItem:
- case QAccessible::PageTab:
- case QAccessible::EditableText:
- case QAccessible::SpinBox:
- case QAccessible::Terminal:
- case QAccessible::ScrollBar:
- state.focusable = true;
- break;
- case QAccessible::ComboBox:
- state.focusable = true;
- state.editable = item()->property("editable").toBool();
- break;
- default:
- break;
- }
+ if (item()->activeFocusOnTab())
+ st.focusable = true;
+ if (item()->hasActiveFocus())
+ st.focused = true;
+
+ if (role() == QAccessible::ComboBox)
+ st.editable = item()->property("editable").toBool();
- return state;
+ return st;
}
QAccessible::Role QAccessibleQuickItem::role() const
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 2ba13be090..f933465100 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -54,6 +54,8 @@
QT_USE_NAMESPACE
+static const quint32 emptyStringIndex = 0;
+
DEFINE_BOOL_CONFIG_OPTION(lookupHints, QML_LOOKUP_HINTS);
using namespace QtQml;
@@ -77,6 +79,7 @@ void QmlObject::init(MemoryPool *pool, int typeNameIndex, int id, const AST::Sou
qmlSignals = pool->New<PoolList<Signal> >();
bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >();
+ declarationsOverride = 0;
}
void QmlObject::dump(DebugStream &out)
@@ -88,6 +91,95 @@ void QmlObject::dump(DebugStream &out)
out << "}" << endl;
}
+QString QmlObject::sanityCheckFunctionNames(const QList<CompiledFunctionOrExpression> &allFunctions, const QSet<QString> &illegalNames, AST::SourceLocation *errorLocation)
+{
+ QSet<int> functionNames;
+ for (Function *f = functions->first; f; f = f->next) {
+ AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(allFunctions.at(f->index).node);
+ Q_ASSERT(function);
+ *errorLocation = function->identifierToken;
+ QString name = function->name.toString();
+ if (functionNames.contains(f->nameIndex))
+ return tr("Duplicate method name");
+ functionNames.insert(f->nameIndex);
+ if (signalNames.contains(f->nameIndex))
+ return tr("Duplicate method name");
+
+ if (name.at(0).isUpper())
+ return tr("Method names cannot begin with an upper case letter");
+ if (illegalNames.contains(name))
+ return tr("Illegal method name");
+ }
+ return QString(); // no error
+}
+
+QString QmlObject::appendSignal(Signal *signal)
+{
+ QmlObject *target = declarationsOverride;
+ if (!target)
+ target = this;
+ if (target->signalNames.contains(signal->nameIndex))
+ return tr("Duplicate signal name");
+ target->signalNames.insert(signal->nameIndex);
+ target->qmlSignals->append(signal);
+ return QString(); // no error
+}
+
+QString QmlObject::appendProperty(QmlProperty *prop, const QString &propertyName, bool isDefaultProperty, const AST::SourceLocation &defaultToken, AST::SourceLocation *errorLocation)
+{
+ QmlObject *target = declarationsOverride;
+ if (!target)
+ target = this;
+
+ if (target->propertyNames.contains(prop->nameIndex))
+ return tr("Duplicate property name");
+
+ if (propertyName.constData()->isUpper())
+ return tr("Property names cannot begin with an upper case letter");
+
+ target->propertyNames.insert(prop->nameIndex);
+
+ const int index = target->properties->append(prop);
+ if (isDefaultProperty) {
+ if (target->indexOfDefaultProperty != -1) {
+ *errorLocation = defaultToken;
+ return tr("Duplicate default property");
+ }
+ target->indexOfDefaultProperty = index;
+ }
+ return QString(); // no error
+}
+
+void QmlObject::appendFunction(Function *f)
+{
+ QmlObject *target = declarationsOverride;
+ if (!target)
+ target = this;
+ target->functions->append(f);
+}
+
+QString QmlObject::appendBinding(Binding *b, bool isListBinding)
+{
+ const bool bindingToDefaultProperty = (b->propertyNameIndex == 0);
+ if (!isListBinding && !bindingToDefaultProperty
+ && b->type != QV4::CompiledData::Binding::Type_GroupProperty
+ && b->type != QV4::CompiledData::Binding::Type_AttachedProperty
+ && !(b->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+ if (bindingNames.contains(b->propertyNameIndex))
+ return tr("Property value set multiple times");
+ bindingNames.insert(b->propertyNameIndex);
+ }
+ if (isListBinding) {
+ bindings->append(b);
+ } else if (bindingToDefaultProperty) {
+ Binding *insertionPoint = bindings->findSortedInsertionPoint<QV4::CompiledData::Location, QV4::CompiledData::Binding, &QV4::CompiledData::Binding::location>(b);
+ bindings->insertAfter(insertionPoint, b);
+ } else {
+ bindings->prepend(b);
+ }
+ return QString(); // no error
+}
+
QStringList Signal::parameterStringList(const QStringList &stringPool) const
{
QStringList result;
@@ -100,6 +192,7 @@ QStringList Signal::parameterStringList(const QStringList &stringPool) const
QQmlCodeGenerator::QQmlCodeGenerator(const QSet<QString> &illegalNames)
: illegalNames(illegalNames)
, _object(0)
+ , _propertyDeclaration(0)
, jsGenerator(0)
{
}
@@ -148,7 +241,7 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
this->pool = output->jsParserEngine.pool();
this->jsGenerator = &output->jsGenerator;
- emptyStringIndex = registerString(QString());
+ Q_ASSERT(registerString(QString()) == emptyStringIndex);
sourceCode = code;
@@ -221,7 +314,7 @@ bool QQmlCodeGenerator::visit(AST::UiObjectDefinition *node)
int idx = defineQMLObject(node);
appendBinding(node->qualifiedTypeNameId->identifierToken, emptyStringIndex, idx);
} else {
- int idx = defineQMLObject(/*qualfied type name id*/0, node->initializer);
+ int idx = defineQMLObject(/*qualfied type name id*/0, node->qualifiedTypeNameId->firstSourceLocation(), node->initializer, /*declarations should go here*/_object);
appendBinding(node->qualifiedTypeNameId, idx);
}
return false;
@@ -229,7 +322,7 @@ bool QQmlCodeGenerator::visit(AST::UiObjectDefinition *node)
bool QQmlCodeGenerator::visit(AST::UiObjectBinding *node)
{
- int idx = defineQMLObject(node->qualifiedTypeNameId, node->initializer);
+ int idx = defineQMLObject(node->qualifiedTypeNameId, node->qualifiedTypeNameId->firstSourceLocation(), node->initializer);
appendBinding(node->qualifiedId, idx, node->hasOnToken);
return false;
}
@@ -293,47 +386,31 @@ void QQmlCodeGenerator::accept(AST::Node *node)
AST::Node::acceptChild(node, this);
}
-bool QQmlCodeGenerator::sanityCheckFunctionNames()
-{
- QSet<QString> functionNames;
- for (Function *f = _object->functions->first; f; f = f->next) {
- AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(_functions.at(f->index).node);
- Q_ASSERT(function);
- QString name = function->name.toString();
- if (functionNames.contains(name))
- COMPILE_EXCEPTION(function->identifierToken, tr("Duplicate method name"));
- functionNames.insert(name);
- if (_object->signalNames.contains(name))
- COMPILE_EXCEPTION(function->identifierToken, tr("Duplicate method name"));
-
- if (name.at(0).isUpper())
- COMPILE_EXCEPTION(function->identifierToken, tr("Method names cannot begin with an upper case letter"));
- if (illegalNames.contains(name))
- COMPILE_EXCEPTION(function->identifierToken, tr("Illegal method name"));
- }
- return true;
-}
-
-int QQmlCodeGenerator::defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId, AST::UiObjectInitializer *initializer)
+int QQmlCodeGenerator::defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId, const AST::SourceLocation &location, AST::UiObjectInitializer *initializer, QmlObject *declarationsOverride)
{
QmlObject *obj = New<QmlObject>();
_objects.append(obj);
const int objectIndex = _objects.size() - 1;
qSwap(_object, obj);
- AST::SourceLocation loc;
- if (qualifiedTypeNameId)
- loc = qualifiedTypeNameId->firstSourceLocation();
- _object->init(pool, registerString(asString(qualifiedTypeNameId)), emptyStringIndex, loc);
+ _object->init(pool, registerString(asString(qualifiedTypeNameId)), emptyStringIndex, location);
+ _object->declarationsOverride = declarationsOverride;
- QSet<QString> propertyNames;
- QSet<QString> signalNames;
+ // A new object is also a boundary for property declarations.
+ QmlProperty *declaration = 0;
+ qSwap(_propertyDeclaration, declaration);
accept(initializer);
- sanityCheckFunctionNames();
+ qSwap(_propertyDeclaration, declaration);
qSwap(_object, obj);
+
+ AST::SourceLocation loc;
+ QString error = obj->sanityCheckFunctionNames(_functions, illegalNames, &loc);
+ if (!error.isEmpty())
+ recordError(loc, error);
+
return objectIndex;
}
@@ -522,7 +599,7 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
QString signalName = node->name.toString();
signal->nameIndex = registerString(signalName);
- AST::SourceLocation loc = node->firstSourceLocation();
+ AST::SourceLocation loc = node->typeToken;
signal->location.line = loc.startLine;
signal->location.column = loc.startColumn;
@@ -582,17 +659,17 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
p = p->next;
}
- if (_object->signalNames.contains(signalName))
- COMPILE_EXCEPTION(node->identifierToken, tr("Duplicate signal name"));
- _object->signalNames.insert(signalName);
-
if (signalName.at(0).isUpper())
COMPILE_EXCEPTION(node->identifierToken, tr("Signal names cannot begin with an upper case letter"));
if (illegalNames.contains(signalName))
COMPILE_EXCEPTION(node->identifierToken, tr("Illegal signal name"));
- _object->qmlSignals->append(signal);
+ QString error = _object->appendSignal(signal);
+ if (!error.isEmpty()) {
+ recordError(node->identifierToken, error);
+ return false;
+ }
} else {
const QStringRef &memberType = node->memberType;
const QStringRef &name = node->name;
@@ -660,7 +737,8 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
else
property->customTypeNameIndex = emptyStringIndex;
- property->nameIndex = registerString(name.toString());
+ const QString propName = name.toString();
+ property->nameIndex = registerString(propName);
AST::SourceLocation loc = node->firstSourceLocation();
property->location.line = loc.startLine;
@@ -708,25 +786,38 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
propertyValue += alias.at(2);
}
property->aliasPropertyValueIndex = registerString(propertyValue);
- } else if (node->statement)
- appendBinding(node->identifierToken, property->nameIndex, node->statement);
+ } else if (node->statement) {
+ qSwap(_propertyDeclaration, property);
+ appendBinding(node->identifierToken, _propertyDeclaration->nameIndex, node->statement);
+ qSwap(_propertyDeclaration, property);
+ }
- _object->properties->append(property);
+ AST::SourceLocation errorLocation;
+ QString error;
- if (node->isDefaultMember) {
- if (_object->indexOfDefaultProperty != -1) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Duplicate default property"));
- error.setLine(node->defaultToken.startLine);
- error.setColumn(node->defaultToken.startColumn);
- errors << error;
- return false;
- }
- _object->indexOfDefaultProperty = _object->properties->count - 1;
+ if (illegalNames.contains(propName))
+ error = tr("Illegal property name");
+ else
+ error = _object->appendProperty(property, propName, node->isDefaultMember, node->defaultToken, &errorLocation);
+
+ if (!error.isEmpty()) {
+ if (errorLocation.startLine == 0)
+ errorLocation = node->identifierToken;
+
+ QQmlError qmlError;
+ qmlError.setDescription(error);
+ qmlError.setLine(errorLocation.startLine);
+ qmlError.setColumn(errorLocation.startColumn);
+ errors << qmlError;
+ return false;
}
- // process QML-like initializers (e.g. property Object o: Object {})
- AST::Node::accept(node->binding, this);
+ if (node->binding) {
+ qSwap(_propertyDeclaration, property);
+ // process QML-like initializers (e.g. property Object o: Object {})
+ AST::Node::accept(node->binding, this);
+ qSwap(_propertyDeclaration, property);
+ }
}
return false;
@@ -738,11 +829,12 @@ bool QQmlCodeGenerator::visit(AST::UiSourceElement *node)
_functions << funDecl;
Function *f = New<Function>();
f->functionDeclaration = funDecl;
- AST::SourceLocation loc = funDecl->firstSourceLocation();
+ AST::SourceLocation loc = funDecl->identifierToken;
f->location.line = loc.startLine;
f->location.column = loc.startColumn;
f->index = _functions.size() - 1;
- _object->functions->append(f);
+ f->nameIndex = registerString(funDecl->name.toString());
+ _object->appendFunction(f);
} else {
QQmlError error;
error.setDescription(QCoreApplication::translate("QQmlParser","JavaScript declaration outside Script element"));
@@ -800,7 +892,12 @@ QStringRef QQmlCodeGenerator::textRefAt(const AST::SourceLocation &first, const
void QQmlCodeGenerator::setBindingValue(QV4::CompiledData::Binding *binding, AST::Statement *statement)
{
+ AST::SourceLocation loc = statement->firstSourceLocation();
+ binding->valueLocation.line = loc.startLine;
+ binding->valueLocation.column = loc.startColumn;
binding->type = QV4::CompiledData::Binding::Type_Invalid;
+ if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+ binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(statement)) {
AST::ExpressionNode *expr = stmt->expression;
@@ -856,13 +953,10 @@ void QQmlCodeGenerator::appendBinding(AST::UiQualifiedId *name, int objectIndex,
qSwap(_object, object);
}
-void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, AST::Statement *value)
+void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, quint32 propertyNameIndex, AST::Statement *value)
{
- if (!sanityCheckPropertyName(nameLocation, propertyNameIndex))
- return;
-
if (stringAt(propertyNameIndex) == QStringLiteral("id")) {
- setId(value);
+ setId(nameLocation, value);
return;
}
@@ -872,14 +966,14 @@ void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, i
binding->location.column = nameLocation.startColumn;
binding->flags = 0;
setBindingValue(binding, value);
- _object->bindings->append(binding);
+ QString error = bindingsTarget()->appendBinding(binding, /*isListBinding*/false);
+ if (!error.isEmpty()) {
+ recordError(nameLocation, error);
+ }
}
-void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem, bool isOnAssignment)
+void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem, bool isOnAssignment)
{
- if (!sanityCheckPropertyName(nameLocation, propertyNameIndex, isListItem | isOnAssignment))
- return;
-
if (stringAt(propertyNameIndex) == QStringLiteral("id")) {
recordError(nameLocation, tr("Invalid component id specification"));
return;
@@ -889,35 +983,55 @@ void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, i
binding->propertyNameIndex = propertyNameIndex;
binding->location.line = nameLocation.startLine;
binding->location.column = nameLocation.startColumn;
+
+ const QmlObject *obj = _objects.at(objectIndex);
+ binding->valueLocation = obj->location;
+
binding->flags = 0;
+ if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+ binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
+
// No type name on the initializer means it must be a group property
- if (stringAt(_objects.at(objectIndex)->inheritedTypeNameIndex).isEmpty())
+ if (_objects.at(objectIndex)->inheritedTypeNameIndex == emptyStringIndex)
binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
else
binding->type = QV4::CompiledData::Binding::Type_Object;
if (isOnAssignment)
binding->flags |= QV4::CompiledData::Binding::IsOnAssignment;
+ if (isListItem)
+ binding->flags |= QV4::CompiledData::Binding::IsListItem;
binding->value.objectIndex = objectIndex;
- _object->bindings->append(binding);
+ QString error = bindingsTarget()->appendBinding(binding, isListItem);
+ if (!error.isEmpty()) {
+ recordError(nameLocation, error);
+ }
}
-bool QQmlCodeGenerator::setId(AST::Statement *value)
+QmlObject *QQmlCodeGenerator::bindingsTarget() const
+{
+ if (_propertyDeclaration && _object->declarationsOverride)
+ return _object->declarationsOverride;
+ return _object;
+}
+
+bool QQmlCodeGenerator::setId(const AST::SourceLocation &idLocation, AST::Statement *value)
{
AST::SourceLocation loc = value->firstSourceLocation();
QStringRef str;
AST::Node *node = value;
if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(node)) {
- if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(stmt->expression))
+ if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(stmt->expression)) {
str = lit->value;
- else
+ node = 0;
+ } else
node = stmt->expression;
}
- if (str.isEmpty())
+ if (node && str.isEmpty())
str = asStringRef(node);
if (str.isEmpty())
@@ -941,6 +1055,9 @@ bool QQmlCodeGenerator::setId(AST::Statement *value)
if (illegalNames.contains(idQString))
COMPILE_EXCEPTION(loc, tr( "ID illegally masks global JavaScript property"));
+ if (_object->idIndex != emptyStringIndex)
+ COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times"));
+
_object->idIndex = registerString(idQString);
_object->locationOfIdProperty.line = loc.startLine;
_object->locationOfIdProperty.column = loc.startColumn;
@@ -950,56 +1067,57 @@ bool QQmlCodeGenerator::setId(AST::Statement *value)
bool QQmlCodeGenerator::resolveQualifiedId(AST::UiQualifiedId **nameToResolve, QmlObject **object)
{
- AST::UiQualifiedId *name = *nameToResolve;
+ AST::UiQualifiedId *qualifiedIdElement = *nameToResolve;
+
+ if (qualifiedIdElement->name == QStringLiteral("id") && qualifiedIdElement->next)
+ COMPILE_EXCEPTION(qualifiedIdElement->identifierToken, tr( "Invalid use of id property"));
- if (name->name == QStringLiteral("id") && name->next)
- COMPILE_EXCEPTION(name->identifierToken, tr( "Invalid use of id property"));
+ // If it's a namespace, prepend the qualifier and we'll resolve it later to the correct type.
+ QString currentName = qualifiedIdElement->name.toString();
+ if (qualifiedIdElement->next) {
+ foreach (QV4::CompiledData::Import* import, _imports)
+ if (import->qualifierIndex != emptyStringIndex
+ && stringAt(import->qualifierIndex) == currentName) {
+ qualifiedIdElement = qualifiedIdElement->next;
+ currentName += QLatin1Char('.');
+ currentName += qualifiedIdElement->name;
+
+ if (!qualifiedIdElement->name.unicode()->isUpper())
+ COMPILE_EXCEPTION(qualifiedIdElement->firstSourceLocation(), tr("Expected type name"));
+
+ break;
+ }
+ }
*object = _object;
- while (name->next) {
+ while (qualifiedIdElement->next) {
Binding *binding = New<Binding>();
- binding->propertyNameIndex = registerString(name->name.toString());
- binding->location.line = name->identifierToken.startLine;
- binding->location.column = name->identifierToken.startColumn;
+ binding->propertyNameIndex = registerString(currentName);
+ binding->location.line = qualifiedIdElement->identifierToken.startLine;
+ binding->location.column = qualifiedIdElement->identifierToken.startColumn;
+ binding->valueLocation.line = binding->valueLocation.column = 0;
binding->flags = 0;
- if (name->name.unicode()->isUpper())
+ if (qualifiedIdElement->name.unicode()->isUpper())
binding->type = QV4::CompiledData::Binding::Type_AttachedProperty;
else
binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
- int objIndex = defineQMLObject(0, 0);
+ int objIndex = defineQMLObject(0, AST::SourceLocation(), 0, 0);
binding->value.objectIndex = objIndex;
- (*object)->bindings->append(binding);
+ QString error = (*object)->appendBinding(binding, /*isListBinding*/false);
+ if (!error.isEmpty()) {
+ recordError(qualifiedIdElement->identifierToken, error);
+ return false;
+ }
*object = _objects[objIndex];
- name = name->next;
+ qualifiedIdElement = qualifiedIdElement->next;
+ if (qualifiedIdElement)
+ currentName = qualifiedIdElement->name.toString();
}
- *nameToResolve = name;
- return true;
-}
-
-bool QQmlCodeGenerator::sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex, bool isListItemOnOrAssignment)
-{
- const QString &name = jsGenerator->strings.at(nameIndex);
- if (name.isEmpty())
- return true;
-
- // List items are implement by multiple bindings to the same name, so allow duplicates.
- if (!isListItemOnOrAssignment) {
- if (_object->propertyNames.contains(name))
- COMPILE_EXCEPTION(nameLocation, tr("Duplicate property name"));
-
- _object->propertyNames.insert(name);
- }
-
- if (name.at(0).isUpper())
- COMPILE_EXCEPTION(nameLocation, tr("Property names cannot begin with an upper case letter"));
-
- if (illegalNames.contains(name))
- COMPILE_EXCEPTION(nameLocation, tr("Illegal property name"));
-
+ *nameToResolve = qualifiedIdElement;
return true;
}
@@ -1016,18 +1134,21 @@ void QQmlCodeGenerator::recordError(const AST::SourceLocation &location, const Q
void QQmlCodeGenerator::collectTypeReferences()
{
foreach (QmlObject *obj, _objects) {
- if (!stringAt(obj->inheritedTypeNameIndex).isEmpty())
- _typeReferences.add(obj->inheritedTypeNameIndex, obj->location);
+ if (obj->inheritedTypeNameIndex != emptyStringIndex) {
+ QV4::CompiledData::TypeReference &r = _typeReferences.add(obj->inheritedTypeNameIndex, obj->location);
+ r.needsCreation = true;
+ }
- for (QmlProperty *prop = obj->properties->first; prop; prop = prop->next) {
+ for (const QmlProperty *prop = obj->firstProperty(); prop; prop = prop->next) {
if (prop->type >= QV4::CompiledData::Property::Custom) {
// ### FIXME: We could report the more accurate location here by using prop->location, but the old
// compiler can't and the tests expect it to be the object location right now.
- _typeReferences.add(prop->customTypeNameIndex, obj->location);
+ QV4::CompiledData::TypeReference &r = _typeReferences.add(prop->customTypeNameIndex, obj->location);
+ r.needsCreation = true;
}
}
- for (Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ for (const Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
_typeReferences.add(binding->propertyNameIndex, binding->location);
}
@@ -1085,10 +1206,10 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const
int objectsSize = 0;
foreach (QmlObject *o, output.objects) {
objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize);
- objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functions->count, o->properties->count, o->qmlSignals->count, o->bindings->count);
+ objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount());
int signalTableSize = 0;
- for (Signal *s = o->qmlSignals->first; s; s = s->next)
+ for (const Signal *s = o->firstSignal(); s; s = s->next)
signalTableSize += QV4::CompiledData::Signal::calculateSize(s->parameters->count);
objectsSize += signalTableSize;
@@ -1131,46 +1252,45 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const
quint32 nextOffset = sizeof(QV4::CompiledData::Object);
- objectToWrite->nFunctions = o->functions->count;
+ objectToWrite->nFunctions = o->functionCount();
objectToWrite->offsetToFunctions = nextOffset;
nextOffset += objectToWrite->nFunctions * sizeof(quint32);
- objectToWrite->nProperties = o->properties->count;
+ objectToWrite->nProperties = o->propertyCount();
objectToWrite->offsetToProperties = nextOffset;
nextOffset += objectToWrite->nProperties * sizeof(QV4::CompiledData::Property);
- objectToWrite->nSignals = o->qmlSignals->count;
+ objectToWrite->nSignals = o->signalCount();
objectToWrite->offsetToSignals = nextOffset;
nextOffset += objectToWrite->nSignals * sizeof(quint32);
- objectToWrite->nBindings = o->bindings->count;
+ objectToWrite->nBindings = o->bindingCount();
objectToWrite->offsetToBindings = nextOffset;
nextOffset += objectToWrite->nBindings * sizeof(QV4::CompiledData::Binding);
quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions);
- for (Function *f = o->functions->first; f; f = f->next)
+ for (const Function *f = o->firstFunction(); f; f = f->next)
*functionsTable++ = runtimeFunctionIndices[f->index];
char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
- for (QmlProperty *p = o->properties->first; p; p = p->next) {
+ for (const QmlProperty *p = o->firstProperty(); p; p = p->next) {
QV4::CompiledData::Property *propertyToWrite = reinterpret_cast<QV4::CompiledData::Property*>(propertiesPtr);
*propertyToWrite = *p;
propertiesPtr += sizeof(QV4::CompiledData::Property);
}
char *bindingPtr = objectPtr + objectToWrite->offsetToBindings;
- for (Binding *b = o->bindings->first; b; b = b->next) {
- QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
- *bindingToWrite = *b;
- if (b->type == QV4::CompiledData::Binding::Type_Script)
- bindingToWrite->value.compiledScriptIndex = runtimeFunctionIndices[b->value.compiledScriptIndex];
- bindingPtr += sizeof(QV4::CompiledData::Binding);
- }
+ bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isValueBindingNoAlias);
+ bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isSignalHandler);
+ bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isAttachedProperty);
+ bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isGroupProperty);
+ bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isValueBindingToAlias);
+ Q_ASSERT((bindingPtr - objectToWrite->offsetToBindings - objectPtr) / sizeof(QV4::CompiledData::Binding) == unsigned(o->bindingCount()));
quint32 *signalOffsetTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToSignals);
quint32 signalTableSize = 0;
char *signalPtr = objectPtr + nextOffset;
- for (Signal *s = o->qmlSignals->first; s; s = s->next) {
+ for (const Signal *s = o->firstSignal(); s; s = s->next) {
*signalOffsetTable++ = signalPtr - objectPtr;
QV4::CompiledData::Signal *signalToWrite = reinterpret_cast<QV4::CompiledData::Signal*>(signalPtr);
@@ -1187,7 +1307,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const
signalPtr += size;
}
- objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functions->count, o->properties->count, o->qmlSignals->count, o->bindings->count);
+ objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount());
objectPtr += signalTableSize;
}
@@ -1202,6 +1322,20 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const
return qmlUnit;
}
+char *QmlUnitGenerator::writeBindings(char *bindingPtr, QmlObject *o, const QVector<int> &runtimeFunctionIndices, BindingFilter filter) const
+{
+ for (const Binding *b = o->firstBinding(); b; b = b->next) {
+ if (!(b->*(filter))())
+ continue;
+ QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
+ *bindingToWrite = *b;
+ if (b->type == QV4::CompiledData::Binding::Type_Script)
+ bindingToWrite->value.compiledScriptIndex = runtimeFunctionIndices[b->value.compiledScriptIndex];
+ bindingPtr += sizeof(QV4::CompiledData::Binding);
+ }
+ return bindingPtr;
+}
+
int QmlUnitGenerator::getStringId(const QString &str) const
{
return jsUnitGenerator->getStringId(str);
@@ -1623,6 +1757,7 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlEnginePrivate *enginePrivate,
: enginePrivate(enginePrivate)
, parsedQML(parsedQML)
, unit(unit)
+ , illegalNames(QV8Engine::get(QQmlEnginePrivate::get(enginePrivate))->illegalNames())
{
}
@@ -1651,7 +1786,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
// map from signal name defined in qml itself to list of parameters
QHash<QString, QStringList> customSignals;
- for (Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ for (Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
QString propertyName = stringAt(binding->propertyNameIndex);
// Attached property?
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
@@ -1690,8 +1825,22 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
QQmlPropertyData *signal = resolver.signal(propertyName, &notInRevision);
if (signal) {
int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex);
- foreach (const QByteArray &param, propertyCache->signalParameterNames(sigIndex))
- parameters << QString::fromUtf8(param);
+ sigIndex = propertyCache->originalClone(sigIndex);
+
+ bool unnamedParameter = false;
+
+ QList<QByteArray> parameterNames = propertyCache->signalParameterNames(sigIndex);
+ for (int i = 0; i < parameterNames.count(); ++i) {
+ const QString param = QString::fromUtf8(parameterNames.at(i));
+ if (param.isEmpty())
+ unnamedParameter = true;
+ else if (unnamedParameter) {
+ COMPILE_EXCEPTION(binding->location, tr("Signal uses unnamed parameter followed by named parameter."));
+ } else if (illegalNames.contains(param)) {
+ COMPILE_EXCEPTION(binding->location, tr("Signal parameter \"%1\" hides global variable.").arg(param));
+ }
+ parameters += param;
+ }
} else {
if (notInRevision) {
// Try assinging it as a property later
@@ -1713,12 +1862,12 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
// build cache if necessary
if (customSignals.isEmpty()) {
- for (Signal *signal = obj->qmlSignals->first; signal; signal = signal->next) {
+ for (const Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
const QString &signalName = stringAt(signal->nameIndex);
customSignals.insert(signalName, signal->parameterStringList(parsedQML->jsGenerator.strings));
}
- for (QmlProperty *property = obj->properties->first; property; property = property->next) {
+ for (const QmlProperty *property = obj->firstProperty(); property; property = property->next) {
const QString propName = stringAt(property->nameIndex);
customSignals.insert(propName, QStringList());
}
@@ -1739,6 +1888,14 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
parameters = entry.value();
}
+ binding->propertyNameIndex = parsedQML->jsGenerator.registerString(propertyName);
+
+ // Binding object to signal means connect the signal to the object's default method.
+ if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerObject;
+ continue;
+ }
+
if (binding->type != QV4::CompiledData::Binding::Type_Script) {
COMPILE_EXCEPTION(binding->location, tr("Incorrectly specified signal assignment"));
}
@@ -1770,7 +1927,6 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
parsedQML->functions[binding->value.compiledScriptIndex] = functionDeclaration;
binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
- binding->propertyNameIndex = parsedQML->jsGenerator.registerString(propertyName);
}
return true;
}
@@ -1785,11 +1941,11 @@ void SignalHandlerConverter::recordError(const QV4::CompiledData::Location &loca
errors << error;
}
-QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision)
+QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, QObject *object, QQmlContextData *context)
{
if (notInRevision) *notInRevision = false;
- QQmlPropertyData *d = cache->property(name, 0, 0);
+ QQmlPropertyData *d = cache->property(name, object, context);
// Find the first property
while (d && d->isFunction())
@@ -1804,11 +1960,11 @@ QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRev
}
-QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision)
+QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision, QObject *object, QQmlContextData *context)
{
if (notInRevision) *notInRevision = false;
- QQmlPropertyData *d = cache->property(name, 0, 0);
+ QQmlPropertyData *d = cache->property(name, object, context);
if (notInRevision) *notInRevision = false;
while (d && !(d->isFunction()))
@@ -1824,7 +1980,7 @@ QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevis
if (name.endsWith(QStringLiteral("Changed"))) {
QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed")));
- d = property(propName, notInRevision);
+ d = property(propName, notInRevision, object, context);
if (d)
return cache->signal(d->notifyIndex);
}
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index c296a3e624..7c09b8bfa2 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -93,15 +93,49 @@ struct PoolList
T *last;
int count;
- void append(T *item) {
+ int append(T *item) {
item->next = 0;
if (last)
last->next = item;
else
first = item;
last = item;
+ return count++;
+ }
+
+ void prepend(T *item) {
+ item->next = first;
+ first = item;
+ if (!last)
+ last = first;
++count;
}
+
+ template <typename Sortable, typename Base, Sortable Base::*sortMember>
+ T *findSortedInsertionPoint(T *item) const
+ {
+ T *insertPos = 0;
+
+ for (T *it = first; it; it = it->next) {
+ if (!(it->*sortMember < item->*sortMember))
+ break;
+ insertPos = it;
+ }
+
+ return insertPos;
+ }
+
+ void insertAfter(T *insertionPoint, T *item) {
+ if (!insertionPoint) {
+ prepend(item);
+ } else if (insertionPoint == last) {
+ append(item);
+ } else {
+ item->next = insertionPoint->next;
+ insertionPoint->next = item;
+ ++count;
+ }
+ }
};
struct QmlObject;
@@ -137,31 +171,71 @@ struct Function
{
AST::FunctionDeclaration *functionDeclaration;
QV4::CompiledData::Location location;
+ int nameIndex;
int index; // index in parsedQML::functions
Function *next;
};
+struct CompiledFunctionOrExpression
+{
+ CompiledFunctionOrExpression()
+ : node(0)
+ , disableAcceleratedLookups(false)
+ {}
+ CompiledFunctionOrExpression(AST::Node *n)
+ : node(n)
+ , disableAcceleratedLookups(false)
+ {}
+ AST::Node *node; // FunctionDeclaration, Statement or Expression
+ QString name;
+ bool disableAcceleratedLookups;
+};
+
struct QmlObject
{
- int inheritedTypeNameIndex;
- int idIndex;
+ Q_DECLARE_TR_FUNCTIONS(QmlObject)
+public:
+ quint32 inheritedTypeNameIndex;
+ quint32 idIndex;
int indexOfDefaultProperty;
QV4::CompiledData::Location location;
QV4::CompiledData::Location locationOfIdProperty;
- PoolList<QmlProperty> *properties;
- PoolList<Signal> *qmlSignals;
- PoolList<Binding> *bindings;
- PoolList<Function> *functions;
+ const QmlProperty *firstProperty() const { return properties->first; }
+ int propertyCount() const { return properties->count; }
+ const Signal *firstSignal() const { return qmlSignals->first; }
+ int signalCount() const { return qmlSignals->count; }
+ Binding *firstBinding() const { return bindings->first; }
+ int bindingCount() const { return bindings->count; }
+ const Function *firstFunction() const { return functions->first; }
+ int functionCount() const { return functions->count; }
- // caches to quickly find duplicates
- QSet<QString> propertyNames;
- QSet<QString> signalNames;
+ // If set, then declarations for this object (and init bindings for these) should go into the
+ // specified object. Used for declarations inside group properties.
+ QmlObject *declarationsOverride;
void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const AST::SourceLocation &location = AST::SourceLocation());
void dump(DebugStream &out);
+
+ QString sanityCheckFunctionNames(const QList<CompiledFunctionOrExpression> &allFunctions, const QSet<QString> &illegalNames, AST::SourceLocation *errorLocation);
+
+ QString appendSignal(Signal *signal);
+ QString appendProperty(QmlProperty *prop, const QString &propertyName, bool isDefaultProperty, const AST::SourceLocation &defaultToken, AST::SourceLocation *errorLocation);
+ void appendFunction(Function *f);
+
+ QString appendBinding(Binding *b, bool isListBinding);
+
+private:
+ PoolList<QmlProperty> *properties;
+ PoolList<Signal> *qmlSignals;
+ PoolList<Binding> *bindings;
+ PoolList<Function> *functions;
+
+ QSet<int> propertyNames;
+ QSet<int> bindingNames;
+ QSet<int> signalNames;
};
struct Pragma
@@ -174,21 +248,6 @@ struct Pragma
QV4::CompiledData::Location location;
};
-struct CompiledFunctionOrExpression
-{
- CompiledFunctionOrExpression()
- : node(0)
- , disableAcceleratedLookups(false)
- {}
- CompiledFunctionOrExpression(AST::Node *n)
- : node(n)
- , disableAcceleratedLookups(false)
- {}
- AST::Node *node; // FunctionDeclaration, Statement or Expression
- QString name;
- bool disableAcceleratedLookups;
-};
-
struct ParsedQML
{
ParsedQML(bool debugMode)
@@ -243,9 +302,9 @@ public:
void accept(AST::Node *node);
// returns index in _objects
- int defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId, AST::UiObjectInitializer *initializer);
- int defineQMLObject(AST::UiObjectDefinition *node)
- { return defineQMLObject(node->qualifiedTypeNameId, node->initializer); }
+ int defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId, const AST::SourceLocation &location, AST::UiObjectInitializer *initializer, QmlObject *declarationsOverride = 0);
+ int defineQMLObject(AST::UiObjectDefinition *node, QmlObject *declarationsOverride = 0)
+ { return defineQMLObject(node->qualifiedTypeNameId, node->qualifiedTypeNameId->firstSourceLocation(), node->initializer, declarationsOverride); }
static QString asString(AST::UiQualifiedId *node);
QStringRef asStringRef(AST::Node *node);
@@ -263,24 +322,24 @@ public:
void appendBinding(AST::UiQualifiedId *name, AST::Statement *value);
void appendBinding(AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment = false);
- void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, AST::Statement *value);
- void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false);
+ void appendBinding(const AST::SourceLocation &nameLocation, quint32 propertyNameIndex, AST::Statement *value);
+ void appendBinding(const AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false);
- bool setId(AST::Statement *value);
+ QmlObject *bindingsTarget() const;
+
+ bool setId(const AST::SourceLocation &idLocation, AST::Statement *value);
// resolves qualified name (font.pixelSize for example) and returns the last name along
// with the object any right-hand-side of a binding should apply to.
bool resolveQualifiedId(AST::UiQualifiedId **nameToResolve, QmlObject **object);
- bool sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex, bool isListItemOnOrAssignment = false);
-
void recordError(const AST::SourceLocation &location, const QString &description);
void collectTypeReferences();
static QQmlScript::LocationSpan location(AST::SourceLocation start, AST::SourceLocation end);
- int registerString(const QString &str) const { return jsGenerator->registerString(str); }
+ quint32 registerString(const QString &str) const { return jsGenerator->registerString(str); }
template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
QString stringAt(int index) const { return jsGenerator->strings.at(index); }
@@ -299,13 +358,12 @@ public:
QV4::CompiledData::TypeReferenceMap _typeReferences;
QmlObject *_object;
+ QmlProperty *_propertyDeclaration;
QQmlJS::MemoryPool *pool;
QString sourceCode;
QUrl url;
QV4::Compiler::JSUnitGenerator *jsGenerator;
- int emptyStringIndex;
- bool sanityCheckFunctionNames();
};
struct Q_QML_EXPORT QmlUnitGenerator
@@ -318,6 +376,9 @@ struct Q_QML_EXPORT QmlUnitGenerator
QV4::CompiledData::QmlUnit *generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices);
private:
+ typedef bool (Binding::*BindingFilter)() const;
+ char *writeBindings(char *bindingPtr, QmlObject *o, const QVector<int> &runtimeFunctionIndices, BindingFilter filter) const;
+
int getStringId(const QString &str) const;
QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
@@ -334,10 +395,10 @@ struct PropertyResolver
return cache->property(index);
}
- QQmlPropertyData *property(const QString &name, bool *notInRevision = 0);
+ QQmlPropertyData *property(const QString &name, bool *notInRevision = 0, QObject *object = 0, QQmlContextData *context = 0);
// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
- QQmlPropertyData *signal(const QString &name, bool *notInRevision);
+ QQmlPropertyData *signal(const QString &name, bool *notInRevision, QObject *object = 0, QQmlContextData *context = 0);
QQmlPropertyCache *cache;
};
@@ -366,6 +427,7 @@ private:
QQmlEnginePrivate *enginePrivate;
ParsedQML *parsedQML;
QQmlCompiledData *unit;
+ const QSet<QString> &illegalNames;
};
struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 06ee180119..dae57fe6f4 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -46,6 +46,7 @@
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlcomponent_p.h>
+#include <private/qqmlstringconverters_p.h>
#define COMPILE_EXCEPTION(token, desc) \
{ \
@@ -83,7 +84,7 @@ bool QQmlTypeCompiler::compile()
QScopedPointer<QQmlCompiledData::TypeReference> ref(new QQmlCompiledData::TypeReference);
QQmlType *qmlType = resolvedType->type;
if (resolvedType->typeData) {
- if (qmlType->isCompositeSingleton()) {
+ if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) {
QQmlError error;
QString reason = tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName());
error.setDescription(reason);
@@ -98,7 +99,7 @@ bool QQmlTypeCompiler::compile()
ref->type = qmlType;
Q_ASSERT(ref->type);
- if (!ref->type->isCreatable()) {
+ if (resolvedType->needsCreation && !ref->type->isCreatable()) {
QQmlError error;
QString reason = ref->type->noCreationReason();
if (reason.isEmpty())
@@ -149,6 +150,17 @@ bool QQmlTypeCompiler::compile()
}
}
+ {
+ QQmlEnumTypeResolver enumResolver(this);
+ if (!enumResolver.resolveEnumBindings())
+ return false;
+ }
+
+ {
+ QQmlAliasAnnotator annotator(this);
+ annotator.annotateBindingsToAliases();
+ }
+
// Collect imported scripts
const QList<QQmlTypeData::ScriptReference> &scripts = typeData->resolvedScripts();
compiledData->scripts.reserve(scripts.count());
@@ -183,6 +195,11 @@ bool QQmlTypeCompiler::compile()
JSCodeGen jsCodeGen(typeData->finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, compiledData->importCache);
const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions);
+ QList<QQmlError> jsErrors = jsCodeGen.errors();
+ if (!jsErrors.isEmpty()) {
+ errors << jsErrors;
+ return false;
+ }
QV4::ExecutionEngine *v4 = engine->v4engine();
@@ -227,6 +244,27 @@ bool QQmlTypeCompiler::compile()
if (!validator.validate())
return false;
+ // Collect some data for instantiation later.
+ int bindingCount = 0;
+ int parserStatusCount = 0;
+ for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
+ bindingCount += obj->nBindings;
+ if (QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ if (QQmlType *qmlType = typeRef->type) {
+ if (qmlType->parserStatusCast() != -1)
+ ++parserStatusCount;
+ }
+ if (typeRef->component) {
+ bindingCount += typeRef->component->totalBindingsCount;
+ parserStatusCount += typeRef->component->totalParserStatusCount;
+ }
+ }
+ }
+
+ compiledData->totalBindingsCount = bindingCount;
+ compiledData->totalParserStatusCount = parserStatusCount;
+
return errors.isEmpty();
}
@@ -380,10 +418,29 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r
const QmlObject *obj = qmlObjects.at(objectIndex);
QQmlPropertyCache *baseTypeCache = 0;
+ QQmlPropertyData *instantiatingProperty = 0;
+ if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ Q_ASSERT(referencingObjectIndex >= 0);
+ QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex);
+ Q_ASSERT(parentCache);
+ Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
- bool needVMEMetaObject = obj->properties->count != 0 || obj->qmlSignals->count != 0 || obj->functions->count != 0;
+ bool notInRevision = false;
+ instantiatingProperty = PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), &notInRevision);
+ if (instantiatingProperty) {
+ if (instantiatingProperty->isQObject()) {
+ baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType);
+ Q_ASSERT(baseTypeCache);
+ } else if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(instantiatingProperty->propType)) {
+ baseTypeCache = enginePrivate->cache(vt->metaObject());
+ Q_ASSERT(baseTypeCache);
+ }
+ }
+ }
+
+ bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
if (!needVMEMetaObject) {
- for (const QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ for (const QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
// On assignments are implemented using value interceptors, which require a VME meta object.
@@ -393,30 +450,17 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r
// group properties and value type group properties. For the former the base type is derived from
// the property that references us, for the latter we only need a meta-object on the referencing object
// because interceptors can't go to the shared value type instances.
- if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
- QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex);
- Q_ASSERT(parentCache);
- Q_ASSERT(!stringAt(instantiatingBinding->propertyNameIndex).isEmpty());
-
- bool notInRevision = false;
- QQmlPropertyData *pd = PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), &notInRevision);
- Q_ASSERT(pd);
- if (QQmlValueTypeFactory::isValueType(pd->propType)) {
- needVMEMetaObject = false;
- if (!ensureMetaObject(referencingObjectIndex))
- return false;
- } else if (pd->isQObject()) {
- baseTypeCache = enginePrivate->rawPropertyCacheForType(pd->propType);
- Q_ASSERT(baseTypeCache);
- }
+ if (instantiatingProperty && QQmlValueTypeFactory::isValueType(instantiatingProperty->propType)) {
+ needVMEMetaObject = false;
+ if (!ensureMetaObject(referencingObjectIndex))
+ return false;
}
break;
}
}
}
- QString typeName = stringAt(obj->inheritedTypeNameIndex);
- if (!typeName.isEmpty()) {
+ if (obj->inheritedTypeNameIndex != 0) {
QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
@@ -431,10 +475,12 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r
baseTypeCache->addref();
}
- for (const QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next)
- if (binding->type == QV4::CompiledData::Binding::Type_Object)
- if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding))
- return false;
+ if (propertyCaches.at(objectIndex)) {
+ for (const QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next)
+ if (binding->type == QV4::CompiledData::Binding::Type_Object || binding->type == QV4::CompiledData::Binding::Type_GroupProperty)
+ if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding))
+ return false;
+ }
return true;
}
@@ -453,9 +499,9 @@ bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex)
bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::QmlObject *obj, QQmlPropertyCache *baseTypeCache)
{
QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate),
- obj->properties->count,
- obj->functions->count + obj->properties->count + obj->qmlSignals->count,
- obj->qmlSignals->count + obj->properties->count);
+ obj->propertyCount(),
+ obj->functionCount() + obj->propertyCount() + obj->signalCount(),
+ obj->signalCount() + obj->propertyCount());
propertyCaches[objectIndex] = cache;
struct TypeData {
@@ -510,25 +556,26 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
int aliasCount = 0;
int varPropCount = 0;
- for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next) {
+ PropertyResolver resolver(baseTypeCache);
+
+ for (const QtQml::QmlProperty *p = obj->firstProperty(); p; p = p->next) {
if (p->type == QV4::CompiledData::Property::Alias)
aliasCount++;
else if (p->type == QV4::CompiledData::Property::Var)
varPropCount++;
-#if 0 // ### Do this elsewhere
// No point doing this for both the alias and non alias cases
- QQmlPropertyData *d = property(obj, p->name);
+ bool notInRevision = false;
+ QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
if (d && d->isFinal())
COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
-#endif
}
typedef QQmlVMEMetaData VMD;
QByteArray &dynamicData = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData)
- + obj->properties->count * sizeof(VMD::PropertyData)
- + obj->functions->count * sizeof(VMD::MethodData)
+ + obj->propertyCount() * sizeof(VMD::PropertyData)
+ + obj->functionCount() * sizeof(VMD::MethodData)
+ aliasCount * sizeof(VMD::AliasData), 0);
int effectivePropertyIndex = cache->propertyIndexCacheStart;
@@ -564,7 +611,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
if (ii == NSS_Var && varPropCount == 0) continue;
else if (ii == NSS_Alias && aliasCount == 0) continue;
- for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next) {
+ for (const QtQml::QmlProperty *p = obj->firstProperty(); p; p = p->next) {
if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias ||
p->type == QV4::CompiledData::Property::Var)) ||
((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) ||
@@ -582,7 +629,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
}
// Dynamic signals
- for (QtQml::Signal *s = obj->qmlSignals->first; s; s = s->next) {
+ for (const QtQml::Signal *s = obj->firstSignal(); s; s = s->next) {
const int paramCount = s->parameters->count;
QList<QByteArray> names;
@@ -640,7 +687,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
// Dynamic slots
- for (QtQml::Function *s = obj->functions->first; s; s = s->next) {
+ for (const QtQml::Function *s = obj->firstFunction(); s; s = s->next) {
AST::FunctionDeclaration *astFunction = s->functionDeclaration;
quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
@@ -668,7 +715,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
// Dynamic properties (except var and aliases)
int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
int propertyIdx = 0;
- for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next, ++propertyIdx) {
+ for (const QtQml::QmlProperty *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {
if (p->type == QV4::CompiledData::Property::Alias ||
p->type == QV4::CompiledData::Property::Var)
@@ -744,7 +791,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
// Now do var properties
propertyIdx = 0;
- for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next, ++propertyIdx) {
+ for (const QtQml::QmlProperty *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {
if (p->type != QV4::CompiledData::Property::Var)
continue;
@@ -770,7 +817,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
// Dynamic slot data - comes after the property data
- for (QtQml::Function *s = obj->functions->first; s; s = s->next) {
+ for (const QtQml::Function *s = obj->firstFunction(); s; s = s->next) {
AST::FunctionDeclaration *astFunction = s->functionDeclaration;
int formalsCount = 0;
AST::FormalParameterList *param = astFunction->formals;
@@ -792,6 +839,187 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
return true;
}
+QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler)
+ : QQmlCompilePass(typeCompiler)
+ , qmlObjects(*typeCompiler->qmlObjects())
+ , propertyCaches(typeCompiler->propertyCaches())
+ , imports(typeCompiler->imports())
+ , resolvedTypes(typeCompiler->resolvedTypes())
+{
+}
+
+bool QQmlEnumTypeResolver::resolveEnumBindings()
+{
+ for (int i = 0; i < qmlObjects.count(); ++i) {
+ QQmlPropertyCache *propertyCache = propertyCaches.at(i);
+ if (!propertyCache)
+ continue;
+ const QmlObject *obj = qmlObjects.at(i);
+
+ PropertyResolver resolver(propertyCache);
+
+ for (QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ continue;
+
+ if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ continue;
+
+ const QString propertyName = stringAt(binding->propertyNameIndex);
+ bool notInRevision = false;
+ QQmlPropertyData *pd = resolver.property(propertyName, &notInRevision);
+ if (!pd)
+ continue;
+
+ if (!pd->isEnum() && pd->propType != QMetaType::Int)
+ continue;
+
+ if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &staticQtMetaObject; }
+};
+
+bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlObject *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, Binding *binding)
+{
+ bool isIntProp = (prop->propType == QMetaType::Int) && !prop->isEnum();
+ if (!prop->isEnum() && !isIntProp)
+ return true;
+
+ if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))
+ COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex)));
+
+ Q_ASSERT(binding->type = QV4::CompiledData::Binding::Type_Script);
+ QString string = stringAt(binding->stringIndex);
+ if (!string.at(0).isUpper())
+ return true;
+
+ int dot = string.indexOf(QLatin1Char('.'));
+ if (dot == -1 || dot == string.length()-1)
+ return true;
+
+ if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
+ return true;
+
+ QHashedStringRef typeName(string.constData(), dot);
+ QString enumValue = string.mid(dot+1);
+
+ if (isIntProp) {
+ // Allow enum assignment to ints.
+ bool ok;
+ int enumval = evaluateEnum(typeName.toString(), enumValue.toUtf8(), &ok);
+ if (ok) {
+ binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->value.d = (double)enumval;
+ binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
+ }
+ return true;
+ }
+ QQmlType *type = 0;
+ imports->resolveType(typeName, &type, 0, 0, 0);
+
+ if (!type && typeName != QLatin1String("Qt"))
+ return true;
+ if (type && type->isComposite()) //No enums on composite (or composite singleton) types
+ return true;
+
+ int value = 0;
+ bool ok = false;
+
+ QQmlCompiledData::TypeReference *tr = resolvedTypes->value(obj->inheritedTypeNameIndex);
+ if (type && tr && tr->type == type) {
+ QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex);
+
+ // When these two match, we can short cut the search
+ if (mprop.isFlagType()) {
+ value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
+ } else {
+ value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
+ }
+ } else {
+ // Otherwise we have to search the whole type
+ if (type) {
+ value = type->enumValue(QHashedStringRef(enumValue), &ok);
+ } else {
+ QByteArray enumName = enumValue.toUtf8();
+ const QMetaObject *metaObject = StaticQtMetaObject::get();
+ for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ value = e.keyToValue(enumName.constData(), &ok);
+ }
+ }
+ }
+
+ if (!ok)
+ return true;
+
+ binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->value.d = (double)value;
+ binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
+ return true;
+}
+
+int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const
+{
+ Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer");
+ *ok = false;
+
+ if (scope != QLatin1String("Qt")) {
+ QQmlType *type = 0;
+ imports->resolveType(scope, &type, 0, 0, 0);
+ return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
+ }
+
+ const QMetaObject *mo = StaticQtMetaObject::get();
+ int i = mo->enumeratorCount();
+ while (i--) {
+ int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ if (*ok)
+ return v;
+ }
+ return -1;
+}
+
+
+QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
+ : QQmlCompilePass(typeCompiler)
+ , qmlObjects(*typeCompiler->qmlObjects())
+ , propertyCaches(typeCompiler->propertyCaches())
+{
+}
+
+void QQmlAliasAnnotator::annotateBindingsToAliases()
+{
+ for (int i = 0; i < qmlObjects.count(); ++i) {
+ QQmlPropertyCache *propertyCache = propertyCaches.at(i);
+ if (!propertyCache)
+ continue;
+
+ const QmlObject *obj = qmlObjects.at(i);
+
+ PropertyResolver resolver(propertyCache);
+ QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+
+ for (QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ if (!binding->isValueBinding())
+ continue;
+ bool notInRevision = false;
+ QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
+ if (pd && pd->isAlias())
+ binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
+ }
+ }
+}
+
QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, enginePrivate(typeCompiler->enginePrivate())
@@ -818,10 +1046,10 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQm
QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
- for (QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ for (QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Object)
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
continue;
const QtQml::QmlObject *targetObject = qmlObjects->at(binding->value.objectIndex);
@@ -832,10 +1060,9 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQm
continue;
QQmlPropertyData *pd = 0;
- QString propertyName = stringAt(binding->propertyNameIndex);
- if (!propertyName.isEmpty()) {
+ if (binding->propertyNameIndex != 0) {
bool notInRevision = false;
- pd = propertyResolver.property(propertyName, &notInRevision);
+ pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
} else {
pd = defaultProperty;
}
@@ -873,7 +1100,9 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQm
QtQml::Binding *syntheticBinding = pool->New<QtQml::Binding>();
*syntheticBinding = *binding;
syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
- syntheticComponent->bindings->append(syntheticBinding);
+ QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
+ Q_ASSERT(error.isEmpty());
+ Q_UNUSED(error);
binding->value.objectIndex = componentIndex;
@@ -891,7 +1120,7 @@ bool QQmlComponentAndAliasResolver::resolve()
const int objCountWithoutSynthesizedComponents = qmlObjects->count();
for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
const QtQml::QmlObject *obj = qmlObjects->at(i);
- if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ if (obj->inheritedTypeNameIndex == 0)
continue;
QQmlCompiledData::TypeReference *tref = resolvedTypes->value(obj->inheritedTypeNameIndex);
@@ -903,17 +1132,17 @@ bool QQmlComponentAndAliasResolver::resolve()
componentRoots.append(i);
- if (obj->functions->count > 0)
+ if (obj->functionCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
- if (obj->properties->count > 0)
+ if (obj->propertyCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
- if (obj->qmlSignals->count > 0)
+ if (obj->signalCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
- if (obj->bindings->count == 0)
+ if (obj->bindingCount() == 0)
COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
- const QtQml::Binding *rootBinding = obj->bindings->first;
+ const QtQml::Binding *rootBinding = obj->firstBinding();
if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
@@ -924,7 +1153,7 @@ bool QQmlComponentAndAliasResolver::resolve()
for (int i = 0; i < componentRoots.count(); ++i) {
const QtQml::QmlObject *component = qmlObjects->at(componentRoots.at(i));
- const QtQml::Binding *rootBinding = component->bindings->first;
+ const QtQml::Binding *rootBinding = component->firstBinding();
_componentIndex = i;
_idToObjectIndex.clear();
@@ -957,8 +1186,7 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
{
const QtQml::QmlObject *obj = qmlObjects->at(objectIndex);
- QString id = stringAt(obj->idIndex);
- if (!id.isEmpty()) {
+ if (obj->idIndex != 0) {
if (_idToObjectIndex.contains(obj->idIndex)) {
recordError(obj->locationOfIdProperty, tr("id is not unique"));
return false;
@@ -967,14 +1195,14 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
_objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count());
}
- for (QtQml::QmlProperty *property = obj->properties->first; property; property = property->next) {
+ for (const QtQml::QmlProperty *property = obj->firstProperty(); property; property = property->next) {
if (property->type == QV4::CompiledData::Property::Alias) {
_objectsWithAliases.append(objectIndex);
break;
}
}
- for (QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ for (const QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Object
&& binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
&& binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
@@ -1003,8 +1231,8 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
int effectiveAliasIndex = 0;
- const QtQml::QmlProperty *p = obj->properties->first;
- for (int propertyIndex = 0; propertyIndex < obj->properties->count; ++propertyIndex, p = p->next) {
+ const QtQml::QmlProperty *p = obj->firstProperty();
+ for (int propertyIndex = 0; propertyIndex < obj->propertyCount(); ++propertyIndex, p = p->next) {
if (p->type != QV4::CompiledData::Property::Alias)
continue;
@@ -1141,6 +1369,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector<int> &runtimeFunctionIndices)
: QQmlCompilePass(typeCompiler)
+ , enginePrivate(typeCompiler->enginePrivate())
, qmlUnit(typeCompiler->qmlUnit())
, resolvedTypes(*typeCompiler->resolvedTypes())
, propertyCaches(typeCompiler->propertyCaches())
@@ -1152,7 +1381,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, con
bool QQmlPropertyValidator::validate()
{
- if (!validateObject(qmlUnit->indexOfRootObject))
+ if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0))
return false;
compiler->setCustomParserBindings(customParserBindings);
return true;
@@ -1179,28 +1408,39 @@ QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::Comp
return id;
}
-bool QQmlPropertyValidator::validateObject(int objectIndex)
+bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding)
{
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
- if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
- return true;
- if (isComponent(objectIndex))
- return true;
+ if (isComponent(objectIndex)) {
+ Q_ASSERT(obj->nBindings == 1);
+ const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
+ Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ return validateObject(componentBinding->value.objectIndex, componentBinding);
+ }
QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
- Q_ASSERT(propertyCache);
+ if (!propertyCache)
+ return true;
QQmlCustomParser *customParser = 0;
QQmlCompiledData::TypeReference *objectType = resolvedTypes.value(obj->inheritedTypeNameIndex);
- Q_ASSERT(objectType);
- if (objectType->type)
+ if (objectType && objectType->type)
customParser = objectType->type->customParser();
QList<const QV4::CompiledData::Binding*> customBindings;
PropertyResolver propertyResolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+ QString defaultPropertyName;
+ QQmlPropertyData *defaultProperty = 0;
+ if (obj->indexOfDefaultProperty != -1) {
+ QQmlPropertyCache *cache = propertyCache->parent();
+ defaultPropertyName = cache->defaultPropertyName();
+ defaultProperty = cache->defaultProperty();
+ } else {
+ defaultPropertyName = propertyCache->defaultPropertyName();
+ defaultProperty = propertyCache->defaultProperty();
+ }
const QV4::CompiledData::Binding *binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
@@ -1223,39 +1463,76 @@ bool QQmlPropertyValidator::validateObject(int objectIndex)
}
if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- if (!validateObject(binding->value.objectIndex))
+ if (!validateObject(binding->value.objectIndex, binding))
return false;
// Nothing further to check for attached properties.
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
continue;
}
- const QString name = stringAt(binding->propertyNameIndex);
+ // Signal handlers were resolved and checked earlier in the signal handler conversion pass.
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ continue;
+
+ QString name = stringAt(binding->propertyNameIndex);
bool bindingToDefaultProperty = false;
bool notInRevision = false;
QQmlPropertyData *pd = 0;
if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
pd = propertyResolver.signal(name, &notInRevision);
else
pd = propertyResolver.property(name, &notInRevision);
if (notInRevision) {
QString typeName = stringAt(obj->inheritedTypeNameIndex);
- if (objectType->type) {
+ if (objectType && objectType->type) {
COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type->module()).arg(objectType->majorVersion).arg(objectType->minorVersion));
} else {
COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
}
}
} else {
+ if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty)
+ COMPILE_EXCEPTION(binding, tr("Cannot assign a value directly to a grouped property"));
+
pd = defaultProperty;
+ name = defaultPropertyName;
bindingToDefaultProperty = true;
}
- if (!pd) {
+ if (pd) {
+ if (!pd->isWritable()
+ && !pd->isQList()
+ && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
+ && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+ ) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
+ return false;
+ }
+
+ if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) {
+ QString error;
+ if (pd->propType == qMetaTypeId<QQmlScriptString>())
+ error = tr( "Cannot assign multiple values to a script property");
+ else
+ error = tr( "Cannot assign multiple values to a singular property");
+ recordError(binding->valueLocation, error);
+ return false;
+ }
+
+ if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ if (!validateLiteralBinding(propertyCache, pd, binding))
+ return false;
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ if (!validateObjectBinding(pd, name, binding))
+ return false;
+ }
+ } else {
if (customParser) {
customBindings << binding;
continue;
@@ -1285,4 +1562,347 @@ bool QQmlPropertyValidator::validateObject(int objectIndex)
return true;
}
+bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
+{
+ if (property->isEnum()) {
+ if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
+ return true;
+
+ QString value = binding->valueAsString(&qmlUnit->header);
+ QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex);
+ bool ok;
+ if (p.isFlagType()) {
+ p.enumerator().keysToValue(value.toUtf8().constData(), &ok);
+ } else
+ p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
+
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
+ return false;
+ }
+ return true;
+ }
+
+ switch (property->propType) {
+ case QMetaType::QVariant:
+ break;
+ case QVariant::String: {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: string expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::StringList: {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: string or string list expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::ByteArray: {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: byte array expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::Url: {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: url expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::UInt: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double d = binding->valueAsNumber();
+ if (double(uint(d)) == d)
+ return true;
+ }
+ recordError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected"));
+ return false;
+ }
+ break;
+ case QVariant::Int: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double d = binding->valueAsNumber();
+ if (double(int(d)) == d)
+ return true;
+ }
+ recordError(binding->valueLocation, tr("Invalid property assignment: int expected"));
+ return false;
+ }
+ break;
+ case QMetaType::Float: {
+ if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::Double: {
+ if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::Color: {
+ bool ok = false;
+ QQmlStringConverters::rgbaFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: color expected"));
+ return false;
+ }
+ }
+ break;
+#ifndef QT_NO_DATESTRING
+ case QVariant::Date: {
+ bool ok = false;
+ QQmlStringConverters::dateFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: date expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::Time: {
+ bool ok = false;
+ QQmlStringConverters::timeFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: time expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::DateTime: {
+ bool ok = false;
+ QQmlStringConverters::dateTimeFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: datetime expected"));
+ return false;
+ }
+ }
+ break;
+#endif // QT_NO_DATESTRING
+ case QVariant::Point: {
+ bool ok = false;
+ QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok).toPoint();
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::PointF: {
+ bool ok = false;
+ QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::Size: {
+ bool ok = false;
+ QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok).toSize();
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::SizeF: {
+ bool ok = false;
+ QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::Rect: {
+ bool ok = false;
+ QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok).toRect();
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: rect expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::RectF: {
+ bool ok = false;
+ QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (!ok) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::Bool: {
+ if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: boolean expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::Vector3D: {
+ struct {
+ float xp;
+ float yp;
+ float zy;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::Vector4D: {
+ struct {
+ float xp;
+ float yp;
+ float zy;
+ float wp;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected"));
+ return false;
+ }
+ }
+ break;
+ case QVariant::RegExp:
+ recordError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
+ return false;
+ default: {
+ // generate single literal value assignment to a list property if required
+ if (property->propType == qMetaTypeId<QList<qreal> >()) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: real or array of reals expected"));
+ return false;
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QList<int> >()) {
+ bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
+ if (ok) {
+ double n = binding->valueAsNumber();
+ if (double(int(n)) != n)
+ ok = false;
+ }
+ if (!ok)
+ recordError(binding->valueLocation, tr("Invalid property assignment: int or array of ints expected"));
+ break;
+ } else if (property->propType == qMetaTypeId<QList<bool> >()) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected"));
+ return false;
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected"));
+ return false;
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QList<QString> >()) {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ recordError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected"));
+ return false;
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QJSValue>()) {
+ break;
+ } else if (property->propType == qMetaTypeId<QQmlScriptString>()) {
+ break;
+ }
+
+ // otherwise, try a custom type assignment
+ QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType);
+ if (!converter) {
+ recordError(binding->location, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType))));
+ return false;
+ }
+ }
+ break;
+ }
+ return true;
+}
+
+bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding)
+{
+ if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
+
+ bool isValueSource = false;
+ bool isPropertyInterceptor = false;
+
+ QQmlType *qmlType = 0;
+ const QV4::CompiledData::Object *targetObject = qmlUnit->objectAt(binding->value.objectIndex);
+ QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex);
+ if (typeRef) {
+ QQmlPropertyCache *cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ const QMetaObject *mo = cache->firstCppMetaObject();
+ while (mo && !qmlType) {
+ qmlType = QQmlMetaType::qmlType(mo);
+ mo = mo->superClass();
+ }
+ Q_ASSERT(qmlType);
+ }
+
+ if (qmlType) {
+ isValueSource = qmlType->propertyValueSourceCast() != -1;
+ isPropertyInterceptor = qmlType->propertyValueInterceptorCast() != -1;
+ }
+
+ if (!isValueSource && !isPropertyInterceptor) {
+ recordError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName));
+ return false;
+ }
+
+ return true;
+ }
+ if (isComponent(binding->value.objectIndex))
+ return true;
+
+ if (QQmlMetaType::isInterface(property->propType)) {
+ // Can only check at instantiation time if the created sub-object successfully casts to the
+ // target interface.
+ return true;
+ } else if (property->propType == QMetaType::QVariant) {
+ // We can convert everything to QVariant :)
+ return true;
+ } else if (property->isQList()) {
+ // ### TODO: list error handling
+ return true;
+ } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
+ return true;
+ } else if (QQmlValueTypeFactory::isValueType(property->propType)) {
+ recordError(binding->location, tr("Unexpected object assignment"));
+ return false;
+ } else {
+ // We want to raw metaObject here as the raw metaobject is the
+ // actual property type before we applied any extensions that might
+ // effect the properties on the type, but don't effect assignability
+ QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType);
+
+ // Will be true if the assgned type inherits propertyMetaObject
+ bool isAssignable = false;
+ // Determine isAssignable value
+ if (propertyMetaObject) {
+ QQmlPropertyCache *c = propertyCaches.value(binding->value.objectIndex);
+ while (c && !isAssignable) {
+ isAssignable |= c == propertyMetaObject;
+ c = c->parent();
+ }
+ }
+
+ if (!isAssignable) {
+ recordError(binding->valueLocation, tr("Cannot assign object to property"));
+ return false;
+ }
+ }
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 28229a13a9..2e97d13481 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -139,6 +139,42 @@ protected:
QVector<QQmlPropertyCache*> propertyCaches;
};
+// ### This will go away when the codegen resolves all enums to constant expressions
+// and we replace the constant expression with a literal binding instead of using
+// a script.
+class QQmlEnumTypeResolver : public QQmlCompilePass
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlEnumTypeResolver)
+public:
+ QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler);
+
+ bool resolveEnumBindings();
+
+private:
+ bool tryQualifiedEnumAssignment(const QmlObject *obj, const QQmlPropertyCache *propertyCache,
+ const QQmlPropertyData *prop,
+ QtQml::Binding *binding);
+ int evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const;
+
+
+ const QList<QtQml::QmlObject*> &qmlObjects;
+ const QVector<QQmlPropertyCache *> propertyCaches;
+ const QQmlImports *imports;
+ QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes;
+};
+
+// Annotate properties bound to aliases with a flag
+class QQmlAliasAnnotator : public QQmlCompilePass
+{
+public:
+ QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler);
+
+ void annotateBindingsToAliases();
+private:
+ const QList<QtQml::QmlObject*> &qmlObjects;
+ const QVector<QQmlPropertyCache *> propertyCaches;
+};
+
class QQmlComponentAndAliasResolver : public QQmlCompilePass
{
Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver)
@@ -190,10 +226,13 @@ public:
virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser);
private:
- bool validateObject(int objectIndex);
+ bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding);
+ bool validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
+ bool validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding);
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
+ QQmlEnginePrivate *enginePrivate;
const QV4::CompiledData::QmlUnit *qmlUnit;
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
const QVector<QQmlPropertyCache *> &propertyCaches;
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 717e7f4ba2..aa8db06fd5 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -67,15 +67,15 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
assert(!runtimeStrings);
assert(data);
- runtimeStrings = (QV4::SafeString *)malloc(data->stringTableSize * sizeof(QV4::SafeString));
+ runtimeStrings = (QV4::StringValue *)malloc(data->stringTableSize * sizeof(QV4::StringValue));
// memset the strings to 0 in case a GC run happens while we're within the loop below
- memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::SafeString));
+ memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::StringValue));
for (uint i = 0; i < data->stringTableSize; ++i)
runtimeStrings[i] = engine->newIdentifier(data->stringAt(i));
- runtimeRegularExpressions = new QV4::SafeValue[data->regexpTableSize];
+ runtimeRegularExpressions = new QV4::Value[data->regexpTableSize];
// memset the regexps to 0 in case a GC run happens while we're within the loop below
- memset(runtimeRegularExpressions, 0, data->regexpTableSize * sizeof(QV4::SafeValue));
+ memset(runtimeRegularExpressions, 0, data->regexpTableSize * sizeof(QV4::Value));
for (uint i = 0; i < data->regexpTableSize; ++i) {
const CompiledData::RegExp *re = data->regexpAt(i);
int flags = 0;
@@ -95,21 +95,24 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
for (uint i = 0; i < data->lookupTableSize; ++i) {
QV4::Lookup *l = runtimeLookups + i;
- if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_Getter)
+ Lookup::Type type = Lookup::Type(compiledLookups[i].type_and_flags);
+ if (type == CompiledData::Lookup::Type_Getter)
l->getter = QV4::Lookup::getterGeneric;
- else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_Setter)
+ else if (type == CompiledData::Lookup::Type_Setter)
l->setter = QV4::Lookup::setterGeneric;
- else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_GlobalGetter)
+ else if (type == CompiledData::Lookup::Type_GlobalGetter)
l->globalGetter = QV4::Lookup::globalGetterGeneric;
- else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_IndexedGetter)
+ else if (type == CompiledData::Lookup::Type_IndexedGetter)
l->indexedGetter = QV4::Lookup::indexedGetterGeneric;
+ else if (type == CompiledData::Lookup::Type_IndexedSetter)
+ l->indexedSetter = QV4::Lookup::indexedSetterGeneric;
for (int j = 0; j < QV4::Lookup::Size; ++j)
l->classList[j] = 0;
l->level = -1;
l->index = UINT_MAX;
l->name = runtimeStrings[compiledLookups[i].nameIndex].asString();
- if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_IndexedGetter)
+ if (type == CompiledData::Lookup::Type_IndexedGetter || type == CompiledData::Lookup::Type_IndexedSetter)
l->engine = engine;
}
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 4208ec9441..94ea4bdc90 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -45,7 +45,7 @@
#include <QVector>
#include <QStringList>
#include <QHash>
-#include <private/qv4value_def_p.h>
+#include <private/qv4value_p.h>
#include <private/qv4executableallocator_p.h>
QT_BEGIN_NAMESPACE
@@ -70,17 +70,32 @@ struct RegExp;
struct Location
{
- int line;
- int column;
+ qint32 line;
+ qint32 column;
+ inline bool operator<(const Location &other) const {
+ return line < other.line ||
+ (line == other.line && column < other.column);
+ }
+};
+
+struct TypeReference
+{
+ TypeReference(const Location &loc)
+ : location(loc)
+ , needsCreation(false)
+ {}
+ Location location; // first use
+ bool needsCreation; // whether the type needs to be creatable or not
};
// map from name index to location of first use
-struct TypeReferenceMap : QHash<int, Location>
+struct TypeReferenceMap : QHash<int, TypeReference>
{
- void add(int nameIndex, const Location &loc) {
- if (contains(nameIndex))
- return;
- insert(nameIndex, loc);
+ TypeReference &add(int nameIndex, const Location &loc) {
+ Iterator it = find(nameIndex);
+ if (it != end())
+ return *it;
+ return *insert(nameIndex, loc);
}
};
@@ -103,7 +118,8 @@ struct Lookup
Type_Getter = 0x0,
Type_Setter = 0x1,
Type_GlobalGetter = 2,
- Type_IndexedGetter = 3
+ Type_IndexedGetter = 3,
+ Type_IndexedSetter = 4
};
quint32 type_and_flags;
@@ -189,8 +205,8 @@ struct Unit
const RegExp *regexpAt(int index) const {
return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
}
- const QV4::SafeValue *constants() const {
- return reinterpret_cast<const QV4::SafeValue*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
+ const QV4::Value *constants() const {
+ return reinterpret_cast<const QV4::Value*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
}
const JSClassMember *jsClassAt(int idx, int *nMembers) const {
@@ -282,7 +298,12 @@ struct Q_QML_EXPORT Binding
enum Flags {
IsSignalHandlerExpression = 0x1,
- IsOnAssignment = 0x2
+ IsSignalHandlerObject = 0x2,
+ IsOnAssignment = 0x4,
+ InitializerForReadOnlyDeclaration = 0x8,
+ IsResolvedEnum = 0x10,
+ IsListItem = 0x20,
+ IsBindingToAlias = 0x40
};
quint32 flags : 16;
@@ -296,6 +317,54 @@ struct Q_QML_EXPORT Binding
quint32 stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
Location location;
+ Location valueLocation;
+
+ bool isValueBinding() const
+ {
+ if (type == Type_AttachedProperty
+ || type == Type_GroupProperty)
+ return false;
+ if (flags & IsSignalHandlerExpression
+ || flags & IsSignalHandlerObject)
+ return false;
+ return true;
+ }
+
+ bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); }
+ bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); }
+
+ bool isSignalHandler() const
+ {
+ if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) {
+ Q_ASSERT(!isValueBinding());
+ Q_ASSERT(!isAttachedProperty());
+ Q_ASSERT(!isGroupProperty());
+ return true;
+ }
+ return false;
+ }
+
+ bool isAttachedProperty() const
+ {
+ if (type == Type_AttachedProperty) {
+ Q_ASSERT(!isValueBinding());
+ Q_ASSERT(!isSignalHandler());
+ Q_ASSERT(!isGroupProperty());
+ return true;
+ }
+ return false;
+ }
+
+ bool isGroupProperty() const
+ {
+ if (type == Type_GroupProperty) {
+ Q_ASSERT(!isValueBinding());
+ Q_ASSERT(!isSignalHandler());
+ Q_ASSERT(!isAttachedProperty());
+ return true;
+ }
+ return false;
+ }
QString valueAsString(const Unit *unit) const;
QString valueAsScriptString(const Unit *unit) const;
@@ -494,9 +563,9 @@ struct Q_QML_EXPORT CompilationUnit
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
- QV4::SafeString *runtimeStrings; // Array
+ QV4::StringValue *runtimeStrings; // Array
QV4::Lookup *runtimeLookups;
- QV4::SafeValue *runtimeRegularExpressions;
+ QV4::Value *runtimeRegularExpressions;
QV4::InternalClass **runtimeClasses;
QVector<QV4::Function *> runtimeFunctions;
// QVector<QV4::Function *> runtimeFunctionsSortedByAddress;
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index d18c43a969..bc47b815f2 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -53,6 +53,8 @@ QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QQmlJS::V4IR::Module *module, in
if (headerSize == -1)
headerSize = sizeof(QV4::CompiledData::Unit);
this->headerSize = headerSize;
+ // Make sure the empty string always gets index 0
+ registerString(QString());
}
int QV4::Compiler::JSUnitGenerator::registerString(const QString &str)
@@ -81,6 +83,15 @@ uint QV4::Compiler::JSUnitGenerator::registerIndexedGetterLookup()
return lookups.size() - 1;
}
+uint QV4::Compiler::JSUnitGenerator::registerIndexedSetterLookup()
+{
+ CompiledData::Lookup l;
+ l.type_and_flags = CompiledData::Lookup::Type_IndexedSetter;
+ l.nameIndex = 0;
+ lookups << l;
+ return lookups.size() - 1;
+}
+
uint QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name)
{
CompiledData::Lookup l;
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 4779b5d3c4..6baefae7b7 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -71,6 +71,7 @@ struct Q_QML_EXPORT JSUnitGenerator {
uint registerSetterLookup(const QString &name);
uint registerGlobalGetterLookup(const QString &name);
uint registerIndexedGetterLookup();
+ uint registerIndexedSetterLookup();
int registerRegExp(QQmlJS::V4IR::RegExp *regexp);
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index a2cc051003..e3e227796e 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -43,7 +43,7 @@
#define QV4INSTR_MOTH_P_H
#include <QtCore/qglobal.h>
-#include <private/qv4value_def_p.h>
+#include <private/qv4value_p.h>
#include <private/qv4function_p.h>
#include <private/qv4runtime_p.h>
@@ -51,16 +51,20 @@ QT_BEGIN_NAMESPACE
#define FOR_EACH_MOTH_INSTR(F) \
F(Ret, ret) \
+ F(Debug, debug) \
F(LoadRuntimeString, loadRuntimeString) \
F(LoadRegExp, loadRegExp) \
F(LoadClosure, loadClosure) \
F(Move, move) \
+ F(MoveConst, moveConst) \
F(SwapTemps, swapTemps) \
F(LoadName, loadName) \
F(GetGlobalLookup, getGlobalLookup) \
F(StoreName, storeName) \
F(LoadElement, loadElement) \
+ F(LoadElementLookup, loadElementLookup) \
F(StoreElement, storeElement) \
+ F(StoreElementLookup, storeElementLookup) \
F(LoadProperty, loadProperty) \
F(GetLookup, getLookup) \
F(StoreProperty, storeProperty) \
@@ -103,7 +107,8 @@ QT_BEGIN_NAMESPACE
F(CreateActivationProperty, createActivationProperty) \
F(ConstructGlobalLookup, constructGlobalLookup) \
F(Jump, jump) \
- F(CJump, cjump) \
+ F(JumpEq, jumpEq) \
+ F(JumpNe, jumpNe) \
F(UNot, unot) \
F(UNotBool, unotBool) \
F(UPlus, uplus) \
@@ -117,15 +122,16 @@ QT_BEGIN_NAMESPACE
F(BitAnd, bitAnd) \
F(BitOr, bitOr) \
F(BitXor, bitXor) \
+ F(Shr, shr) \
+ F(Shl, shl) \
F(BitAndConst, bitAndConst) \
F(BitOrConst, bitOrConst) \
F(BitXorConst, bitXorConst) \
+ F(ShrConst, shrConst) \
+ F(ShlConst, shlConst) \
F(Mul, mul) \
F(Sub, sub) \
F(BinopContext, binopContext) \
- F(AddNumberParams, addNumberParams) \
- F(MulNumberParams, mulNumberParams) \
- F(SubNumberParams, subNumberParams) \
F(LoadThis, loadThis) \
F(LoadQmlIdArray, loadQmlIdArray) \
F(LoadQmlImportedScripts, loadQmlImportedScripts) \
@@ -140,11 +146,9 @@ QT_BEGIN_NAMESPACE
#define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QQmlJS::Moth::Instr) - 1)
#ifdef MOTH_THREADED_INTERPRETER
-# define MOTH_INSTR_HEADER void *code; \
- unsigned int breakPoint : 1;
+# define MOTH_INSTR_HEADER void *code;
#else
-# define MOTH_INSTR_HEADER quint8 instructionType; \
- unsigned int breakPoint : 1;
+# define MOTH_INSTR_HEADER quint32 instructionType;
#endif
#define MOTH_INSTR_ENUM(I, FMT) I,
@@ -232,6 +236,10 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
+ struct instr_debug {
+ MOTH_INSTR_HEADER
+ quint32 breakPoint;
+ };
struct instr_loadRuntimeString {
MOTH_INSTR_HEADER
int stringId;
@@ -247,6 +255,11 @@ union Instr
Param source;
Param result;
};
+ struct instr_moveConst {
+ MOTH_INSTR_HEADER
+ QV4::ReturnedValue source;
+ Param result;
+ };
struct instr_swapTemps {
MOTH_INSTR_HEADER
Param left;
@@ -322,12 +335,26 @@ union Instr
Param index;
Param result;
};
+ struct instr_loadElementLookup {
+ MOTH_INSTR_HEADER
+ uint lookup;
+ Param base;
+ Param index;
+ Param result;
+ };
struct instr_storeElement {
MOTH_INSTR_HEADER
Param base;
Param index;
Param source;
};
+ struct instr_storeElementLookup {
+ MOTH_INSTR_HEADER
+ uint lookup;
+ Param base;
+ Param index;
+ Param source;
+ };
struct instr_push {
MOTH_INSTR_HEADER
quint32 value;
@@ -527,11 +554,15 @@ union Instr
MOTH_INSTR_HEADER
ptrdiff_t offset;
};
- struct instr_cjump {
+ struct instr_jumpEq {
+ MOTH_INSTR_HEADER
+ ptrdiff_t offset;
+ Param condition;
+ };
+ struct instr_jumpNe {
MOTH_INSTR_HEADER
ptrdiff_t offset;
Param condition;
- bool invert;
};
struct instr_unot {
MOTH_INSTR_HEADER
@@ -604,57 +635,63 @@ union Instr
Param rhs;
Param result;
};
- struct instr_bitAndConst {
+ struct instr_shr {
MOTH_INSTR_HEADER
Param lhs;
- int rhs;
+ Param rhs;
Param result;
};
- struct instr_bitOrConst {
+ struct instr_shl {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_bitAndConst {
MOTH_INSTR_HEADER
Param lhs;
int rhs;
Param result;
};
- struct instr_bitXorConst {
+ struct instr_bitOrConst {
MOTH_INSTR_HEADER
Param lhs;
int rhs;
Param result;
};
- struct instr_mul {
+ struct instr_bitXorConst {
MOTH_INSTR_HEADER
Param lhs;
- Param rhs;
+ int rhs;
Param result;
};
- struct instr_sub {
+ struct instr_shrConst {
MOTH_INSTR_HEADER
Param lhs;
- Param rhs;
+ int rhs;
Param result;
};
- struct instr_binopContext {
+ struct instr_shlConst {
MOTH_INSTR_HEADER
- QV4::BinOpContext alu;
Param lhs;
- Param rhs;
+ int rhs;
Param result;
};
- struct instr_addNumberParams {
+ struct instr_mul {
MOTH_INSTR_HEADER
Param lhs;
Param rhs;
Param result;
};
- struct instr_mulNumberParams {
+ struct instr_sub {
MOTH_INSTR_HEADER
Param lhs;
Param rhs;
Param result;
};
- struct instr_subNumberParams {
+ struct instr_binopContext {
MOTH_INSTR_HEADER
+ QV4::BinOpContext alu;
Param lhs;
Param rhs;
Param result;
@@ -687,16 +724,20 @@ union Instr
instr_common common;
instr_ret ret;
+ instr_debug debug;
instr_loadRuntimeString loadRuntimeString;
instr_loadRegExp loadRegExp;
instr_move move;
+ instr_moveConst moveConst;
instr_swapTemps swapTemps;
instr_loadClosure loadClosure;
instr_loadName loadName;
instr_getGlobalLookup getGlobalLookup;
instr_storeName storeName;
instr_loadElement loadElement;
+ instr_loadElementLookup loadElementLookup;
instr_storeElement storeElement;
+ instr_storeElementLookup storeElementLookup;
instr_loadProperty loadProperty;
instr_getLookup getLookup;
instr_loadQObjectProperty loadQObjectProperty;
@@ -739,7 +780,8 @@ union Instr
instr_createActivationProperty createActivationProperty;
instr_constructGlobalLookup constructGlobalLookup;
instr_jump jump;
- instr_cjump cjump;
+ instr_jumpEq jumpEq;
+ instr_jumpNe jumpNe;
instr_unot unot;
instr_unotBool unotBool;
instr_uplus uplus;
@@ -753,15 +795,16 @@ union Instr
instr_bitAnd bitAnd;
instr_bitOr bitOr;
instr_bitXor bitXor;
+ instr_shr shr;
+ instr_shl shl;
instr_bitAndConst bitAndConst;
instr_bitOrConst bitOrConst;
instr_bitXorConst bitXorConst;
+ instr_shrConst shrConst;
+ instr_shlConst shlConst;
instr_mul mul;
instr_sub sub;
instr_binopContext binopContext;
- instr_addNumberParams addNumberParams;
- instr_mulNumberParams mulNumberParams;
- instr_subNumberParams subNumberParams;
instr_loadThis loadThis;
instr_loadQmlIdArray loadQmlIdArray;
instr_loadQmlImportedScripts loadQmlImportedScripts;
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index b8b16a4151..a1145c2f10 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -245,12 +245,12 @@ Assembler::Pointer Assembler::loadTempAddress(RegisterID baseReg, V4IR::Temp *t)
case V4IR::Temp::Formal:
case V4IR::Temp::ScopedFormal: {
loadPtr(Address(context, qOffsetOf(ExecutionContext, callData)), baseReg);
- offset = sizeof(CallData) + (t->index - 1) * sizeof(SafeValue);
+ offset = sizeof(CallData) + (t->index - 1) * sizeof(Value);
} break;
case V4IR::Temp::Local:
case V4IR::Temp::ScopedLocal: {
loadPtr(Address(context, qOffsetOf(CallContext, locals)), baseReg);
- offset = t->index * sizeof(SafeValue);
+ offset = t->index * sizeof(Value);
} break;
case V4IR::Temp::StackSlot: {
return stackSlotPointer(t);
@@ -266,7 +266,7 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s
loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, compilationUnit)), Assembler::ScratchRegister);
loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg);
const int id = _isel->registerString(string);
- return Pointer(reg, id * sizeof(QV4::SafeString));
+ return Pointer(reg, id * sizeof(QV4::StringValue));
}
void Assembler::loadStringRef(RegisterID reg, const QString &string)
@@ -274,7 +274,7 @@ void Assembler::loadStringRef(RegisterID reg, const QString &string)
loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, compilationUnit)), reg);
loadPtr(Address(reg, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg);
const int id = _isel->registerString(string);
- addPtr(TrustedImmPtr(id * sizeof(QV4::SafeString)), reg);
+ addPtr(TrustedImmPtr(id * sizeof(QV4::StringValue)), reg);
}
template <typename Result, typename Source>
@@ -615,7 +615,7 @@ void InstructionSelection::run(int functionIndex)
const int locals = _as->stackLayout().calculateJSStackFrameSize();
_as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, engine)), Assembler::ScratchRegister);
_as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)), Assembler::LocalsRegister);
- _as->addPtr(Assembler::TrustedImm32(sizeof(QV4::SafeValue)*locals), Assembler::LocalsRegister);
+ _as->addPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister);
_as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
int lastLine = -1;
@@ -1023,107 +1023,19 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR:
return;
}
-#if 0 // QT_POINTER_SIZE == 8
- V4IR::Temp *tbase = base->asTemp();
- V4IR::Temp *tindex = index->asTemp();
- if (tbase && tindex &&
- tbase->kind != V4IR::Temp::PhysicalRegister) {
- Assembler::Pointer addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase);
- _as->load64(addr, Assembler::ScratchRegister);
- _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsManaged_Shift), Assembler::ReturnValueRegister);
- Assembler::Jump notManaged = _as->branch64(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm64(0));
- // check whether we have an object with a simple array
- // ### need to check we have an object first!
- Assembler::Address managedType(Assembler::ScratchRegister, qOffsetOf(QV4::Object, arrayData) + qOffsetOf(QV4::ArrayData, flags));
- _as->load8(managedType, Assembler::ReturnValueRegister);
- _as->and32(Assembler::TrustedImm32(QV4::ArrayData::SimpleArray), Assembler::ReturnValueRegister);
- Assembler::Jump notSimple = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0));
-
- bool needNegativeCheck = false;
- Assembler::Jump fallback, fallback2;
- if (tindex->kind == V4IR::Temp::PhysicalRegister) {
- if (tindex->type == V4IR::SInt32Type) {
- fallback = _as->branch32(Assembler::LessThan, (Assembler::RegisterID)tindex->index, Assembler::TrustedImm32(0));
- _as->move((Assembler::RegisterID) tindex->index, Assembler::ScratchRegister);
- needNegativeCheck = true;
- } else {
- // double, convert and check if it's a int
- fallback2 = _as->branchTruncateDoubleToUint32((Assembler::FPRegisterID) tindex->index, Assembler::ScratchRegister);
- _as->convertInt32ToDouble(Assembler::ScratchRegister, Assembler::FPGpr0);
- fallback = _as->branchDouble(Assembler::DoubleNotEqual, Assembler::FPGpr0, (Assembler::FPRegisterID) tindex->index);
- }
- } else {
- Assembler::Pointer indexAddr = _as->loadTempAddress(Assembler::ReturnValueRegister, tindex);
- _as->load64(indexAddr, Assembler::ScratchRegister);
- _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsNumber_Shift), Assembler::ReturnValueRegister);
- Assembler::Jump isInteger = _as->branch64(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm64(1));
-
- // other type, convert to double and check if it's a int
- // this check is ok to do even if the type is something else than a double, as
- // that would result in a NaN
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ReturnValueRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- _as->move64ToDouble(Assembler::ReturnValueRegister, Assembler::FPGpr0);
- fallback2 = _as->branchTruncateDoubleToUint32(Assembler::FPGpr0, Assembler::ScratchRegister);
- _as->convertInt32ToDouble(Assembler::ScratchRegister, Assembler::FPGpr1);
- fallback = _as->branchDouble(Assembler::DoubleNotEqualOrUnordered, Assembler::FPGpr0, Assembler::FPGpr1);
-
- isInteger.link(_as);
- _as->or32(Assembler::TrustedImm32(0), Assembler::ScratchRegister);
- needNegativeCheck = true;
- }
-
- // get data, ScratchRegister holds index
- addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase);
- _as->load64(addr, Assembler::ReturnValueRegister);
- Address dataLen(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData) + qOffsetOf(ArrayData, length));
- Assembler::Jump outOfRange;
- if (needNegativeCheck)
- outOfRange = _as->branch32(Assembler::LessThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0));
- Assembler::Jump outOfRange2 = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, dataLen);
- Address arrayData(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData) + qOffsetOf(ArrayData, data));
- _as->load64(arrayData, Assembler::ReturnValueRegister);
- Q_ASSERT(sizeof(Property) == (1<<4));
- _as->lshift64(Assembler::TrustedImm32(4), Assembler::ScratchRegister);
- _as->add64(Assembler::ReturnValueRegister, Assembler::ScratchRegister);
- Address value(Assembler::ScratchRegister, qOffsetOf(Property, value));
- _as->load64(value, Assembler::ReturnValueRegister);
-
- // check that the value is not empty
- _as->move(Assembler::ReturnValueRegister, Assembler::ScratchRegister);
- _as->urshift64(Assembler::TrustedImm32(32), Assembler::ScratchRegister);
- Assembler::Jump emptyValue = _as->branch32(Assembler::Equal, Assembler::TrustedImm32(QV4::Value::Empty_Type), Assembler::ScratchRegister);
- _as->storeReturnValue(target);
-
- Assembler::Jump done = _as->jump();
-
- emptyValue.link(_as);
- if (outOfRange.isSet())
- outOfRange.link(_as);
- outOfRange2.link(_as);
- if (fallback.isSet())
- fallback.link(_as);
- if (fallback2.isSet())
- fallback2.link(_as);
- notSimple.link(_as);
- notManaged.link(_as);
-
- generateFunctionCall(target, __qmljs_get_element, Assembler::ContextRegister,
- Assembler::PointerToValue(base), Assembler::PointerToValue(index));
-
- done.link(_as);
- return;
- }
-#endif
-
generateFunctionCall(target, __qmljs_get_element, Assembler::ContextRegister,
Assembler::PointerToValue(base), Assembler::PointerToValue(index));
}
void InstructionSelection::setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex)
{
+ if (useFastLookups) {
+ uint lookup = registerIndexedSetterLookup();
+ generateLookupCall(Assembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter),
+ Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
+ Assembler::PointerToValue(source));
+ return;
+ }
generateFunctionCall(Assembler::Void, __qmljs_set_element, Assembler::ContextRegister,
Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
Assembler::PointerToValue(source));
@@ -2019,7 +1931,7 @@ void InstructionSelection::visitRet(V4IR::Ret *s)
_as->exceptionReturnLabel = _as->label();
const int locals = _as->stackLayout().calculateJSStackFrameSize();
- _as->subPtr(Assembler::TrustedImm32(sizeof(QV4::SafeValue)*locals), Assembler::LocalsRegister);
+ _as->subPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister);
_as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, engine)), Assembler::ScratchRegister);
_as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index a146220015..b1e981533b 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -45,7 +45,7 @@
#include "qv4jsir_p.h"
#include "qv4isel_p.h"
#include "qv4isel_util_p.h"
-#include "private/qv4value_def_p.h"
+#include "private/qv4value_p.h"
#include "private/qv4lookup_p.h"
#include <QtCore/QHash>
@@ -351,7 +351,7 @@ public:
// space for the callee saved registers
int frameSize = RegisterSize * calleeSavedRegisterCount;
- frameSize += savedRegCount * sizeof(QV4::SafeValue); // these get written out as Values, not as native registers
+ frameSize += savedRegCount * sizeof(QV4::Value); // these get written out as Values, not as native registers
frameSize = WTF::roundUpToMultipleOf(StackAlignment, frameSize + stackSpaceAllocatedOtherwise);
frameSize -= stackSpaceAllocatedOtherwise;
@@ -361,8 +361,8 @@ public:
int calculateJSStackFrameSize() const
{
- const int locals = (localCount + sizeof(QV4::CallData)/sizeof(QV4::SafeValue) - 1 + maxOutgoingArgumentCount) + 1;
- int frameSize = locals * sizeof(QV4::SafeValue);
+ const int locals = (localCount + sizeof(QV4::CallData)/sizeof(QV4::Value) - 1 + maxOutgoingArgumentCount) + 1;
+ int frameSize = locals * sizeof(QV4::Value);
return frameSize;
}
@@ -372,7 +372,7 @@ public:
Q_ASSERT(idx < localCount);
Pointer addr = callDataAddress(0);
- addr.offset -= sizeof(QV4::SafeValue) * (idx + 1);
+ addr.offset -= sizeof(QV4::Value) * (idx + 1);
return addr;
}
@@ -384,11 +384,11 @@ public:
Q_ASSERT(argument < maxOutgoingArgumentCount);
const int index = maxOutgoingArgumentCount - argument;
- return Pointer(Assembler::LocalsRegister, sizeof(QV4::SafeValue) * (-index));
+ return Pointer(Assembler::LocalsRegister, sizeof(QV4::Value) * (-index));
}
Pointer callDataAddress(int offset = 0) const {
- return Pointer(Assembler::LocalsRegister, -(sizeof(QV4::CallData) + sizeof(QV4::SafeValue) * (maxOutgoingArgumentCount - 1)) + offset);
+ return Pointer(Assembler::LocalsRegister, -(sizeof(QV4::CallData) + sizeof(QV4::Value) * (maxOutgoingArgumentCount - 1)) + offset);
}
Address savedRegPointer(int offset) const
@@ -396,7 +396,7 @@ public:
Q_ASSERT(offset >= 0);
Q_ASSERT(offset < savedRegCount);
- const int off = offset * sizeof(QV4::SafeValue);
+ const int off = offset * sizeof(QV4::Value);
return Address(Assembler::StackFrameRegister, - calleeSavedRegisterSpace() - off);
}
@@ -657,7 +657,7 @@ public:
void storeUInt32ReturnValue(RegisterID dest)
{
- Pointer tmp(StackPointerRegister, -int(sizeof(QV4::SafeValue)));
+ Pointer tmp(StackPointerRegister, -int(sizeof(QV4::Value)));
storeReturnValue(tmp);
toUInt32Register(tmp, dest);
}
@@ -669,7 +669,7 @@ public:
xor64(ScratchRegister, ReturnValueRegister);
move64ToDouble(ReturnValueRegister, dest);
#else
- Pointer tmp(StackPointerRegister, -int(sizeof(QV4::SafeValue)));
+ Pointer tmp(StackPointerRegister, -int(sizeof(QV4::Value)));
storeReturnValue(tmp);
loadDouble(tmp, dest);
#endif
@@ -1580,8 +1580,8 @@ private:
int prepareVariableArguments(V4IR::ExprList* args);
int prepareCallData(V4IR::ExprList* args, V4IR::Expr *thisObject);
- template <typename Retval, typename Arg1, typename Arg2>
- void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2)
+ template <typename Retval, typename Arg1, typename Arg2, typename Arg3>
+ void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3)
{
Assembler::RegisterID lookupRegister;
#if CPU(ARM)
@@ -1595,13 +1595,13 @@ private:
getterSetter.offset += getterSetterOffset;
_as->generateFunctionCallImp(retval, "lookup getter/setter",
- RelativeCall(getterSetter), lookupAddr, arg1, arg2);
+ RelativeCall(getterSetter), lookupAddr, arg1, arg2, arg3);
}
- template <typename Arg1>
- void generateLookupCall(uint index, uint getterSetterOffset, Arg1 arg1)
+ template <typename Retval, typename Arg1, typename Arg2>
+ void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2)
{
- generateLookupCall(index, getterSetterOffset, arg1, Assembler::VoidType());
+ generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, Assembler::VoidType());
}
/// This is a temporary method, and will be removed when registers are fully supported.
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index bf9af178fe..130725f3ed 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -47,6 +47,7 @@
#include <private/qv4function_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qqmlengine_p.h>
#undef USE_TYPE_INFO
@@ -150,6 +151,167 @@ inline bool isBoolType(V4IR::Expr *e)
return (e->type == V4IR::BoolType);
}
+/*
+ * stack slot allocation:
+ *
+ * foreach bb do
+ * foreach stmt do
+ * if the current statement is not a phi-node:
+ * purge ranges that end before the current statement
+ * check for life ranges to activate, and if they don't have a stackslot associated then allocate one
+ * renumber temps to stack
+ * for phi nodes: check if all temps (src+dst) are assigned stack slots and marked as allocated
+ * if it's a jump:
+ * foreach phi node in the successor:
+ * allocate slots for each temp (both sources and targets) if they don't have one allocated already
+ * insert moves before the jump
+ */
+class AllocateStackSlots: protected ConvertTemps
+{
+ const QVector<V4IR::LifeTimeInterval> _intervals;
+ QVector<const V4IR::LifeTimeInterval *> _unhandled;
+ QVector<const V4IR::LifeTimeInterval *> _live;
+ QBitArray _slotIsInUse;
+ V4IR::Function *_function;
+
+public:
+ AllocateStackSlots(const QVector<V4IR::LifeTimeInterval> &intervals)
+ : _intervals(intervals)
+ , _slotIsInUse(intervals.size(), false)
+ , _function(0)
+ {
+ _live.reserve(8);
+ _unhandled.reserve(_intervals.size());
+ for (int i = _intervals.size() - 1; i >= 0; --i)
+ _unhandled.append(&_intervals.at(i));
+ }
+
+ void forFunction(V4IR::Function *function)
+ {
+ V4IR::Optimizer::showMeTheCode(function);
+ _function = function;
+ toStackSlots(function);
+
+// QTextStream os(stdout, QIODevice::WriteOnly);
+// os << "Frame layout:" << endl;
+// foreach (int t, _stackSlotForTemp.keys()) {
+// os << "\t" << t << " -> " << _stackSlotForTemp[t] << endl;
+// }
+ }
+
+protected:
+ virtual int allocateFreeSlot()
+ {
+ for (int i = 0, ei = _slotIsInUse.size(); i != ei; ++i) {
+ if (!_slotIsInUse[i]) {
+ if (_nextUnusedStackSlot <= i) {
+ Q_ASSERT(_nextUnusedStackSlot == i);
+ _nextUnusedStackSlot = i + 1;
+ }
+ _slotIsInUse[i] = true;
+ return i;
+ }
+ }
+
+ Q_UNREACHABLE();
+ return -1;
+ }
+
+ virtual void process(V4IR::Stmt *s)
+ {
+ Q_ASSERT(s->id > 0);
+
+// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id);
+
+ if (V4IR::Phi *phi = s->asPhi()) {
+ visitPhi(phi);
+ } else {
+ // purge ranges no longer alive:
+ for (int i = 0; i < _live.size(); ) {
+ const V4IR::LifeTimeInterval *lti = _live.at(i);
+ if (lti->end() < s->id) {
+// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index];
+ _live.remove(i);
+ Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]);
+ _slotIsInUse[_stackSlotForTemp[lti->temp().index]] = false;
+ continue;
+ } else {
+ ++i;
+ }
+ }
+
+ // active new ranges:
+ while (!_unhandled.isEmpty()) {
+ const V4IR::LifeTimeInterval *lti = _unhandled.last();
+ if (lti->start() > s->id)
+ break; // we're done
+ Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index));
+ _stackSlotForTemp[lti->temp().index] = allocateFreeSlot();
+// qDebug() << "\t - activating temp" << lti->temp().index << "on slot" << _stackSlotForTemp[lti->temp().index];
+ _live.append(lti);
+ _unhandled.removeLast();
+ }
+
+ s->accept(this);
+ }
+
+ if (V4IR::Jump *jump = s->asJump()) {
+ V4IR::MoveMapping moves;
+ foreach (V4IR::Stmt *succStmt, jump->target->statements) {
+ if (V4IR::Phi *phi = succStmt->asPhi()) {
+ forceActivation(*phi->targetTemp);
+ for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) {
+ V4IR::Expr *e = phi->d->incoming[i];
+ if (V4IR::Temp *t = e->asTemp()) {
+ forceActivation(*t);
+ }
+ if (jump->target->in[i] == _currentBasicBlock)
+ moves.add(phi->d->incoming[i], phi->targetTemp);
+ }
+ } else {
+ break;
+ }
+ }
+ moves.order();
+ QList<V4IR::Move *> newMoves = moves.insertMoves(_currentBasicBlock, _function, true);
+ foreach (V4IR::Move *move, newMoves)
+ move->accept(this);
+ }
+ }
+
+ void forceActivation(const V4IR::Temp &t)
+ {
+ if (_stackSlotForTemp.contains(t.index))
+ return;
+
+ int i = _unhandled.size() - 1;
+ for (; i >= 0; --i) {
+ const V4IR::LifeTimeInterval *lti = _unhandled[i];
+ if (lti->temp() == t) {
+ _live.append(lti);
+ _unhandled.remove(i);
+ break;
+ }
+ }
+ Q_ASSERT(i >= 0); // check that we always found the entry
+
+ _stackSlotForTemp[t.index] = allocateFreeSlot();
+// qDebug() << "\t - force activating temp" << t.index << "on slot" << _stackSlotForTemp[t.index];
+ }
+
+ virtual void visitPhi(V4IR::Phi *phi)
+ {
+ Q_UNUSED(phi);
+#if !defined(QT_NO_DEBUG)
+ Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index));
+ Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]);
+ foreach (V4IR::Expr *e, phi->d->incoming) {
+ if (V4IR::Temp *t = e->asTemp())
+ Q_ASSERT(_stackSlotForTemp.contains(t->index));
+ }
+#endif // defined(QT_NO_DEBUG)
+ }
+};
} // anonymous namespace
InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
@@ -194,10 +356,19 @@ void InstructionSelection::run(int functionIndex)
V4IR::Optimizer opt(_function);
opt.run(qmlEngine);
if (opt.isInSSA()) {
- opt.convertOutOfSSA();
+ static const bool doStackSlotAllocation =
+ qgetenv("QV4_NO_INTERPRETER_STACK_SLOT_ALLOCATION").isEmpty();
+
+ if (doStackSlotAllocation) {
+ AllocateStackSlots(opt.lifeRanges()).forFunction(_function);
+ } else {
+ opt.convertOutOfSSA();
+ ConvertTemps().toStackSlots(_function);
+ }
opt.showMeTheCode(_function);
+ } else {
+ ConvertTemps().toStackSlots(_function);
}
- ConvertTemps().toStackSlots(_function);
QSet<V4IR::Jump *> removableJumps = opt.calculateOptionalJumps();
qSwap(_removableJumps, removableJumps);
@@ -217,7 +388,13 @@ void InstructionSelection::run(int functionIndex)
QVector<uint> lineNumberMappings;
lineNumberMappings.reserve(_function->basicBlocks.size() * 2);
+ uint currentLine = -1;
for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
+ if (irModule->debugMode) {
+ Instruction::Debug debug;
+ debug.breakPoint = 0;
+ addInstruction(debug);
+ }
_block = _function->basicBlocks[i];
_nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
_addrs.insert(_block, _codeNext - _codeStart);
@@ -237,8 +414,15 @@ void InstructionSelection::run(int functionIndex)
foreach (V4IR::Stmt *s, _block->statements) {
_currentStatement = s;
- if (s->location.isValid())
+ if (s->location.isValid()) {
lineNumberMappings << _codeNext - _codeStart << s->location.startLine;
+ if (irModule->debugMode && s->location.startLine != currentLine) {
+ Instruction::Debug debug;
+ debug.breakPoint = 0;
+ addInstruction(debug);
+ currentLine = s->location.startLine;
+ }
+ }
s->accept(this);
}
@@ -323,7 +507,7 @@ void InstructionSelection::callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4
void InstructionSelection::convertType(V4IR::Temp *source, V4IR::Temp *target)
{
// FIXME: do something more useful with this info
- if (target->type & V4IR::NumberType)
+ if (target->type & V4IR::NumberType && !(source->type & V4IR::NumberType))
unop(V4IR::OpUPlus, source, target);
else
copyValue(source, target);
@@ -428,8 +612,8 @@ void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targe
{
assert(sourceConst);
- Instruction::Move move;
- move.source = getParam(sourceConst);
+ Instruction::MoveConst move;
+ move.source = convertToValue(sourceConst).asReturnedValue();
move.result = getResultParam(targetTemp);
addInstruction(move);
}
@@ -546,6 +730,15 @@ void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyInde
void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
{
+ if (useFastLookups) {
+ Instruction::LoadElementLookup load;
+ load.lookup = registerIndexedGetterLookup();
+ load.base = getParam(base);
+ load.index = getParam(index);
+ load.result = getResultParam(target);
+ addInstruction(load);
+ return;
+ }
Instruction::LoadElement load;
load.base = getParam(base);
load.index = getParam(index);
@@ -556,6 +749,15 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR:
void InstructionSelection::setElement(V4IR::Expr *source, V4IR::Expr *targetBase,
V4IR::Expr *targetIndex)
{
+ if (useFastLookups) {
+ Instruction::StoreElementLookup store;
+ store.lookup = registerIndexedSetterLookup();
+ store.base = getParam(targetBase);
+ store.index = getParam(targetIndex);
+ store.source = getParam(source);
+ addInstruction(store);
+ return;
+ }
Instruction::StoreElement store;
store.base = getParam(targetBase);
store.index = getParam(targetIndex);
@@ -613,7 +815,8 @@ void InstructionSelection::unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::
Instruction::Move move;
move.source = getParam(sourceTemp);
move.result = getResultParam(targetTemp);
- addInstruction(move);
+ if (move.source != move.result)
+ addInstruction(move);
return;
}
Instruction::UPlus uplus;
@@ -664,37 +867,6 @@ void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR:
Param InstructionSelection::binopHelper(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target)
{
- if (isNumberType(leftSource) && isNumberType(rightSource)) {
- switch (oper) {
- case V4IR::OpAdd: {
- Instruction::AddNumberParams instr;
- instr.lhs = getParam(leftSource);
- instr.rhs = getParam(rightSource);
- instr.result = getResultParam(target);
- addInstruction(instr);
- return instr.result;
- }
- case V4IR::OpMul: {
- Instruction::MulNumberParams instr;
- instr.lhs = getParam(leftSource);
- instr.rhs = getParam(rightSource);
- instr.result = getResultParam(target);
- addInstruction(instr);
- return instr.result;
- }
- case V4IR::OpSub: {
- Instruction::SubNumberParams instr;
- instr.lhs = getParam(leftSource);
- instr.rhs = getParam(rightSource);
- instr.result = getResultParam(target);
- addInstruction(instr);
- return instr.result;
- }
- default:
- break;
- }
- }
-
if (oper == V4IR::OpAdd) {
Instruction::Add add;
add.lhs = getParam(leftSource);
@@ -773,6 +945,38 @@ Param InstructionSelection::binopHelper(V4IR::AluOp oper, V4IR::Expr *leftSource
addInstruction(bitXor);
return bitXor.result;
}
+ if (oper == V4IR::OpRShift) {
+ if (V4IR::Const *c = rightSource->asConst()) {
+ Instruction::ShrConst shr;
+ shr.lhs = getParam(leftSource);
+ shr.rhs = convertToValue(c).Value::toInt32() & 0x1f;
+ shr.result = getResultParam(target);
+ addInstruction(shr);
+ return shr.result;
+ }
+ Instruction::Shr shr;
+ shr.lhs = getParam(leftSource);
+ shr.rhs = getParam(rightSource);
+ shr.result = getResultParam(target);
+ addInstruction(shr);
+ return shr.result;
+ }
+ if (oper == V4IR::OpLShift) {
+ if (V4IR::Const *c = rightSource->asConst()) {
+ Instruction::ShlConst shl;
+ shl.lhs = getParam(leftSource);
+ shl.rhs = convertToValue(c).Value::toInt32() & 0x1f;
+ shl.result = getResultParam(target);
+ addInstruction(shl);
+ return shl.result;
+ }
+ Instruction::Shl shl;
+ shl.lhs = getParam(leftSource);
+ shl.rhs = getParam(rightSource);
+ shl.result = getResultParam(target);
+ addInstruction(shl);
+ return shl.result;
+ }
if (oper == V4IR::OpInstanceof || oper == V4IR::OpIn || oper == V4IR::OpAdd) {
Instruction::BinopContext binop;
@@ -810,10 +1014,17 @@ void InstructionSelection::prepareCallArgs(V4IR::ExprList *e, quint32 &argc, qui
// We need to move all the temps into the function arg array
assert(argLocation >= 0);
while (e) {
- Instruction::Move move;
- move.source = getParam(e->expr);
- move.result = Param::createTemp(argLocation);
- addInstruction(move);
+ if (V4IR::Const *c = e->expr->asConst()) {
+ Instruction::MoveConst move;
+ move.source = convertToValue(c).asReturnedValue();
+ move.result = Param::createTemp(argLocation);
+ addInstruction(move);
+ } else {
+ Instruction::Move move;
+ move.source = getParam(e->expr);
+ move.result = Param::createTemp(argLocation);
+ addInstruction(move);
+ }
++argLocation;
++argc;
e = e->next;
@@ -846,16 +1057,16 @@ void InstructionSelection::visitCJump(V4IR::CJump *s)
Q_UNIMPLEMENTED();
}
- Instruction::CJump jump;
- jump.offset = 0;
- jump.condition = condition;
-
if (s->iftrue == _nextBlock) {
- jump.invert = true;
+ Instruction::JumpNe jump;
+ jump.offset = 0;
+ jump.condition = condition;
ptrdiff_t falseLoc = addInstruction(jump) + (((const char *)&jump.offset) - ((const char *)&jump));
_patches[s->iffalse].append(falseLoc);
} else {
- jump.invert = false;
+ Instruction::JumpEq jump;
+ jump.offset = 0;
+ jump.condition = condition;
ptrdiff_t trueLoc = addInstruction(jump) + (((const char *)&jump.offset) - ((const char *)&jump));
_patches[s->iftrue].append(trueLoc);
@@ -959,9 +1170,8 @@ void InstructionSelection::callBuiltinDeleteName(const QString &name, V4IR::Temp
void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
{
- Instruction::Move move;
- int idx = jsUnitGenerator()->registerConstant(QV4::Encode(false));
- move.source = Param::createConstant(idx);
+ Instruction::MoveConst move;
+ move.source = QV4::Encode(false);
move.result = getResultParam(result);
addInstruction(move);
}
@@ -1082,10 +1292,17 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
bool isData = it->expr->asConst()->value;
it = it->next;
- Instruction::Move move;
- move.source = getParam(it->expr);
- move.result = Param::createTemp(argLocation);
- addInstruction(move);
+ if (V4IR::Const *c = it->expr->asConst()) {
+ Instruction::MoveConst move;
+ move.source = convertToValue(c).asReturnedValue();
+ move.result = Param::createTemp(argLocation);
+ addInstruction(move);
+ } else {
+ Instruction::Move move;
+ move.source = getParam(it->expr);
+ move.result = Param::createTemp(argLocation);
+ addInstruction(move);
+ }
++argLocation;
if (!isData) {
@@ -1124,12 +1341,12 @@ void QQmlJS::Moth::InstructionSelection::callBuiltinConvertThisToObject()
ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
{
+
#ifdef MOTH_THREADED_INTERPRETER
instr.common.code = VME::instructionJumpTable()[static_cast<int>(type)];
#else
instr.common.instructionType = type;
#endif
- instr.common.breakPoint = 0;
int instructionSize = Instr::size(type);
if (_codeEnd - _codeNext < instructionSize) {
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index d8a85ff249..b43868d186 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -46,7 +46,7 @@
#include <private/qv4isel_p.h>
#include <private/qv4isel_util_p.h>
#include <private/qv4jsir_p.h>
-#include <private/qv4value_def_p.h>
+#include <private/qv4value_p.h>
#include "qv4instr_moth_p.h"
QT_BEGIN_NAMESPACE
@@ -160,7 +160,7 @@ private:
int scratchTempIndex() const { return _function->tempCount; }
int callDataStart() const { return scratchTempIndex() + 1; }
- int outgoingArgumentTempStart() const { return callDataStart() + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue); }
+ int outgoingArgumentTempStart() const { return callDataStart() + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value); }
int frameSize() const { return outgoingArgumentTempStart() + _function->maxNumberOfArguments; }
template <int Instr>
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 6f33098172..57222672b9 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -73,6 +73,7 @@ public:
int registerString(const QString &str) { return jsGenerator->registerString(str); }
uint registerIndexedGetterLookup() { return jsGenerator->registerIndexedGetterLookup(); }
+ uint registerIndexedSetterLookup() { return jsGenerator->registerIndexedSetterLookup(); }
uint registerGetterLookup(const QString &name) { return jsGenerator->registerGetterLookup(name); }
uint registerSetterLookup(const QString &name) { return jsGenerator->registerSetterLookup(name); }
uint registerGlobalGetterLookup(const QString &name) { return jsGenerator->registerGlobalGetterLookup(name); }
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index 38ea682d3b..637746dce1 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -42,7 +42,7 @@
#ifndef QV4ISEL_UTIL_P_H
#define QV4ISEL_UTIL_P_H
-#include "private/qv4value_def_p.h"
+#include "private/qv4value_p.h"
#include "qv4jsir_p.h"
QT_BEGIN_NAMESPACE
@@ -97,38 +97,52 @@ inline QV4::Primitive convertToValue(V4IR::Const *c)
class ConvertTemps: protected V4IR::StmtVisitor, protected V4IR::ExprVisitor
{
- int _nextFreeStackSlot;
- QHash<V4IR::Temp, int> _stackSlotForTemp;
-
void renumber(V4IR::Temp *t)
{
if (t->kind != V4IR::Temp::VirtualRegister)
return;
- int stackSlot = _stackSlotForTemp.value(*t, -1);
+ int stackSlot = _stackSlotForTemp.value(t->index, -1);
if (stackSlot == -1) {
- stackSlot = _nextFreeStackSlot++;
- _stackSlotForTemp[*t] = stackSlot;
+ stackSlot = allocateFreeSlot();
+ _stackSlotForTemp[t->index] = stackSlot;
}
t->kind = V4IR::Temp::StackSlot;
t->index = stackSlot;
}
+protected:
+ int _nextUnusedStackSlot;
+ QHash<int, int> _stackSlotForTemp;
+ V4IR::BasicBlock *_currentBasicBlock;
+ virtual int allocateFreeSlot()
+ {
+ return _nextUnusedStackSlot++;
+ }
+
+ virtual void process(V4IR::Stmt *s)
+ {
+ s->accept(this);
+ }
+
public:
ConvertTemps()
- : _nextFreeStackSlot(0)
+ : _nextUnusedStackSlot(0)
+ , _currentBasicBlock(0)
{}
void toStackSlots(V4IR::Function *function)
{
_stackSlotForTemp.reserve(function->tempCount);
- foreach (V4IR::BasicBlock *bb, function->basicBlocks)
+ foreach (V4IR::BasicBlock *bb, function->basicBlocks) {
+ _currentBasicBlock = bb;
foreach (V4IR::Stmt *s, bb->statements)
- s->accept(this);
+ process(s);
+ }
- function->tempCount = _nextFreeStackSlot;
+ function->tempCount = _nextUnusedStackSlot;
}
protected:
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index 2f1f64e523..bc88d5849a 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -40,7 +40,7 @@
****************************************************************************/
#include "qv4regalloc_p.h"
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <algorithm>
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 6b4d7e7434..3ffaca5134 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -3552,7 +3552,13 @@ private:
for (int i = bb->statements.size() - 1; i >= 0; --i) {
Stmt *s = bb->statements[i];
if (Phi *phi = s->asPhi()) {
- live.remove(*phi->targetTemp);
+ LiveRegs::iterator it = live.find(*phi->targetTemp);
+ if (it == live.end()) {
+ // a phi node target that is only defined, but never used
+ _intervals[*phi->targetTemp].setFrom(s);
+ } else {
+ live.erase(it);
+ }
continue;
}
collector.collect(s);
@@ -3811,7 +3817,6 @@ void Optimizer::convertOutOfSSA() {
// There should be no critical edges at this point.
foreach (BasicBlock *bb, function->basicBlocks) {
- const int id = bb->statements.last()->id;
MoveMapping moves;
foreach (BasicBlock *successor, bb->out) {
@@ -3820,7 +3825,7 @@ void Optimizer::convertOutOfSSA() {
foreach (Stmt *s, successor->statements) {
if (Phi *phi = s->asPhi()) {
moves.add(clone(phi->d->incoming[inIdx], function),
- clone(phi->targetTemp, function)->asTemp(), id);
+ clone(phi->targetTemp, function)->asTemp());
} else {
break;
}
@@ -3946,7 +3951,7 @@ MoveMapping::Moves MoveMapping::sourceUsages(Expr *e, const Moves &moves)
return usages;
}
-void MoveMapping::add(Expr *from, Temp *to, int id) {
+void MoveMapping::add(Expr *from, Temp *to) {
if (Temp *t = from->asTemp()) {
if (overlappingStorage(*t, *to)) {
// assignments like fp1 = fp1 or var{&1} = double{&1} can safely be skipped.
@@ -3962,7 +3967,7 @@ void MoveMapping::add(Expr *from, Temp *to, int id) {
}
}
- Move m(from, to, id);
+ Move m(from, to);
if (_moves.contains(m))
return;
_moves.append(m);
@@ -3989,16 +3994,21 @@ void MoveMapping::order()
qSwap(_moves, output);
}
-void MoveMapping::insertMoves(BasicBlock *bb, Function *function, bool atEnd) const
+QList<V4IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, Function *function, bool atEnd) const
{
+ QList<V4IR::Move *> newMoves;
+ newMoves.reserve(_moves.size());
+
int insertionPoint = atEnd ? bb->statements.size() - 1 : 0;
foreach (const Move &m, _moves) {
V4IR::Move *move = function->New<V4IR::Move>();
- move->init(m.to, m.from);
- move->id = m.id;
+ move->init(clone(m.to, function), clone(m.from, function));
move->swap = m.needsSwap;
bb->statements.insert(insertionPoint++, move);
+ newMoves.append(move);
}
+
+ return newMoves;
}
void MoveMapping::dump() const
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index 65d4f0834a..95bed40a27 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -170,11 +170,10 @@ class MoveMapping
struct Move {
Expr *from;
Temp *to;
- int id;
bool needsSwap;
- Move(Expr *from, Temp *to, int id)
- : from(from), to(to), id(id), needsSwap(false)
+ Move(Expr *from, Temp *to)
+ : from(from), to(to), needsSwap(false)
{}
bool operator==(const Move &other) const
@@ -187,9 +186,9 @@ class MoveMapping
static Moves sourceUsages(Expr *e, const Moves &moves);
public:
- void add(Expr *from, Temp *to, int id = 0);
+ void add(Expr *from, Temp *to);
void order();
- void insertMoves(BasicBlock *bb, Function *function, bool atEnd) const;
+ QList<V4IR::Move *> insertMoves(BasicBlock *bb, Function *function, bool atEnd) const;
void dump() const;
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
index 0523762971..f1e17df12b 100644
--- a/src/qml/debugger/qqmldebugserver.cpp
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -42,6 +42,12 @@
#include "qqmldebugserver_p.h"
#include "qqmldebugservice_p.h"
#include "qqmldebugservice_p_p.h"
+#include "qqmlenginedebugservice_p.h"
+#include "qv4debugservice_p.h"
+#include "qv4profilerservice_p.h"
+#include "qdebugmessageservice_p.h"
+#include "qqmlprofilerservice_p.h"
+
#include <private/qqmlengine_p.h>
#include <private/qqmlglobal_p.h>
@@ -56,6 +62,17 @@
QT_BEGIN_NAMESPACE
+// We can't friend the Q_GLOBAL_STATIC to have the constructor available so we need a little
+// workaround here. Using this wrapper we can also make QQmlEnginePrivate's cleanup() available to
+// qAddPostRoutine(). We can't do the cleanup in the destructor because we need a QApplication to
+// be available when stopping the plugins.
+struct QQmlDebugServerInstanceWrapper {
+ QQmlDebugServer m_instance;
+ void cleanup();
+};
+
+Q_GLOBAL_STATIC(QQmlDebugServerInstanceWrapper, debugServerInstance)
+
/*
QQmlDebug Protocol (Version 1):
@@ -93,6 +110,7 @@ public:
QQmlDebugServerPrivate();
void advertisePlugins();
+ void cleanup();
QQmlDebugServerConnection *loadConnectionPlugin(const QString &pluginName);
QQmlDebugServerConnection *connection;
@@ -115,6 +133,9 @@ private:
void _q_sendMessages(const QList<QByteArray> &messages);
};
+void QQmlDebugServerInstanceWrapper::cleanup()
+{ m_instance.d_func()->cleanup(); }
+
class QQmlDebugServerThread : public QThread
{
public:
@@ -174,6 +195,35 @@ void QQmlDebugServerPrivate::advertisePlugins()
QMetaObject::invokeMethod(q, "_q_sendMessages", Qt::QueuedConnection, Q_ARG(QList<QByteArray>, QList<QByteArray>() << message));
}
+void QQmlDebugServerPrivate::cleanup()
+{
+ Q_Q(QQmlDebugServer);
+ {
+ QReadLocker lock(&pluginsLock);
+ foreach (QQmlDebugService *service, plugins.values()) {
+ changeServiceStateCalls.ref();
+ QMetaObject::invokeMethod(q, "_q_changeServiceState", Qt::QueuedConnection,
+ Q_ARG(QString, service->name()),
+ Q_ARG(QQmlDebugService::State, QQmlDebugService::NotConnected));
+ }
+ }
+
+ // Wait for changeServiceState calls to finish
+ // (while running an event loop because some services
+ // might again use slots to execute stuff in the GUI thread)
+ QEventLoop loop;
+ while (!changeServiceStateCalls.testAndSetOrdered(0, 0))
+ loop.processEvents();
+
+ // Stop the thread while the application is still there.
+ if (thread) {
+ thread->exit();
+ thread->wait();
+ delete thread;
+ thread = 0;
+ }
+}
+
QQmlDebugServerConnection *QQmlDebugServerPrivate::loadConnectionPlugin(
const QString &pluginName)
{
@@ -222,11 +272,13 @@ QQmlDebugServerConnection *QQmlDebugServerPrivate::loadConnectionPlugin(
void QQmlDebugServerThread::run()
{
- QQmlDebugServer *server = QQmlDebugServer::instance();
+ QQmlDebugServerInstanceWrapper *wrapper = debugServerInstance();
+ Q_ASSERT_X(wrapper != 0, Q_FUNC_INFO, "There should always be a debug server available here.");
+ QQmlDebugServer *server = &wrapper->m_instance;
QQmlDebugServerConnection *connection
= server->d_func()->loadConnectionPlugin(m_pluginName);
if (connection) {
- connection->setServer(QQmlDebugServer::instance());
+ connection->setServer(server);
connection->setPortRange(m_portFrom, m_portTo, m_block, m_hostAddress);
} else {
QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
@@ -255,112 +307,107 @@ bool QQmlDebugServer::blockingMode() const
return d->blockingMode;
}
-static QQmlDebugServer *qQmlDebugServer = 0;
-
-
-static void cleanup()
+QQmlDebugServer *QQmlDebugServer::instance()
{
- delete qQmlDebugServer;
- qQmlDebugServer = 0;
+ QQmlDebugServerInstanceWrapper *wrapper = debugServerInstance();
+ if (wrapper && wrapper->m_instance.d_func()->thread) {
+ QQmlDebugServer *ret = &(wrapper->m_instance);
+ QQmlDebugServerPrivate *d = ret->d_func();
+ QMutexLocker locker(&d->helloMutex);
+ if (d->blockingMode && !d->gotHello)
+ d->helloCondition.wait(&d->helloMutex);
+ return ret;
+ } else {
+ return 0;
+ }
}
-QQmlDebugServer *QQmlDebugServer::instance()
+static void cleanup()
{
- static bool commandLineTested = false;
+ QQmlDebugServerInstanceWrapper *wrapper = debugServerInstance();
+ if (wrapper)
+ wrapper->cleanup();
+}
- if (!commandLineTested) {
- commandLineTested = true;
- QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
+QQmlDebugServer::QQmlDebugServer()
+ : QObject(*(new QQmlDebugServerPrivate))
+{
+ QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
#ifndef QT_QML_NO_DEBUGGER
- // ### remove port definition when protocol is changed
- int portFrom = 0;
- int portTo = 0;
- bool block = false;
- bool ok = false;
- QString hostAddress;
-
- // format: qmljsdebugger=port:<port_from>[,port_to],host:<ip address>][,block]
- if (!appD->qmljsDebugArgumentsString().isEmpty()) {
- if (!QQmlEnginePrivate::qml_debugging_enabled) {
- qWarning() << QString(QLatin1String(
- "QML Debugger: Ignoring \"-qmljsdebugger=%1\". "
- "Debugging has not been enabled.")).arg(
- appD->qmljsDebugArgumentsString());
- return 0;
- }
+ // ### remove port definition when protocol is changed
+ int portFrom = 0;
+ int portTo = 0;
+ bool block = false;
+ bool ok = false;
+ QString hostAddress;
+
+ // format: qmljsdebugger=port:<port_from>[,port_to],host:<ip address>][,block]
+ if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ if (!QQmlEnginePrivate::qml_debugging_enabled) {
+ qWarning() << QString(QLatin1String(
+ "QML Debugger: Ignoring \"-qmljsdebugger=%1\". "
+ "Debugging has not been enabled.")).arg(
+ appD->qmljsDebugArgumentsString());
+ return;
+ }
- QString pluginName;
- QStringList lstjsDebugArguments = appD->qmljsDebugArgumentsString()
- .split(QLatin1Char(','));
- QStringList::const_iterator argsItEnd = lstjsDebugArguments.end();
- QStringList::const_iterator argsIt = lstjsDebugArguments.begin();
- for (; argsIt != argsItEnd; ++argsIt) {
- const QString strArgument = *argsIt;
- if (strArgument.startsWith(QLatin1String("port:"))) {
- pluginName = QLatin1String("qmldbg_tcp");
- portFrom = strArgument.mid(5).toInt(&ok);
- portTo = portFrom;
- QStringList::const_iterator argsNext = argsIt + 1;
- if (argsNext == argsItEnd)
- break;
- const QString nextArgument = *argsNext;
- if (ok && nextArgument.contains(QRegExp(QStringLiteral("^\\s*\\d+\\s*$")))) {
- portTo = nextArgument.toInt(&ok);
- ++argsIt;
- }
- } else if (strArgument.startsWith(QLatin1String("host:"))) {
- hostAddress = strArgument.mid(5);
- } else if (strArgument == QLatin1String("block")) {
- block = true;
- } else {
- qWarning() << QString::fromLatin1("QML Debugger: Invalid argument '%1' "
- "detected. Ignoring the same.")
- .arg(strArgument);
+ QString pluginName;
+ QStringList lstjsDebugArguments = appD->qmljsDebugArgumentsString()
+ .split(QLatin1Char(','));
+ QStringList::const_iterator argsItEnd = lstjsDebugArguments.end();
+ QStringList::const_iterator argsIt = lstjsDebugArguments.begin();
+ for (; argsIt != argsItEnd; ++argsIt) {
+ const QString strArgument = *argsIt;
+ if (strArgument.startsWith(QLatin1String("port:"))) {
+ pluginName = QLatin1String("qmldbg_tcp");
+ portFrom = strArgument.mid(5).toInt(&ok);
+ portTo = portFrom;
+ QStringList::const_iterator argsNext = argsIt + 1;
+ if (argsNext == argsItEnd)
+ break;
+ const QString nextArgument = *argsNext;
+ if (ok && nextArgument.contains(QRegExp(QStringLiteral("^\\s*\\d+\\s*$")))) {
+ portTo = nextArgument.toInt(&ok);
+ ++argsIt;
}
+ } else if (strArgument.startsWith(QLatin1String("host:"))) {
+ hostAddress = strArgument.mid(5);
+ } else if (strArgument == QLatin1String("block")) {
+ block = true;
+ } else {
+ qWarning() << QString::fromLatin1("QML Debugger: Invalid argument '%1' "
+ "detected. Ignoring the same.")
+ .arg(strArgument);
}
+ }
- if (ok) {
- qQmlDebugServer = new QQmlDebugServer();
- QQmlDebugServerThread *thread = new QQmlDebugServerThread;
- qQmlDebugServer->d_func()->thread = thread;
- qQmlDebugServer->moveToThread(thread);
- thread->setPluginName(pluginName);
- thread->setPortRange(portFrom, portTo, block, hostAddress);
-
- QQmlDebugServerPrivate *d = qQmlDebugServer->d_func();
- d->blockingMode = block;
-
- QMutexLocker locker(&d->helloMutex);
- thread->start();
+ if (ok) {
+ qAddPostRoutine(cleanup);
+ Q_D(QQmlDebugServer);
+ d->thread = new QQmlDebugServerThread;
+ moveToThread(d->thread);
+ d->thread->setPluginName(pluginName);
+ d->thread->setPortRange(portFrom, portTo, block, hostAddress);
- if (d->blockingMode)
- d->helloCondition.wait(&d->helloMutex);
+ d->blockingMode = block;
+ d->thread->start();
- } else {
- qWarning() << QString(QLatin1String(
- "QML Debugger: Ignoring \"-qmljsdebugger=%1\". "
- "Format is qmljsdebugger=port:<port_from>[,port_to],host:"
- "<ip address>][,block]")).arg(appD->qmljsDebugArgumentsString());
- }
- }
-#else
- if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ } else {
qWarning() << QString(QLatin1String(
- "QML Debugger: Ignoring \"-qmljsdebugger=%1\". "
- "QtQml is not configured for debugging.")).arg(
- appD->qmljsDebugArgumentsString());
+ "QML Debugger: Ignoring \"-qmljsdebugger=%1\". "
+ "Format is qmljsdebugger=port:<port_from>[,port_to],host:"
+ "<ip address>][,block]")).arg(appD->qmljsDebugArgumentsString());
}
-#endif
}
-
- return qQmlDebugServer;
-}
-
-QQmlDebugServer::QQmlDebugServer()
- : QObject(*(new QQmlDebugServerPrivate))
-{
- qAddPostRoutine(cleanup);
+#else
+ if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ qWarning() << QString(QLatin1String(
+ "QML Debugger: Ignoring \"-qmljsdebugger=%1\". "
+ "QtQml is not configured for debugging.")).arg(
+ appD->qmljsDebugArgumentsString());
+ }
+#endif
}
// called from GUI thread!
@@ -368,28 +415,7 @@ QQmlDebugServer::~QQmlDebugServer()
{
Q_D(QQmlDebugServer);
- {
- QReadLocker lock(&d->pluginsLock);
- foreach (QQmlDebugService *service, d->plugins.values()) {
- d->changeServiceStateCalls.ref();
- QMetaObject::invokeMethod(this, "_q_changeServiceState", Qt::QueuedConnection,
- Q_ARG(QString, service->name()),
- Q_ARG(QQmlDebugService::State, QQmlDebugService::NotConnected));
- }
- }
-
- // Wait for changeServiceState calls to finish
- // (while running an event loop because some services
- // might again use slots to execute stuff in the GUI thread)
- QEventLoop loop;
- while (!d->changeServiceStateCalls.testAndSetOrdered(0, 0))
- loop.processEvents();
-
- if (d->thread) {
- d->thread->exit();
- d->thread->wait();
- delete d->thread;
- }
+ delete d->thread;
delete d->connection;
}
@@ -409,6 +435,7 @@ void QQmlDebugServer::receiveMessage(const QByteArray &message)
int op = -1;
in >> op;
if (op == 0) {
+ QWriteLocker lock(&d->pluginsLock);
int version;
in >> version >> d->clientPlugins;
@@ -423,24 +450,22 @@ void QQmlDebugServer::receiveMessage(const QByteArray &message)
// the plugins below start sending messages.
QByteArray helloAnswer;
- {
- QReadLocker readPluginsLock(&d->pluginsLock);
- QQmlDebugStream out(&helloAnswer, QIODevice::WriteOnly);
- QStringList pluginNames;
- QList<float> pluginVersions;
- foreach (QQmlDebugService *service, d->plugins.values()) {
- pluginNames << service->name();
- pluginVersions << service->version();
- }
-
- out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion
- << pluginNames << pluginVersions << s_dataStreamVersion;
+ QQmlDebugStream out(&helloAnswer, QIODevice::WriteOnly);
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ foreach (QQmlDebugService *service, d->plugins.values()) {
+ pluginNames << service->name();
+ pluginVersions << service->version();
}
+
+ out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion
+ << pluginNames << pluginVersions << s_dataStreamVersion;
+
d->connection->send(QList<QByteArray>() << helloAnswer);
+ QMutexLocker helloLock(&d->helloMutex);
d->gotHello = true;
- QReadLocker lock(&d->pluginsLock);
QHash<QString, QQmlDebugService*>::ConstIterator iter = d->plugins.constBegin();
for (; iter != d->plugins.constEnd(); ++iter) {
QQmlDebugService::State newState = QQmlDebugService::Unavailable;
@@ -450,16 +475,15 @@ void QQmlDebugServer::receiveMessage(const QByteArray &message)
d->_q_changeServiceState(iter.value()->name(), newState);
}
- QMutexLocker helloLock(&d->helloMutex);
d->helloCondition.wakeAll();
} else if (op == 1) {
+ QWriteLocker lock(&d->pluginsLock);
// Service Discovery
QStringList oldClientPlugins = d->clientPlugins;
in >> d->clientPlugins;
- QReadLocker lock(&d->pluginsLock);
QHash<QString, QQmlDebugService*>::ConstIterator iter = d->plugins.constBegin();
for (; iter != d->plugins.constEnd(); ++iter) {
const QString pluginName = iter.key();
@@ -507,7 +531,10 @@ void QQmlDebugServerPrivate::_q_changeServiceState(const QString &serviceName,
QQmlDebugService *service = 0;
{
- QReadLocker lock(&pluginsLock);
+ // Write lock here, because this can be called from receiveMessage which already has a write
+ // lock. We cannot downgrade it. We also don't want to give up the write lock and later get
+ // a read lock as that technique has great potential for deadlocks.
+ QWriteLocker lock(&pluginsLock);
service = plugins.value(serviceName);
}
@@ -543,27 +570,50 @@ QStringList QQmlDebugServer::serviceNames() const
return d->plugins.keys();
}
-bool QQmlDebugServer::addService(QQmlDebugService *service)
+void QQmlDebugServer::addEngine(QQmlEngine *engine)
{
Q_D(QQmlDebugServer);
+ QReadLocker lock(&d->pluginsLock);
- // to be executed in GUI thread
- Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+ foreach (QQmlDebugService *service, d->plugins)
+ service->engineAboutToBeAdded(engine);
- {
- QWriteLocker lock(&d->pluginsLock);
- if (!service || d->plugins.contains(service->name()))
- return false;
- d->plugins.insert(service->name(), service);
- }
- {
- QReadLocker lock(&d->pluginsLock);
- d->advertisePlugins();
- QQmlDebugService::State newState = QQmlDebugService::Unavailable;
- if (d->clientPlugins.contains(service->name()))
- newState = QQmlDebugService::Enabled;
- service->d_func()->state = newState;
- }
+ // TODO: Later wait here for initialization.
+
+ foreach (QQmlDebugService *service, d->plugins)
+ service->engineAdded(engine);
+}
+
+void QQmlDebugServer::removeEngine(QQmlEngine *engine)
+{
+ Q_D(QQmlDebugServer);
+ QReadLocker lock(&d->pluginsLock);
+
+ foreach (QQmlDebugService *service, d->plugins)
+ service->engineAboutToBeRemoved(engine);
+
+ // TODO: Later wait here for cleanup
+
+ foreach (QQmlDebugService *service, d->plugins)
+ service->engineRemoved(engine);
+}
+
+bool QQmlDebugServer::addService(QQmlDebugService *service)
+{
+ Q_D(QQmlDebugServer);
+
+ // to be executed outside of debugger thread
+ Q_ASSERT(QThread::currentThread() != thread());
+
+ QWriteLocker lock(&d->pluginsLock);
+ if (!service || d->plugins.contains(service->name()))
+ return false;
+ d->plugins.insert(service->name(), service);
+ d->advertisePlugins();
+ QQmlDebugService::State newState = QQmlDebugService::Unavailable;
+ if (d->clientPlugins.contains(service->name()))
+ newState = QQmlDebugService::Enabled;
+ service->d_func()->state = newState;
return true;
}
@@ -571,24 +621,22 @@ bool QQmlDebugServer::removeService(QQmlDebugService *service)
{
Q_D(QQmlDebugServer);
- // to be executed in GUI thread
- Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+ // to be executed outside of debugger thread
+ Q_ASSERT(QThread::currentThread() != thread());
- {
- QWriteLocker lock(&d->pluginsLock);
- QQmlDebugService::State newState = QQmlDebugService::NotConnected;
+ QWriteLocker lock(&d->pluginsLock);
+ QQmlDebugService::State newState = QQmlDebugService::NotConnected;
- d->changeServiceStateCalls.ref();
- QMetaObject::invokeMethod(this, "_q_changeServiceState", Qt::QueuedConnection,
- Q_ARG(QString, service->name()),
- Q_ARG(QQmlDebugService::State, newState));
+ d->changeServiceStateCalls.ref();
+ QMetaObject::invokeMethod(this, "_q_changeServiceState", Qt::QueuedConnection,
+ Q_ARG(QString, service->name()),
+ Q_ARG(QQmlDebugService::State, newState));
- if (!service || !d->plugins.contains(service->name()))
- return false;
- d->plugins.remove(service->name());
+ if (!service || !d->plugins.contains(service->name()))
+ return false;
+ d->plugins.remove(service->name());
- d->advertisePlugins();
- }
+ d->advertisePlugins();
return true;
}
diff --git a/src/qml/debugger/qqmldebugserver_p.h b/src/qml/debugger/qqmldebugserver_p.h
index e285d7cfe7..2d3ffb9351 100644
--- a/src/qml/debugger/qqmldebugserver_p.h
+++ b/src/qml/debugger/qqmldebugserver_p.h
@@ -77,6 +77,8 @@ public:
QList<QQmlDebugService*> services() const;
QStringList serviceNames() const;
+ void addEngine(QQmlEngine *engine);
+ void removeEngine(QQmlEngine *engine);
bool addService(QQmlDebugService *service);
bool removeService(QQmlDebugService *service);
@@ -89,6 +91,7 @@ private:
friend class QQmlDebugService;
friend class QQmlDebugServicePrivate;
friend class QQmlDebugServerThread;
+ friend struct QQmlDebugServerInstanceWrapper;
QQmlDebugServer();
Q_PRIVATE_SLOT(d_func(), void _q_changeServiceState(const QString &serviceName,
QQmlDebugService::State state))
diff --git a/src/qml/debugger/qqmldebugservice.cpp b/src/qml/debugger/qqmldebugservice.cpp
index d8fc2f2bb2..f9e6643305 100644
--- a/src/qml/debugger/qqmldebugservice.cpp
+++ b/src/qml/debugger/qqmldebugservice.cpp
@@ -318,6 +318,22 @@ void QQmlDebugService::messageReceived(const QByteArray &)
{
}
+void QQmlDebugService::engineAboutToBeAdded(QQmlEngine *)
+{
+}
+
+void QQmlDebugService::engineAboutToBeRemoved(QQmlEngine *)
+{
+}
+
+void QQmlDebugService::engineAdded(QQmlEngine *)
+{
+}
+
+void QQmlDebugService::engineRemoved(QQmlEngine *)
+{
+}
+
QQmlDebugStream::QQmlDebugStream()
: QDataStream()
{
diff --git a/src/qml/debugger/qqmldebugservice_p.h b/src/qml/debugger/qqmldebugservice_p.h
index 71a116f6a5..fd2a8c361a 100644
--- a/src/qml/debugger/qqmldebugservice_p.h
+++ b/src/qml/debugger/qqmldebugservice_p.h
@@ -60,6 +60,7 @@
QT_BEGIN_NAMESPACE
+class QQmlEngine;
class QQmlDebugServicePrivate;
class Q_QML_PRIVATE_EXPORT QQmlDebugService : public QObject
@@ -103,6 +104,11 @@ protected:
virtual void stateChanged(State);
virtual void messageReceived(const QByteArray &);
+ virtual void engineAboutToBeAdded(QQmlEngine *);
+ virtual void engineAboutToBeRemoved(QQmlEngine *);
+ virtual void engineAdded(QQmlEngine *);
+ virtual void engineRemoved(QQmlEngine *);
+
private:
friend class QQmlDebugServer;
friend class QQmlDebugServerPrivate;
diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp
index 300561050f..0530b93a82 100644
--- a/src/qml/debugger/qqmlenginedebugservice.cpp
+++ b/src/qml/debugger/qqmlenginedebugservice.cpp
@@ -759,7 +759,7 @@ void QQmlEngineDebugService::propertyChanged(int id, int objectId, const QMetaPr
sendMessage(reply);
}
-void QQmlEngineDebugService::addEngine(QQmlEngine *engine)
+void QQmlEngineDebugService::engineAboutToBeAdded(QQmlEngine *engine)
{
Q_ASSERT(engine);
Q_ASSERT(!m_engines.contains(engine));
@@ -767,7 +767,7 @@ void QQmlEngineDebugService::addEngine(QQmlEngine *engine)
m_engines.append(engine);
}
-void QQmlEngineDebugService::remEngine(QQmlEngine *engine)
+void QQmlEngineDebugService::engineAboutToBeRemoved(QQmlEngine *engine)
{
Q_ASSERT(engine);
Q_ASSERT(m_engines.contains(engine));
diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h
index bbd6aac1b1..4809ee3ed5 100644
--- a/src/qml/debugger/qqmlenginedebugservice_p.h
+++ b/src/qml/debugger/qqmlenginedebugservice_p.h
@@ -96,8 +96,8 @@ public:
bool hasNotifySignal;
};
- void addEngine(QQmlEngine *);
- void remEngine(QQmlEngine *);
+ void engineAboutToBeAdded(QQmlEngine *);
+ void engineAboutToBeRemoved(QQmlEngine *);
void objectCreated(QQmlEngine *, QObject *);
void setStatesDelegate(QQmlDebugStatesDelegate *);
diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp
index 91d27f9b11..5d4574231e 100644
--- a/src/qml/debugger/qqmlprofilerservice.cpp
+++ b/src/qml/debugger/qqmlprofilerservice.cpp
@@ -50,7 +50,7 @@
QT_BEGIN_NAMESPACE
// instance will be set, unset in constructor. Allows static methods to be inlined.
-QQmlProfilerService *QQmlProfilerService::instance = 0;
+QQmlProfilerService *QQmlProfilerService::m_instance = 0;
Q_GLOBAL_STATIC(QQmlProfilerService, profilerInstance)
bool QQmlProfilerService::enabled = false;
@@ -154,13 +154,14 @@ QQmlProfilerService::QQmlProfilerService()
QQmlProfilerService::~QQmlProfilerService()
{
enabled = false;
- instance = 0;
+ m_instance = 0;
}
-void QQmlProfilerService::initialize()
+QQmlProfilerService *QQmlProfilerService::instance()
{
// just make sure that the service is properly registered
- instance = profilerInstance();
+ m_instance = profilerInstance();
+ return m_instance;
}
bool QQmlProfilerService::startProfiling()
diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h
index c3329dbb89..cdc49f2ea7 100644
--- a/src/qml/debugger/qqmlprofilerservice_p.h
+++ b/src/qml/debugger/qqmlprofilerservice_p.h
@@ -234,7 +234,7 @@ public:
MaximumSceneGraphFrameType
};
- static void initialize();
+ static QQmlProfilerService *instance();
static bool startProfiling();
static bool stopProfiling();
@@ -242,7 +242,7 @@ public:
template<EventType DetailType>
static void addEvent()
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(), 1 << Event,
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << Event,
1 << DetailType));
}
@@ -251,7 +251,7 @@ public:
int animCount = QUnifiedTimer::instance()->runningAnimationCount();
if (animCount > 0 && delta > 0) {
- instance->processMessage(QQmlProfilerData(instance->timestamp(), 1 << Event,
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << Event,
1 << AnimationFrame, QString(), 0, 0,
1000 / (int)delta /* trim fps to integer */,
animCount));
@@ -262,7 +262,7 @@ public:
static void sceneGraphFrame(qint64 value1, qint64 value2 = -1, qint64 value3 = -1,
qint64 value4 = -1, qint64 value5 = -1)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(), 1 << SceneGraphFrame,
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << SceneGraphFrame,
1 << FrameType1 | 1 << FrameType2,
value1, value2, value3, value4, value5));
}
@@ -270,13 +270,13 @@ public:
template<PixmapEventType PixmapState>
static void pixmapStateChanged(const QUrl &url)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(), 1 << PixmapCacheEvent,
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << PixmapCacheEvent,
1 << PixmapState, url));
}
static void pixmapLoadingFinished(const QUrl &url, const QSize &size)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(), 1 << PixmapCacheEvent,
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << PixmapCacheEvent,
(1 << PixmapLoadingFinished) | ((size.width() > 0 && size.height() > 0) ? (1 << PixmapSizeKnown) : 0),
url, size.width(), size.height()));
}
@@ -284,7 +284,7 @@ public:
template<PixmapEventType CountType>
static void pixmapCountChanged(const QUrl &url, int count)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(), 1 << PixmapCacheEvent,
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << PixmapCacheEvent,
1 << CountType, url, 0, 0, 0, count));
}
@@ -305,7 +305,7 @@ private:
static void startBinding(const QString &fileName, int line, int column, BindingType bindingType)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(),
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(),
(1 << RangeStart | 1 << RangeLocation),
1 << Binding, fileName, line, column, 0, 0,
bindingType));
@@ -315,14 +315,14 @@ private:
// This is somewhat pointless but important for backwards compatibility.
static void startCompiling(const QString &name)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(),
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(),
(1 << RangeStart | 1 << RangeLocation | 1 << RangeData), 1 << Compiling,
name, 1, 1, 0, 0, QmlBinding));
}
static void startHandlingSignal(const QString &fileName, int line, int column)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(),
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(),
(1 << RangeStart | 1 << RangeLocation),
1 << HandlingSignal, fileName, line, column, 0, 0,
QmlBinding));
@@ -330,7 +330,7 @@ private:
static void startCreating(const QString &typeName, const QUrl &fileName, int line, int column)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(),
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(),
(1 << RangeStart | 1 << RangeLocation | 1 << RangeData),
1 << Creating, typeName, fileName, line, column,
0, 0, QmlBinding));
@@ -338,21 +338,21 @@ private:
static void startCreating(const QString &typeName)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(),
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(),
(1 << RangeStart | 1 << RangeData), 1 << Creating,
typeName, 0, 0, 0, 0, QmlBinding));
}
static void creatingLocation(const QUrl &fileName, int line, int column)
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(), 1 << RangeLocation,
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << RangeLocation,
1 << Creating, fileName, line, column));
}
template<RangeType Range>
static void endRange()
{
- instance->processMessage(QQmlProfilerData(instance->timestamp(), 1 << RangeEnd,
+ m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << RangeEnd,
1 << Range));
}
@@ -375,7 +375,7 @@ private:
QMutex m_initializeMutex;
QWaitCondition m_initializeCondition;
- static QQmlProfilerService *instance;
+ static QQmlProfilerService *m_instance;
friend struct QQmlBindingProfiler;
friend struct QQmlHandlingSignalProfiler;
@@ -402,20 +402,19 @@ struct QQmlBindingProfiler {
struct QQmlHandlingSignalProfiler {
QQmlHandlingSignalProfiler(QQmlBoundSignalExpression *expression)
{
- if (QQmlProfilerService::enabled) {
- if (expression->sourceFile().isEmpty()) {
- QV4::Function *function = expression->function();
- if (function) {
- Q_QML_PROFILE(startHandlingSignal(
- function->sourceFile(), function->compiledFunction->location.line,
- function->compiledFunction->location.column));
- }
+ Q_QML_PROFILE_IF_ENABLED({
+ QV4::Function *function;
+ if (expression->sourceFile().isEmpty() && (function = expression->function())) {
+ QQmlProfilerService::startHandlingSignal(
+ function->sourceFile(), function->compiledFunction->location.line,
+ function->compiledFunction->location.column);
+
} else {
- Q_QML_PROFILE(startHandlingSignal(
+ QQmlProfilerService::startHandlingSignal(
expression->sourceFile(), expression->lineNumber(),
- expression->columnNumber()));
+ expression->columnNumber());
}
- }
+ });
}
~QQmlHandlingSignalProfiler()
@@ -455,9 +454,9 @@ public:
{
ranges.clear();
if (running)
- QQmlProfilerService::instance->endRange<QQmlProfilerService::Creating>();
+ QQmlProfilerService::m_instance->endRange<QQmlProfilerService::Creating>();
for (int i = 0; i < backgroundRanges.count(); ++i) {
- QQmlProfilerService::instance->endRange<QQmlProfilerService::Creating>();
+ QQmlProfilerService::m_instance->endRange<QQmlProfilerService::Creating>();
}
backgroundRanges.clear();
running = false;
@@ -466,10 +465,10 @@ public:
void startBackground(const QString &typeName)
{
if (running) {
- QQmlProfilerService::instance->endRange<QQmlProfilerService::Creating>();
+ QQmlProfilerService::m_instance->endRange<QQmlProfilerService::Creating>();
running = false;
}
- QQmlProfilerService::instance->startCreating(typeName);
+ QQmlProfilerService::m_instance->startCreating(typeName);
backgroundRanges.push(typeName);
}
@@ -477,13 +476,13 @@ public:
{
switchRange();
setCurrentRange(typeName, url, line, column);
- QQmlProfilerService::instance->startCreating(typeName, url, line, column);
+ QQmlProfilerService::m_instance->startCreating(typeName, url, line, column);
}
void stop()
{
if (running) {
- QQmlProfilerService::instance->endRange<QQmlProfilerService::Creating>();
+ QQmlProfilerService::m_instance->endRange<QQmlProfilerService::Creating>();
running = false;
}
}
@@ -493,7 +492,7 @@ public:
if (ranges.count() > 0) {
switchRange();
currentRange = ranges.pop();
- QQmlProfilerService::instance->startCreating(currentRange.typeName, currentRange.url,
+ QQmlProfilerService::m_instance->startCreating(currentRange.typeName, currentRange.url,
currentRange.line, currentRange.column);
}
}
@@ -509,7 +508,7 @@ public:
if (backgroundRanges.count() > 0) {
switchRange();
setCurrentRange(backgroundRanges.pop(), url, line, column);
- QQmlProfilerService::instance->creatingLocation(url, line, column);
+ QQmlProfilerService::m_instance->creatingLocation(url, line, column);
}
}
@@ -518,7 +517,7 @@ private:
void switchRange()
{
if (running)
- QQmlProfilerService::instance->endRange<QQmlProfilerService::Creating>();
+ QQmlProfilerService::m_instance->endRange<QQmlProfilerService::Creating>();
else
running = true;
}
diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp
index 372a51e997..0058e78e7f 100644
--- a/src/qml/debugger/qv4debugservice.cpp
+++ b/src/qml/debugger/qv4debugservice.cpp
@@ -1022,10 +1022,10 @@ QV4DebugService *QV4DebugService::instance()
return v4ServiceInstance();
}
-void QV4DebugService::addEngine(const QQmlEngine *engine)
+void QV4DebugService::engineAboutToBeAdded(QQmlEngine *engine)
{
Q_D(QV4DebugService);
-
+ QMutexLocker lock(&d->initializeMutex);
if (engine) {
QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
if (QQmlDebugServer *server = QQmlDebugServer::instance()) {
@@ -1041,9 +1041,10 @@ void QV4DebugService::addEngine(const QQmlEngine *engine)
}
}
-void QV4DebugService::removeEngine(const QQmlEngine *engine)
+void QV4DebugService::engineAboutToBeRemoved(QQmlEngine *engine)
{
Q_D(QV4DebugService);
+ QMutexLocker lock(&d->initializeMutex);
if (engine){
const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
if (ee) {
diff --git a/src/qml/debugger/qv4debugservice_p.h b/src/qml/debugger/qv4debugservice_p.h
index e35010bebf..0aa38150c6 100644
--- a/src/qml/debugger/qv4debugservice_p.h
+++ b/src/qml/debugger/qv4debugservice_p.h
@@ -69,8 +69,8 @@ public:
~QV4DebugService();
static QV4DebugService *instance();
- void addEngine(const QQmlEngine *engine);
- void removeEngine(const QQmlEngine *engine);
+ void engineAboutToBeAdded(QQmlEngine *engine);
+ void engineAboutToBeRemoved(QQmlEngine *engine);
void signalEmitted(const QString &signal);
diff --git a/src/qml/debugger/qv4profilerservice.cpp b/src/qml/debugger/qv4profilerservice.cpp
index 50bec8ec25..b064f57089 100644
--- a/src/qml/debugger/qv4profilerservice.cpp
+++ b/src/qml/debugger/qv4profilerservice.cpp
@@ -127,12 +127,6 @@ QV4ProfilerService *QV4ProfilerService::instance()
return v4ProfilerInstance();
}
-void QV4ProfilerService::initialize()
-{
- // just make sure that the service is properly registered
- v4ProfilerInstance();
-}
-
void QV4ProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
{
Q_D(QV4ProfilerService);
diff --git a/src/qml/debugger/qv4profilerservice_p.h b/src/qml/debugger/qv4profilerservice_p.h
index 252c154a68..cf330e5a1b 100644
--- a/src/qml/debugger/qv4profilerservice_p.h
+++ b/src/qml/debugger/qv4profilerservice_p.h
@@ -92,7 +92,6 @@ public:
~QV4ProfilerService();
static QV4ProfilerService *instance();
- static void initialize();
public Q_SLOTS:
void startProfiling(const QString &title);
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index c8de31ef78..38a8e40cb2 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -45,7 +45,7 @@
#include "qjsengine.h"
#include "qjsvalue.h"
#include "qjsvalue_p.h"
-#include "qv4value_p.h"
+#include "qv4value_inl_p.h"
#include "qv4object_p.h"
#include "qv4functionobject_p.h"
#include "qv4dateobject_p.h"
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index d8da664cc6..41856b1e98 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -55,7 +55,7 @@
#include <qjsvalue.h>
#include <private/qtqmlglobal_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4string_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4object_p.h>
diff --git a/src/qml/jsapi/qjsvalueiterator_p.h b/src/qml/jsapi/qjsvalueiterator_p.h
index 80d1885811..882c779c00 100644
--- a/src/qml/jsapi/qjsvalueiterator_p.h
+++ b/src/qml/jsapi/qjsvalueiterator_p.h
@@ -58,11 +58,11 @@ public:
QV4::PersistentValue iterator;
QV4::Property currentProperty;
QV4::PropertyAttributes currentAttributes;
- QV4::SafeString currentName;
+ QV4::StringValue currentName;
uint currentIndex;
QV4::Property nextProperty;
QV4::PropertyAttributes nextAttributes;
- QV4::SafeString nextName;
+ QV4::StringValue nextName;
uint nextIndex;
};
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index a90cea96c2..43eb61ac9a 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -6,6 +6,7 @@ SOURCES += \
$$PWD/qv4context.cpp \
$$PWD/qv4runtime.cpp \
$$PWD/qv4value.cpp \
+ $$PWD/qv4persistent.cpp \
$$PWD/qv4debugging.cpp \
$$PWD/qv4lookup.cpp \
$$PWD/qv4identifier.cpp \
@@ -49,8 +50,9 @@ HEADERS += \
$$PWD/qv4context_p.h \
$$PWD/qv4runtime_p.h \
$$PWD/qv4math_p.h \
+ $$PWD/qv4value_inl_p.h \
$$PWD/qv4value_p.h \
- $$PWD/qv4value_def_p.h \
+ $$PWD/qv4persistent_p.h \
$$PWD/qv4debugging_p.h \
$$PWD/qv4lookup_p.h \
$$PWD/qv4identifier_p.h \
diff --git a/src/qml/jsruntime/qv4alloca_p.h b/src/qml/jsruntime/qv4alloca_p.h
index e51c6dff00..a76c327b04 100644
--- a/src/qml/jsruntime/qv4alloca_p.h
+++ b/src/qml/jsruntime/qv4alloca_p.h
@@ -49,10 +49,8 @@
# ifndef __GNUC__
# define alloca _alloca
# endif
-#else
-#if !defined(__FreeBSD__) && !defined(__DragonFly__)
+#elif !defined(Q_OS_BSD4) || defined(Q_OS_DARWIN)
# include <alloca.h>
#endif
-#endif
#endif
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 20354272f2..b50c4f081d 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -80,7 +80,7 @@ struct ArgumentsObject: Object {
Q_MANAGED_TYPE(ArgumentsObject)
CallContext *context;
bool fullyCreated;
- QVector<SafeValue> mappedArguments;
+ QVector<Value> mappedArguments;
ArgumentsObject(CallContext *context);
~ArgumentsObject() {}
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 9c6ff94583..44727cba17 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -110,7 +110,7 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e
newType = Complex;
alloc = qMax(alloc, 2*oldAlloc) + offset;
- size_t size = alloc*sizeof(SafeValue);
+ size_t size = alloc*sizeof(Value);
if (enforceAttributes)
size += alloc*sizeof(PropertyAttributes);
@@ -120,7 +120,7 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e
new (newData) SimpleArrayData(o->engine());
newData->alloc = alloc - offset;
newData->type = newType;
- newData->data = reinterpret_cast<SafeValue *>(newData + 1) + offset;
+ newData->data = reinterpret_cast<Value *>(newData + 1) + offset;
newData->attrs = enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->data + alloc) + offset : 0;
newData->offset = offset;
newData->len = d ? static_cast<SimpleArrayData *>(d)->len : 0;
@@ -131,13 +131,13 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e
new (newData) SparseArrayData(o->engine());
newData->alloc = alloc;
newData->type = newType;
- newData->data = reinterpret_cast<SafeValue *>(newData + 1);
+ newData->data = reinterpret_cast<Value *>(newData + 1);
newData->attrs = enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->data + alloc) : 0;
o->arrayData = newData;
}
if (d) {
- memcpy(o->arrayData->data, d->data, sizeof(SafeValue)*toCopy);
+ memcpy(o->arrayData->data, d->data, sizeof(Value)*toCopy);
if (enforceAttributes) {
if (d->attrs)
memcpy(o->arrayData->attrs, d->attrs, sizeof(PropertyAttributes)*toCopy);
@@ -267,7 +267,7 @@ PropertyAttributes SimpleArrayData::attribute(const ArrayData *d, uint index)
return d->attrs[index];
}
-void SimpleArrayData::push_front(Object *o, SafeValue *values, uint n)
+void SimpleArrayData::push_front(Object *o, Value *values, uint n)
{
SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
Q_ASSERT(!dd->attrs);
@@ -309,8 +309,8 @@ uint SimpleArrayData::truncate(Object *o, uint newLen)
return newLen;
if (dd->attrs) {
- SafeValue *it = dd->data + dd->len;
- const SafeValue *begin = dd->data + newLen;
+ Value *it = dd->data + dd->len;
+ const Value *begin = dd->data + newLen;
while (--it >= begin) {
if (!it->isEmpty() && !dd->attrs[it - dd->data].isConfigurable()) {
newLen = it - dd->data + 1;
@@ -328,7 +328,7 @@ uint SimpleArrayData::length(const ArrayData *d)
return static_cast<const SimpleArrayData *>(d)->len;
}
-bool SimpleArrayData::putArray(Object *o, uint index, SafeValue *values, uint n)
+bool SimpleArrayData::putArray(Object *o, uint index, Value *values, uint n)
{
SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
if (index + n > dd->alloc) {
@@ -347,7 +347,7 @@ void SparseArrayData::free(ArrayData *d, uint idx)
{
Q_ASSERT(d && d->type == ArrayData::Sparse);
SparseArrayData *dd = static_cast<SparseArrayData *>(d);
- SafeValue *v = dd->data + idx;
+ Value *v = dd->data + idx;
if (dd->attrs && dd->attrs[idx].isAccessor()) {
// double slot, free both. Order is important, so we have a double slot for allocation again afterwards.
v[1].tag = Value::Empty_Type;
@@ -502,7 +502,7 @@ PropertyAttributes SparseArrayData::attribute(const ArrayData *d, uint index)
return d->attrs[n->value];
}
-void SparseArrayData::push_front(Object *o, SafeValue *values, uint n)
+void SparseArrayData::push_front(Object *o, Value *values, uint n)
{
Q_ASSERT(!o->arrayData->attrs);
for (int i = n - 1; i >= 0; --i) {
@@ -561,7 +561,7 @@ uint SparseArrayData::length(const ArrayData *d)
return n ? n->key() + 1 : 0;
}
-bool SparseArrayData::putArray(Object *o, uint index, SafeValue *values, uint n)
+bool SparseArrayData::putArray(Object *o, uint index, Value *values, uint n)
{
for (uint i = 0; i < n; ++i)
put(o, index + i, values[i]);
@@ -630,6 +630,47 @@ Property *ArrayData::insert(Object *o, uint index, bool isAccessor)
return reinterpret_cast<Property *>(o->arrayData->data + n->value);
}
+
+class ArrayElementLessThan
+{
+public:
+ inline ArrayElementLessThan(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn)
+ : m_context(context), thisObject(thisObject), m_comparefn(comparefn) {}
+
+ bool operator()(const Value &v1, const Value &v2) const;
+
+private:
+ ExecutionContext *m_context;
+ ObjectRef thisObject;
+ const ValueRef m_comparefn;
+};
+
+
+bool ArrayElementLessThan::operator()(const Value &v1, const Value &v2) const
+{
+ Scope scope(m_context);
+
+ if (v1.isUndefined() || v1.isEmpty())
+ return false;
+ if (v2.isUndefined() || v2.isEmpty())
+ return true;
+ ScopedObject o(scope, m_comparefn);
+ if (o) {
+ Scope scope(o->engine());
+ ScopedValue result(scope);
+ ScopedCallData callData(scope, 2);
+ callData->thisObject = Primitive::undefinedValue();
+ callData->args[0] = v1;
+ callData->args[1] = v2;
+ result = __qmljs_call_value(m_context, m_comparefn, callData);
+
+ return result->toNumber() < 0;
+ }
+ ScopedString p1s(scope, v1.toString(m_context));
+ ScopedString p2s(scope, v2.toString(m_context));
+ return p1s->toQString() < p2s->toQString();
+}
+
void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint len)
{
if (!len)
@@ -720,7 +761,7 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu
ArrayElementLessThan lessThan(context, thisObject, comparefn);
- SafeValue *begin = thisObject->arrayData->data;
+ Value *begin = thisObject->arrayData->data;
std::sort(begin, begin + len, lessThan);
#ifdef CHECK_SPARSE_ARRAYS
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 48b17a239f..f127c75fb0 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -67,11 +67,11 @@ struct ArrayVTable
ArrayData *(*reallocate)(Object *o, uint n, bool enforceAttributes);
ReturnedValue (*get)(const ArrayData *d, uint index);
bool (*put)(Object *o, uint index, ValueRef value);
- bool (*putArray)(Object *o, uint index, SafeValue *values, uint n);
+ bool (*putArray)(Object *o, uint index, Value *values, uint n);
bool (*del)(Object *o, uint index);
void (*setAttribute)(Object *o, uint index, PropertyAttributes attrs);
PropertyAttributes (*attribute)(const ArrayData *d, uint index);
- void (*push_front)(Object *o, SafeValue *values, uint n);
+ void (*push_front)(Object *o, Value *values, uint n);
ReturnedValue (*pop_front)(Object *o);
uint (*truncate)(Object *o, uint newLen);
uint (*length)(const ArrayData *d);
@@ -95,7 +95,7 @@ struct Q_QML_EXPORT ArrayData : public Managed
uint alloc;
Type type;
PropertyAttributes *attrs;
- SafeValue *data;
+ Value *data;
const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(internalClass->vtable); }
bool isSparse() const { return this && type == Sparse; }
@@ -154,11 +154,11 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData
static ReturnedValue get(const ArrayData *d, uint index);
static bool put(Object *o, uint index, ValueRef value);
- static bool putArray(Object *o, uint index, SafeValue *values, uint n);
+ static bool putArray(Object *o, uint index, Value *values, uint n);
static bool del(Object *o, uint index);
static void setAttribute(Object *o, uint index, PropertyAttributes attrs);
static PropertyAttributes attribute(const ArrayData *d, uint index);
- static void push_front(Object *o, SafeValue *values, uint n);
+ static void push_front(Object *o, Value *values, uint n);
static ReturnedValue pop_front(Object *o);
static uint truncate(Object *o, uint newLen);
static uint length(const ArrayData *d);
@@ -184,11 +184,11 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
static ReturnedValue get(const ArrayData *d, uint index);
static bool put(Object *o, uint index, ValueRef value);
- static bool putArray(Object *o, uint index, SafeValue *values, uint n);
+ static bool putArray(Object *o, uint index, Value *values, uint n);
static bool del(Object *o, uint index);
static void setAttribute(Object *o, uint index, PropertyAttributes attrs);
static PropertyAttributes attribute(const ArrayData *d, uint index);
- static void push_front(Object *o, SafeValue *values, uint n);
+ static void push_front(Object *o, Value *values, uint n);
static ReturnedValue pop_front(Object *o);
static uint truncate(Object *o, uint newLen);
static uint length(const ArrayData *d);
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 9a2407fe2c..652c0f00ac 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -629,8 +629,8 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
Q_ASSERT(instance->arrayType() == ArrayData::Simple || instance->arrayType() == ArrayData::Complex);
if (len > instance->arrayData->length())
len = instance->arrayData->length();
- SafeValue *val = instance->arrayData->data;
- SafeValue *end = val + len;
+ Value *val = instance->arrayData->data;
+ Value *end = val + len;
val += fromIndex;
while (val < end) {
if (!val->isEmpty()) {
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index cc712c759b..15fea72b25 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -71,13 +71,13 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData
c->lookups = c->compilationUnit->runtimeLookups;
}
- c->locals = (SafeValue *)(c + 1);
+ c->locals = (Value *)(c + 1);
if (function->varCount)
std::fill(c->locals, c->locals + function->varCount, Primitive::undefinedValue());
c->callData = reinterpret_cast<CallData *>(c->locals + function->varCount);
- ::memcpy(c->callData, callData, sizeof(CallData) + (callData->argc - 1) * sizeof(SafeValue));
+ ::memcpy(c->callData, callData, sizeof(CallData) + (callData->argc - 1) * sizeof(Value));
if (callData->argc < static_cast<int>(function->formalParameterCount))
std::fill(c->callData->args + c->callData->argc, c->callData->args + function->formalParameterCount, Primitive::undefinedValue());
c->callData->argc = qMax((uint)callData->argc, function->formalParameterCount);
@@ -214,7 +214,7 @@ CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject
lookups = compilationUnit->runtimeLookups;
}
- locals = (SafeValue *)(this + 1);
+ locals = (Value *)(this + 1);
if (function->varCount)
std::fill(locals, locals + function->varCount, Primitive::undefinedValue());
}
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index b794c28582..5904d0b638 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -42,7 +42,7 @@
#define QMLJS_ENVIRONMENT_H
#include "qv4global_p.h"
-#include "qv4value_def_p.h"
+#include "qv4scopedvalue_p.h"
#include "qv4managed_p.h"
#include "qv4engine_p.h"
@@ -174,13 +174,17 @@ struct CallContext : public ExecutionContext
FunctionObject *function;
int realArgumentCount;
- SafeValue *locals;
+ Value *locals;
Object *activation;
inline ReturnedValue argument(int i);
bool needsOwnArguments() const;
};
+inline ReturnedValue CallContext::argument(int i) {
+ return i < callData->argc ? callData->args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
+}
+
struct GlobalContext : public ExecutionContext
{
GlobalContext(ExecutionEngine *engine);
@@ -192,8 +196,8 @@ struct CatchContext : public ExecutionContext
{
CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue);
- SafeString exceptionVarName;
- SafeValue exceptionValue;
+ StringValue exceptionVarName;
+ Value exceptionValue;
};
struct WithContext : public ExecutionContext
@@ -243,6 +247,15 @@ struct ExecutionContextSaver
}
};
+inline Scope::Scope(ExecutionContext *ctx)
+ : engine(ctx->engine)
+#ifndef QT_NO_DEBUG
+ , size(0)
+#endif
+{
+ mark = engine->jsStackTop;
+}
+
/* Function *f, int argc */
#define requiredMemoryForExecutionContect(f, argc) \
sizeof(CallContext) + sizeof(Value) * (f->varCount + qMax((uint)argc, f->formalParameterCount)) + sizeof(CallData)
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index ad8dec87c9..c52e8c3ee1 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -54,7 +54,7 @@ namespace QV4 {
struct DateObject: Object {
V4_OBJECT
Q_MANAGED_TYPE(DateObject)
- SafeValue value;
+ Value value;
DateObject(ExecutionEngine *engine, const ValueRef date): Object(engine->dateClass) {
value = date;
}
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 4170b6817f..9ab1622fee 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -179,7 +179,7 @@ void Debugger::resume(Speed speed)
return;
if (!m_returnedValue.isUndefined())
- m_returnedValue = Primitive::undefinedValue();
+ m_returnedValue = Encode::undefined();
clearTemporaryBreakPoints();
if (speed == StepOver)
@@ -648,15 +648,15 @@ void Debugger::applyPendingBreakPoints()
void Debugger::setBreakOnInstruction(Function *function, qptrdiff codeOffset, bool onoff)
{
uchar *codePtr = const_cast<uchar *>(function->codeData) + codeOffset;
- QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
- instruction->common.breakPoint = onoff;
+ QQmlJS::Moth::Instr::instr_debug *debug = reinterpret_cast<QQmlJS::Moth::Instr::instr_debug *>(codePtr);
+ debug->breakPoint = onoff;
}
bool Debugger::hasBreakOnInstruction(Function *function, qptrdiff codeOffset)
{
uchar *codePtr = const_cast<uchar *>(function->codeData) + codeOffset;
- QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
- return instruction->common.breakPoint;
+ QQmlJS::Moth::Instr::instr_debug *debug = reinterpret_cast<QQmlJS::Moth::Instr::instr_debug *>(codePtr);
+ return debug->breakPoint;
}
bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 093fe96dd5..16bacbfafd 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -40,7 +40,7 @@
****************************************************************************/
#include <qv4engine_p.h>
#include <qv4context_p.h>
-#include <qv4value_p.h>
+#include <qv4value_inl_p.h>
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
#include <qv4objectiterator_p.h>
@@ -157,10 +157,10 @@ quintptr getStackLimit()
ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
- : memoryManager(new QV4::MemoryManager)
+ : current(0)
+ , memoryManager(new QV4::MemoryManager)
, executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
- , current(0)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
, debugger(0)
@@ -197,11 +197,11 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
// we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection
// and ScopedValues allocated outside of JIT'ed methods.
*jsStack = WTF::PageAllocation::allocate(2*JSStackLimit, WTF::OSAllocator::JSVMStackPages, true);
- jsStackBase = (SafeValue *)jsStack->base();
+ jsStackBase = (Value *)jsStack->base();
jsStackTop = jsStackBase;
// set up stack limits
- jsStackLimit = jsStackBase + JSStackLimit/sizeof(SafeValue);
+ jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value);
cStackLimit = getStackLimit();
Scope scope(this);
@@ -457,7 +457,7 @@ Returned<FunctionObject> *ExecutionEngine::newBuiltinFunction(ExecutionContext *
return f->asReturned<FunctionObject>();
}
-Returned<BoundFunction> *ExecutionEngine::newBoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<SafeValue> &boundArgs)
+Returned<BoundFunction> *ExecutionEngine::newBoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs)
{
Q_ASSERT(target);
@@ -560,7 +560,7 @@ Returned<RegExpObject> *ExecutionEngine::newRegExpObject(const QString &pattern,
return newRegExpObject(re, global);
}
-Returned<RegExpObject> *ExecutionEngine::newRegExpObject(Referenced<RegExp> re, bool global)
+Returned<RegExpObject> *ExecutionEngine::newRegExpObject(RegExpRef re, bool global)
{
RegExpObject *object = new (memoryManager) RegExpObject(this, re, global);
return object->asReturned<RegExpObject>();
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index ecb5f2b4d5..63c57b8478 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -121,11 +121,6 @@ struct ExecutionContextSaver;
struct Q_QML_EXPORT ExecutionEngine
{
- MemoryManager *memoryManager;
- ExecutableAllocator *executableAllocator;
- ExecutableAllocator *regExpAllocator;
- QScopedPointer<QQmlJS::EvalISelFactory> iselFactory;
-
private:
friend struct ExecutionContextSaver;
friend struct ExecutionContext;
@@ -133,20 +128,27 @@ private:
public:
ExecutionContext *currentContext() const { return current; }
+ Value *jsStackTop;
+ quint32 hasException;
GlobalContext *rootContext;
- SafeValue *jsStackTop;
- SafeValue *jsStackLimit;
+ MemoryManager *memoryManager;
+ ExecutableAllocator *executableAllocator;
+ ExecutableAllocator *regExpAllocator;
+ QScopedPointer<QQmlJS::EvalISelFactory> iselFactory;
+
+
+ Value *jsStackLimit;
quintptr cStackLimit;
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
enum { JSStackLimit = 4*1024*1024 };
WTF::PageAllocation *jsStack;
- SafeValue *jsStackBase;
+ Value *jsStackBase;
- SafeValue *stackPush(uint nValues) {
- SafeValue *ptr = jsStackTop;
+ Value *stackPush(uint nValues) {
+ Value *ptr = jsStackTop;
jsStackTop = ptr + nValues;
return ptr;
}
@@ -174,22 +176,22 @@ public:
QV8Engine *v8Engine;
- SafeValue objectCtor;
- SafeValue stringCtor;
- SafeValue numberCtor;
- SafeValue booleanCtor;
- SafeValue arrayCtor;
- SafeValue functionCtor;
- SafeValue dateCtor;
- SafeValue regExpCtor;
- SafeValue errorCtor;
- SafeValue evalErrorCtor;
- SafeValue rangeErrorCtor;
- SafeValue referenceErrorCtor;
- SafeValue syntaxErrorCtor;
- SafeValue typeErrorCtor;
- SafeValue uRIErrorCtor;
- SafeValue sequencePrototype;
+ Value objectCtor;
+ Value stringCtor;
+ Value numberCtor;
+ Value booleanCtor;
+ Value arrayCtor;
+ Value functionCtor;
+ Value dateCtor;
+ Value regExpCtor;
+ Value errorCtor;
+ Value evalErrorCtor;
+ Value rangeErrorCtor;
+ Value referenceErrorCtor;
+ Value syntaxErrorCtor;
+ Value typeErrorCtor;
+ Value uRIErrorCtor;
+ Value sequencePrototype;
QQmlJS::MemoryPool classPool;
InternalClass *emptyClass;
@@ -228,36 +230,36 @@ public:
QVector<Property> argumentsAccessors;
- SafeString id_undefined;
- SafeString id_null;
- SafeString id_true;
- SafeString id_false;
- SafeString id_boolean;
- SafeString id_number;
- SafeString id_string;
- SafeString id_object;
- SafeString id_function;
- SafeString id_length;
- SafeString id_prototype;
- SafeString id_constructor;
- SafeString id_arguments;
- SafeString id_caller;
- SafeString id_callee;
- SafeString id_this;
- SafeString id___proto__;
- SafeString id_enumerable;
- SafeString id_configurable;
- SafeString id_writable;
- SafeString id_value;
- SafeString id_get;
- SafeString id_set;
- SafeString id_eval;
- SafeString id_uintMax;
- SafeString id_name;
- SafeString id_index;
- SafeString id_input;
- SafeString id_toString;
- SafeString id_valueOf;
+ StringValue id_undefined;
+ StringValue id_null;
+ StringValue id_true;
+ StringValue id_false;
+ StringValue id_boolean;
+ StringValue id_number;
+ StringValue id_string;
+ StringValue id_object;
+ StringValue id_function;
+ StringValue id_length;
+ StringValue id_prototype;
+ StringValue id_constructor;
+ StringValue id_arguments;
+ StringValue id_caller;
+ StringValue id_callee;
+ StringValue id_this;
+ StringValue id___proto__;
+ StringValue id_enumerable;
+ StringValue id_configurable;
+ StringValue id_writable;
+ StringValue id_value;
+ StringValue id_get;
+ StringValue id_set;
+ StringValue id_eval;
+ StringValue id_uintMax;
+ StringValue id_name;
+ StringValue id_index;
+ StringValue id_input;
+ StringValue id_toString;
+ StringValue id_valueOf;
QSet<CompiledData::CompilationUnit*> compilationUnits;
QMap<quintptr, QV4::Function*> allFunctions;
@@ -295,7 +297,7 @@ public:
ExecutionContext *popContext();
Returned<FunctionObject> *newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *));
- Returned<BoundFunction> *newBoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<SafeValue> &boundArgs);
+ Returned<BoundFunction> *newBoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs);
Returned<Object> *newObject();
Returned<Object> *newObject(InternalClass *internalClass);
@@ -315,7 +317,7 @@ public:
Returned<DateObject> *newDateObject(const QDateTime &dt);
Returned<RegExpObject> *newRegExpObject(const QString &pattern, int flags);
- Returned<RegExpObject> *newRegExpObject(Referenced<RegExp> re, bool global);
+ Returned<RegExpObject> *newRegExpObject(RegExpRef re, bool global);
Returned<RegExpObject> *newRegExpObject(const QRegExp &re);
Returned<Object> *newErrorObject(const ValueRef value);
@@ -352,8 +354,7 @@ public:
bool recheckCStackLimits();
// Exception handling
- SafeValue exceptionValue;
- quint32 hasException;
+ Value exceptionValue;
StackTrace exceptionStackTrace;
ReturnedValue throwException(const ValueRef value);
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 0e90e213c4..811b445f9e 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -42,7 +42,7 @@
#include "qv4function_p.h"
#include "qv4managed_p.h"
#include "qv4string_p.h"
-#include "qv4value_p.h"
+#include "qv4value_inl_p.h"
#include "qv4engine_p.h"
#include "qv4lookup_p.h"
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 8d07853b45..377b45bfa3 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -47,7 +47,7 @@
#include <QtCore/QByteArray>
#include <QtCore/qurl.h>
-#include "qv4value_def_p.h"
+#include "qv4value_p.h"
#include <private/qv4compileddata_p.h>
#include <private/qv4engine_p.h>
@@ -81,7 +81,7 @@ struct InternalClass;
struct Lookup;
struct Function {
- SafeString name;
+ StringValue name;
const CompiledData::Function *compiledFunction;
CompiledData::CompilationUnit *compilationUnit;
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index a6ed03cea8..a3e47c42ca 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -352,7 +352,7 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
} else {
int alen = qMin(len, arr->arrayData->length());
if (alen)
- memcpy(callData->args, arr->arrayData->data, alen*sizeof(SafeValue));
+ memcpy(callData->args, arr->arrayData->data, alen*sizeof(Value));
for (quint32 i = alen; i < len; ++i)
callData->args[i] = Primitive::undefinedValue();
}
@@ -387,7 +387,7 @@ ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
return ctx->throwTypeError();
ScopedValue boundThis(scope, ctx->argument(0));
- QVector<SafeValue> boundArgs;
+ QVector<Value> boundArgs;
for (int i = 1; i < ctx->callData->argc; ++i)
boundArgs += ctx->callData->args[i];
@@ -643,7 +643,7 @@ DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
DEFINE_OBJECT_VTABLE(BoundFunction);
-BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<SafeValue> &boundArgs)
+BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs)
: FunctionObject(scope, QStringLiteral("__bound function__"))
, target(target)
, boundArgs(boundArgs)
@@ -683,8 +683,8 @@ ReturnedValue BoundFunction::call(Managed *that, CallData *dd)
ScopedCallData callData(scope, f->boundArgs.size() + dd->argc);
callData->thisObject = f->boundThis;
- memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(SafeValue));
- memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(SafeValue));
+ memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value));
+ memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value));
return f->target->call(callData);
}
@@ -696,8 +696,8 @@ ReturnedValue BoundFunction::construct(Managed *that, CallData *dd)
return Encode::undefined();
ScopedCallData callData(scope, f->boundArgs.size() + dd->argc);
- memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(SafeValue));
- memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(SafeValue));
+ memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value));
+ memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value));
return f->target->construct(callData);
}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 64a1dc92d2..af4ec024d5 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -111,7 +111,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
};
ExecutionContext *scope;
- SafeString name;
+ StringValue name;
unsigned int formalParameterCount;
unsigned int varCount;
Function *function;
@@ -155,6 +155,8 @@ inline FunctionObject *value_cast(const Value &v) {
return v.asFunctionObject();
}
+DEFINE_REF(FunctionObject, Object);
+
struct FunctionCtor: FunctionObject
{
V4_OBJECT
@@ -228,10 +230,10 @@ struct SimpleScriptFunction: FunctionObject {
struct BoundFunction: FunctionObject {
V4_OBJECT
FunctionObject *target;
- SafeValue boundThis;
- QVector<SafeValue> boundArgs;
+ Value boundThis;
+ QVector<Value> boundArgs;
- BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<SafeValue> &boundArgs);
+ BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs);
~BoundFunction() {}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 1d465df0c0..746513cc2f 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -156,12 +156,16 @@ template<typename T> struct Returned;
typedef Returned<String> ReturnedString;
typedef Returned<Object> ReturnedObject;
typedef Returned<FunctionObject> ReturnedFunctionObject;
-template<typename T> struct Referenced;
-typedef Referenced<Managed> ManagedRef;
-typedef Referenced<String> StringRef;
-typedef Referenced<Object> ObjectRef;
-typedef Referenced<ArrayObject> ArrayObjectRef;
-typedef Referenced<FunctionObject> FunctionObjectRef;
+struct ManagedRef;
+struct StringRef;
+struct ObjectRef;
+struct ArrayObjectRef;
+struct FunctionObjectRef;
+struct RegExpRef;
+
+struct PersistentValuePrivate;
+class PersistentValue;
+class WeakValue;
namespace Global {
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 224d383614..76a8b0c25c 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -41,7 +41,7 @@
#include "qv4globalobject_p.h"
#include "qv4mm_p.h"
-#include "qv4value_p.h"
+#include "qv4value_inl_p.h"
#include "qv4context_p.h"
#include "qv4function_p.h"
#include "qv4debugging_p.h"
diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h
index c4c72f3a83..d1cadb3aa5 100644
--- a/src/qml/jsruntime/qv4include_p.h
+++ b/src/qml/jsruntime/qv4include_p.h
@@ -58,7 +58,7 @@
#include <private/qqmlcontext_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4context_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index c9d22523a9..4a75272843 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -180,6 +180,63 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const ValueRef object, c
return indexedGetterFallback(l, object, index);
}
+void Lookup::indexedSetterGeneric(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v)
+{
+ if (object->isObject()) {
+ Object *o = object->objectValue();
+ if (o->arrayData && o->arrayData->type == ArrayData::Simple && index->asArrayIndex() < UINT_MAX) {
+ l->indexedSetter = indexedSetterObjectInt;
+ indexedSetterObjectInt(l, object, index, v);
+ return;
+ }
+ }
+ indexedSetterFallback(l, object, index, v);
+}
+
+void Lookup::indexedSetterFallback(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef value)
+{
+ ExecutionContext *ctx = l->engine->currentContext();
+ Scope scope(ctx);
+ ScopedObject o(scope, object->toObject(ctx));
+ if (scope.engine->hasException)
+ return;
+
+ uint idx = index->asArrayIndex();
+ if (idx < UINT_MAX) {
+ if (o->arrayData && o->arrayData->type == ArrayData::Simple) {
+ SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData);
+ if (s && idx < s->len && !s->data[idx].isEmpty()) {
+ s->data[idx] = value;
+ return;
+ }
+ }
+ o->putIndexed(idx, value);
+ return;
+ }
+
+ ScopedString name(scope, index->toString(ctx));
+ o->put(name, value);
+}
+
+void Lookup::indexedSetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v)
+{
+ uint idx = index->asArrayIndex();
+ if (idx == UINT_MAX || !object->isObject()) {
+ indexedSetterGeneric(l, object, index, v);
+ return;
+ }
+
+ Object *o = object->objectValue();
+ if (o->arrayData && o->arrayData->type == ArrayData::Simple) {
+ SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData);
+ if (idx < s->len && !s->data[idx].isEmpty()) {
+ s->data[idx] = v;
+ return;
+ }
+ }
+ indexedSetterFallback(l, object, index, v);
+}
+
ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object)
{
if (Object *o = object->asObject())
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 50874411de..7f107bf8eb 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -56,6 +56,7 @@ struct Lookup {
enum { Size = 4 };
union {
ReturnedValue (*indexedGetter)(Lookup *l, const ValueRef object, const ValueRef index);
+ void (*indexedSetter)(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v);
ReturnedValue (*getter)(Lookup *l, const ValueRef object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionContext *ctx);
void (*setter)(Lookup *l, const ValueRef object, const ValueRef v);
@@ -78,6 +79,10 @@ struct Lookup {
static ReturnedValue indexedGetterFallback(Lookup *l, const ValueRef object, const ValueRef index);
static ReturnedValue indexedGetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index);
+ static void indexedSetterGeneric(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v);
+ static void indexedSetterFallback(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef value);
+ static void indexedSetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v);
+
static ReturnedValue getterGeneric(Lookup *l, const ValueRef object);
static ReturnedValue getter0(Lookup *l, const ValueRef object);
static ReturnedValue getter1(Lookup *l, const ValueRef object);
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index da2aab627e..8c6f2daf9b 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -45,7 +45,7 @@
#include <QtCore/QVector>
#include <QtCore/QDebug>
#include "qv4global_p.h"
-#include "qv4value_def_p.h"
+#include "qv4value_p.h"
#include "qv4internalclass_p.h"
QT_BEGIN_NAMESPACE
@@ -230,7 +230,7 @@ protected:
Managed(InternalClass *internal)
: internalClass(internal), _data(0)
{
- Q_ASSERT(!internalClass || internalClass->vtable);
+ Q_ASSERT(internalClass && internalClass->vtable);
inUse = 1; extensible = 1;
}
@@ -353,6 +353,7 @@ private:
friend struct ObjectIterator;
};
+
template<>
inline Managed *value_cast(const Value &v) {
return v.asManaged();
@@ -381,6 +382,68 @@ inline FunctionObject *managed_cast(Managed *m)
}
+Value *extractValuePointer(const ScopedValue &);
+template<typename T>
+Value *extractValuePointer(const Scoped<T> &);
+
+#define DEFINE_REF_METHODS(Class, Base) \
+ Class##Ref(const QV4::ScopedValue &v) \
+ { QV4::Value *val = extractValuePointer(v); ptr = QV4::value_cast<Class>(*val) ? val : 0; } \
+ Class##Ref(const QV4::Scoped<Class> &v) { ptr = extractValuePointer(v); } \
+ Class##Ref(QV4::TypedValue<Class> &v) { ptr = &v; } \
+ Class##Ref(QV4::Value &v) { ptr = QV4::value_cast<Class>(v) ? &v : 0; } \
+ Class##Ref &operator=(Class *t) { \
+ if (sizeof(void *) == 4) \
+ ptr->tag = QV4::Value::Managed_Type; \
+ ptr->m = t; \
+ return *this; \
+ } \
+ Class##Ref &operator=(QV4::Returned<Class> *t) { \
+ if (sizeof(void *) == 4) \
+ ptr->tag = QV4::Value::Managed_Type; \
+ ptr->m = t->getPointer(); \
+ return *this; \
+ } \
+ operator const Class *() const { return ptr ? static_cast<Class*>(ptr->managed()) : 0; } \
+ const Class *operator->() const { return static_cast<Class*>(ptr->managed()); } \
+ operator Class *() { return ptr ? static_cast<Class*>(ptr->managed()) : 0; } \
+ Class *operator->() { return static_cast<Class*>(ptr->managed()); } \
+ Class *getPointer() const { return static_cast<Class *>(ptr->managed()); } \
+ operator QV4::Returned<Class> *() const { return ptr ? QV4::Returned<Class>::create(getPointer()) : 0; } \
+ static Class##Ref null() { Class##Ref c; c.ptr = 0; return c; } \
+protected: \
+ Class##Ref() {} \
+public: \
+
+#define DEFINE_REF(Class, Base) \
+struct Class##Ref : public Base##Ref \
+{ DEFINE_REF_METHODS(Class, Base) } \
+
+
+struct ManagedRef {
+ // Important: Do NOT add a copy constructor to this class or any derived class
+ // adding a copy constructor actually changes the calling convention, ie.
+ // is not even binary compatible. Adding it would break assumptions made
+ // in the jit'ed code.
+ DEFINE_REF_METHODS(Managed, Managed);
+
+ bool operator==(const ManagedRef &other) {
+ if (ptr == other.ptr)
+ return true;
+ return ptr && other.ptr && ptr->m == other.ptr->m;
+ }
+ bool operator!=(const ManagedRef &other) {
+ return !operator==(other);
+ }
+ bool operator!() const { return !ptr || !ptr->managed(); }
+
+ bool isNull() const { return !ptr; }
+ ReturnedValue asReturnedValue() const { return ptr ? ptr->val : Primitive::undefinedValue().asReturnedValue(); }
+
+public:
+ Value *ptr;
+};
+
}
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index 0ba0b18cda..7bb41f1eec 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -355,7 +355,7 @@ Managed *MemoryManager::alloc(std::size_t size)
void MemoryManager::mark()
{
- SafeValue *markBase = m_d->engine->jsStackTop;
+ Value *markBase = m_d->engine->jsStackTop;
m_d->engine->markObjects();
@@ -698,8 +698,8 @@ void MemoryManager::collectFromStack() const
void MemoryManager::collectFromJSStack() const
{
- SafeValue *v = engine()->jsStackBase;
- SafeValue *top = engine()->jsStackTop;
+ Value *v = engine()->jsStackBase;
+ Value *top = engine()->jsStackTop;
while (v < top) {
Managed *m = v->asManaged();
if (m && m->inUse)
diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h
index 7d28319536..a8fd585332 100644
--- a/src/qml/jsruntime/qv4mm_p.h
+++ b/src/qml/jsruntime/qv4mm_p.h
@@ -44,7 +44,7 @@
#include "qv4global_p.h"
#include "qv4context_p.h"
-#include "qv4value_p.h"
+#include "qv4value_inl_p.h"
#include <QScopedPointer>
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 93ad51d26f..de84747221 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -198,9 +198,10 @@ void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)
void Object::defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
{
ExecutionEngine *v4 = engine();
- Property p;
- p.setGetter(getter ? v4->newBuiltinFunction(v4->rootContext, name, getter)->getPointer() : 0);
- p.setSetter(setter ? v4->newBuiltinFunction(v4->rootContext, name, setter)->getPointer() : 0);
+ QV4::Scope scope(v4);
+ ScopedProperty p(scope);
+ p->setGetter(getter ? v4->newBuiltinFunction(v4->rootContext, name, getter)->getPointer() : 0);
+ p->setSetter(setter ? v4->newBuiltinFunction(v4->rootContext, name, setter)->getPointer() : 0);
insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
@@ -581,7 +582,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin
}
// dense arrays
while (it->arrayIndex < o->arrayData->length()) {
- SafeValue *val = o->arrayData->data + it->arrayIndex;
+ Value *val = o->arrayData->data + it->arrayIndex;
PropertyAttributes a = o->arrayData->attributes(it->arrayIndex);
++it->arrayIndex;
if (!val->isEmpty()
@@ -1118,7 +1119,7 @@ void Object::copyArrayData(Object *other)
d->len = static_cast<SimpleArrayData *>(other->arrayData)->len;
d->offset = 0;
}
- memcpy(arrayData->data, other->arrayData->data, arrayData->alloc*sizeof(SafeValue));
+ memcpy(arrayData->data, other->arrayData->data, arrayData->alloc*sizeof(Value));
}
setArrayLengthUnchecked(other->getLength());
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index ca54388359..e3361ae160 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -191,7 +191,7 @@ public:
bool arrayPut(uint index, ValueRef value) {
return arrayData->vtable()->put(this, index, value);
}
- bool arrayPut(uint index, SafeValue *values, uint n) {
+ bool arrayPut(uint index, Value *values, uint n) {
return arrayData->vtable()->putArray(this, index, values, n);
}
void setArrayAttributes(uint i, PropertyAttributes a) {
@@ -206,7 +206,7 @@ public:
void push_back(const ValueRef v);
ArrayData::Type arrayType() const {
- return arrayData ? (ArrayData::Type)arrayData->type : ArrayData::Simple;
+ return arrayData ? arrayData->type : ArrayData::Simple;
}
// ### remove me
void setArrayType(ArrayData::Type t) {
@@ -304,7 +304,7 @@ private:
struct BooleanObject: Object {
V4_OBJECT
Q_MANAGED_TYPE(BooleanObject)
- SafeValue value;
+ Value value;
BooleanObject(ExecutionEngine *engine, const ValueRef val)
: Object(engine->booleanClass) {
value = val;
@@ -320,7 +320,7 @@ protected:
struct NumberObject: Object {
V4_OBJECT
Q_MANAGED_TYPE(NumberObject)
- SafeValue value;
+ Value value;
NumberObject(ExecutionEngine *engine, const ValueRef val)
: Object(engine->numberClass) {
value = val;
@@ -417,11 +417,28 @@ inline ArrayObject *value_cast(const Value &v) {
}
template<>
-inline ReturnedValue value_convert<Object>(ExecutionContext *ctx, const Value &v)
+inline ReturnedValue value_convert<Object>(ExecutionEngine *e, const Value &v)
{
- return v.toObject(ctx)->asReturnedValue();
+ return v.toObject(e->currentContext())->asReturnedValue();
}
+struct ObjectRef : public ManagedRef
+{
+ DEFINE_REF_METHODS(Object, Managed)
+
+ static ObjectRef fromValuePointer(Value *s) {
+ ObjectRef r;
+ r.ptr = s;
+ if (sizeof(void *) == 8)
+ r.ptr->val = 0;
+ else
+ *r.ptr = Value::fromManaged(0);
+ return r;
+ }
+};
+
+DEFINE_REF(ArrayObject, Object);
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 0e35996710..e5f693c323 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -46,26 +46,26 @@
using namespace QV4;
-ObjectIterator::ObjectIterator(SafeObject *scratch1, SafeObject *scratch2, const ObjectRef o, uint flags)
- : object(*scratch1)
- , current(*scratch2)
+ObjectIterator::ObjectIterator(Value *scratch1, Value *scratch2, const ObjectRef o, uint flags)
+ : object(ObjectRef::fromValuePointer(scratch1))
+ , current(ObjectRef::fromValuePointer(scratch2))
, arrayNode(0)
, arrayIndex(0)
, memberIndex(0)
, flags(flags)
{
- object = o;
- current = o;
+ object = o.getPointer();
+ current = o.getPointer();
- if (object && object->asArgumentsObject()) {
+ if (!!object && object->asArgumentsObject()) {
Scope scope(object->engine());
Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
}
}
ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
- : object(*static_cast<SafeObject *>(scope.alloc(1)))
- , current(*static_cast<SafeObject *>(scope.alloc(1)))
+ : object(ObjectRef::fromValuePointer(scope.alloc(1)))
+ , current(ObjectRef::fromValuePointer(scope.alloc(1)))
, arrayNode(0)
, arrayIndex(0)
, memberIndex(0)
@@ -74,7 +74,7 @@ ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
object = o;
current = o;
- if (object && object->asArgumentsObject()) {
+ if (!!object && object->asArgumentsObject()) {
Scope scope(object->engine());
Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
}
@@ -103,7 +103,7 @@ void ObjectIterator::next(StringRef name, uint *index, Property *pd, PropertyAtt
Object *o = object;
bool shadowed = false;
while (o != current) {
- if ((name && o->hasOwnProperty(name)) ||
+ if ((!!name && o->hasOwnProperty(name)) ||
(*index != UINT_MAX && o->hasOwnProperty(*index))) {
shadowed = true;
break;
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 08a740fc37..c87f284288 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -74,7 +74,7 @@ struct Q_QML_EXPORT ObjectIterator
uint memberIndex;
uint flags;
- ObjectIterator(SafeObject *scratch1, SafeObject *scratch2, const ObjectRef o, uint flags);
+ ObjectIterator(Value *scratch1, Value *scratch2, const ObjectRef o, uint flags);
ObjectIterator(Scope &scope, const ObjectRef o, uint flags);
void next(StringRef name, uint *index, Property *pd, PropertyAttributes *attributes = 0);
ReturnedValue nextPropertyName(ValueRef value);
@@ -87,7 +87,8 @@ struct ForEachIteratorObject: Object {
Q_MANAGED_TYPE(ForeachIteratorObject)
ObjectIterator it;
ForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o)
- : Object(ctx->engine), it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) {
+ : Object(ctx->engine), it(workArea, workArea + 1,
+ o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) {
setVTable(staticVTable());
}
@@ -96,7 +97,7 @@ struct ForEachIteratorObject: Object {
protected:
static void markObjects(Managed *that, ExecutionEngine *e);
- SafeObject workArea[2];
+ Value workArea[2];
};
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
new file mode 100644
index 0000000000..72e3651757
--- /dev/null
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4persistent_p.h"
+#include "qv4mm_p.h"
+
+using namespace QV4;
+
+PersistentValue::PersistentValue(const ValueRef val)
+ : d(new PersistentValuePrivate(val.asReturnedValue()))
+{
+}
+
+PersistentValue::PersistentValue(ReturnedValue val)
+ : d(new PersistentValuePrivate(val))
+{
+}
+
+PersistentValue::PersistentValue(const PersistentValue &other)
+ : d(other.d)
+{
+ if (d)
+ d->ref();
+}
+
+PersistentValue &PersistentValue::operator=(const PersistentValue &other)
+{
+ if (d == other.d)
+ return *this;
+
+ // the memory manager cleans up those with a refcount of 0
+
+ if (d)
+ d->deref();
+ d = other.d;
+ if (d)
+ d->ref();
+
+ return *this;
+}
+
+PersistentValue &PersistentValue::operator =(const ValueRef other)
+{
+ if (!d) {
+ d = new PersistentValuePrivate(other.asReturnedValue());
+ return *this;
+ }
+ d = d->detach(other.asReturnedValue());
+ return *this;
+}
+
+PersistentValue &PersistentValue::operator =(ReturnedValue other)
+{
+ if (!d) {
+ d = new PersistentValuePrivate(other);
+ return *this;
+ }
+ d = d->detach(other);
+ return *this;
+}
+
+PersistentValue::~PersistentValue()
+{
+ if (d)
+ d->deref();
+}
+
+WeakValue::WeakValue(const ValueRef val)
+ : d(new PersistentValuePrivate(val.asReturnedValue(), /*engine*/0, /*weak*/true))
+{
+}
+
+WeakValue::WeakValue(const WeakValue &other)
+ : d(other.d)
+{
+ if (d)
+ d->ref();
+}
+
+WeakValue::WeakValue(ReturnedValue val)
+ : d(new PersistentValuePrivate(val, /*engine*/0, /*weak*/true))
+{
+}
+
+WeakValue &WeakValue::operator=(const WeakValue &other)
+{
+ if (d == other.d)
+ return *this;
+
+ // the memory manager cleans up those with a refcount of 0
+
+ if (d)
+ d->deref();
+ d = other.d;
+ if (d)
+ d->ref();
+
+ return *this;
+}
+
+WeakValue &WeakValue::operator =(const ValueRef other)
+{
+ if (!d) {
+ d = new PersistentValuePrivate(other.asReturnedValue(), /*engine*/0, /*weak*/true);
+ return *this;
+ }
+ d = d->detach(other.asReturnedValue(), /*weak*/true);
+ return *this;
+}
+
+WeakValue &WeakValue::operator =(const ReturnedValue &other)
+{
+ if (!d) {
+ d = new PersistentValuePrivate(other, /*engine*/0, /*weak*/true);
+ return *this;
+ }
+ d = d->detach(other, /*weak*/true);
+ return *this;
+}
+
+
+WeakValue::~WeakValue()
+{
+ if (d)
+ d->deref();
+}
+
+void WeakValue::markOnce(ExecutionEngine *e)
+{
+ if (!d)
+ return;
+ d->value.mark(e);
+}
+
+PersistentValuePrivate::PersistentValuePrivate(ReturnedValue v, ExecutionEngine *e, bool weak)
+ : refcount(1)
+ , weak(weak)
+ , engine(e)
+ , prev(0)
+ , next(0)
+{
+ value.val = v;
+ init();
+}
+
+void PersistentValuePrivate::init()
+{
+ if (!engine) {
+ Managed *m = value.asManaged();
+ if (!m)
+ return;
+
+ engine = m->engine();
+ }
+ if (engine && !prev) {
+ PersistentValuePrivate **listRoot = weak ? &engine->memoryManager->m_weakValues : &engine->memoryManager->m_persistentValues;
+
+ prev = listRoot;
+ next = *listRoot;
+ *prev = this;
+ if (next)
+ next->prev = &this->next;
+ }
+}
+
+PersistentValuePrivate::~PersistentValuePrivate()
+{
+}
+
+void PersistentValuePrivate::removeFromList()
+{
+ if (prev) {
+ if (next)
+ next->prev = prev;
+ *prev = next;
+ next = 0;
+ prev = 0;
+ }
+}
+
+void PersistentValuePrivate::deref()
+{
+ // if engine is not 0, they are registered with the memory manager
+ // and will get cleaned up in the next gc run
+ if (!--refcount) {
+ removeFromList();
+ delete this;
+ }
+}
+
+PersistentValuePrivate *PersistentValuePrivate::detach(const QV4::ReturnedValue val, bool weak)
+{
+ if (refcount == 1) {
+ value.val = val;
+
+ Managed *m = value.asManaged();
+ if (!prev) {
+ if (m) {
+ ExecutionEngine *engine = m->engine();
+ if (engine) {
+ PersistentValuePrivate **listRoot = weak ? &engine->memoryManager->m_weakValues : &engine->memoryManager->m_persistentValues;
+ prev = listRoot;
+ next = *listRoot;
+ *prev = this;
+ if (next)
+ next->prev = &this->next;
+ }
+ }
+ } else if (!m)
+ removeFromList();
+
+ return this;
+ }
+ --refcount;
+ return new PersistentValuePrivate(val, engine, weak);
+}
+
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
new file mode 100644
index 0000000000..21f37f3d96
--- /dev/null
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4PERSISTENT_H
+#define QV4PERSISTENT_H
+
+#include "qv4value_inl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Q_QML_PRIVATE_EXPORT PersistentValuePrivate
+{
+ PersistentValuePrivate(ReturnedValue v, ExecutionEngine *engine = 0, bool weak = false);
+ virtual ~PersistentValuePrivate();
+ Value value;
+ uint refcount;
+ bool weak;
+ QV4::ExecutionEngine *engine;
+ PersistentValuePrivate **prev;
+ PersistentValuePrivate *next;
+
+ void init();
+ void removeFromList();
+ void ref() { ++refcount; }
+ void deref();
+ PersistentValuePrivate *detach(const ReturnedValue value, bool weak = false);
+
+ bool checkEngine(QV4::ExecutionEngine *otherEngine) {
+ if (!engine) {
+ Q_ASSERT(!value.isObject());
+ engine = otherEngine;
+ }
+ return (engine == otherEngine);
+ }
+};
+
+class Q_QML_EXPORT PersistentValue
+{
+public:
+ PersistentValue() : d(0) {}
+ PersistentValue(const PersistentValue &other);
+ PersistentValue &operator=(const PersistentValue &other);
+
+ PersistentValue(const ValueRef val);
+ PersistentValue(ReturnedValue val);
+ template<typename T>
+ PersistentValue(Returned<T> *obj);
+ PersistentValue(const ManagedRef obj);
+ PersistentValue &operator=(const ValueRef other);
+ PersistentValue &operator=(const ScopedValue &other);
+ PersistentValue &operator =(ReturnedValue other);
+ template<typename T>
+ PersistentValue &operator=(Returned<T> *obj);
+ PersistentValue &operator=(const ManagedRef obj);
+ ~PersistentValue();
+
+ ReturnedValue value() const {
+ return (d ? d->value.asReturnedValue() : Primitive::undefinedValue().asReturnedValue());
+ }
+
+ ExecutionEngine *engine() {
+ if (!d)
+ return 0;
+ if (d->engine)
+ return d->engine;
+ Managed *m = d->value.asManaged();
+ return m ? m->engine() : 0;
+ }
+
+ bool isUndefined() const { return !d || d->value.isUndefined(); }
+ bool isNullOrUndefined() const { return !d || d->value.isNullOrUndefined(); }
+ void clear() {
+ *this = PersistentValue();
+ }
+
+private:
+ friend struct ValueRef;
+ PersistentValuePrivate *d;
+};
+
+class Q_QML_EXPORT WeakValue
+{
+public:
+ WeakValue() : d(0) {}
+ WeakValue(const ValueRef val);
+ WeakValue(const WeakValue &other);
+ WeakValue(ReturnedValue val);
+ template<typename T>
+ WeakValue(Returned<T> *obj);
+ WeakValue &operator=(const WeakValue &other);
+ WeakValue &operator=(const ValueRef other);
+ WeakValue &operator =(const ReturnedValue &other);
+ template<typename T>
+ WeakValue &operator=(Returned<T> *obj);
+
+ ~WeakValue();
+
+ ReturnedValue value() const {
+ return (d ? d->value.asReturnedValue() : Primitive::undefinedValue().asReturnedValue());
+ }
+
+ ExecutionEngine *engine() {
+ if (!d)
+ return 0;
+ if (d->engine)
+ return d->engine;
+ Managed *m = d->value.asManaged();
+ return m ? m->engine() : 0;
+ }
+
+ bool isUndefined() const { return !d || d->value.isUndefined(); }
+ bool isNullOrUndefined() const { return !d || d->value.isNullOrUndefined(); }
+ void clear() {
+ *this = WeakValue();
+ }
+
+ void markOnce(ExecutionEngine *e);
+
+private:
+ friend struct ValueRef;
+ PersistentValuePrivate *d;
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h
index 6381fe7687..aceb6022f8 100644
--- a/src/qml/jsruntime/qv4property_p.h
+++ b/src/qml/jsruntime/qv4property_p.h
@@ -42,7 +42,7 @@
#define QV4PROPERTYDESCRIPTOR_H
#include "qv4global_p.h"
-#include "qv4value_p.h"
+#include "qv4value_inl_p.h"
#include "qv4internalclass_p.h"
QT_BEGIN_NAMESPACE
@@ -52,8 +52,8 @@ namespace QV4 {
struct FunctionObject;
struct Property {
- SafeValue value;
- SafeValue set;
+ Value value;
+ Value set;
// Section 8.10
inline void fullyPopulated(PropertyAttributes *attrs) {
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 235aaf94db..9bc01d12cc 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -694,7 +694,7 @@ PropertyAttributes QObjectWrapper::query(const Managed *m, StringRef name)
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(engine);
QQmlPropertyData local;
if (that->findProperty(engine, qmlContext, name, IgnoreRevision, &local)
- || name->equals(const_cast<SafeString &>(that->m_destroy)) || name->equals(engine->id_toString))
+ || name->equals(const_cast<StringValue &>(that->m_destroy)) || name->equals(engine->id_toString))
return QV4::Attr_Data;
else
return QV4::Object::query(m, name);
@@ -1702,7 +1702,8 @@ QV4::ReturnedValue CallArgument::toValue(QV8Engine *engine)
} else if (type == -1 || type == qMetaTypeId<QVariant>()) {
QVariant value = *qvariantPtr;
QV4::ScopedValue rv(scope, engine->fromVariant(value));
- if (QV4::Referenced<QObjectWrapper> qobjectWrapper = rv->asRef<QV4::QObjectWrapper>()) {
+ QV4::QObjectWrapperRef qobjectWrapper = rv;
+ if (!!qobjectWrapper) {
if (QObject *object = qobjectWrapper->object())
QQmlData::get(object, true)->setImplicitDestructible();
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index f6d1ac0790..ca38c5b0dc 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -62,7 +62,7 @@
#include <private/qqmlpropertycache_p.h>
#include <private/qintrusivelist_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4functionobject_p.h>
QT_BEGIN_NAMESPACE
@@ -111,7 +111,7 @@ private:
QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
QPointer<QObject> m_object;
- SafeString m_destroy;
+ StringValue m_destroy;
static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
static void put(Managed *m, const StringRef name, const ValueRef value);
@@ -200,6 +200,8 @@ private Q_SLOTS:
void removeDestroyedObject(QObject*);
};
+DEFINE_REF(QObjectWrapper, Object);
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 1b93542f8a..74c8a2d35e 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -80,7 +80,7 @@ RegExpObject::RegExpObject(InternalClass *ic)
init(ic->engine);
}
-RegExpObject::RegExpObject(ExecutionEngine *engine, Referenced<RegExp> value, bool global)
+RegExpObject::RegExpObject(ExecutionEngine *engine, RegExpRef value, bool global)
: Object(engine->regExpClass)
, value(value)
, global(global)
@@ -433,7 +433,7 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx)
return ctx->throwTypeError();
ScopedCallData callData(scope, ctx->callData->argc);
- memcpy(callData->args, ctx->callData->args, ctx->callData->argc*sizeof(SafeValue));
+ memcpy(callData->args, ctx->callData->args, ctx->callData->argc*sizeof(Value));
Scoped<RegExpObject> re(scope, ctx->engine->regExpCtor.asFunctionObject()->construct(callData));
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index a4cb4b9fb5..1b408749d3 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -84,7 +84,7 @@ struct RegExpObject: Object {
Property *lastIndexProperty(ExecutionContext *ctx);
bool global;
- RegExpObject(ExecutionEngine *engine, Referenced<RegExp> value, bool global);
+ RegExpObject(ExecutionEngine *engine, RegExpRef value, bool global);
RegExpObject(ExecutionEngine *engine, const QRegExp &re);
~RegExpObject() {}
@@ -101,14 +101,15 @@ protected:
static void markObjects(Managed *that, ExecutionEngine *e);
};
+DEFINE_REF(RegExp, Object);
struct RegExpCtor: FunctionObject
{
V4_OBJECT
RegExpCtor(ExecutionContext *scope);
- SafeValue lastMatch;
- SafeString lastInput;
+ Value lastMatch;
+ StringValue lastInput;
int lastMatchStart;
int lastMatchEnd;
void clearLastMatch();
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index c929b39e6a..a3cae3382d 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -383,8 +383,8 @@ ReturnedValue __qmljs_object_default_value(Object *object, int typeHint)
if (engine->hasException)
return Encode::undefined();
- SafeString *meth1 = &engine->id_toString;
- SafeString *meth2 = &engine->id_valueOf;
+ StringValue *meth1 = &engine->id_toString;
+ StringValue *meth2 = &engine->id_valueOf;
if (typeHint == NUMBER_HINT)
qSwap(meth1, meth2);
@@ -613,10 +613,14 @@ void __qmljs_set_element(ExecutionContext *ctx, const ValueRef object, const Val
uint idx = index->asArrayIndex();
if (idx < UINT_MAX) {
- if (o->arrayType() == ArrayData::Simple && idx < o->arrayData->length())
- o->arrayPut(idx, value);
- else
- o->putIndexed(idx, value);
+ if (o->arrayType() == ArrayData::Simple) {
+ SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData);
+ if (s && idx < s->len && !s->data[idx].isEmpty()) {
+ s->data[idx] = value;
+ return;
+ }
+ }
+ o->putIndexed(idx, value);
return;
}
@@ -890,7 +894,7 @@ ReturnedValue __qmljs_call_property(ExecutionContext *context, const StringRef n
ReturnedValue __qmljs_call_property_lookup(ExecutionContext *context, uint index, CallDataRef callData)
{
Lookup *l = context->lookups + index;
- SafeValue v;
+ Value v;
v = l->getter(l, callData->thisObject);
if (!v.isObject())
return context->throwTypeError();
@@ -978,7 +982,7 @@ ReturnedValue __qmljs_construct_property(ExecutionContext *context, const String
ReturnedValue __qmljs_construct_property_lookup(ExecutionContext *context, uint index, CallDataRef callData)
{
Lookup *l = context->lookups + index;
- SafeValue v;
+ Value v;
v = l->getter(l, callData->thisObject);
if (!v.isObject())
return context->throwTypeError();
@@ -1098,7 +1102,7 @@ void __qmljs_builtin_define_property(ExecutionContext *ctx, const ValueRef objec
}
}
-ReturnedValue __qmljs_builtin_define_array(ExecutionContext *ctx, SafeValue *values, uint length)
+ReturnedValue __qmljs_builtin_define_array(ExecutionContext *ctx, Value *values, uint length)
{
Scope scope(ctx);
Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject());
@@ -1304,7 +1308,7 @@ QV4::ReturnedValue __qmljs_get_qml_singleton(QV4::NoThrowContext *ctx, const QV4
void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx)
{
- SafeValue *t = &ctx->callData->thisObject;
+ Value *t = &ctx->callData->thisObject;
if (t->isObject())
return;
if (t->isNullOrUndefined()) {
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 2e252b1067..3c2824ee23 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -42,9 +42,10 @@
#define QMLJS_RUNTIME_H
#include "qv4global_p.h"
-#include "qv4value_p.h"
+#include "qv4value_inl_p.h"
#include "qv4math_p.h"
#include "qv4scopedvalue_p.h"
+#include "qv4context_p.h"
#include <QtCore/QString>
#include <QtCore/qnumeric.h>
@@ -141,7 +142,7 @@ QV4::ExecutionContext *__qmljs_builtin_pop_scope(QV4::ExecutionContext *ctx);
ReturnedValue __qmljs_builtin_unwind_exception(ExecutionContext *ctx);
void __qmljs_builtin_declare_var(QV4::ExecutionContext *ctx, bool deletable, const QV4::StringRef name);
void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, QV4::ValueRef val);
-QV4::ReturnedValue __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, SafeValue *values, uint length);
+QV4::ReturnedValue __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, Value *values, uint length);
void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, const QV4::ValueRef getter, const QV4::ValueRef setter);
QV4::ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId);
QV4::ReturnedValue __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx);
@@ -305,12 +306,7 @@ inline QV4::ReturnedValue __qmljs_compl(const QV4::ValueRef value)
{
TRACE1(value);
- int n;
- if (value->integerCompatible())
- n = value->int_32;
- else
- n = value->toInt32();
-
+ int n = value->toInt32();
return Encode((int)~n);
}
@@ -327,9 +323,6 @@ inline ReturnedValue __qmljs_bit_or(const QV4::ValueRef left, const QV4::ValueRe
{
TRACE2(left, right);
- if (QV4::Value::integerCompatible(*left, *right))
- return Encode(left->integerValue() | right->integerValue());
-
int lval = left->toInt32();
int rval = right->toInt32();
return Encode(lval | rval);
@@ -339,9 +332,6 @@ inline ReturnedValue __qmljs_bit_xor(const QV4::ValueRef left, const QV4::ValueR
{
TRACE2(left, right);
- if (QV4::Value::integerCompatible(*left, *right))
- return Encode(left->integerValue() ^ right->integerValue());
-
int lval = left->toInt32();
int rval = right->toInt32();
return Encode(lval ^ rval);
@@ -351,9 +341,6 @@ inline ReturnedValue __qmljs_bit_and(const QV4::ValueRef left, const QV4::ValueR
{
TRACE2(left, right);
- if (QV4::Value::integerCompatible(*left, *right))
- return Encode(left->integerValue() & right->integerValue());
-
int lval = left->toInt32();
int rval = right->toInt32();
return Encode(lval & rval);
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 2c71a36a3d..5d471ab4fb 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -41,8 +41,9 @@
#ifndef QV4SCOPEDVALUE_P_H
#define QV4SCOPEDVALUE_P_H
-#include "qv4context_p.h"
-#include "qv4value_def_p.h"
+#include "qv4engine_p.h"
+#include "qv4value_p.h"
+#include "qv4persistent_p.h"
QT_BEGIN_NAMESPACE
@@ -54,15 +55,7 @@ namespace QV4 {
struct ScopedValue;
struct Scope {
- explicit Scope(ExecutionContext *ctx)
- : engine(ctx->engine)
-#ifndef QT_NO_DEBUG
- , size(0)
-#endif
- {
- mark = engine->jsStackTop;
- }
-
+ inline explicit Scope(ExecutionContext *ctx);
explicit Scope(ExecutionEngine *e)
: engine(e)
#ifndef QT_NO_DEBUG
@@ -75,13 +68,13 @@ struct Scope {
~Scope() {
#ifndef QT_NO_DEBUG
Q_ASSERT(engine->jsStackTop >= mark);
- memset(mark, 0, (engine->jsStackTop - mark)*sizeof(SafeValue));
+ memset(mark, 0, (engine->jsStackTop - mark)*sizeof(Value));
#endif
engine->jsStackTop = mark;
}
- SafeValue *alloc(int nValues) {
- SafeValue *ptr = engine->jsStackTop;
+ Value *alloc(int nValues) {
+ Value *ptr = engine->jsStackTop;
engine->jsStackTop += nValues;
#ifndef QT_NO_DEBUG
size += nValues;
@@ -94,7 +87,7 @@ struct Scope {
}
ExecutionEngine *engine;
- SafeValue *mark;
+ Value *mark;
#ifndef QT_NO_DEBUG
mutable int size;
#endif
@@ -178,17 +171,17 @@ struct ScopedValue
return *this;
}
- SafeValue *operator->() {
+ Value *operator->() {
return ptr;
}
- const SafeValue *operator->() const {
+ const Value *operator->() const {
return ptr;
}
ReturnedValue asReturnedValue() const { return ptr->val; }
- SafeValue *ptr;
+ Value *ptr;
};
template<typename T>
@@ -234,7 +227,7 @@ struct Scoped
Scoped(const Scope &scope, const Value &v, _Convert)
{
ptr = scope.engine->jsStackTop++;
- ptr->val = value_convert<T>(scope.engine->currentContext(), v);
+ ptr->val = value_convert<T>(scope.engine, v);
#ifndef QT_NO_DEBUG
++scope.size;
#endif
@@ -281,7 +274,7 @@ struct Scoped
Scoped(const Scope &scope, const ReturnedValue &v, _Convert)
{
ptr = scope.engine->jsStackTop++;
- ptr->val = value_convert<T>(scope.engine->currentContext(), QV4::Value::fromReturnedValue(v));
+ ptr->val = value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v));
#ifndef QT_NO_DEBUG
++scope.size;
#endif
@@ -339,7 +332,7 @@ struct Scoped
#endif
}
- SafeValue *ptr;
+ Value *ptr;
};
struct CallData
@@ -356,14 +349,14 @@ struct CallData
return i < argc ? args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
}
- SafeValue thisObject;
- SafeValue args[1];
+ Value thisObject;
+ Value args[1];
};
struct ScopedCallData {
ScopedCallData(Scope &scope, int argc)
{
- int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue);
+ int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value);
ptr = reinterpret_cast<CallData *>(scope.engine->stackPush(size));
ptr->tag = QV4::Value::Integer_Type;
ptr->argc = argc;
@@ -385,141 +378,10 @@ struct ScopedCallData {
CallData *ptr;
};
-struct ValueRef {
- ValueRef(const ScopedValue &v)
- : ptr(v.ptr) {}
- template <typename T>
- ValueRef(const Scoped<T> &v)
- : ptr(v.ptr) {}
- ValueRef(const PersistentValue &v)
- : ptr(&v.d->value) {}
- ValueRef(PersistentValuePrivate *p)
- : ptr(&p->value) {}
- ValueRef(SafeValue &v) { ptr = &v; }
- // Important: Do NOT add a copy constructor to this class
- // adding a copy constructor actually changes the calling convention, ie.
- // is not even binary compatible. Adding it would break assumptions made
- // in the jit'ed code.
- ValueRef &operator=(const ScopedValue &o)
- { *ptr = *o.ptr; return *this; }
- ValueRef &operator=(const ValueRef &o)
- { *ptr = *o.ptr; return *this; }
- ValueRef &operator=(const Value &v)
- { *ptr = v; return *this; }
- ValueRef &operator=(const ReturnedValue &v) {
- ptr->val = v;
- return *this;
- }
- template <typename T>
- ValueRef &operator=(Returned<T> *v) {
- ptr->val = v->asReturnedValue();
- return *this;
- }
-
- operator const Value *() const {
- return ptr;
- }
- const Value *operator->() const {
- return ptr;
- }
-
- operator Value *() {
- return ptr;
- }
- SafeValue *operator->() {
- return ptr;
- }
-
- static ValueRef fromRawValue(Value *v) {
- return ValueRef(v);
- }
- static const ValueRef fromRawValue(const Value *v) {
- return ValueRef(const_cast<Value *>(v));
- }
-
- ReturnedValue asReturnedValue() const { return ptr->val; }
-
- // ### get rid of this one!
- ValueRef(Value *v) { ptr = reinterpret_cast<SafeValue *>(v); }
-private:
- SafeValue *ptr;
-};
-
-
-template<typename T>
-struct Referenced {
- // Important: Do NOT add a copy constructor to this class
- // adding a copy constructor actually changes the calling convention, ie.
- // is not even binary compatible. Adding it would break assumptions made
- // in the jit'ed code.
- Referenced(const Scoped<T> &v)
- : ptr(v.ptr) {}
- Referenced(Safe<T> &v) { ptr = &v; }
- Referenced(SafeValue &v) {
- ptr = value_cast<T>(v) ? &v : 0;
- }
-
- Referenced &operator=(const Referenced &o)
- { *ptr = *o.ptr; return *this; }
- Referenced &operator=(T *t)
- {
-#if QT_POINTER_SIZE == 4
- ptr->tag = Value::Managed_Type;
-#endif
- ptr->m = t;
- return *this;
- }
- Referenced &operator=(Returned<T> *t) {
-#if QT_POINTER_SIZE == 4
- ptr->tag = Value::Managed_Type;
-#endif
- ptr->m = t->getPointer();
- return *this;
- }
-
- operator const T *() const {
- return ptr ? static_cast<T*>(ptr->managed()) : 0;
- }
- const T *operator->() const {
- return static_cast<T*>(ptr->managed());
- }
-
- operator T *() {
- return ptr ? static_cast<T*>(ptr->managed()) : 0;
- }
- T *operator->() {
- return static_cast<T*>(ptr->managed());
- }
-
- T *getPointer() const {
- return static_cast<T *>(ptr->managed());
- }
- ReturnedValue asReturnedValue() const { return ptr ? ptr->val : Primitive::undefinedValue().asReturnedValue(); }
- operator Returned<T> *() const { return ptr ? Returned<T>::create(getPointer()) : 0; }
-
- bool operator==(const Referenced<T> &other) {
- if (ptr == other.ptr)
- return true;
- return ptr && other.ptr && ptr->m == other.ptr->m;
- }
- bool operator!=(const Referenced<T> &other) {
- if (ptr == other.ptr)
- return false;
- return !ptr || ptr->m != other.ptr->m;
- }
- bool operator!() const { return !ptr || !ptr->managed(); }
-
- static Referenced null() { return Referenced(Null); }
- bool isNull() const { return !ptr; }
-private:
- enum _Null { Null };
- Referenced(_Null) { ptr = 0; }
- SafeValue *ptr;
-};
-typedef Referenced<String> StringRef;
-typedef Referenced<Object> ObjectRef;
-typedef Referenced<FunctionObject> FunctionObjectRef;
+struct StringRef;
+struct ObjectRef;
+struct FunctionObjectRef;
template<typename T>
inline Scoped<T>::Scoped(const Scope &scope, const ValueRef &v)
@@ -569,51 +431,6 @@ private:
CallData *ptr;
};
-struct Encode {
- static ReturnedValue undefined() {
- return quint64(Value::Undefined_Type) << Value::Tag_Shift;
- }
- static ReturnedValue null() {
- return quint64(Value::_Null_Type) << Value::Tag_Shift;
- }
-
- Encode(bool b) {
- val = (quint64(Value::_Boolean_Type) << Value::Tag_Shift) | (uint)b;
- }
- Encode(double d) {
- Value v;
- v.setDouble(d);
- val = v.val;
- }
- Encode(int i) {
- val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | (uint)i;
- }
- Encode(uint i) {
- if (i <= INT_MAX) {
- val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | i;
- } else {
- Value v;
- v.setDouble(i);
- val = v.val;
- }
- }
- Encode(ReturnedValue v) {
- val = v;
- }
-
- template<typename T>
- Encode(Returned<T> *t) {
- val = t->getPointer()->asReturnedValue();
- }
-
- operator ReturnedValue() const {
- return val;
- }
- quint64 val;
-private:
- Encode(void *);
-};
-
template <typename T>
inline Value &Value::operator=(Returned<T> *t)
@@ -622,81 +439,68 @@ inline Value &Value::operator=(Returned<T> *t)
return *this;
}
-inline SafeValue &SafeValue::operator =(const ScopedValue &v)
+inline Value &Value::operator =(const ScopedValue &v)
{
val = v.ptr->val;
return *this;
}
template<typename T>
-inline SafeValue &SafeValue::operator=(Returned<T> *t)
-{
- val = t->getPointer()->asReturnedValue();
- return *this;
-}
-
-template<typename T>
-inline SafeValue &SafeValue::operator=(const Scoped<T> &t)
+inline Value &Value::operator=(const Scoped<T> &t)
{
val = t.ptr->val;
return *this;
}
-inline SafeValue &SafeValue::operator=(const ValueRef v)
+inline Value &Value::operator=(const ValueRef v)
{
val = v.asReturnedValue();
return *this;
}
template<typename T>
-inline Returned<T> *SafeValue::as()
+inline Returned<T> *Value::as()
{
return Returned<T>::create(value_cast<T>(*this));
}
-template<typename T> inline
-Referenced<T> SafeValue::asRef()
-{
- return Referenced<T>(*this);
-}
-
template<typename T>
-inline Safe<T> &Safe<T>::operator =(T *t)
+inline TypedValue<T> &TypedValue<T>::operator =(T *t)
{
val = t->asReturnedValue();
return *this;
}
template<typename T>
-inline Safe<T> &Safe<T>::operator =(const Scoped<T> &v)
+inline TypedValue<T> &TypedValue<T>::operator =(const Scoped<T> &v)
{
val = v.ptr->val;
return *this;
}
template<typename T>
-inline Safe<T> &Safe<T>::operator=(Returned<T> *t)
+inline TypedValue<T> &TypedValue<T>::operator=(Returned<T> *t)
{
val = t->getPointer()->asReturnedValue();
return *this;
}
-template<typename T>
-inline Safe<T> &Safe<T>::operator =(const Referenced<T> &v)
-{
- val = v.asReturnedValue();
- return *this;
-}
+//template<typename T>
+//inline TypedValue<T> &TypedValue<T>::operator =(const ManagedRef<T> &v)
+//{
+// val = v.asReturnedValue();
+// return *this;
+//}
template<typename T>
-inline Safe<T> &Safe<T>::operator=(const Safe<T> &t)
+inline TypedValue<T> &TypedValue<T>::operator=(const TypedValue<T> &t)
{
val = t.val;
return *this;
}
template<typename T>
-inline Returned<T> * Safe<T>::ret() const
+inline Returned<T> * TypedValue<T>::ret() const
{
return Returned<T>::create(static_cast<T *>(managed()));
}
@@ -713,9 +517,8 @@ PersistentValue::PersistentValue(Returned<T> *obj)
{
}
-template<typename T>
-inline PersistentValue::PersistentValue(const Referenced<T> obj)
- : d(new PersistentValuePrivate(*obj.ptr))
+inline PersistentValue::PersistentValue(const ManagedRef obj)
+ : d(new PersistentValuePrivate(obj.asReturnedValue()))
{
}
@@ -725,12 +528,15 @@ inline PersistentValue &PersistentValue::operator=(Returned<T> *obj)
return operator=(QV4::Value::fromManaged(obj->getPointer()).asReturnedValue());
}
-template<typename T>
-inline PersistentValue &PersistentValue::operator=(const Referenced<T> obj)
+inline PersistentValue &PersistentValue::operator=(const ManagedRef obj)
{
- return operator=(*obj.ptr);
+ return operator=(obj.asReturnedValue());
}
+inline PersistentValue &PersistentValue::operator=(const ScopedValue &other)
+{
+ return operator=(other.asReturnedValue());
+}
template<typename T>
inline WeakValue::WeakValue(Returned<T> *obj)
@@ -744,10 +550,53 @@ inline WeakValue &WeakValue::operator=(Returned<T> *obj)
return operator=(QV4::Value::fromManaged(obj->getPointer()).asReturnedValue());
}
-inline ReturnedValue CallContext::argument(int i) {
- return i < callData->argc ? callData->args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
+inline ValueRef::ValueRef(const ScopedValue &v)
+ : ptr(v.ptr)
+{}
+
+template <typename T>
+inline ValueRef::ValueRef(const Scoped<T> &v)
+ : ptr(v.ptr)
+{}
+
+inline ValueRef::ValueRef(const PersistentValue &v)
+ : ptr(&v.d->value)
+{}
+
+inline ValueRef::ValueRef(PersistentValuePrivate *p)
+ : ptr(&p->value)
+{}
+
+inline ValueRef &ValueRef::operator=(const ScopedValue &o)
+{
+ *ptr = *o.ptr;
+ return *this;
+}
+
+
+inline Value *extractValuePointer(const ScopedValue &v)
+{
+ return v.ptr;
}
+template<typename T>
+Value *extractValuePointer(const Scoped<T> &v)
+{
+ return v.ptr;
+}
+
+struct ScopedProperty
+{
+ ScopedProperty(Scope &scope)
+ {
+ property = reinterpret_cast<Property*>(scope.alloc(sizeof(Property) / sizeof(Value)));
+ }
+
+ Property *operator->() { return property; }
+ operator const Property &() { return *property; }
+
+ Property *property;
+};
}
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index c50b025bc9..7d94195304 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -168,7 +168,7 @@ Script::Script(ExecutionEngine *v4, ObjectRef qml, CompiledData::CompilationUnit
Q_ASSERT(vmFunction);
Scope valueScope(v4);
ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit));
- compilationUnitHolder = holder;
+ compilationUnitHolder = holder.asReturnedValue();
} else
vmFunction = 0;
}
@@ -236,7 +236,7 @@ void Script::parse()
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
vmFunction = compilationUnit->linkToEngine(v4);
ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit));
- compilationUnitHolder = holder;
+ compilationUnitHolder = holder.asReturnedValue();
}
if (!vmFunction) {
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 4039f81896..a82dcffbca 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -175,10 +175,10 @@ public:
, m_propertyIndex(-1)
, m_isReference(false)
{
- setArrayType(ArrayData::Custom);
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
Q_UNUSED(protectThis);
+ setArrayType(ArrayData::Custom);
init();
}
@@ -188,10 +188,10 @@ public:
, m_propertyIndex(propertyIndex)
, m_isReference(true)
{
- setArrayType(ArrayData::Custom);
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
Q_UNUSED(protectThis);
+ setArrayType(ArrayData::Custom);
loadReference();
init();
}
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 54a96863df..4a5e82b688 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -56,7 +56,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/qvariant.h>
-#include "qv4value_p.h"
+#include "qv4value_inl_p.h"
#include "qv4object_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index 50899c3893..3d754389a2 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -45,7 +45,7 @@
#include <private/qqmllistmodel_p.h>
#include <private/qqmllistmodelworkeragent_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4dateobject_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qv4sequenceobject_p.h>
diff --git a/src/qml/jsruntime/qv4serialize_p.h b/src/qml/jsruntime/qv4serialize_p.h
index a9f40e43cd..5ab8ae9258 100644
--- a/src/qml/jsruntime/qv4serialize_p.h
+++ b/src/qml/jsruntime/qv4serialize_p.h
@@ -54,7 +54,7 @@
//
#include <QtCore/qbytearray.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp
index 7169f5c20e..ffd1adf98b 100644
--- a/src/qml/jsruntime/qv4sparsearray.cpp
+++ b/src/qml/jsruntime/qv4sparsearray.cpp
@@ -53,32 +53,6 @@
using namespace QV4;
-bool ArrayElementLessThan::operator()(const SafeValue &v1, const SafeValue &v2) const
-{
- Scope scope(m_context);
-
- if (v1.isUndefined() || v1.isEmpty())
- return false;
- if (v2.isUndefined() || v2.isEmpty())
- return true;
- ScopedObject o(scope, m_comparefn);
- if (o) {
- Scope scope(o->engine());
- ScopedValue result(scope);
- ScopedCallData callData(scope, 2);
- callData->thisObject = Primitive::undefinedValue();
- callData->args[0] = v1;
- callData->args[1] = v2;
- result = __qmljs_call_value(m_context, m_comparefn, callData);
-
- return result->toNumber() < 0;
- }
- ScopedString p1s(scope, v1.toString(m_context));
- ScopedString p2s(scope, v2.toString(m_context));
- return p1s->toQString() < p2s->toQString();
-}
-
-
const SparseArrayNode *SparseArrayNode::nextNode() const
{
const SparseArrayNode *n = this;
diff --git a/src/qml/jsruntime/qv4sparsearray_p.h b/src/qml/jsruntime/qv4sparsearray_p.h
index 6c2808b6b1..0bcbc805f3 100644
--- a/src/qml/jsruntime/qv4sparsearray_p.h
+++ b/src/qml/jsruntime/qv4sparsearray_p.h
@@ -39,12 +39,12 @@
**
****************************************************************************/
-#ifndef QV4ARRAY_H
-#define QV4ARRAY_H
+#ifndef QV4SPARSEARRAY_H
+#define QV4SPARSEARRAY_H
#include "qv4global_p.h"
#include <QtCore/qmap.h>
-#include "qv4value_p.h"
+#include "qv4value_inl_p.h"
#include "qv4scopedvalue_p.h"
#include "qv4property_p.h"
#include <assert.h>
@@ -62,21 +62,6 @@ namespace QV4 {
struct SparseArray;
-class ArrayElementLessThan
-{
-public:
- inline ArrayElementLessThan(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn)
- : m_context(context), thisObject(thisObject), m_comparefn(comparefn) {}
-
- bool operator()(const SafeValue &v1, const SafeValue &v2) const;
-
-private:
- ExecutionContext *m_context;
- ObjectRef thisObject;
- const ValueRef m_comparefn;
-};
-
-
struct SparseArrayNode
{
quintptr p;
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index e3d8326d84..ade64d1352 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -66,10 +66,6 @@ struct Q_QML_EXPORT String : public Managed {
StringType_ArrayIndex
};
- String()
- : Managed(0), _text(QStringData::sharedNull()), identifier(0)
- , stringHash(UINT_MAX), largestSubLength(0), len(0)
- { subtype = StringType_Unknown; }
String(ExecutionEngine *engine, const QString &text);
String(ExecutionEngine *engine, String *l, String *n);
~String() {
@@ -186,11 +182,13 @@ inline String *value_cast(const Value &v) {
}
template<>
-inline ReturnedValue value_convert<String>(ExecutionContext *ctx, const Value &v)
+inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v)
{
- return v.toString(ctx)->asReturnedValue();
+ return v.toString(e)->asReturnedValue();
}
+DEFINE_REF(String, Managed);
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 9b26343c63..c38fd5b75f 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -53,7 +53,7 @@ struct StringObject: Object {
V4_OBJECT
Q_MANAGED_TYPE(StringObject)
- SafeValue value;
+ Value value;
mutable Property tmpProperty;
StringObject(ExecutionEngine *engine, const ValueRef value);
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index 30f7e8cdb0..c91084caee 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -262,6 +262,11 @@ double Primitive::toInteger(double number)
return std::signbit(number) ? -v : v;
}
+String *Value::toString(ExecutionEngine *e) const
+{
+ return toString(e->currentContext());
+}
+
String *Value::toString(ExecutionContext *ctx) const
{
if (isString())
@@ -276,213 +281,3 @@ Object *Value::toObject(ExecutionContext *ctx) const
return __qmljs_convert_to_object(ctx, ValueRef::fromRawValue(this))->getPointer();
}
-
-PersistentValue::PersistentValue(const ValueRef val)
- : d(new PersistentValuePrivate(val.asReturnedValue()))
-{
-}
-
-PersistentValue::PersistentValue(ReturnedValue val)
- : d(new PersistentValuePrivate(val))
-{
-}
-
-PersistentValue::PersistentValue(const PersistentValue &other)
- : d(other.d)
-{
- if (d)
- d->ref();
-}
-
-PersistentValue &PersistentValue::operator=(const PersistentValue &other)
-{
- if (d == other.d)
- return *this;
-
- // the memory manager cleans up those with a refcount of 0
-
- if (d)
- d->deref();
- d = other.d;
- if (d)
- d->ref();
-
- return *this;
-}
-
-PersistentValue &PersistentValue::operator =(const ValueRef other)
-{
- if (!d) {
- d = new PersistentValuePrivate(other.asReturnedValue());
- return *this;
- }
- d = d->detach(other.asReturnedValue());
- return *this;
-}
-
-PersistentValue &PersistentValue::operator =(ReturnedValue other)
-{
- if (!d) {
- d = new PersistentValuePrivate(other);
- return *this;
- }
- d = d->detach(other);
- return *this;
-}
-
-PersistentValue::~PersistentValue()
-{
- if (d)
- d->deref();
-}
-
-WeakValue::WeakValue(const ValueRef val)
- : d(new PersistentValuePrivate(val.asReturnedValue(), /*engine*/0, /*weak*/true))
-{
-}
-
-WeakValue::WeakValue(const WeakValue &other)
- : d(other.d)
-{
- if (d)
- d->ref();
-}
-
-WeakValue::WeakValue(ReturnedValue val)
- : d(new PersistentValuePrivate(val, /*engine*/0, /*weak*/true))
-{
-}
-
-WeakValue &WeakValue::operator=(const WeakValue &other)
-{
- if (d == other.d)
- return *this;
-
- // the memory manager cleans up those with a refcount of 0
-
- if (d)
- d->deref();
- d = other.d;
- if (d)
- d->ref();
-
- return *this;
-}
-
-WeakValue &WeakValue::operator =(const ValueRef other)
-{
- if (!d) {
- d = new PersistentValuePrivate(other.asReturnedValue(), /*engine*/0, /*weak*/true);
- return *this;
- }
- d = d->detach(other.asReturnedValue(), /*weak*/true);
- return *this;
-}
-
-WeakValue &WeakValue::operator =(const ReturnedValue &other)
-{
- if (!d) {
- d = new PersistentValuePrivate(other, /*engine*/0, /*weak*/true);
- return *this;
- }
- d = d->detach(other, /*weak*/true);
- return *this;
-}
-
-
-WeakValue::~WeakValue()
-{
- if (d)
- d->deref();
-}
-
-void WeakValue::markOnce(ExecutionEngine *e)
-{
- if (!d)
- return;
- d->value.mark(e);
-}
-
-PersistentValuePrivate::PersistentValuePrivate(ReturnedValue v, ExecutionEngine *e, bool weak)
- : refcount(1)
- , weak(weak)
- , engine(e)
- , prev(0)
- , next(0)
-{
- value.val = v;
- init();
-}
-
-void PersistentValuePrivate::init()
-{
- if (!engine) {
- Managed *m = value.asManaged();
- if (!m)
- return;
-
- engine = m->engine();
- }
- if (engine && !prev) {
- PersistentValuePrivate **listRoot = weak ? &engine->memoryManager->m_weakValues : &engine->memoryManager->m_persistentValues;
-
- prev = listRoot;
- next = *listRoot;
- *prev = this;
- if (next)
- next->prev = &this->next;
- }
-}
-
-PersistentValuePrivate::~PersistentValuePrivate()
-{
-}
-
-void PersistentValuePrivate::removeFromList()
-{
- if (prev) {
- if (next)
- next->prev = prev;
- *prev = next;
- next = 0;
- prev = 0;
- }
-}
-
-void PersistentValuePrivate::deref()
-{
- // if engine is not 0, they are registered with the memory manager
- // and will get cleaned up in the next gc run
- if (!--refcount) {
- removeFromList();
- delete this;
- }
-}
-
-PersistentValuePrivate *PersistentValuePrivate::detach(const QV4::ReturnedValue val, bool weak)
-{
- if (refcount == 1) {
- value.val = val;
-
- Managed *m = value.asManaged();
- if (!prev) {
- if (m) {
- ExecutionEngine *engine = m->engine();
- if (engine) {
- PersistentValuePrivate **listRoot = weak ? &engine->memoryManager->m_weakValues : &engine->memoryManager->m_persistentValues;
- prev = listRoot;
- next = *listRoot;
- *prev = this;
- if (next)
- next->prev = &this->next;
- }
- }
- } else if (!m)
- removeFromList();
-
- return this;
- }
- --refcount;
- return new PersistentValuePrivate(val, engine, weak);
-}
-
diff --git a/src/qml/jsruntime/qv4value_def_p.h b/src/qml/jsruntime/qv4value_def_p.h
deleted file mode 100644
index cf351c125a..0000000000
--- a/src/qml/jsruntime/qv4value_def_p.h
+++ /dev/null
@@ -1,476 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, 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, Digia gives you certain additional
-** rights. These rights are described in the Digia 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.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef QV4VALUE_DEF_P_H
-#define QV4VALUE_DEF_P_H
-
-#include <QtCore/QString>
-#include "qv4global_p.h"
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-typedef uint Bool;
-
-template <typename T>
-struct Returned : private T
-{
- static Returned<T> *create(T *t) { return static_cast<Returned<T> *>(t); }
- T *getPointer() { return this; }
- template<typename X>
- static T *getPointer(Returned<X> *x) { return x->getPointer(); }
- template<typename X>
- Returned<X> *as() { return Returned<X>::create(Returned<X>::getPointer(this)); }
- using T::asReturnedValue;
-};
-
-struct Q_QML_EXPORT Value
-{
- /*
- We use two different ways of encoding JS values. One for 32bit and one for 64bit systems.
-
- In both cases, we 8 bytes for a value and different variant of NaN boxing. A Double NaN (actually -qNaN)
- is indicated by a number that has the top 13 bits set. THe other values are usually set to 0 by the
- processor, and are thus free for us to store other data. We keep pointers in there for managed objects,
- and encode the other types using the free space given to use by the unused bits for NaN values. This also
- works for pointers on 64 bit systems, as they all currently only have 48 bits of addressable memory.
-
- On 32bit, we store doubles as doubles. All other values, have the high 32bits set to a value that
- will make the number a NaN. The Masks below are used for encoding the other types.
-
- On 64 bit, we xor Doubles with (0xffff8000 << 32). Thas has the effect that no doubles will get encoded
- with the 13 highest bits all 0. We are now using special values for bits 14-17 to encode our values. These
- can be used, as the highest valid pointer on a 64 bit system is 2^48-1.
-
- If they are all 0, we have a pointer to a Managed object. If bit 14 is set we have an integer.
- This makes testing for pointers and numbers very fast (we have a number if any of the highest 14 bits is set).
-
- Bit 15-17 is then used to encode other immediates.
- */
-
-
- union {
- quint64 val;
-#if QT_POINTER_SIZE == 8
- Managed *m;
- Object *o;
- String *s;
-#else
- double dbl;
-#endif
- struct {
-#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN
- uint tag;
-#endif
- union {
- uint uint_32;
- int int_32;
-#if QT_POINTER_SIZE == 4
- Managed *m;
- Object *o;
- String *s;
-#endif
- };
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- uint tag;
-#endif
- };
- };
-
-#if QT_POINTER_SIZE == 4
- enum Masks {
- NaN_Mask = 0x7ff80000,
- NotDouble_Mask = 0x7ffc0000,
- Type_Mask = 0xffff8000,
- Immediate_Mask = NotDouble_Mask | 0x00008000,
- IsNullOrUndefined_Mask = Immediate_Mask | 0x20000,
- Tag_Shift = 32
- };
- enum ValueType {
- Undefined_Type = Immediate_Mask | 0x00000,
- Null_Type = Immediate_Mask | 0x10000,
- Boolean_Type = Immediate_Mask | 0x20000,
- Integer_Type = Immediate_Mask | 0x30000,
- Managed_Type = NotDouble_Mask | 0x00000,
- Empty_Type = NotDouble_Mask | 0x30000
- };
-
- enum ImmediateFlags {
- ConvertibleToInt = Immediate_Mask | 0x1
- };
-
- enum ValueTypeInternal {
- _Null_Type = Null_Type | ConvertibleToInt,
- _Boolean_Type = Boolean_Type | ConvertibleToInt,
- _Integer_Type = Integer_Type | ConvertibleToInt,
-
- };
-#else
- static const quint64 NaNEncodeMask = 0xffff800000000000ll;
- static const quint64 IsInt32Mask = 0x0002000000000000ll;
- static const quint64 IsDoubleMask = 0xfffc000000000000ll;
- static const quint64 IsNumberMask = IsInt32Mask|IsDoubleMask;
- static const quint64 IsNullOrUndefinedMask = 0x0000800000000000ll;
- static const quint64 IsNullOrBooleanMask = 0x0001000000000000ll;
- static const quint64 IsConvertibleToIntMask = IsInt32Mask|IsNullOrBooleanMask;
-
- enum Masks {
- NaN_Mask = 0x7ff80000,
- Type_Mask = 0xffff8000,
- IsDouble_Mask = 0xfffc0000,
- Immediate_Mask = 0x00018000,
- IsNullOrUndefined_Mask = 0x00008000,
- IsNullOrBoolean_Mask = 0x00010000,
- Tag_Shift = 32
- };
- enum ValueType {
- Undefined_Type = IsNullOrUndefined_Mask,
- Null_Type = IsNullOrUndefined_Mask|IsNullOrBoolean_Mask,
- Boolean_Type = IsNullOrBoolean_Mask,
- Integer_Type = 0x20000|IsNullOrBoolean_Mask,
- Managed_Type = 0,
- Empty_Type = Undefined_Type | 0x4000
- };
- enum {
- IsDouble_Shift = 64-14,
- IsNumber_Shift = 64-15,
- IsConvertibleToInt_Shift = 64-16,
- IsManaged_Shift = 64-17
- };
-
-
- enum ValueTypeInternal {
- _Null_Type = Null_Type,
- _Boolean_Type = Boolean_Type,
- _Integer_Type = Integer_Type
- };
-#endif
-
- inline unsigned type() const {
- return tag & Type_Mask;
- }
-
- // used internally in property
- inline bool isEmpty() const { return tag == Empty_Type; }
-
- inline bool isUndefined() const { return tag == Undefined_Type; }
- inline bool isNull() const { return tag == _Null_Type; }
- inline bool isBoolean() const { return tag == _Boolean_Type; }
-#if QT_POINTER_SIZE == 8
- inline bool isInteger() const { return (val >> IsNumber_Shift) == 1; }
- inline bool isDouble() const { return (val >> IsDouble_Shift); }
- inline bool isNumber() const { return (val >> IsNumber_Shift); }
- inline bool isManaged() const { return !(val >> IsManaged_Shift); }
- inline bool isNullOrUndefined() const { return ((val >> IsManaged_Shift) & ~2) == 1; }
- inline bool integerCompatible() const { return ((val >> IsConvertibleToInt_Shift) & ~2) == 1; }
- static inline bool integerCompatible(Value a, Value b) {
- return a.integerCompatible() && b.integerCompatible();
- }
- static inline bool bothDouble(Value a, Value b) {
- return a.isDouble() && b.isDouble();
- }
- double doubleValue() const {
- Q_ASSERT(isDouble());
- union {
- quint64 i;
- double d;
- } v;
- v.i = val ^ NaNEncodeMask;
- return v.d;
- }
- void setDouble(double d) {
- union {
- quint64 i;
- double d;
- } v;
- v.d = d;
- val = v.i ^ NaNEncodeMask;
- Q_ASSERT(isDouble());
- }
- bool isNaN() const { return (tag & 0x7fff8000) == 0x00078000; }
-#else
- inline bool isInteger() const { return tag == _Integer_Type; }
- inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; }
- inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; }
- inline bool isManaged() const { return tag == Managed_Type; }
- inline bool isNullOrUndefined() const { return (tag & IsNullOrUndefined_Mask) == Undefined_Type; }
- inline bool integerCompatible() const { return (tag & ConvertibleToInt) == ConvertibleToInt; }
- static inline bool integerCompatible(Value a, Value b) {
- return ((a.tag & b.tag) & ConvertibleToInt) == ConvertibleToInt;
- }
- static inline bool bothDouble(Value a, Value b) {
- return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask;
- }
- double doubleValue() const { return dbl; }
- void setDouble(double d) { dbl = d; }
- bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
-#endif
- inline bool isString() const;
- inline bool isObject() const;
- inline bool isInt32() {
- if (tag == _Integer_Type)
- return true;
- if (isDouble()) {
- double d = doubleValue();
- int i = (int)d;
- if (i == d) {
- int_32 = i;
- tag = _Integer_Type;
- return true;
- }
- }
- return false;
- }
- double asDouble() const {
- if (tag == _Integer_Type)
- return int_32;
- return doubleValue();
- }
-
- bool booleanValue() const {
- return int_32;
- }
- int integerValue() const {
- return int_32;
- }
-
- String *stringValue() const {
- return s;
- }
- Object *objectValue() const {
- return o;
- }
- Managed *managed() const {
- return m;
- }
-
- quint64 rawValue() const {
- return val;
- }
-
- static inline Value fromManaged(Managed *o);
-
- int toUInt16() const;
- inline int toInt32() const;
- inline unsigned int toUInt32() const;
-
- inline bool toBoolean() const;
- double toInteger() const;
- inline double toNumber() const;
- double toNumberImpl() const;
- QString toQStringNoThrow() const;
- QString toQString() const;
- String *toString(ExecutionContext *ctx) const;
- Object *toObject(ExecutionContext *ctx) const;
-
- inline bool isPrimitive() const;
- inline bool tryIntegerConversion() {
- bool b = integerCompatible();
- if (b)
- tag = _Integer_Type;
- return b;
- }
-
- inline String *asString() const;
- inline Managed *asManaged() const;
- inline Object *asObject() const;
- inline FunctionObject *asFunctionObject() const;
- inline NumberObject *asNumberObject() const;
- inline StringObject *asStringObject() const;
- inline DateObject *asDateObject() const;
- inline ArrayObject *asArrayObject() const;
- inline ErrorObject *asErrorObject() const;
-
- template<typename T> inline T *as() const;
-
- inline uint asArrayIndex() const;
- inline uint asArrayLength(bool *ok) const;
-
- inline ExecutionEngine *engine() const;
-
- ReturnedValue asReturnedValue() const { return val; }
- static Value fromReturnedValue(ReturnedValue val) { Value v; v.val = val; return v; }
- Value &operator=(ReturnedValue v) { val = v; return *this; }
- template <typename T>
- inline Value &operator=(Returned<T> *t);
-
- // Section 9.12
- bool sameValue(Value other) const;
-
- inline void mark(ExecutionEngine *e) const;
-};
-
-inline Managed *Value::asManaged() const
-{
- if (isManaged())
- return managed();
- return 0;
-}
-
-inline String *Value::asString() const
-{
- if (isString())
- return stringValue();
- return 0;
-}
-
-struct Q_QML_EXPORT Primitive : public Value
-{
- inline static Primitive emptyValue();
- static inline Primitive fromBoolean(bool b);
- static inline Primitive fromInt32(int i);
- inline static Primitive undefinedValue();
- static inline Primitive nullValue();
- static inline Primitive fromDouble(double d);
- static inline Primitive fromUInt32(uint i);
-
- static double toInteger(double fromNumber);
- static int toInt32(double value);
- static unsigned int toUInt32(double value);
-
- inline operator ValueRef();
- Value asValue() const { return *this; }
-};
-
-inline Primitive Primitive::undefinedValue()
-{
- Primitive v;
-#if QT_POINTER_SIZE == 8
- v.val = quint64(Undefined_Type) << Tag_Shift;
-#else
- v.tag = Undefined_Type;
- v.int_32 = 0;
-#endif
- return v;
-}
-
-inline Primitive Primitive::emptyValue()
-{
- Primitive v;
- v.tag = Value::Empty_Type;
- v.uint_32 = 0;
- return v;
-}
-
-inline Value Value::fromManaged(Managed *m)
-{
- if (!m)
- return QV4::Primitive::undefinedValue();
- Value v;
-#if QT_POINTER_SIZE == 8
- v.m = m;
-#else
- v.tag = Managed_Type;
- v.m = m;
-#endif
- return v;
-}
-
-struct SafeValue : public Value
-{
- SafeValue &operator =(const ScopedValue &v);
- template<typename T>
- SafeValue &operator=(Returned<T> *t);
- SafeValue &operator=(ReturnedValue v) {
- val = v;
- return *this;
- }
- template<typename T>
- SafeValue &operator=(T *t) {
- val = Value::fromManaged(t).val;
- return *this;
- }
-
- template<typename T>
- SafeValue &operator=(const Scoped<T> &t);
- SafeValue &operator=(const ValueRef v);
- SafeValue &operator=(const Value &v) {
- val = v.val;
- return *this;
- }
- template<typename T>
- inline Returned<T> *as();
- template<typename T>
- inline Referenced<T> asRef();
-};
-
-template <typename T>
-struct Safe : public SafeValue
-{
- template<typename X>
- Safe &operator =(X *x) {
- val = Value::fromManaged(x).val;
- }
- Safe &operator =(T *t);
- Safe &operator =(const Scoped<T> &v);
- Safe &operator =(const Referenced<T> &v);
- Safe &operator =(Returned<T> *t);
-
- Safe &operator =(const Safe<T> &t);
-
- bool operator!() const { return !managed(); }
-
- T *operator->() { return static_cast<T *>(managed()); }
- const T *operator->() const { return static_cast<T *>(managed()); }
- T *getPointer() const { return static_cast<T *>(managed()); }
- Returned<T> *ret() const;
-
- void mark(ExecutionEngine *e) { if (managed()) managed()->mark(e); }
-};
-typedef Safe<String> SafeString;
-typedef Safe<Object> SafeObject;
-
-template<typename T>
-T *value_cast(const Value &v)
-{
- return v.as<T>();
-}
-
-template<typename T>
-ReturnedValue value_convert(ExecutionContext *ctx, const Value &v);
-
-
-
-}
-
-QT_END_NAMESPACE
-
-#endif // QV4VALUE_DEF_P_H
diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h
new file mode 100644
index 0000000000..d82af0643e
--- /dev/null
+++ b/src/qml/jsruntime/qv4value_inl_p.h
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4VALUE_INL_H
+#define QV4VALUE_INL_H
+
+#include <cmath> // this HAS to come
+
+#include <QtCore/QString>
+#include <QtCore/qnumeric.h>
+#include "qv4global_p.h"
+#include "qv4string_p.h"
+#include <QtCore/QDebug>
+#include "qv4managed_p.h"
+#include "qv4engine_p.h"
+#include <private/qtqmlglobal_p.h>
+
+//#include <wtf/MathExtras.h>
+
+#include "qv4value_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+inline bool Value::isString() const
+{
+ if (!isManaged())
+ return false;
+ return managed() && managed()->internalClass->vtable->isString;
+}
+inline bool Value::isObject() const
+{
+ if (!isManaged())
+ return false;
+ return managed() && managed()->internalClass->vtable->isObject;
+}
+
+inline bool Value::isPrimitive() const
+{
+ return !isObject();
+}
+
+inline ExecutionEngine *Value::engine() const
+{
+ Managed *m = asManaged();
+ return m ? m->engine() : 0;
+}
+
+inline void Value::mark(ExecutionEngine *e) const
+{
+ if (!val)
+ return;
+ Managed *m = asManaged();
+ if (m)
+ m->mark(e);
+}
+
+inline Primitive Primitive::nullValue()
+{
+ Primitive v;
+#if QT_POINTER_SIZE == 8
+ v.val = quint64(_Null_Type) << Tag_Shift;
+#else
+ v.tag = _Null_Type;
+ v.int_32 = 0;
+#endif
+ return v;
+}
+
+inline Primitive Primitive::fromBoolean(bool b)
+{
+ Primitive v;
+ v.tag = _Boolean_Type;
+ v.int_32 = (bool)b;
+ return v;
+}
+
+inline Primitive Primitive::fromDouble(double d)
+{
+ Primitive v;
+ v.setDouble(d);
+ return v;
+}
+
+inline Primitive Primitive::fromInt32(int i)
+{
+ Primitive v;
+ v.tag = _Integer_Type;
+ v.int_32 = i;
+ return v;
+}
+
+inline Primitive Primitive::fromUInt32(uint i)
+{
+ Primitive v;
+ if (i < INT_MAX) {
+ v.tag = _Integer_Type;
+ v.int_32 = (int)i;
+ } else {
+ v.setDouble(i);
+ }
+ return v;
+}
+
+inline double Value::toNumber() const
+{
+ if (integerCompatible())
+ return int_32;
+ if (isDouble())
+ return doubleValue();
+ return toNumberImpl();
+}
+
+inline int Value::toInt32() const
+{
+ if (integerCompatible())
+ return int_32;
+ double d;
+ if (isDouble())
+ d = doubleValue();
+ else
+ d = toNumberImpl();
+
+ const double D32 = 4294967296.0;
+ const double D31 = D32 / 2.0;
+
+ if ((d >= -D31 && d < D31))
+ return static_cast<int>(d);
+
+ return Primitive::toInt32(d);
+}
+
+inline unsigned int Value::toUInt32() const
+{
+ return (unsigned int)toInt32();
+}
+
+
+inline bool Value::toBoolean() const
+{
+ switch (type()) {
+ case Value::Undefined_Type:
+ case Value::Null_Type:
+ return false;
+ case Value::Boolean_Type:
+ case Value::Integer_Type:
+ return (bool)int_32;
+ case Value::Managed_Type:
+ if (isString())
+ return stringValue()->toQString().length() > 0;
+ return true;
+ default: // double
+ return doubleValue() && !std::isnan(doubleValue());
+ }
+}
+
+inline uint Value::asArrayIndex() const
+{
+#if QT_POINTER_SIZE == 8
+ if (!isNumber())
+ return UINT_MAX;
+ if (isInteger())
+ return int_32 >= 0 ? (uint)int_32 : UINT_MAX;
+#else
+ if (isInteger() && int_32 >= 0)
+ return (uint)int_32;
+ if (!isDouble())
+ return UINT_MAX;
+#endif
+ double d = doubleValue();
+ uint idx = (uint)d;
+ if (idx != d)
+ return UINT_MAX;
+ return idx;
+}
+
+inline uint Value::asArrayLength(bool *ok) const
+{
+ *ok = true;
+ if (integerCompatible() && int_32 >= 0)
+ return (uint)int_32;
+ if (isDouble()) {
+ double d = doubleValue();
+ uint idx = (uint)d;
+ if (idx != d) {
+ *ok = false;
+ return UINT_MAX;
+ }
+ return idx;
+ }
+ if (isString())
+ return stringValue()->toUInt(ok);
+
+ uint idx = toUInt32();
+ double d = toNumber();
+ if (d != idx) {
+ *ok = false;
+ return UINT_MAX;
+ }
+ return idx;
+}
+
+inline Object *Value::asObject() const
+{
+ return isObject() ? objectValue() : 0;
+}
+
+inline FunctionObject *Value::asFunctionObject() const
+{
+ return isObject() ? managed()->asFunctionObject() : 0;
+}
+
+inline NumberObject *Value::asNumberObject() const
+{
+ return isObject() ? managed()->asNumberObject() : 0;
+}
+
+inline StringObject *Value::asStringObject() const
+{
+ return isObject() ? managed()->asStringObject() : 0;
+}
+
+inline DateObject *Value::asDateObject() const
+{
+ return isObject() ? managed()->asDateObject() : 0;
+}
+
+inline ArrayObject *Value::asArrayObject() const
+{
+ return isObject() ? managed()->asArrayObject() : 0;
+}
+
+inline ErrorObject *Value::asErrorObject() const
+{
+ return isObject() ? managed()->asErrorObject() : 0;
+}
+
+template<typename T>
+inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as<T>() : 0; }
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index b93fcbe4bd..27c81d59a5 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -38,360 +38,530 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef QMLJS_VALUE_H
-#define QMLJS_VALUE_H
+#ifndef QV4VALUE_P_H
+#define QV4VALUE_P_H
-#include <cmath> // this HAS to come
+#include <limits.h>
#include <QtCore/QString>
-#include <QtCore/qnumeric.h>
#include "qv4global_p.h"
-#include "qv4string_p.h"
-#include <QtCore/QDebug>
-#include "qv4managed_p.h"
-#include "qv4engine_p.h"
-#include <private/qtqmlglobal_p.h>
-
-//#include <wtf/MathExtras.h>
-
-#include "qv4value_def_p.h"
QT_BEGIN_NAMESPACE
namespace QV4 {
-inline bool Value::isString() const
-{
- if (!isManaged())
- return false;
- return managed() && managed()->internalClass->vtable->isString;
-}
-inline bool Value::isObject() const
-{
- if (!isManaged())
- return false;
- return managed() && managed()->internalClass->vtable->isObject;
-}
+typedef uint Bool;
-inline bool Value::isPrimitive() const
+template <typename T>
+struct Returned : private T
{
- return !isObject();
-}
+ static Returned<T> *create(T *t) { return static_cast<Returned<T> *>(t); }
+ T *getPointer() { return this; }
+ template<typename X>
+ static T *getPointer(Returned<X> *x) { return x->getPointer(); }
+ template<typename X>
+ Returned<X> *as() { return Returned<X>::create(Returned<X>::getPointer(this)); }
+ using T::asReturnedValue;
+};
-inline ExecutionEngine *Value::engine() const
+struct Q_QML_EXPORT Value
{
- Managed *m = asManaged();
- return m ? m->engine() : 0;
-}
+ /*
+ We use two different ways of encoding JS values. One for 32bit and one for 64bit systems.
-inline void Value::mark(ExecutionEngine *e) const
-{
- if (!val)
- return;
- Managed *m = asManaged();
- if (m)
- m->mark(e);
-}
+ In both cases, we 8 bytes for a value and different variant of NaN boxing. A Double NaN (actually -qNaN)
+ is indicated by a number that has the top 13 bits set. THe other values are usually set to 0 by the
+ processor, and are thus free for us to store other data. We keep pointers in there for managed objects,
+ and encode the other types using the free space given to use by the unused bits for NaN values. This also
+ works for pointers on 64 bit systems, as they all currently only have 48 bits of addressable memory.
-inline Primitive Primitive::nullValue()
-{
- Primitive v;
+ On 32bit, we store doubles as doubles. All other values, have the high 32bits set to a value that
+ will make the number a NaN. The Masks below are used for encoding the other types.
+
+ On 64 bit, we xor Doubles with (0xffff8000 << 32). Thas has the effect that no doubles will get encoded
+ with the 13 highest bits all 0. We are now using special values for bits 14-17 to encode our values. These
+ can be used, as the highest valid pointer on a 64 bit system is 2^48-1.
+
+ If they are all 0, we have a pointer to a Managed object. If bit 14 is set we have an integer.
+ This makes testing for pointers and numbers very fast (we have a number if any of the highest 14 bits is set).
+
+ Bit 15-17 is then used to encode other immediates.
+ */
+
+
+ union {
+ quint64 val;
#if QT_POINTER_SIZE == 8
- v.val = quint64(_Null_Type) << Tag_Shift;
+ Managed *m;
+ Object *o;
+ String *s;
#else
- v.tag = _Null_Type;
- v.int_32 = 0;
+ double dbl;
+#endif
+ struct {
+#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN
+ uint tag;
+#endif
+ union {
+ uint uint_32;
+ int int_32;
+#if QT_POINTER_SIZE == 4
+ Managed *m;
+ Object *o;
+ String *s;
+#endif
+ };
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ uint tag;
+#endif
+ };
+ };
+
+#if QT_POINTER_SIZE == 4
+ enum Masks {
+ NaN_Mask = 0x7ff80000,
+ NotDouble_Mask = 0x7ffc0000,
+ Type_Mask = 0xffff8000,
+ Immediate_Mask = NotDouble_Mask | 0x00008000,
+ IsNullOrUndefined_Mask = Immediate_Mask | 0x20000,
+ Tag_Shift = 32
+ };
+ enum ValueType {
+ Undefined_Type = Immediate_Mask | 0x00000,
+ Null_Type = Immediate_Mask | 0x10000,
+ Boolean_Type = Immediate_Mask | 0x20000,
+ Integer_Type = Immediate_Mask | 0x30000,
+ Managed_Type = NotDouble_Mask | 0x00000,
+ Empty_Type = NotDouble_Mask | 0x30000
+ };
+
+ enum ImmediateFlags {
+ ConvertibleToInt = Immediate_Mask | 0x1
+ };
+
+ enum ValueTypeInternal {
+ _Null_Type = Null_Type | ConvertibleToInt,
+ _Boolean_Type = Boolean_Type | ConvertibleToInt,
+ _Integer_Type = Integer_Type | ConvertibleToInt,
+
+ };
+#else
+ static const quint64 NaNEncodeMask = 0xffff800000000000ll;
+ static const quint64 IsInt32Mask = 0x0002000000000000ll;
+ static const quint64 IsDoubleMask = 0xfffc000000000000ll;
+ static const quint64 IsNumberMask = IsInt32Mask|IsDoubleMask;
+ static const quint64 IsNullOrUndefinedMask = 0x0000800000000000ll;
+ static const quint64 IsNullOrBooleanMask = 0x0001000000000000ll;
+ static const quint64 IsConvertibleToIntMask = IsInt32Mask|IsNullOrBooleanMask;
+
+ enum Masks {
+ NaN_Mask = 0x7ff80000,
+ Type_Mask = 0xffff8000,
+ IsDouble_Mask = 0xfffc0000,
+ Immediate_Mask = 0x00018000,
+ IsNullOrUndefined_Mask = 0x00008000,
+ IsNullOrBoolean_Mask = 0x00010000,
+ Tag_Shift = 32
+ };
+ enum ValueType {
+ Undefined_Type = IsNullOrUndefined_Mask,
+ Null_Type = IsNullOrUndefined_Mask|IsNullOrBoolean_Mask,
+ Boolean_Type = IsNullOrBoolean_Mask,
+ Integer_Type = 0x20000|IsNullOrBoolean_Mask,
+ Managed_Type = 0,
+ Empty_Type = Undefined_Type | 0x4000
+ };
+ enum {
+ IsDouble_Shift = 64-14,
+ IsNumber_Shift = 64-15,
+ IsConvertibleToInt_Shift = 64-16,
+ IsManaged_Shift = 64-17
+ };
+
+
+ enum ValueTypeInternal {
+ _Null_Type = Null_Type,
+ _Boolean_Type = Boolean_Type,
+ _Integer_Type = Integer_Type
+ };
#endif
- return v;
-}
-
-inline Primitive Primitive::fromBoolean(bool b)
-{
- Primitive v;
- v.tag = _Boolean_Type;
- v.int_32 = (bool)b;
- return v;
-}
-inline Primitive Primitive::fromDouble(double d)
-{
- Primitive v;
- v.setDouble(d);
- return v;
-}
+ inline unsigned type() const {
+ return tag & Type_Mask;
+ }
-inline Primitive Primitive::fromInt32(int i)
-{
- Primitive v;
- v.tag = _Integer_Type;
- v.int_32 = i;
- return v;
-}
+ // used internally in property
+ inline bool isEmpty() const { return tag == Empty_Type; }
-inline Primitive Primitive::fromUInt32(uint i)
-{
- Primitive v;
- if (i < INT_MAX) {
- v.tag = _Integer_Type;
- v.int_32 = (int)i;
- } else {
- v.setDouble(i);
+ inline bool isUndefined() const { return tag == Undefined_Type; }
+ inline bool isNull() const { return tag == _Null_Type; }
+ inline bool isBoolean() const { return tag == _Boolean_Type; }
+#if QT_POINTER_SIZE == 8
+ inline bool isInteger() const { return (val >> IsNumber_Shift) == 1; }
+ inline bool isDouble() const { return (val >> IsDouble_Shift); }
+ inline bool isNumber() const { return (val >> IsNumber_Shift); }
+ inline bool isManaged() const { return !(val >> IsManaged_Shift); }
+ inline bool isNullOrUndefined() const { return ((val >> IsManaged_Shift) & ~2) == 1; }
+ inline bool integerCompatible() const { return ((val >> IsConvertibleToInt_Shift) & ~2) == 1; }
+ static inline bool integerCompatible(Value a, Value b) {
+ return a.integerCompatible() && b.integerCompatible();
}
- return v;
-}
-
-inline double Value::toNumber() const
-{
- if (integerCompatible())
- return int_32;
- if (isDouble())
+ static inline bool bothDouble(Value a, Value b) {
+ return a.isDouble() && b.isDouble();
+ }
+ double doubleValue() const {
+ Q_ASSERT(isDouble());
+ union {
+ quint64 i;
+ double d;
+ } v;
+ v.i = val ^ NaNEncodeMask;
+ return v.d;
+ }
+ void setDouble(double d) {
+ union {
+ quint64 i;
+ double d;
+ } v;
+ v.d = d;
+ val = v.i ^ NaNEncodeMask;
+ Q_ASSERT(isDouble());
+ }
+ bool isNaN() const { return (tag & 0x7fff8000) == 0x00078000; }
+#else
+ inline bool isInteger() const { return tag == _Integer_Type; }
+ inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; }
+ inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; }
+ inline bool isManaged() const { return tag == Managed_Type; }
+ inline bool isNullOrUndefined() const { return (tag & IsNullOrUndefined_Mask) == Undefined_Type; }
+ inline bool integerCompatible() const { return (tag & ConvertibleToInt) == ConvertibleToInt; }
+ static inline bool integerCompatible(Value a, Value b) {
+ return ((a.tag & b.tag) & ConvertibleToInt) == ConvertibleToInt;
+ }
+ static inline bool bothDouble(Value a, Value b) {
+ return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask;
+ }
+ double doubleValue() const { return dbl; }
+ void setDouble(double d) { dbl = d; }
+ bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
+#endif
+ inline bool isString() const;
+ inline bool isObject() const;
+ inline bool isInt32() {
+ if (tag == _Integer_Type)
+ return true;
+ if (isDouble()) {
+ double d = doubleValue();
+ int i = (int)d;
+ if (i == d) {
+ int_32 = i;
+ tag = _Integer_Type;
+ return true;
+ }
+ }
+ return false;
+ }
+ double asDouble() const {
+ if (tag == _Integer_Type)
+ return int_32;
return doubleValue();
- return toNumberImpl();
-}
+ }
-inline int Value::toInt32() const
-{
- if (integerCompatible())
+ bool booleanValue() const {
+ return int_32;
+ }
+ int integerValue() const {
return int_32;
- double d;
- if (isDouble())
- d = doubleValue();
- else
- d = toNumberImpl();
+ }
- const double D32 = 4294967296.0;
- const double D31 = D32 / 2.0;
+ String *stringValue() const {
+ return s;
+ }
+ Object *objectValue() const {
+ return o;
+ }
+ Managed *managed() const {
+ return m;
+ }
- if ((d >= -D31 && d < D31))
- return static_cast<int>(d);
+ quint64 rawValue() const {
+ return val;
+ }
- return Primitive::toInt32(d);
-}
+ static inline Value fromManaged(Managed *o);
+
+ int toUInt16() const;
+ inline int toInt32() const;
+ inline unsigned int toUInt32() const;
+
+ inline bool toBoolean() const;
+ double toInteger() const;
+ inline double toNumber() const;
+ double toNumberImpl() const;
+ QString toQStringNoThrow() const;
+ QString toQString() const;
+ String *toString(ExecutionEngine *e) const;
+ String *toString(ExecutionContext *ctx) const;
+ Object *toObject(ExecutionContext *ctx) const;
+
+ inline bool isPrimitive() const;
+ inline bool tryIntegerConversion() {
+ bool b = integerCompatible();
+ if (b)
+ tag = _Integer_Type;
+ return b;
+ }
-inline unsigned int Value::toUInt32() const
-{
- return (unsigned int)toInt32();
-}
+ inline String *asString() const;
+ inline Managed *asManaged() const;
+ inline Object *asObject() const;
+ inline FunctionObject *asFunctionObject() const;
+ inline NumberObject *asNumberObject() const;
+ inline StringObject *asStringObject() const;
+ inline DateObject *asDateObject() const;
+ inline ArrayObject *asArrayObject() const;
+ inline ErrorObject *asErrorObject() const;
+ template<typename T> inline T *as() const;
-inline bool Value::toBoolean() const
-{
- switch (type()) {
- case Value::Undefined_Type:
- case Value::Null_Type:
- return false;
- case Value::Boolean_Type:
- case Value::Integer_Type:
- return (bool)int_32;
- case Value::Managed_Type:
- if (isString())
- return stringValue()->toQString().length() > 0;
- return true;
- default: // double
- return doubleValue() && !std::isnan(doubleValue());
- }
-}
+ inline uint asArrayIndex() const;
+ inline uint asArrayLength(bool *ok) const;
-inline uint Value::asArrayIndex() const
-{
-#if QT_POINTER_SIZE == 8
- if (!isNumber())
- return UINT_MAX;
- if (isInteger())
- return int_32 >= 0 ? (uint)int_32 : UINT_MAX;
-#else
- if (isInteger() && int_32 >= 0)
- return (uint)int_32;
- if (!isDouble())
- return UINT_MAX;
-#endif
- double d = doubleValue();
- uint idx = (uint)d;
- if (idx != d)
- return UINT_MAX;
- return idx;
-}
+ inline ExecutionEngine *engine() const;
-inline uint Value::asArrayLength(bool *ok) const
-{
- *ok = true;
- if (integerCompatible() && int_32 >= 0)
- return (uint)int_32;
- if (isDouble()) {
- double d = doubleValue();
- uint idx = (uint)d;
- if (idx != d) {
- *ok = false;
- return UINT_MAX;
- }
- return idx;
+ ReturnedValue asReturnedValue() const { return val; }
+ static Value fromReturnedValue(ReturnedValue val) { Value v; v.val = val; return v; }
+
+ // Section 9.12
+ bool sameValue(Value other) const;
+
+ inline void mark(ExecutionEngine *e) const;
+
+ Value &operator =(const ScopedValue &v);
+ Value &operator=(ReturnedValue v) { val = v; return *this; }
+ template<typename T>
+ Value &operator=(Returned<T> *t);
+ template<typename T>
+ Value &operator=(T *t) {
+ val = Value::fromManaged(t).val;
+ return *this;
}
- if (isString())
- return stringValue()->toUInt(ok);
- uint idx = toUInt32();
- double d = toNumber();
- if (d != idx) {
- *ok = false;
- return UINT_MAX;
+ template<typename T>
+ Value &operator=(const Scoped<T> &t);
+ Value &operator=(const ValueRef v);
+ Value &operator=(const Value &v) {
+ val = v.val;
+ return *this;
}
- return idx;
-}
+ template<typename T>
+ inline Returned<T> *as();
+};
-inline Object *Value::asObject() const
+inline Managed *Value::asManaged() const
{
- return isObject() ? objectValue() : 0;
+ if (isManaged())
+ return managed();
+ return 0;
}
-inline FunctionObject *Value::asFunctionObject() const
+inline String *Value::asString() const
{
- return isObject() ? managed()->asFunctionObject() : 0;
+ if (isString())
+ return stringValue();
+ return 0;
}
-inline NumberObject *Value::asNumberObject() const
+struct Q_QML_EXPORT Primitive : public Value
{
- return isObject() ? managed()->asNumberObject() : 0;
-}
+ inline static Primitive emptyValue();
+ static inline Primitive fromBoolean(bool b);
+ static inline Primitive fromInt32(int i);
+ inline static Primitive undefinedValue();
+ static inline Primitive nullValue();
+ static inline Primitive fromDouble(double d);
+ static inline Primitive fromUInt32(uint i);
+
+ static double toInteger(double fromNumber);
+ static int toInt32(double value);
+ static unsigned int toUInt32(double value);
+
+ inline operator ValueRef();
+ Value asValue() const { return *this; }
+};
-inline StringObject *Value::asStringObject() const
+inline Primitive Primitive::undefinedValue()
{
- return isObject() ? managed()->asStringObject() : 0;
+ Primitive v;
+#if QT_POINTER_SIZE == 8
+ v.val = quint64(Undefined_Type) << Tag_Shift;
+#else
+ v.tag = Undefined_Type;
+ v.int_32 = 0;
+#endif
+ return v;
}
-inline DateObject *Value::asDateObject() const
+inline Primitive Primitive::emptyValue()
{
- return isObject() ? managed()->asDateObject() : 0;
+ Primitive v;
+ v.tag = Value::Empty_Type;
+ v.uint_32 = 0;
+ return v;
}
-inline ArrayObject *Value::asArrayObject() const
+inline Value Value::fromManaged(Managed *m)
{
- return isObject() ? managed()->asArrayObject() : 0;
+ if (!m)
+ return QV4::Primitive::undefinedValue();
+ Value v;
+#if QT_POINTER_SIZE == 8
+ v.m = m;
+#else
+ v.tag = Managed_Type;
+ v.m = m;
+#endif
+ return v;
}
-inline ErrorObject *Value::asErrorObject() const
+template <typename T>
+struct TypedValue : public Value
{
- return isObject() ? managed()->asErrorObject() : 0;
-}
+ template<typename X>
+ TypedValue &operator =(X *x) {
+ val = Value::fromManaged(x).val;
+ }
+ TypedValue &operator =(T *t);
+ TypedValue &operator =(const Scoped<T> &v);
+// TypedValue &operator =(const ManagedRef<T> &v);
+ TypedValue &operator =(Returned<T> *t);
-template<typename T>
-inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as<T>() : 0; }
+ TypedValue &operator =(const TypedValue<T> &t);
-struct Q_QML_PRIVATE_EXPORT PersistentValuePrivate
-{
- PersistentValuePrivate(ReturnedValue v, ExecutionEngine *engine = 0, bool weak = false);
- virtual ~PersistentValuePrivate();
- SafeValue value;
- uint refcount;
- bool weak;
- QV4::ExecutionEngine *engine;
- PersistentValuePrivate **prev;
- PersistentValuePrivate *next;
-
- void init();
- void removeFromList();
- void ref() { ++refcount; }
- void deref();
- PersistentValuePrivate *detach(const ReturnedValue value, bool weak = false);
-
- bool checkEngine(QV4::ExecutionEngine *otherEngine) {
- if (!engine) {
- Q_ASSERT(!value.isObject());
- engine = otherEngine;
- }
- return (engine == otherEngine);
- }
-};
+ bool operator!() const { return !managed(); }
-class Q_QML_EXPORT PersistentValue
-{
-public:
- PersistentValue() : d(0) {}
- PersistentValue(const PersistentValue &other);
- PersistentValue &operator=(const PersistentValue &other);
+ T *operator->() { return static_cast<T *>(managed()); }
+ const T *operator->() const { return static_cast<T *>(managed()); }
+ T *getPointer() const { return static_cast<T *>(managed()); }
+ Returned<T> *ret() const;
+
+ void mark(ExecutionEngine *e) { if (managed()) managed()->mark(e); }
+};
+typedef TypedValue<String> StringValue;
- PersistentValue(const ValueRef val);
- PersistentValue(ReturnedValue val);
- template<typename T>
- PersistentValue(Returned<T> *obj);
- template<typename T>
- PersistentValue(const Referenced<T> obj);
- PersistentValue &operator=(const ValueRef other);
- PersistentValue &operator =(ReturnedValue other);
- template<typename T>
- PersistentValue &operator=(Returned<T> *obj);
- template<typename T>
- PersistentValue &operator=(const Referenced<T> obj);
- ~PersistentValue();
- ReturnedValue value() const {
- return (d ? d->value.asReturnedValue() : Primitive::undefinedValue().asReturnedValue());
+struct Encode {
+ static ReturnedValue undefined() {
+ return quint64(Value::Undefined_Type) << Value::Tag_Shift;
+ }
+ static ReturnedValue null() {
+ return quint64(Value::_Null_Type) << Value::Tag_Shift;
}
- ExecutionEngine *engine() {
- if (!d)
- return 0;
- if (d->engine)
- return d->engine;
- Managed *m = d->value.asManaged();
- return m ? m->engine() : 0;
+ Encode(bool b) {
+ val = (quint64(Value::_Boolean_Type) << Value::Tag_Shift) | (uint)b;
+ }
+ Encode(double d) {
+ Value v;
+ v.setDouble(d);
+ val = v.val;
+ }
+ Encode(int i) {
+ val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | (uint)i;
+ }
+ Encode(uint i) {
+ if (i <= INT_MAX) {
+ val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | i;
+ } else {
+ Value v;
+ v.setDouble(i);
+ val = v.val;
+ }
+ }
+ Encode(ReturnedValue v) {
+ val = v;
}
- bool isUndefined() const { return !d || d->value.isUndefined(); }
- bool isNullOrUndefined() const { return !d || d->value.isNullOrUndefined(); }
- void clear() {
- *this = PersistentValue();
+ template<typename T>
+ Encode(Returned<T> *t) {
+ val = t->getPointer()->asReturnedValue();
}
+ operator ReturnedValue() const {
+ return val;
+ }
+ quint64 val;
private:
- friend struct ValueRef;
- PersistentValuePrivate *d;
+ Encode(void *);
};
-class Q_QML_EXPORT WeakValue
-{
-public:
- WeakValue() : d(0) {}
- WeakValue(const ValueRef val);
- WeakValue(const WeakValue &other);
- WeakValue(ReturnedValue val);
- template<typename T>
- WeakValue(Returned<T> *obj);
- WeakValue &operator=(const WeakValue &other);
- WeakValue &operator=(const ValueRef other);
- WeakValue &operator =(const ReturnedValue &other);
- template<typename T>
- WeakValue &operator=(Returned<T> *obj);
-
- ~WeakValue();
+struct ValueRef {
+ ValueRef(const ScopedValue &v);
+ template <typename T>
+ ValueRef(const Scoped<T> &v);
+ ValueRef(const PersistentValue &v);
+ ValueRef(PersistentValuePrivate *p);
+ ValueRef(Value &v) { ptr = &v; }
+ // Important: Do NOT add a copy constructor to this class
+ // adding a copy constructor actually changes the calling convention, ie.
+ // is not even binary compatible. Adding it would break assumptions made
+ // in the jit'ed code.
+ ValueRef &operator=(const ScopedValue &o);
+ ValueRef &operator=(const Value &v)
+ { *ptr = v; return *this; }
+ ValueRef &operator=(const ReturnedValue &v) {
+ ptr->val = v;
+ return *this;
+ }
+ template <typename T>
+ ValueRef &operator=(Returned<T> *v) {
+ ptr->val = v->asReturnedValue();
+ return *this;
+ }
- ReturnedValue value() const {
- return (d ? d->value.asReturnedValue() : Primitive::undefinedValue().asReturnedValue());
+ operator const Value *() const {
+ return ptr;
+ }
+ const Value *operator->() const {
+ return ptr;
}
- ExecutionEngine *engine() {
- if (!d)
- return 0;
- if (d->engine)
- return d->engine;
- Managed *m = d->value.asManaged();
- return m ? m->engine() : 0;
+ operator Value *() {
+ return ptr;
+ }
+ Value *operator->() {
+ return ptr;
}
- bool isUndefined() const { return !d || d->value.isUndefined(); }
- bool isNullOrUndefined() const { return !d || d->value.isNullOrUndefined(); }
- void clear() {
- *this = WeakValue();
+ static ValueRef fromRawValue(Value *v) {
+ return ValueRef(v);
+ }
+ static const ValueRef fromRawValue(const Value *v) {
+ return ValueRef(const_cast<Value *>(v));
}
- void markOnce(ExecutionEngine *e);
+ ReturnedValue asReturnedValue() const { return ptr->val; }
+ // ### get rid of this one!
+ ValueRef(Value *v) { ptr = reinterpret_cast<Value *>(v); }
private:
- friend struct ValueRef;
- PersistentValuePrivate *d;
+ Value *ptr;
};
-} // namespace QV4
+
+template<typename T>
+T *value_cast(const Value &v)
+{
+ return v.as<T>();
+}
+
+template<typename T>
+ReturnedValue value_convert(ExecutionEngine *e, const Value &v);
+
+
+
+}
QT_END_NAMESPACE
-#endif
+#endif // QV4VALUE_DEF_P_H
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 5bfd7786e9..92cc19d8b9 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -77,7 +77,7 @@ QVariant VariantObject::toVariant(const QV4::ValueRef v)
if (v->isBoolean())
return QVariant(v->booleanValue());
if (v->isNumber()) {
- QV4::SafeValue val;
+ QV4::Value val;
val = v;
if (val.isInt32())
return QVariant(val.integerValue());
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index 3715dbc8c4..656608d49b 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -57,7 +57,7 @@
#include <QtQml/qqmllist.h>
#include <QtCore/qvariant.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
@@ -82,6 +82,8 @@ public:
static bool isEqualTo(Managed *m, Managed *other);
};
+DEFINE_REF(VariantObject, Object);
+
struct VariantPrototype : VariantObject
{
public:
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 9d6540ebe9..df8e3632fb 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -41,7 +41,7 @@
#include "qv4vme_moth_p.h"
#include "qv4instr_moth_p.h"
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4debugging_p.h>
#include <private/qv4math_p.h>
#include <private/qv4scopedvalue_p.h>
@@ -64,8 +64,6 @@ using namespace QQmlJS::Moth;
#define MOTH_BEGIN_INSTR_COMMON(I) { \
const InstrMeta<(int)Instr::I>::DataType &instr = InstrMeta<(int)Instr::I>::data(*genericInstr); \
code += InstrMeta<(int)Instr::I>::Size; \
- if (debugger && (instr.breakPoint || debugger->pauseAtNextOpportunity())) \
- debugger->maybeBreakAtInstruction(code, instr.breakPoint); \
Q_UNUSED(instr); \
TRACE_INSTR(I)
@@ -74,11 +72,6 @@ using namespace QQmlJS::Moth;
# define MOTH_BEGIN_INSTR(I) op_##I: \
MOTH_BEGIN_INSTR_COMMON(I)
-# define MOTH_NEXT_INSTR(I) { \
- genericInstr = reinterpret_cast<const Instr *>(code); \
- goto *genericInstr->common.code; \
- }
-
# define MOTH_END_INSTR(I) } \
genericInstr = reinterpret_cast<const Instr *>(code); \
goto *genericInstr->common.code; \
@@ -89,10 +82,6 @@ using namespace QQmlJS::Moth;
case Instr::I: \
MOTH_BEGIN_INSTR_COMMON(I)
-# define MOTH_NEXT_INSTR(I) { \
- continue; \
- }
-
# define MOTH_END_INSTR(I) } \
continue;
@@ -161,16 +150,15 @@ Param traceParam(const Param &param)
#define STOREVALUE(param, value) { \
QV4::ReturnedValue tmp = (value); \
- if (context->engine->hasException) \
+ if (engine->hasException) \
goto catchException; \
VALUE(param) = tmp; \
}
#define CHECK_EXCEPTION \
- if (context->engine->hasException) \
+ if (engine->hasException) \
goto catchException
-QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
- QV4::SafeValue *stack, unsigned stackSize
+QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
#ifdef MOTH_THREADED_INTERPRETER
, void ***storeJumpTable
#endif
@@ -192,15 +180,18 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
}
#endif
+ QV4::Value *stack = 0;
+ unsigned stackSize = 0;
+
const uchar *exceptionHandler = 0;
- QV4::Debugging::Debugger *debugger = context->engine->debugger;
+ QV4::ExecutionEngine *engine = context->engine;
#ifdef DO_TRACE_INSTR
qDebug("Starting VME with context=%p and code=%p", context, code);
#endif // DO_TRACE_INSTR
- QV4::SafeString * const runtimeStrings = context->compilationUnit->runtimeStrings;
+ QV4::StringValue * const runtimeStrings = context->compilationUnit->runtimeStrings;
context->interpreterInstructionPointer = &code;
// setup lookup scopes
@@ -213,9 +204,9 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
}
}
- QV4::SafeValue **scopes = static_cast<QV4::SafeValue **>(alloca(sizeof(QV4::SafeValue *)*(2 + 2*scopeDepth)));
+ QV4::Value **scopes = static_cast<QV4::Value **>(alloca(sizeof(QV4::Value *)*(2 + 2*scopeDepth)));
{
- scopes[0] = const_cast<QV4::SafeValue *>(context->compilationUnit->data->constants());
+ scopes[0] = const_cast<QV4::Value *>(context->compilationUnit->data->constants());
// stack gets setup in push instruction
scopes[1] = 0;
QV4::ExecutionContext *scope = context;
@@ -247,6 +238,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
VALUE(instr.result) = VALUE(instr.source);
MOTH_END_INSTR(Move)
+ MOTH_BEGIN_INSTR(MoveConst)
+ VALUE(instr.result) = instr.source;
+ MOTH_END_INSTR(MoveConst)
+
MOTH_BEGIN_INSTR(SwapTemps)
qSwap(VALUE(instr.left), VALUE(instr.right));
MOTH_END_INSTR(MoveTemp)
@@ -286,11 +281,22 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
STOREVALUE(instr.result, __qmljs_get_element(context, VALUEPTR(instr.base), VALUEPTR(instr.index)));
MOTH_END_INSTR(LoadElement)
+ MOTH_BEGIN_INSTR(LoadElementLookup)
+ QV4::Lookup *l = context->lookups + instr.lookup;
+ STOREVALUE(instr.result, l->indexedGetter(l, VALUEPTR(instr.base), VALUEPTR(instr.index)));
+ MOTH_END_INSTR(LoadElementLookup)
+
MOTH_BEGIN_INSTR(StoreElement)
__qmljs_set_element(context, VALUEPTR(instr.base), VALUEPTR(instr.index), VALUEPTR(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElement)
+ MOTH_BEGIN_INSTR(StoreElementLookup)
+ QV4::Lookup *l = context->lookups + instr.lookup;
+ l->indexedSetter(l, VALUEPTR(instr.base), VALUEPTR(instr.index), VALUEPTR(instr.source));
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(StoreElementLookup)
+
MOTH_BEGIN_INSTR(LoadProperty)
STOREVALUE(instr.result, __qmljs_get_property(context, VALUEPTR(instr.base), runtimeStrings[instr.name]));
MOTH_END_INSTR(LoadProperty)
@@ -328,7 +334,9 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
TRACE(inline, "stack size: %u", instr.value);
stackSize = instr.value;
stack = context->engine->stackPush(stackSize);
- memset(stack, 0, stackSize * sizeof(QV4::SafeValue));
+#ifndef QT_NO_DEBUG
+ memset(stack, 0, stackSize * sizeof(QV4::Value));
+#endif
scopes[1] = stack;
MOTH_END_INSTR(Push)
@@ -343,7 +351,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
}
}
#endif // DO_TRACE_INSTR
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -353,7 +361,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_BEGIN_INSTR(CallProperty)
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -363,7 +371,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_BEGIN_INSTR(CallPropertyLookup)
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -372,7 +380,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -382,7 +390,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_BEGIN_INSTR(CallActivationProperty)
TRACE(args, "starting at %d, length %d", instr.args, instr.argc);
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -392,7 +400,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_BEGIN_INSTR(CallGlobalLookup)
TRACE(args, "starting at %d, length %d", instr.args, instr.argc);
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -475,12 +483,12 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_BEGIN_INSTR(CallBuiltinDefineArray)
Q_ASSERT(instr.args + instr.argc <= stackSize);
- QV4::SafeValue *args = stack + instr.args;
+ QV4::Value *args = stack + instr.args;
STOREVALUE(instr.result, __qmljs_builtin_define_array(context, args, instr.argc));
MOTH_END_INSTR(CallBuiltinDefineArray)
MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral)
- QV4::SafeValue *args = stack + instr.args;
+ QV4::Value *args = stack + instr.args;
STOREVALUE(instr.result, __qmljs_builtin_define_object_literal(context, args, instr.internalClassId));
MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
@@ -494,7 +502,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_END_INSTR(CallBuiltinConvertThisToObject)
MOTH_BEGIN_INSTR(CreateValue)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -503,7 +511,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_END_INSTR(CreateValue)
MOTH_BEGIN_INSTR(CreateProperty)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -512,7 +520,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_END_INSTR(CreateProperty)
MOTH_BEGIN_INSTR(ConstructPropertyLookup)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -522,7 +530,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_BEGIN_INSTR(CreateActivationProperty)
TRACE(inline, "property name = %s, args = %d, argc = %d", runtimeStrings[instr.name]->toQString().toUtf8().constData(), instr.args, instr.argc);
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -532,7 +540,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
MOTH_BEGIN_INSTR(ConstructGlobalLookup)
TRACE(inline, "property name = %s, args = %d, argc = %d", runtimeStrings[instr.name]->toQString().toUtf8().constData(), instr.args, instr.argc);
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
@@ -544,14 +552,19 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
code = ((uchar *)&instr.offset) + instr.offset;
MOTH_END_INSTR(Jump)
- MOTH_BEGIN_INSTR(CJump)
- uint cond = __qmljs_to_boolean(VALUEPTR(instr.condition));
+ MOTH_BEGIN_INSTR(JumpEq)
+ bool cond = VALUEPTR(instr.condition)->toBoolean();
TRACE(condition, "%s", cond ? "TRUE" : "FALSE");
- if (instr.invert)
- cond = !cond;
if (cond)
code = ((uchar *)&instr.offset) + instr.offset;
- MOTH_END_INSTR(CJump)
+ MOTH_END_INSTR(JumpEq)
+
+ MOTH_BEGIN_INSTR(JumpNe)
+ bool cond = VALUEPTR(instr.condition)->toBoolean();
+ TRACE(condition, "%s", cond ? "TRUE" : "FALSE");
+ if (!cond)
+ code = ((uchar *)&instr.offset) + instr.offset;
+ MOTH_END_INSTR(JumpNe)
MOTH_BEGIN_INSTR(UNot)
STOREVALUE(instr.result, __qmljs_not(VALUEPTR(instr.source)));
@@ -606,6 +619,14 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
STOREVALUE(instr.result, __qmljs_bit_xor(VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
MOTH_END_INSTR(BitXor)
+ MOTH_BEGIN_INSTR(Shr)
+ STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() >> (VALUEPTR(instr.rhs)->toInt32() & 0x1f))));
+ MOTH_END_INSTR(Shr)
+
+ MOTH_BEGIN_INSTR(Shl)
+ STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() << (VALUEPTR(instr.rhs)->toInt32() & 0x1f))));
+ MOTH_END_INSTR(Shl)
+
MOTH_BEGIN_INSTR(BitAndConst)
int lhs = VALUEPTR(instr.lhs)->toInt32();
STOREVALUE(instr.result, QV4::Encode((int)(lhs & instr.rhs)));
@@ -621,6 +642,14 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
STOREVALUE(instr.result, QV4::Encode((int)(lhs ^ instr.rhs)));
MOTH_END_INSTR(BitXor)
+ MOTH_BEGIN_INSTR(ShrConst)
+ STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() >> instr.rhs)));
+ MOTH_END_INSTR(ShrConst)
+
+ MOTH_BEGIN_INSTR(ShlConst)
+ STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() << instr.rhs)));
+ MOTH_END_INSTR(ShlConst)
+
MOTH_BEGIN_INSTR(Mul)
STOREVALUE(instr.result, __qmljs_mul(VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
MOTH_END_INSTR(Mul)
@@ -633,30 +662,18 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
STOREVALUE(instr.result, instr.alu(context, VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
MOTH_END_INSTR(BinopContext)
- MOTH_BEGIN_INSTR(AddNumberParams)
- double lhs = VALUE(instr.lhs).asDouble();
- double rhs = VALUE(instr.rhs).asDouble();
- VALUEPTR(instr.result)->setDouble(lhs + rhs);
- MOTH_END_INSTR(AddNumberParams)
-
- MOTH_BEGIN_INSTR(MulNumberParams)
- double lhs = VALUE(instr.lhs).asDouble();
- double rhs = VALUE(instr.rhs).asDouble();
- VALUEPTR(instr.result)->setDouble(lhs * rhs);
- MOTH_END_INSTR(MulNumberParams)
-
- MOTH_BEGIN_INSTR(SubNumberParams)
- double lhs = VALUE(instr.lhs).asDouble();
- double rhs = VALUE(instr.rhs).asDouble();
- VALUEPTR(instr.result)->setDouble(lhs - rhs);
- MOTH_END_INSTR(SubNumberParams)
-
MOTH_BEGIN_INSTR(Ret)
context->engine->stackPop(stackSize);
// TRACE(Ret, "returning value %s", result.toString(context)->toQString().toUtf8().constData());
return VALUE(instr.result).asReturnedValue();
MOTH_END_INSTR(Ret)
+ MOTH_BEGIN_INSTR(Debug)
+ QV4::Debugging::Debugger *debugger = context->engine->debugger;
+ if (debugger && (instr.breakPoint || debugger->pauseAtNextOpportunity()))
+ debugger->maybeBreakAtInstruction(code, instr.breakPoint);
+ MOTH_END_INSTR(Debug)
+
MOTH_BEGIN_INSTR(LoadThis)
VALUE(instr.result) = context->callData->thisObject;
MOTH_END_INSTR(LoadThis)
@@ -709,7 +726,7 @@ void **VME::instructionJumpTable()
static void **jumpTable = 0;
if (!jumpTable) {
const uchar *code = 0;
- VME().run(0, code, 0, 0, &jumpTable);
+ VME().run(0, code, &jumpTable);
}
return jumpTable;
}
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index 974dfdd615..8d0822f16f 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -60,8 +60,7 @@ public:
#endif
private:
- QV4::ReturnedValue run(QV4::ExecutionContext *, const uchar *code,
- QV4::SafeValue *stack = 0, unsigned stackSize = 0
+ QV4::ReturnedValue run(QV4::ExecutionContext *, const uchar *code
#ifdef MOTH_THREADED_INTERPRETER
, void ***storeJumpTable = 0
#endif
diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h
index 31a530fa64..6bfd353771 100644
--- a/src/qml/qml/ftw/qfinitestack_p.h
+++ b/src/qml/qml/ftw/qfinitestack_p.h
@@ -114,6 +114,7 @@ T &QFiniteStack<T>::top()
template<typename T>
void QFiniteStack<T>::push(const T &o)
{
+ Q_ASSERT(_size < _alloc);
if (QTypeInfo<T>::isComplex) {
new (_array + _size++) T(o);
} else {
@@ -124,6 +125,7 @@ void QFiniteStack<T>::push(const T &o)
template<typename T>
T QFiniteStack<T>::pop()
{
+ Q_ASSERT(_size > 0);
--_size;
if (QTypeInfo<T>::isComplex) {
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index bc56fe1f2d..d0476a92d4 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -54,7 +54,7 @@
#include <private/qv4debugservice_p.h>
#include "qqmlinfo.h"
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <QtCore/qstringbuilder.h>
#include <QtCore/qdebug.h>
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index 05ec0ab9c7..75740e17e6 100644
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -88,7 +88,7 @@ int QQmlCompiledData::indexForUrl(const QUrl &data)
QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine)
: engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false),
- rootPropertyCache(0), compilationUnit(0), qmlUnit(0)
+ rootPropertyCache(0), compilationUnit(0), qmlUnit(0), totalBindingsCount(0), totalParserStatusCount(0)
{
Q_ASSERT(engine);
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index e36f3fd967..9262e2a119 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -1925,7 +1925,7 @@ bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
if (!isAttachedPropertyName(prop->name()))
- COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
+ COMPILE_EXCEPTION(prop, tr("Expected type name"));
// Setup attached property data
@@ -2377,7 +2377,7 @@ bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
const BindingContext &ctxt)
{
if (prop->values.isMany())
- COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
+ COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a script property"));
if (prop->values.first()->object)
COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
@@ -3456,7 +3456,7 @@ bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
Q_ASSERT(prop->parent->metatype);
if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
- COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
+ COMPILE_EXCEPTION(value, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
JSBindingReference *reference = pool->New<JSBindingReference>();
reference->expression = value->value;
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index c63f430b0a..2ce850da5d 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -85,6 +85,7 @@ class QQmlComponent;
class QQmlContext;
class QQmlContextData;
+// ### Merge with QV4::CompiledData::CompilationUnit
class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup
{
public:
@@ -161,6 +162,8 @@ public:
// hash key is object index
QHash<int, QByteArray> customParserData;
QVector<int> customParserBindings; // index is binding identifier, value is compiled function index.
+ int totalBindingsCount; // Number of bindings used in this type
+ int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
bool isCompositeType() const { return !datas.at(qmlUnit->indexOfRootObject).isEmpty(); }
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index a36150ee42..6abf805a4a 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -862,7 +862,7 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
enginePriv->referenceScarceResources();
QObject *rv = 0;
if (enginePriv->useNewCompiler) {
- state.creator = new QmlObjectCreator(context, cc);
+ state.creator = new QmlObjectCreator(context, cc, creationContext);
rv = state.creator->create(start);
if (!rv)
state.errors = state.creator->errors;
@@ -914,7 +914,8 @@ void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionS
{
if (state->completePending) {
if (enginePriv->useNewCompiler) {
- state->creator->finalize();
+ QQmlInstantiationInterrupt interrupt;
+ state->creator->finalize(interrupt);
} else {
state->vme.complete();
}
@@ -991,7 +992,7 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
if (p->activeVME) { // XXX should only be allowed during begin
a->add(&p->activeVME->componentAttached);
} else if (p->activeObjectCreator) {
- a->add(&p->activeObjectCreator->componentAttached);
+ a->add(p->activeObjectCreator->componentAttached);
} else {
QQmlData *d = QQmlData::get(obj);
Q_ASSERT(d);
@@ -1057,7 +1058,7 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
p->compiledData = d->cc;
p->compiledData->addref();
if (enginePriv->useNewCompiler) {
- p->creator.reset(new QmlObjectCreator(contextData, d->cc));
+ p->creator.reset(new QmlObjectCreator(contextData, d->cc, d->creationContext));
p->subComponentToCreate = d->start;
} else
p->vme.init(contextData, d->cc, d->start, d->creationContext);
@@ -1085,9 +1086,9 @@ public:
QScopedPointer<QQmlComponentIncubator> incubator;
QV8Engine *v8;
QPointer<QObject> parent;
- QV4::SafeValue valuemap;
- QV4::SafeValue qmlGlobal;
- QV4::SafeValue m_statusChanged;
+ QV4::Value valuemap;
+ QV4::Value qmlGlobal;
+ QV4::Value m_statusChanged;
void statusChanged(QQmlIncubator::Status);
void setInitialState(QObject *);
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index d3ef02a9ad..1ca9c6ac12 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -46,7 +46,7 @@
#include <private/qqmlcontext_p.h>
#include <private/qv4engine_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4objectproto_p.h>
#include <private/qv4mm_p.h>
#include <private/qv4function_p.h>
diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h
index bd56d4bcec..0ecec93652 100644
--- a/src/qml/qml/qqmlcontextwrapper_p.h
+++ b/src/qml/qml/qqmlcontextwrapper_p.h
@@ -56,7 +56,7 @@
#include <QtCore/qglobal.h>
#include <private/qtqmlglobal_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4object_p.h>
#include <private/qqmlcontext_p.h>
#include <private/qv4functionobject_p.h>
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index c4b19394f0..93060e97fb 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -56,7 +56,8 @@
#include <private/qtqmlglobal_p.h>
#include <private/qobject_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
+#include <private/qv4persistent_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 965741241a..0529e41007 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -62,6 +62,7 @@
#include "qqmllist_p.h"
#include "qqmltypenamecache_p.h"
#include "qqmlnotifier_p.h"
+#include <private/qqmldebugserver_p.h>
#include <private/qqmlprofilerservice_p.h>
#include <private/qv4debugservice_p.h>
#include <private/qdebugmessageservice_p.h>
@@ -813,11 +814,12 @@ void QQmlEnginePrivate::init()
if (QCoreApplication::instance()->thread() == q->thread() &&
QQmlEngineDebugService::isDebuggingEnabled()) {
isDebugging = true;
- QQmlEngineDebugService::instance()->addEngine(q);
- QV4DebugService::instance()->addEngine(q);
- QV4ProfilerService::initialize();
- QQmlProfilerService::initialize();
+ QQmlEngineDebugService::instance();
+ QV4DebugService::instance();
+ QV4ProfilerService::instance();
+ QQmlProfilerService::instance();
QDebugMessageService::instance();
+ QQmlDebugServer::instance()->addEngine(q);
}
}
@@ -895,10 +897,8 @@ QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent)
QQmlEngine::~QQmlEngine()
{
Q_D(QQmlEngine);
- if (d->isDebugging) {
- QQmlEngineDebugService::instance()->remEngine(this);
- QV4DebugService::instance()->removeEngine(this);
- }
+ if (d->isDebugging)
+ QQmlDebugServer::instance()->removeEngine(this);
// Emit onDestruction signals for the root context before
// we destroy the contexts, engine, Singleton Types etc. that
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 0848af07e3..97f82a2e8d 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -180,17 +180,22 @@ struct RegisteredPlugin {
QPluginLoader* loader;
};
-typedef QMap<QString, RegisteredPlugin> StringRegisteredPluginMap;
+struct StringRegisteredPluginMap : public QMap<QString, RegisteredPlugin> {
+ QMutex mutex;
+};
+
Q_GLOBAL_STATIC(StringRegisteredPluginMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri and the PluginLoaders
void qmlClearEnginePlugins()
{
- foreach (RegisteredPlugin plugin, qmlEnginePluginsWithRegisteredTypes()->values()) {
+ StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
+ QMutexLocker lock(&plugins->mutex);
+ foreach (RegisteredPlugin plugin, plugins->values()) {
QPluginLoader* loader = plugin.loader;
if (!loader->unload())
qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString()));
delete loader;
}
- qmlEnginePluginsWithRegisteredTypes()->clear();
+ plugins->clear();
}
typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
@@ -1909,10 +1914,12 @@ bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &ur
const QString absoluteFilePath = fileInfo.absoluteFilePath();
bool engineInitialized = initializedPlugins.contains(absoluteFilePath);
- bool typesRegistered = qmlEnginePluginsWithRegisteredTypes()->contains(absoluteFilePath);
+ StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
+ QMutexLocker lock(&plugins->mutex);
+ bool typesRegistered = plugins->contains(absoluteFilePath);
if (typesRegistered) {
- Q_ASSERT_X(qmlEnginePluginsWithRegisteredTypes()->value(absoluteFilePath).uri == uri,
+ Q_ASSERT_X(plugins->value(absoluteFilePath).uri == uri,
"QQmlImportDatabase::importPlugin",
"Internal error: Plugin imported previously with different uri");
}
@@ -1942,7 +1949,7 @@ bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &ur
return false;
}
} else {
- loader = qmlEnginePluginsWithRegisteredTypes()->value(absoluteFilePath).loader;
+ loader = plugins->value(absoluteFilePath).loader;
}
QObject *instance = loader->instance();
@@ -1951,7 +1958,7 @@ bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &ur
RegisteredPlugin plugin;
plugin.uri = uri;
plugin.loader = loader;
- qmlEnginePluginsWithRegisteredTypes()->insert(absoluteFilePath, plugin);
+ plugins->insert(absoluteFilePath, plugin);
// Continue with shared code path for dynamic and static plugins:
if (!importPlugin(instance, fileInfo.absolutePath(), uri, typeNamespace, false, errors))
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 10fd05ab58..1cc75387a3 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -91,14 +91,17 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
p->changeStatus(QQmlIncubator::Loading);
if (!watcher.hasRecursed()) {
- QQmlVME::Interrupt i;
+ QQmlInstantiationInterrupt i;
p->incubate(i);
}
} else {
incubatorList.insert(p.data());
incubatorCount++;
- p->vmeGuard.guard(&p->vme);
+ if (useNewCompiler)
+ p->vmeGuard.guard(p->creator.data());
+ else
+ p->vmeGuard.guard(&p->vme);
p->changeStatus(QQmlIncubator::Loading);
if (incubationController)
@@ -254,7 +257,7 @@ void QQmlIncubationController::incubatingObjectCountChanged(int incubatingObject
Q_UNUSED(incubatingObjectCount);
}
-void QQmlIncubatorPrivate::forceCompletion(QQmlVME::Interrupt &i)
+void QQmlIncubatorPrivate::forceCompletion(QQmlInstantiationInterrupt &i)
{
while (QQmlIncubator::Loading == status) {
while (QQmlIncubator::Loading == status && !waitingFor.isEmpty())
@@ -264,7 +267,7 @@ void QQmlIncubatorPrivate::forceCompletion(QQmlVME::Interrupt &i)
}
}
-void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
+void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
{
if (!compiledData)
return;
@@ -345,7 +348,7 @@ void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
QQmlContextData *ctxt = 0;
if (enginePriv->useNewCompiler)
- ctxt = creator->finalize();
+ ctxt = creator->finalize(i);
else
ctxt = vme.complete(i);
if (ctxt) {
@@ -379,7 +382,10 @@ finishIncubate:
}
}
} else {
- vmeGuard.guard(&vme);
+ if (enginePriv->useNewCompiler)
+ vmeGuard.guard(creator.data());
+ else
+ vmeGuard.guard(&vme);
}
}
@@ -391,7 +397,7 @@ void QQmlIncubationController::incubateFor(int msecs)
if (!d || !d->incubatorCount)
return;
- QQmlVME::Interrupt i(msecs * 1000000);
+ QQmlInstantiationInterrupt i(msecs * 1000000);
i.reset();
do {
static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
@@ -410,7 +416,7 @@ void QQmlIncubationController::incubateWhile(volatile bool *flag, int msecs)
if (!d || !d->incubatorCount)
return;
- QQmlVME::Interrupt i(flag, msecs * 1000000);
+ QQmlInstantiationInterrupt i(flag, msecs * 1000000);
i.reset();
do {
static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
@@ -609,7 +615,7 @@ returns, the incubator will not be in the Loading state.
*/
void QQmlIncubator::forceCompletion()
{
- QQmlVME::Interrupt i;
+ QQmlInstantiationInterrupt i;
d->forceCompletion(i);
}
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index a8b549bd28..b7009bfe43 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -104,8 +104,8 @@ public:
void clear();
- void forceCompletion(QQmlVME::Interrupt &i);
- void incubate(QQmlVME::Interrupt &i);
+ void forceCompletion(QQmlInstantiationInterrupt &i);
+ void incubate(QQmlInstantiationInterrupt &i);
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 499ade1ca5..b7673bdb37 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -43,7 +43,7 @@
#include <private/qqmlexpression_p.h>
#include <private/qqmlcontextwrapper_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4script_p.h>
#include <private/qv4errorobject_p.h>
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 2c35e12227..0d60fee5d0 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -57,6 +57,9 @@ QmlListWrapper::QmlListWrapper(QV8Engine *engine)
v8(engine)
{
setVTable(staticVTable());
+ QV4::Scope scope(QV8Engine::getV4(engine));
+ QV4::ScopedObject protectThis(scope, this);
+ Q_UNUSED(protectThis);
setArrayType(ArrayData::Custom);
}
diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h
index a8105d256e..a7ce8b30bf 100644
--- a/src/qml/qml/qqmllistwrapper_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -58,7 +58,7 @@
#include <QtQml/qqmllist.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 24a8327722..e2063a979f 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -55,6 +55,7 @@
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlscriptstring_p.h>
#include <private/qqmlpropertyvalueinterceptor_p.h>
+#include <private/qqmlvaluetypeproxybinding_p.h>
QT_USE_NAMESPACE
@@ -79,19 +80,24 @@ static void removeBindingOnProperty(QObject *o, int index)
if (binding) binding->destroy();
}
-QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData)
+QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, QQmlContextData *rootContext,
+ QFiniteStack<QQmlAbstractBinding *> *inheritedBindingStack, QFiniteStack<QQmlParserStatus *> *inheritedParserStatusStack)
: componentAttached(0)
, url(compiledData->url)
, engine(parentContext->engine)
, qmlUnit(compiledData->qmlUnit)
, jsUnit(compiledData->compilationUnit)
, parentContext(parentContext)
+ , creationContext(creationContext)
, context(0)
, resolvedTypes(compiledData->resolvedTypes)
, propertyCaches(compiledData->propertyCaches)
, vmeMetaObjectData(compiledData->datas)
+ , allCreatedBindings(0)
+ , allParserStatusCallbacks(0)
+ , ownBindingAndParserStatusStacks(false)
, compiledData(compiledData)
- , rootContext(0)
+ , rootContext(rootContext)
, _qobject(0)
, _scopeObject(0)
, _valueTypeProperty(0)
@@ -103,12 +109,51 @@ QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledD
{
if (!compiledData->isInitialized())
compiledData->initialize(engine);
+
+ componentAttachedImpl = 0;
+ componentAttached = &componentAttachedImpl;
+
+ if (inheritedBindingStack) {
+ Q_ASSERT(rootContext);
+ Q_ASSERT(inheritedParserStatusStack);
+ allCreatedBindings = inheritedBindingStack;
+ allParserStatusCallbacks = inheritedParserStatusStack;
+ ownBindingAndParserStatusStacks = false;
+ } else {
+ ownBindingAndParserStatusStacks = true;
+ allCreatedBindings = new QFiniteStack<QQmlAbstractBinding*>;
+ allCreatedBindings->allocate(compiledData->totalBindingsCount);
+ allParserStatusCallbacks = new QFiniteStack<QQmlParserStatus*>;
+ allParserStatusCallbacks->allocate(compiledData->totalParserStatusCount);
+ }
+}
+
+QmlObjectCreator::~QmlObjectCreator()
+{
+ if (ownBindingAndParserStatusStacks) {
+ for (int i = 0; i < allCreatedBindings->count(); ++i) {
+ QQmlAbstractBinding *b = allCreatedBindings->at(i);
+ if (b)
+ b->m_mePtr = 0;
+ }
+ for (int i = 0; i < allParserStatusCallbacks->count(); ++i) {
+ QQmlParserStatus *ps = allParserStatusCallbacks->at(i);
+ if (ps)
+ ps->d = 0;
+ }
+
+ delete allCreatedBindings;
+ delete allParserStatusCallbacks;
+ }
}
QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
{
int objectToCreate;
+ Q_ASSERT(!ownBindingAndParserStatusStacks || allCreatedBindings->isEmpty());
+ Q_ASSERT(!ownBindingAndParserStatusStacks || allParserStatusCallbacks->isEmpty());
+
if (subComponentIndex == -1) {
objectIndexToId = compiledData->objectIndexToIdForRoot;
objectToCreate = qmlUnit->indexOfRootObject;
@@ -126,8 +171,10 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
context->imports->addref();
context->setParent(parentContext);
- if (!rootContext)
+ if (!rootContext) {
rootContext = context;
+ rootContext->isRootObjectInCreation = true;
+ }
QVector<QQmlContextData::ObjectIdMapping> mapping(objectIndexToId.count());
for (QHash<int, int>::ConstIterator it = objectIndexToId.constBegin(), end = objectIndexToId.constEnd();
@@ -145,19 +192,15 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Scope scope(v4);
QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count()));
+ context->importedScripts = scripts;
for (int i = 0; i < compiledData->scripts.count(); ++i) {
QQmlScriptData *s = compiledData->scripts.at(i);
scripts->putIndexed(i, s->scriptValueForContext(context));
}
- context->importedScripts = scripts;
- } else if (parentContext) {
- context->importedScripts = parentContext->importedScripts;
+ } else if (creationContext) {
+ context->importedScripts = creationContext->importedScripts;
}
- QVector<QQmlParserStatus*> parserStatusCallbacks;
- parserStatusCallbacks.resize(qmlUnit->nObjects);
- qSwap(_parserStatusCallbacks, parserStatusCallbacks);
-
QObject *instance = createInstance(objectToCreate, parent);
if (instance) {
QQmlData *ddata = QQmlData::get(instance);
@@ -168,9 +211,6 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
context->contextObject = instance;
}
- qSwap(_parserStatusCallbacks, parserStatusCallbacks);
- allParserStatusCallbacks.prepend(parserStatusCallbacks);
-
return instance;
}
@@ -185,9 +225,11 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
QV4::Scope scope(v4);
// ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
- if (property->isEnum()) {
+ if (property->isEnum() && !(binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)) {
QVariant value = binding->valueAsString(&qmlUnit->header);
- QQmlPropertyPrivate::write(_qobject, *property, value, context);
+ bool ok = QQmlPropertyPrivate::write(_qobject, *property, value, context);
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
return;
}
@@ -235,109 +277,79 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
}
break;
case QVariant::String: {
- if (binding->type == QV4::CompiledData::Binding::Type_String) {
- QString value = binding->valueAsString(&qmlUnit->header);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: string expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+ QString value = binding->valueAsString(&qmlUnit->header);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::StringList: {
- if (binding->type == QV4::CompiledData::Binding::Type_String) {
- QStringList value(binding->valueAsString(&qmlUnit->header));
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: string or string list expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+ QStringList value(binding->valueAsString(&qmlUnit->header));
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::ByteArray: {
- if (binding->type == QV4::CompiledData::Binding::Type_String) {
- QByteArray value(binding->valueAsString(&qmlUnit->header).toUtf8());
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: byte array expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+ QByteArray value(binding->valueAsString(&qmlUnit->header).toUtf8());
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::Url: {
- if (binding->type == QV4::CompiledData::Binding::Type_String) {
- QString string = binding->valueAsString(&qmlUnit->header);
- // Encoded dir-separators defeat QUrl processing - decode them first
- string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- QUrl value = string.isEmpty() ? QUrl() : this->url.resolved(QUrl(string));
- // Apply URL interceptor
- if (engine->urlInterceptor())
- value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: url expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+ QString string = binding->valueAsString(&qmlUnit->header);
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
+ QUrl value = string.isEmpty() ? QUrl() : this->url.resolved(QUrl(string));
+ // Apply URL interceptor
+ if (engine->urlInterceptor())
+ value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = binding->valueAsNumber();
- if (double(uint(d)) == d) {
- uint value = uint(d);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- break;
- }
- }
- recordError(binding->location, tr("Invalid property assignment: unsigned int expected"));
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ double d = binding->valueAsNumber();
+ uint value = uint(d);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ break;
}
break;
case QVariant::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = binding->valueAsNumber();
- if (double(int(d)) == d) {
- int value = int(d);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- break;
- }
- }
- recordError(binding->location, tr("Invalid property assignment: int expected"));
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ double d = binding->valueAsNumber();
+ int value = int(d);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ break;
}
break;
case QMetaType::Float: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- float value = float(binding->valueAsNumber());
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: number expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ float value = float(binding->valueAsNumber());
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::Double: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double value = binding->valueAsNumber();
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: number expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ double value = binding->valueAsNumber();
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::Color: {
bool ok = false;
uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(&qmlUnit->header), &ok);
-
- if (ok) {
- struct { void *data[4]; } buffer;
- if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) {
- argv[0] = reinterpret_cast<void *>(&buffer);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- }
- } else {
- recordError(binding->location, tr("Invalid property assignment: color expected"));
+ Q_ASSERT(ok);
+ struct { void *data[4]; } buffer;
+ if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) {
+ argv[0] = reinterpret_cast<void *>(&buffer);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
}
break;
@@ -345,111 +357,87 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
case QVariant::Date: {
bool ok = false;
QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(&qmlUnit->header), &ok);
- if (ok) {
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: date expected"));
- }
+ Q_ASSERT(ok);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::Time: {
bool ok = false;
QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(&qmlUnit->header), &ok);
- if (ok) {
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: time expected"));
- }
+ Q_ASSERT(ok);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::DateTime: {
bool ok = false;
QDateTime value = QQmlStringConverters::dateTimeFromString(binding->valueAsString(&qmlUnit->header), &ok);
- if (ok) {
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: datetime expected"));
+ // ### VME compatibility :(
+ {
+ const qint64 date = value.date().toJulianDay();
+ const int msecsSinceStartOfDay = value.time().msecsSinceStartOfDay();
+ value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay));
}
+ Q_ASSERT(ok);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
#endif // QT_NO_DATESTRING
case QVariant::Point: {
bool ok = false;
QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok).toPoint();
- if (ok) {
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: point expected"));
- }
+ Q_ASSERT(ok);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::PointF: {
bool ok = false;
QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok);
- if (ok) {
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: point expected"));
- }
+ Q_ASSERT(ok);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::Size: {
bool ok = false;
QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok).toSize();
- if (ok) {
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: size expected"));
- }
+ Q_ASSERT(ok);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::SizeF: {
bool ok = false;
QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok);
- if (ok) {
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: size expected"));
- }
+ Q_ASSERT(ok);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::Rect: {
bool ok = false;
QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok).toRect();
- if (ok) {
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: point expected"));
- }
+ Q_ASSERT(ok);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::RectF: {
bool ok = false;
QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok);
- if (ok) {
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: point expected"));
- }
+ Q_ASSERT(ok);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::Bool: {
- if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
- bool value = binding->valueAsBoolean();
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: boolean expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
+ bool value = binding->valueAsBoolean();
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::Vector3D: {
@@ -458,12 +446,11 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
float yp;
float zy;
} vec;
- if (QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
- argv[0] = reinterpret_cast<void *>(&vec);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: 3D vector expected"));
- }
+ bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec));
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
+ argv[0] = reinterpret_cast<void *>(&vec);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::Vector4D: {
@@ -473,74 +460,55 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
float zy;
float wp;
} vec;
- if (QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
- argv[0] = reinterpret_cast<void *>(&vec);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: 4D vector expected"));
- }
+ bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec));
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
+ argv[0] = reinterpret_cast<void *>(&vec);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
case QVariant::RegExp:
- recordError(binding->location, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
+ Q_ASSERT(!"not possible");
break;
default: {
// generate single literal value assignment to a list property if required
if (property->propType == qMetaTypeId<QList<qreal> >()) {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- QList<qreal> value;
- value.append(binding->valueAsNumber());
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: real or array of reals expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ QList<qreal> value;
+ value.append(binding->valueAsNumber());
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
break;
} else if (property->propType == qMetaTypeId<QList<int> >()) {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double n = binding->valueAsNumber();
- if (double(int(n)) == n) {
- QList<int> value;
- value.append(int(n));
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- break;
- } else {
- recordError(binding->location, tr("Invalid property assignment: int or array of ints expected"));
- }
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ double n = binding->valueAsNumber();
+ QList<int> value;
+ value.append(int(n));
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
break;
} else if (property->propType == qMetaTypeId<QList<bool> >()) {
- if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
- QList<bool> value;
- value.append(binding->valueAsBoolean());
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: bool or array of bools expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
+ QList<bool> value;
+ value.append(binding->valueAsBoolean());
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
break;
} else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
- if (binding->type == QV4::CompiledData::Binding::Type_String) {
- QString urlString = binding->valueAsString(&qmlUnit->header);
- QUrl u = urlString.isEmpty() ? QUrl() : this->url.resolved(QUrl(urlString));
- QList<QUrl> value;
- value.append(u);
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: url or array of urls expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+ QString urlString = binding->valueAsString(&qmlUnit->header);
+ QUrl u = urlString.isEmpty() ? QUrl() : this->url.resolved(QUrl(urlString));
+ QList<QUrl> value;
+ value.append(u);
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
break;
} else if (property->propType == qMetaTypeId<QList<QString> >()) {
- if (binding->type == QV4::CompiledData::Binding::Type_String) {
- QList<QString> value;
- value.append(binding->valueAsString(&qmlUnit->header));
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: string or array of strings expected"));
- }
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+ QList<QString> value;
+ value.append(binding->valueAsString(&qmlUnit->header));
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
break;
} else if (property->propType == qMetaTypeId<QJSValue>()) {
QJSValue value;
@@ -563,25 +531,33 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
// otherwise, try a custom type assignment
QString stringValue = binding->valueAsString(&qmlUnit->header);
QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType);
- if (converter) {
- QVariant value = (*converter)(stringValue);
+ Q_ASSERT(converter);
+ QVariant value = (*converter)(stringValue);
- QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex);
- if (value.isNull() || ((int)metaProperty.type() != property->propType && metaProperty.userType() != property->propType)) {
- recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
- break;
- }
-
- argv[0] = value.data();
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType))));
+ QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex);
+ if (value.isNull() || ((int)metaProperty.type() != property->propType && metaProperty.userType() != property->propType)) {
+ recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
+ break;
}
+
+ argv[0] = value.data();
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
}
}
+static QQmlType *qmlTypeForObject(QObject *object)
+{
+ QQmlType *type = 0;
+ const QMetaObject *mo = object->metaObject();
+ while (mo && !type) {
+ type = QQmlMetaType::qmlType(mo);
+ mo = mo->superClass();
+ }
+ return type;
+}
+
void QmlObjectCreator::setupBindings()
{
QQmlListProperty<void> savedList;
@@ -593,7 +569,7 @@ void QmlObjectCreator::setupBindings()
QString id = stringAt(_compiledObject->idIndex);
if (!id.isEmpty()) {
QQmlPropertyData *idProperty = _propertyCache->property(QStringLiteral("id"), _qobject, context);
- if (idProperty) {
+ if (idProperty && idProperty->isWritable()) {
QV4::CompiledData::Binding idBinding;
idBinding.propertyNameIndex = 0; // Not used
idBinding.flags = 0;
@@ -604,6 +580,36 @@ void QmlObjectCreator::setupBindings()
}
}
+ // ### this is best done through type-compile-time binding skip lists.
+ if (_valueTypeProperty) {
+ QQmlAbstractBinding *binding =
+ QQmlPropertyPrivate::binding(_bindingTarget, _valueTypeProperty->coreIndex, -1);
+
+ if (binding && binding->bindingType() != QQmlAbstractBinding::ValueTypeProxy) {
+ QQmlPropertyPrivate::setBinding(_bindingTarget, _valueTypeProperty->coreIndex, -1, 0);
+ binding->destroy();
+ } else if (binding) {
+ QQmlValueTypeProxyBinding *proxy =
+ static_cast<QQmlValueTypeProxyBinding *>(binding);
+
+ if (qmlTypeForObject(_bindingTarget)) {
+ quint32 bindingSkipList = 0;
+
+ const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
+ for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ continue;
+ property = binding->propertyNameIndex != 0 ? _propertyCache->property(stringAt(binding->propertyNameIndex), _qobject, context) : defaultProperty;
+ if (property)
+ bindingSkipList |= (1 << property->coreIndex);
+ }
+ property = 0;
+
+ proxy->removeBindings(bindingSkipList);
+ }
+ }
+ }
+
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
@@ -611,10 +617,17 @@ void QmlObjectCreator::setupBindings()
if (name.isEmpty())
property = 0;
- if (!property || (i > 0 && (binding - 1)->propertyNameIndex != binding->propertyNameIndex)) {
- if (!name.isEmpty())
- property = _propertyCache->property(name, _qobject, context);
- else
+ if (!property
+ || (i > 0 && ((binding - 1)->propertyNameIndex != binding->propertyNameIndex
+ || (binding - 1)->flags != binding->flags))
+ ) {
+ if (!name.isEmpty()) {
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ property = PropertyResolver(_propertyCache).signal(name, /*notInRevision*/0, _qobject, context);
+ else
+ property = _propertyCache->property(name, _qobject, context);
+ } else
property = defaultProperty;
if (property && property->isQList()) {
@@ -625,14 +638,14 @@ void QmlObjectCreator::setupBindings()
}
- if (!setPropertyValue(property, i, binding))
+ if (!setPropertyBinding(property, binding))
return;
}
qSwap(_currentList, savedList);
}
-bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingIndex, const QV4::CompiledData::Binding *binding)
+bool QmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
{
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
@@ -667,6 +680,7 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
QObject *createdSubObject = 0;
if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ Q_ASSERT(!_valueTypeProperty);
createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget);
if (!createdSubObject)
return false;
@@ -726,7 +740,8 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
}
if (_ddata->hasBindingBit(property->coreIndex) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment))
+ && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ && !_valueTypeProperty)
removeBindingOnProperty(_bindingTarget, property->coreIndex);
if (binding->type == QV4::CompiledData::Binding::Type_Script) {
@@ -756,10 +771,20 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine);
qmlBinding->setTarget(_bindingTarget, targetCorePropertyData, context);
- qmlBinding->addToObject();
- _createdBindings[bindingIndex] = qmlBinding;
- qmlBinding->m_mePtr = &_createdBindings[bindingIndex];
+ if (targetCorePropertyData.isAlias()) {
+ QQmlAbstractBinding *old =
+ QQmlPropertyPrivate::setBindingNoEnable(_bindingTarget,
+ targetCorePropertyData.coreIndex,
+ targetCorePropertyData.getValueTypeCoreIndex(),
+ qmlBinding);
+ if (old) { old->destroy(); }
+ } else {
+ qmlBinding->addToObject();
+ }
+
+ allCreatedBindings->push(qmlBinding);
+ qmlBinding->m_mePtr = &allCreatedBindings->top();
}
return true;
}
@@ -767,12 +792,7 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
if (binding->type == QV4::CompiledData::Binding::Type_Object) {
if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
// ### determine value source and interceptor casts ahead of time.
- QQmlType *type = 0;
- const QMetaObject *mo = createdSubObject->metaObject();
- while (mo && !type) {
- type = QQmlMetaType::qmlType(mo);
- mo = mo->superClass();
- }
+ QQmlType *type = qmlTypeForObject(createdSubObject);
Q_ASSERT(type);
QQmlPropertyData targetCorePropertyData = *property;
@@ -802,6 +822,30 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
return false;
}
+ // Assigning object to signal property?
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ if (!property->isFunction()) {
+ recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(property->name(_qobject)));
+ return false;
+ }
+ QMetaMethod method = QQmlMetaType::defaultMethod(createdSubObject);
+ if (!method.isValid()) {
+ recordError(binding->valueLocation, tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(createdSubObject->metaObject()->className())));
+ return false;
+ }
+
+ QMetaMethod signalMethod = _qobject->metaObject()->method(property->coreIndex);
+ if (!QMetaObject::checkConnectArgs(signalMethod, method)) {
+ recordError(binding->valueLocation, tr("Cannot connect mismatched signal/slot %1 %vs. %2")
+ .arg(QString::fromLatin1(method.methodSignature().constData()))
+ .arg(QString::fromLatin1(signalMethod.methodSignature().constData())));
+ return false;
+ }
+
+ QQmlPropertyPrivate::connect(_qobject, property->coreIndex, createdSubObject, method.methodIndex());
+ return true;
+ }
+
QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
int propertyWriteStatus = -1;
@@ -842,33 +886,9 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
if (_currentList.append)
_currentList.append(&_currentList, itemToAdd);
} else {
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
-
- // We want to raw metaObject here as the raw metaobject is the
- // actual property type before we applied any extensions that might
- // effect the properties on the type, but don't effect assignability
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType);
-
- // Will be true if the assgned type inherits propertyMetaObject
- bool isAssignable = false;
- // Determine isAssignable value
- if (propertyMetaObject) {
- QQmlPropertyCache *c = propertyCaches.value(binding->value.objectIndex);
- if (!c)
- c = enginePrivate->cache(createdSubObject);
- while (c && !isAssignable) {
- isAssignable |= c == propertyMetaObject;
- c = c->parent();
- }
- }
-
- if (isAssignable) {
- argv[0] = &createdSubObject;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Cannot assign object to property"));
- return false;
- }
+ // pointer compatibility was tested in QQmlPropertyValidator at type compile time
+ argv[0] = &createdSubObject;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
return true;
}
@@ -918,6 +938,7 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
bool isComponent = false;
QObject *instance = 0;
QQmlCustomParser *customParser = 0;
+ QQmlParserStatus *parserStatus = 0;
if (compiledData->isComponent(index)) {
isComponent = true;
@@ -938,14 +959,16 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
}
const int parserStatusCast = type->parserStatusCast();
- if (parserStatusCast != -1) {
- QQmlParserStatus *parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
- parserStatus->classBegin();
- _parserStatusCallbacks[index] = parserStatus;
- parserStatus->d = &_parserStatusCallbacks[index];
- }
+ if (parserStatusCast != -1)
+ parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
customParser = type->customParser();
+
+ if (rootContext->isRootObjectInCreation) {
+ QQmlData *ddata = QQmlData::get(instance, /*create*/true);
+ ddata->rootObjectInCreation = true;
+ rootContext->isRootObjectInCreation = false;
+ }
} else {
Q_ASSERT(typeRef->component);
if (typeRef->component->qmlUnit->isSingleton())
@@ -953,16 +976,13 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
return 0;
}
- QmlObjectCreator subCreator(context, typeRef->component);
+ QmlObjectCreator subCreator(context, typeRef->component, creationContext, rootContext, allCreatedBindings, allParserStatusCallbacks);
+ subCreator.componentAttached = componentAttached;
instance = subCreator.create();
if (!instance) {
errors += subCreator.errors;
return 0;
}
- if (subCreator.componentAttached)
- subCreator.componentAttached->add(&componentAttached);
- allCreatedBindings << subCreator.allCreatedBindings;
- allParserStatusCallbacks << subCreator.allParserStatusCallbacks;
}
// ### use no-event variant
if (parent)
@@ -970,6 +990,7 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
}
QQmlData *ddata = QQmlData::get(instance, /*create*/true);
+ ddata->setImplicitDestructible();
if (static_cast<quint32>(index) == qmlUnit->indexOfRootObject) {
if (ddata->context) {
Q_ASSERT(ddata->context != context);
@@ -986,6 +1007,12 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
ddata->outerContext = context;
+ if (parserStatus) {
+ parserStatus->classBegin();
+ allParserStatusCallbacks->push(parserStatus);
+ parserStatus->d = &allParserStatusCallbacks->top();
+ }
+
QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(index);
if (idEntry != objectIndexToId.constEnd())
context->setIdProperty(idEntry.value(), instance);
@@ -1007,8 +1034,10 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Scope valueScope(v4);
- QV4::ScopedObject jsScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject));
- QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, jsScopeObject));
+ QV4::ScopedValue scopeObjectProtector(valueScope, ddata ? ddata->jsWrapper.value() : 0);
+ Q_UNUSED(scopeObjectProtector);
+ QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject));
+ QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, qmlScope));
QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context();
qSwap(_qmlContext, qmlContext);
@@ -1021,51 +1050,41 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
return result ? instance : 0;
}
-QQmlContextData *QmlObjectCreator::finalize()
+QQmlContextData *QmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
{
{
QQmlTrace trace("VME Binding Enable");
trace.event("begin binding eval");
- Q_ASSERT(allCreatedBindings.isEmpty() || allCreatedBindings.isDetached());
+ while (!allCreatedBindings->isEmpty()) {
+ if (interrupt.shouldInterrupt())
+ return 0;
- for (QLinkedList<QVector<QQmlAbstractBinding*> >::Iterator it = allCreatedBindings.begin(), end = allCreatedBindings.end();
- it != end; ++it) {
- const QVector<QQmlAbstractBinding *> &bindings = *it;
- for (int i = 0; i < bindings.count(); ++i) {
- QQmlAbstractBinding *b = bindings.at(i);
- if (!b)
- continue;
- b->m_mePtr = 0;
- QQmlData *data = QQmlData::get(b->object());
- Q_ASSERT(data);
- data->clearPendingBindingBit(b->propertyIndex());
- b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::DontRemoveBinding);
- }
+ QQmlAbstractBinding *b = allCreatedBindings->pop();
+ if (!b)
+ continue;
+ b->m_mePtr = 0;
+ QQmlData *data = QQmlData::get(b->object());
+ Q_ASSERT(data);
+ data->clearPendingBindingBit(b->propertyIndex());
+ b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::DontRemoveBinding);
}
}
if (true /* ### componentCompleteEnabled()*/) { // the qml designer does the component complete later
QQmlTrace trace("VME Component Complete");
- for (QLinkedList<QVector<QQmlParserStatus*> >::ConstIterator it = allParserStatusCallbacks.constBegin(), end = allParserStatusCallbacks.constEnd();
- it != end; ++it) {
- const QVector<QQmlParserStatus *> &parserStatusCallbacks = *it;
- for (int i = parserStatusCallbacks.count() - 1; i >= 0; --i) {
- QQmlParserStatus *status = parserStatusCallbacks.at(i);
-
- if (status && status->d) {
- status->d = 0;
- status->componentComplete();
- }
+ while (!allParserStatusCallbacks->isEmpty()) {
+ QQmlParserStatus *status = allParserStatusCallbacks->pop();
- #if 0 // ###
- if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return 0;
- #endif
+ if (status && status->d) {
+ status->d = 0;
+ status->componentComplete();
}
+
+ if (interrupt.shouldInterrupt())
+ return 0;
}
- allParserStatusCallbacks.clear();
}
{
@@ -1077,18 +1096,14 @@ QQmlContextData *QmlObjectCreator::finalize()
void *args[] = { 0 };
QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
}
-#if 0 // ###
- if (watcher.hasRecursed())
- return 0;
-#endif
}
finalizeCallbacks.clear();
}
{
QQmlTrace trace("VME Component.onCompleted Callbacks");
- while (componentAttached) {
- QQmlComponentAttached *a = componentAttached;
+ while (componentAttachedImpl) {
+ QQmlComponentAttached *a = componentAttachedImpl;
a->rem();
QQmlData *d = QQmlData::get(a->parent());
Q_ASSERT(d);
@@ -1097,10 +1112,8 @@ QQmlContextData *QmlObjectCreator::finalize()
// ### designer if (componentCompleteEnabled())
emit a->completed();
-#if 0 // ###
- if (watcher.hasRecursed() || interrupt.shouldInterrupt())
+ if (interrupt.shouldInterrupt())
return 0;
-#endif
}
}
@@ -1127,11 +1140,11 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi
vmeMetaObject = new QQmlVMEMetaObject(_qobject, _propertyCache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()));
if (_ddata->propertyCache)
_ddata->propertyCache->release();
- _ddata->propertyCache = _propertyCache;
- _ddata->propertyCache->addref();
} else {
vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
}
+ _ddata->propertyCache = _propertyCache;
+ _ddata->propertyCache->addref();
_ddata->lineNumber = _compiledObject->location.line;
_ddata->columnNumber = _compiledObject->location.column;
@@ -1139,14 +1152,10 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi
qSwap(_vmeMetaObject, vmeMetaObject);
QVector<QQmlAbstractBinding*> createdBindings(_compiledObject->nBindings, 0);
- qSwap(_createdBindings, createdBindings);
- setupBindings();
setupFunctions();
+ setupBindings();
- allCreatedBindings.append(_createdBindings);
-
- qSwap(_createdBindings, createdBindings);
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
qSwap(_ddata, declarativeData);
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 951c3a2eed..68f2eaeab3 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -46,34 +46,39 @@
#include <private/qv4compileddata_p.h>
#include <private/qqmlcompiler_p.h>
#include <private/qqmltypecompiler_p.h>
-#include <QLinkedList>
+#include <private/qfinitestack_p.h>
QT_BEGIN_NAMESPACE
class QQmlAbstractBinding;
struct QQmlTypeCompiler;
+class QQmlInstantiationInterrupt;
class QmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QmlObjectCreator)
public:
- QmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData);
+ QmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData, QQmlContextData *creationContext, QQmlContextData *rootContext = 0,
+ QFiniteStack<QQmlAbstractBinding*> *inheritedBindingStack = 0, QFiniteStack<QQmlParserStatus*> *inheritedParserStatusStack = 0);
+ ~QmlObjectCreator();
QObject *create(int subComponentIndex = -1, QObject *parent = 0);
- QQmlContextData *finalize();
+ QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt);
- QQmlComponentAttached *componentAttached;
+ QQmlComponentAttached **componentAttached;
QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
QList<QQmlError> errors;
+ QQmlContextData *parentContextData() const { return parentContext; }
+
private:
QObject *createInstance(int index, QObject *parent = 0);
bool populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty);
void setupBindings();
- bool setPropertyValue(QQmlPropertyData *property, int index, const QV4::CompiledData::Binding *binding);
+ bool setPropertyBinding(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setupFunctions();
@@ -85,15 +90,18 @@ private:
const QV4::CompiledData::QmlUnit *qmlUnit;
const QV4::CompiledData::CompilationUnit *jsUnit;
QQmlContextData *parentContext;
+ QQmlContextData *creationContext;
QQmlContextData *context;
const QHash<int, QQmlCompiledData::TypeReference*> resolvedTypes;
const QVector<QQmlPropertyCache *> propertyCaches;
const QVector<QByteArray> vmeMetaObjectData;
QHash<int, int> objectIndexToId;
- QLinkedList<QVector<QQmlAbstractBinding*> > allCreatedBindings;
- QLinkedList<QVector<QQmlParserStatus*> > allParserStatusCallbacks;
+ QFiniteStack<QQmlAbstractBinding*> *allCreatedBindings;
+ QFiniteStack<QQmlParserStatus*> *allParserStatusCallbacks;
+ bool ownBindingAndParserStatusStacks;
QQmlCompiledData *compiledData;
QQmlContextData *rootContext;
+ QQmlComponentAttached *componentAttachedImpl;
QObject *_qobject;
QObject *_scopeObject;
@@ -104,10 +112,8 @@ private:
QQmlData *_ddata;
QQmlRefPointer<QQmlPropertyCache> _propertyCache;
QQmlVMEMetaObject *_vmeMetaObject;
- QVector<QQmlAbstractBinding*> _createdBindings;
QQmlListProperty<void> _currentList;
QV4::ExecutionContext *_qmlContext;
- QVector<QQmlParserStatus*> _parserStatusCallbacks;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index d026b95201..a0af0e94ef 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -50,7 +50,7 @@
#include <private/qqmlaccessors_p.h>
#include <private/qmetaobjectbuilder_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <QtCore/qdebug.h>
@@ -1195,7 +1195,7 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
int argc = m.parameterCount();
if (!rv->arguments) {
- A *args = c->createArgumentsObject(argc);
+ A *args = c->createArgumentsObject(argc, m.parameterNames());
rv->arguments = args;
}
A *args = static_cast<A *>(rv->arguments);
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index bc0cef9f4c..fe7f204e87 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -62,7 +62,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
QT_BEGIN_NAMESPACE
@@ -351,7 +351,7 @@ private:
QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
QQmlPropertyCacheMethodArguments *createArgumentsObject(int count,
- const QList<QByteArray> &names = QList<QByteArray>());
+ const QList<QByteArray> &names);
QQmlPropertyData *signal(int, QQmlPropertyCache **) const;
typedef QVector<QQmlPropertyData> IndexCache;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index f734b77eec..7c32d4f19c 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2453,8 +2453,8 @@ void QQmlTypeData::resolveTypes()
error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(name).arg(error.description()));
}
- error.setLine(unresolvedRef->line);
- error.setColumn(unresolvedRef->column);
+ error.setLine(unresolvedRef->location.line);
+ error.setColumn(unresolvedRef->location.column);
errors.prepend(error);
setError(errors);
@@ -2468,8 +2468,10 @@ void QQmlTypeData::resolveTypes()
ref.majorVersion = majorVersion;
ref.minorVersion = minorVersion;
- ref.location.line = unresolvedRef->line;
- ref.location.column = unresolvedRef->column;
+ ref.location.line = unresolvedRef->location.line;
+ ref.location.column = unresolvedRef->location.column;
+
+ ref.needsCreation = unresolvedRef->needsCreation;
m_resolvedTypes.insert(unresolvedRef.key(), ref);
}
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 976f5a5ffb..ab6f47e8de 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -69,7 +69,7 @@
#include <private/qqmlbundle_p.h>
#include <private/qflagpointer_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4script_p.h>
QT_BEGIN_NAMESPACE
@@ -396,7 +396,7 @@ class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
public:
struct TypeReference
{
- TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0) {}
+ TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0), needsCreation(true) {}
QQmlScript::Location location;
QQmlType *type;
@@ -404,6 +404,7 @@ public:
int minorVersion;
QQmlTypeData *typeData;
QString prefix; // used by CompositeSingleton types
+ bool needsCreation;
};
struct ScriptReference
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index eb1eee5096..355a6751a9 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -56,7 +56,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/qpointer.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index 256573966a..d66dbbba0c 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -56,7 +56,7 @@
#include <QtCore/qglobal.h>
#include <private/qtqmlglobal_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index e60413327a..7d1e8cc8f0 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -184,7 +184,7 @@ struct ActiveVMERestorer
};
}
-QObject *QQmlVME::execute(QList<QQmlError> *errors, const Interrupt &interrupt)
+QObject *QQmlVME::execute(QList<QQmlError> *errors, const QQmlInstantiationInterrupt &interrupt)
{
Q_ASSERT(states.count() >= 1);
@@ -226,7 +226,7 @@ static QVariant variantFromString(const QString &string)
return QQmlStringConverters::variantFromString(string);
}
-static QV4::ExecutionContext *qmlBindingContext(QQmlEngine *engine, QV4::ExecutionEngine *v4, QV4::SafeValue *qmlBindingWrappers, QQmlContextData *context, QObject *scope, int objIdx)
+static QV4::ExecutionContext *qmlBindingContext(QQmlEngine *engine, QV4::ExecutionEngine *v4, QV4::Value *qmlBindingWrappers, QQmlContextData *context, QObject *scope, int objIdx)
{
QV4::Scope valueScope(v4);
QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, qmlBindingWrappers[objIdx]);
@@ -330,7 +330,7 @@ static QV4::ExecutionContext *qmlBindingContext(QQmlEngine *engine, QV4::Executi
removeBindingOnProperty(o, index)
QObject *QQmlVME::run(QList<QQmlError> *errors,
- const Interrupt &interrupt
+ const QQmlInstantiationInterrupt &interrupt
#ifdef QML_THREADED_VME_INTERPRETER
, void * const **storeJumpTable
#endif
@@ -355,7 +355,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QV4::ExecutionEngine *v4 = ep->v4engine();
QV4::Scope valueScope(v4);
QV4::ScopedValue tmpValue(valueScope);
- QV4::SafeValue *qmlBindingWrappers = valueScope.alloc(objects.capacity());
+ QV4::Value *qmlBindingWrappers = valueScope.alloc(objects.capacity());
std::fill(qmlBindingWrappers, qmlBindingWrappers + objects.capacity(), QV4::Primitive::undefinedValue());
int status = -1; // needed for dbus
@@ -1134,14 +1134,14 @@ void *const *QQmlVME::instructionJumpTable()
static void * const *jumpTable = 0;
if (!jumpTable) {
QQmlVME dummy;
- QQmlVME::Interrupt i;
+ QQmlInstantiationInterrupt i;
dummy.run(0, i, &jumpTable);
}
return jumpTable;
}
#endif
-QQmlContextData *QQmlVME::complete(const Interrupt &interrupt)
+QQmlContextData *QQmlVME::complete(const QQmlInstantiationInterrupt &interrupt)
{
Q_ASSERT(engine ||
(bindValues.isEmpty() &&
@@ -1307,6 +1307,14 @@ void QQmlVMEGuard::guard(QQmlVME *vme)
m_contexts[m_contextCount - 1] = vme->rootContext.contextData();
}
+void QQmlVMEGuard::guard(QmlObjectCreator *creator)
+{
+ clear();
+ m_contextCount = 1;
+ m_contexts = new QQmlGuardedContextData[m_contextCount];
+ m_contexts[0] = creator->parentContextData();
+}
+
void QQmlVMEGuard::clear()
{
delete [] m_objects;
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index d26812a68f..4da1aec74b 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -102,28 +102,28 @@ Q_DECLARE_TYPEINFO(QQmlVMETypes::List, Q_PRIMITIVE_TYPE | Q_MOVABLE_TYPE);
template<>
class QTypeInfo<QQmlVMETypes::State> : public QTypeInfoMerger<QQmlVMETypes::State, QBitField> {}; //Q_DECLARE_TYPEINFO
+class QQmlInstantiationInterrupt {
+public:
+ inline QQmlInstantiationInterrupt();
+ inline QQmlInstantiationInterrupt(volatile bool *runWhile, int nsecs=0);
+ inline QQmlInstantiationInterrupt(int nsecs);
+
+ inline void reset();
+ inline bool shouldInterrupt() const;
+private:
+ enum Mode { None, Time, Flag };
+ Mode mode;
+ struct {
+ QElapsedTimer timer;
+ int nsecs;
+ };
+ volatile bool *runWhile;
+};
+
class Q_QML_PRIVATE_EXPORT QQmlVME
{
Q_DECLARE_TR_FUNCTIONS(QQmlVME)
public:
- class Interrupt {
- public:
- inline Interrupt();
- inline Interrupt(volatile bool *runWhile, int nsecs=0);
- inline Interrupt(int nsecs);
-
- inline void reset();
- inline bool shouldInterrupt() const;
- private:
- enum Mode { None, Time, Flag };
- Mode mode;
- struct {
- QElapsedTimer timer;
- int nsecs;
- };
- volatile bool *runWhile;
- };
-
QQmlVME() : data(0), componentAttached(0) {}
QQmlVME(void *data) : data(data), componentAttached(0) {}
@@ -136,8 +136,8 @@ public:
bool initDeferred(QObject *);
void reset();
- QObject *execute(QList<QQmlError> *errors, const Interrupt & = Interrupt());
- QQmlContextData *complete(const Interrupt & = Interrupt());
+ QObject *execute(QList<QQmlError> *errors, const QQmlInstantiationInterrupt & = QQmlInstantiationInterrupt());
+ QQmlContextData *complete(const QQmlInstantiationInterrupt & = QQmlInstantiationInterrupt());
static void enableComponentComplete();
static void disableComponentComplete();
@@ -146,7 +146,7 @@ public:
private:
friend class QQmlVMEGuard;
- QObject *run(QList<QQmlError> *errors, const Interrupt &
+ QObject *run(QList<QQmlError> *errors, const QQmlInstantiationInterrupt &
#ifdef QML_THREADED_VME_INTERPRETER
, void *const**storeJumpTable = 0
#endif
@@ -196,6 +196,7 @@ public:
~QQmlVMEGuard();
void guard(QQmlVME *);
+ void guard(QmlObjectCreator *);
void clear();
bool isOK() const;
@@ -207,28 +208,28 @@ private:
QQmlGuardedContextData *m_contexts;
};
-QQmlVME::Interrupt::Interrupt()
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt()
: mode(None), nsecs(0), runWhile(0)
{
}
-QQmlVME::Interrupt::Interrupt(volatile bool *runWhile, int nsecs)
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(volatile bool *runWhile, int nsecs)
: mode(Flag), nsecs(nsecs), runWhile(runWhile)
{
}
-QQmlVME::Interrupt::Interrupt(int nsecs)
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(int nsecs)
: mode(Time), nsecs(nsecs), runWhile(0)
{
}
-void QQmlVME::Interrupt::reset()
+void QQmlInstantiationInterrupt::reset()
{
if (mode == Time || nsecs)
timer.start();
}
-bool QQmlVME::Interrupt::shouldInterrupt() const
+bool QQmlInstantiationInterrupt::shouldInterrupt() const
{
if (mode == None) {
return false;
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 0b966484ca..f9cb9565b3 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -1086,7 +1086,8 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
// And, if the new value is a scarce resource, we need to ensure that it does not get
// automatically released by the engine until no other references to it exist.
QV4::ScopedValue newv(scope, QQmlEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value));
- if (QV4::Referenced<QV4::VariantObject> v = newv->asRef<QV4::VariantObject>())
+ QV4::VariantObjectRef v = newv;
+ if (!!v)
v->addVmePropertyReference();
// Write the value and emit change signal as appropriate.
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 77db107668..778559d0c4 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -71,7 +71,7 @@
#include <private/qv8engine_p.h>
#include <private/qflagpointer_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 316d066097..76327e3a69 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -68,7 +68,7 @@
#include <QtCore/qdatetime.h>
#include <private/qsimd_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4dateobject_p.h>
#include <private/qv4objectiterator_p.h>
#include <private/qv4mm_p.h>
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index e390ef56dd..1295e671f0 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -68,7 +68,7 @@
#include <private/qqmlpropertycache_p.h>
#include <private/qv4qobjectwrapper_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4object_p.h>
#include <private/qv4identifier_p.h>
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index f10f54038d..3b02e1850b 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -52,7 +52,7 @@
#include <private/qqmlincubator_p.h>
#include <private/qqmlcompiler_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4functionobject_p.h>
QT_BEGIN_NAMESPACE
@@ -1629,45 +1629,45 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
proto->defineAccessorProperty(QStringLiteral("model"), QQmlDelegateModelItem::get_model, 0);
proto->defineAccessorProperty(QStringLiteral("groups"), QQmlDelegateModelItem::get_groups, QQmlDelegateModelItem::set_groups);
QV4::ScopedString s(scope);
- QV4::Property p;
+ QV4::ScopedProperty p(scope);
s = v4->newString(QStringLiteral("isUnresolved"));
- p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, 30, QQmlDelegateModelItem::get_member));
- p.setSetter(0);
+ p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, 30, QQmlDelegateModelItem::get_member));
+ p->setSetter(0);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4->newString(QStringLiteral("inItems"));
- p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member));
- p.setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member));
+ p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member));
+ p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4->newString(QStringLiteral("inPersistedItems"));
- p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member));
- p.setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member));
+ p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member));
+ p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4->newString(QStringLiteral("itemsIndex"));
- p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index));
+ p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4->newString(QStringLiteral("persistedItemsIndex"));
- p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index));
- p.setSetter(0);
+ p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index));
+ p->setSetter(0);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
for (int i = 2; i < groupNames.count(); ++i) {
QString propertyName = QStringLiteral("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
s = v4->newString(propertyName);
- p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_member));
- p.setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::set_member));
+ p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_member));
+ p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::set_member));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
for (int i = 2; i < groupNames.count(); ++i) {
const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
s = v4->newString(propertyName);
- p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_index));
- p.setSetter(0);
+ p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_index));
+ p->setSetter(0);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
modelItemProto = proto;
@@ -1873,7 +1873,7 @@ void QQmlDelegateModelItem::incubateObject(
incubatorPriv->compiledData = componentPriv->cc;
incubatorPriv->compiledData->addref();
if (enginePriv->useNewCompiler) {
- incubatorPriv->creator.reset(new QmlObjectCreator(context, componentPriv->cc));
+ incubatorPriv->creator.reset(new QmlObjectCreator(context, componentPriv->cc, componentPriv->creationContext));
incubatorPriv->subComponentToCreate = componentPriv->start;
} else {
incubatorPriv->vme.init(
@@ -3198,6 +3198,9 @@ public:
: Object(engine)
{
setVTable(staticVTable());
+ QV4::Scope scope(engine);
+ QV4::ScopedObject protectThis(scope, this);
+ Q_UNUSED(protectThis);
setArrayType(QV4::ArrayData::Custom);
}
virtual ~QQmlDelegateModelGroupChangeArray() {}
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 5af33a34f8..da34101c36 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -62,7 +62,7 @@
#include <private/qv8engine_p.h>
#include <private/qv4serialize_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4script_p.h>
#include <private/qv4scopedvalue_p.h>
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index 36c3623d8b..d38e5ac3df 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -46,7 +46,7 @@
#include <private/qqmlproperty_p.h>
#include <private/qv8engine_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4functionobject_p.h>
QT_BEGIN_NAMESPACE
@@ -219,6 +219,7 @@ public:
QV4::Scoped<QV4::Object> proto(scope, v4->newObject());
proto->defineAccessorProperty(QStringLiteral("index"), get_index, 0);
proto->defineAccessorProperty(QStringLiteral("hasModelChildren"), get_hasModelChildren, 0);
+ QV4::ScopedProperty p(scope);
typedef QHash<QByteArray, int>::const_iterator iterator;
for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {
@@ -226,9 +227,8 @@ public:
const QByteArray &propertyName = it.key();
QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
- QV4::Property p;
- p.setGetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::get_property));
- p.setSetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::set_property));
+ p->setGetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::get_property));
+ p->setSetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::set_property));
proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
}
prototype = proto;
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 763dd5251b..ed5c8d7bcb 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -54,7 +54,7 @@
#include <QtCore/QBuffer>
#include <QtCore/qdatetime.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4scopedvalue_p.h>
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index f636d5a619..9851983201 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -65,7 +65,7 @@
#include <QtCore/qnumeric.h>
#include <private/qquickwindow_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4objectproto_p.h>
#include <private/qv4scopedvalue_p.h>
@@ -871,6 +871,9 @@ struct QQuickJSContext2DPixelData : public QV4::Object
: QV4::Object(engine)
{
setVTable(staticVTable());
+ QV4::Scope scope(engine);
+ QV4::ScopedObject protectThis(scope, this);
+ Q_UNUSED(protectThis);
setArrayType(QV4::ArrayData::Custom);
}
@@ -915,9 +918,11 @@ struct QQuickJSContext2DImageData : public QV4::Object
- QV4::SafeValue pixelData;
+ QV4::Value pixelData;
};
+DEFINE_REF(QQuickJSContext2DImageData, QV4::Object);
+
DEFINE_OBJECT_VTABLE(QQuickJSContext2DImageData);
static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
@@ -2109,7 +2114,8 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_path(QV4::CallContext *ctx)
QV4::ScopedValue value(scope, ctx->argument(0));
r->context->beginPath();
- if (QV4::Referenced<QV4::QObjectWrapper> qobjectWrapper = value->asRef<QV4::QObjectWrapper>()) {
+ QV4::QObjectWrapperRef qobjectWrapper = value;
+ if (!!qobjectWrapper) {
if (QQuickPath *path = qobject_cast<QQuickPath*>(qobjectWrapper->object()))
r->context->m_path = path->path();
} else {
@@ -2980,7 +2986,8 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
pixmap = r->context->createPixmap(url);
} else if (arg->isObject()) {
- if (QV4::Referenced<QV4::QObjectWrapper> qobjectWrapper = arg->asRef<QV4::QObjectWrapper>()) {
+ QV4::QObjectWrapperRef qobjectWrapper = arg;
+ if (!!qobjectWrapper) {
if (QQuickImage *imageItem = qobject_cast<QQuickImage*>(qobjectWrapper->object())) {
pixmap = r->context->createPixmap(imageItem->source());
} else if (QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(qobjectWrapper->object())) {
@@ -2990,19 +2997,22 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
- } else if (QV4::Referenced<QQuickJSContext2DImageData> imageData = arg->asRef<QQuickJSContext2DImageData>()) {
- QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
- if (pix && !pix->image.isNull()) {
- pixmap.take(new QQuickCanvasPixmap(pix->image));
+ } else {
+ QQuickJSContext2DImageDataRef imageData = arg;
+ if (!!imageData) {
+ QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
+ if (pix && !pix->image.isNull()) {
+ pixmap.take(new QQuickCanvasPixmap(pix->image));
+ } else {
+ V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
+ }
} else {
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
+ QUrl url(arg->toQStringNoThrow());
+ if (url.isValid())
+ pixmap = r->context->createPixmap(url);
+ else
+ V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
- } else {
- QUrl url(arg->toQStringNoThrow());
- if (url.isValid())
- pixmap = r->context->createPixmap(url);
- else
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
@@ -3260,7 +3270,8 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::CallC
if (ctx->callData->argc == 1) {
QV4::ScopedValue arg0(scope, ctx->callData->args[0]);
- if (QV4::Referenced<QQuickJSContext2DImageData> imgData = arg0->asRef<QQuickJSContext2DImageData>()) {
+ QQuickJSContext2DImageDataRef imgData = arg0;
+ if (!!imgData) {
QV4::Scoped<QQuickJSContext2DPixelData> pa(scope, imgData->pixelData.as<QQuickJSContext2DPixelData>());
if (pa) {
qreal w = pa->image.width();
@@ -3337,7 +3348,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont
if (!qIsFinite(dx) || !qIsFinite(dy))
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
- QV4::Referenced<QQuickJSContext2DImageData> imageData = arg0->asRef<QQuickJSContext2DImageData>();
+ QQuickJSContext2DImageDataRef imageData = arg0;
if (!imageData)
return ctx->callData->thisObject.asReturnedValue();
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 6399da3dee..4390ae62cc 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -55,7 +55,7 @@
#include <private/qv8engine_p.h>
#include <QtCore/QWaitCondition>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
//#define QQUICKCONTEXT2D_DEBUG //enable this for just DEBUG purpose!
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 3c00a7d62d..b5cc6ea3ef 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -139,6 +139,57 @@ QT_BEGIN_NAMESPACE
\endtable
*/
+/*! \qmlproperty bool focusable
+ \brief This property holds whether this item is focusable.
+
+ By default, this property is false except for items where the role is one of
+ CheckBox, RadioButton, Button, MenuItem, PageTab, EditableText, SpinBox, ComboBox,
+ Terminal or ScrollBar.
+*/
+/*! \qmlproperty bool focused
+ \brief This property holds whether this item currently has the active focus.
+
+ By default, this property is false, but it will return true for items that
+ have \l QQuickItem::hasActiveFocus() returning true.
+*/
+/*! \qmlproperty bool checkable
+ \brief This property holds whether this item is checkable (like a check box or some buttons).
+*/
+/*! \qmlproperty bool checked
+ \brief This property holds whether this item is currently checked.
+*/
+/*! \qmlproperty bool editable
+ \brief This property holds whether this item has editable text.
+*/
+/*! \qmlproperty bool multiLine
+ \brief This property holds whether this item has multiple text lines.
+*/
+/*! \qmlproperty bool readOnly
+ \brief This property holds whether this item while being of type \l QAccessible::EditableText
+ is set to read-only.
+*/
+/*! \qmlproperty bool selected
+ \brief This property holds whether this item is selected.
+*/
+/*! \qmlproperty bool selectable
+ \brief This property holds whether this item can be selected.
+*/
+/*! \qmlproperty bool pressed
+ \brief This property holds whether this item is pressed (for example a button during a mouse click).
+*/
+/*! \qmlproperty bool checkStateMixed
+ \brief This property holds whether this item is in the partially checked state.
+*/
+/*! \qmlproperty bool defaultButton
+ \brief This property holds whether this item is the default button of a dialog.
+*/
+/*! \qmlproperty bool passwordEdit
+ \brief This property holds whether this item is a password text edit.
+*/
+/*! \qmlproperty bool selectableText
+ \brief This property holds whether this item contains selectable text.
+*/
+
QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
: QObject(parent), m_role(QAccessible::NoRole)
{
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 298c473cf8..1f2c6bf532 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -55,15 +55,46 @@
QT_BEGIN_NAMESPACE
+#define STATE_PROPERTY(P) \
+ Q_PROPERTY(bool P READ P WRITE set_ ## P NOTIFY P ## Changed FINAL) \
+ bool P() const { return m_state.P ; } \
+ void set_ ## P(bool arg) \
+ { \
+ if (m_state.P == arg) \
+ return; \
+ m_state.P = arg; \
+ emit P ## Changed(arg); \
+ QAccessible::State changedState; \
+ changedState.P = true; \
+ QAccessibleStateChangeEvent ev(parent(), changedState); \
+ QAccessible::updateAccessibility(&ev); \
+ } \
+ Q_SIGNAL void P ## Changed(bool arg);
+
+
class Q_QUICK_PRIVATE_EXPORT QQuickAccessibleAttached : public QObject
{
Q_OBJECT
- Q_PROPERTY(QAccessible::Role role READ role WRITE setRole NOTIFY roleChanged)
- Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
- Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged)
+ Q_PROPERTY(QAccessible::Role role READ role WRITE setRole NOTIFY roleChanged FINAL)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
+ Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged FINAL)
public:
- Q_ENUMS(QAccessible::Role QAccessible::Event QAccessible::State)
+ Q_ENUMS(QAccessible::Role QAccessible::Event)
+ STATE_PROPERTY(checkable)
+ STATE_PROPERTY(checked)
+ STATE_PROPERTY(editable)
+ STATE_PROPERTY(focusable)
+ STATE_PROPERTY(focused)
+ STATE_PROPERTY(multiLine)
+ STATE_PROPERTY(readOnly)
+ STATE_PROPERTY(selected)
+ STATE_PROPERTY(selectable)
+ STATE_PROPERTY(pressed)
+ STATE_PROPERTY(checkStateMixed)
+ STATE_PROPERTY(defaultButton)
+ STATE_PROPERTY(passwordEdit)
+ STATE_PROPERTY(selectableText)
QQuickAccessibleAttached(QObject *parent);
~QQuickAccessibleAttached();
@@ -76,9 +107,33 @@ public:
Q_EMIT roleChanged();
// There is no way to signify role changes at the moment.
// QAccessible::updateAccessibility(parent(), 0, QAccessible::);
+
+ switch (role) {
+ case QAccessible::CheckBox:
+ case QAccessible::RadioButton:
+ m_state.focusable = true;
+ m_state.checkable = true;
+ break;
+ case QAccessible::Button:
+ case QAccessible::MenuItem:
+ case QAccessible::PageTab:
+ case QAccessible::EditableText:
+ case QAccessible::SpinBox:
+ case QAccessible::ComboBox:
+ case QAccessible::Terminal:
+ case QAccessible::ScrollBar:
+ m_state.focusable = true;
+ break;
+ default:
+ break;
+ }
}
}
- QString name() const { return m_name; }
+ QString name() const {
+ if (m_state.passwordEdit)
+ return QString();
+ return m_name;
+ }
void setName(const QString &name) {
if (name != m_name) {
m_name = name;
@@ -102,12 +157,12 @@ public:
// Factory function
static QQuickAccessibleAttached *qmlAttachedProperties(QObject *obj);
- // Property getter
- static QObject *attachedProperties(const QObject *obj)
+ static QQuickAccessibleAttached *attachedProperties(const QObject *obj)
{
- return qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj, false);
+ return qobject_cast<QQuickAccessibleAttached*>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj, false));
}
+ // Property getter
static QVariant property(const QObject *object, const char *propertyName)
{
if (QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object))
@@ -128,8 +183,8 @@ public:
static QObject *findAccessible(QObject *object, QAccessible::Role role = QAccessible::NoRole)
{
while (object) {
- QObject *att = QQuickAccessibleAttached::attachedProperties(object);
- if (att && (role == QAccessible::NoRole || att->property("role").toInt() == role)) {
+ QQuickAccessibleAttached *att = QQuickAccessibleAttached::attachedProperties(object);
+ if (att && (role == QAccessible::NoRole || att->role() == role)) {
break;
}
object = object->parent();
@@ -137,6 +192,8 @@ public:
return object;
}
+ QAccessible::State state() { return m_state; }
+
public Q_SLOTS:
void valueChanged() {
QAccessibleValueChangeEvent ev(parent(), parent()->property("value"));
@@ -153,7 +210,10 @@ Q_SIGNALS:
void descriptionChanged();
private:
+ QQuickItem *item() const { return static_cast<QQuickItem*>(parent()); }
+
QAccessible::Role m_role;
+ QAccessible::State m_state;
QString m_name;
QString m_description;
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index c666af2729..2b08cc2598 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
class QQuickItem;
class QQuickTransformPrivate;
-class QQuickTransform : public QObject
+class Q_QUICK_EXPORT QQuickTransform : public QObject
{
Q_OBJECT
public:
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 96746223ce..a52ccf4832 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -269,6 +269,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickText, 2>(uri, 2, 2, "Text");
qmlRegisterType<QQuickTextEdit, 2>(uri, 2, 2, "TextEdit");
+
+ qmlRegisterType<QQuickText, 3>(uri, 2, 3, "Text");
+ qmlRegisterType<QQuickTextEdit, 3>(uri, 2, 3, "TextEdit");
}
static void initResources()
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 32c271222d..5783418619 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -58,7 +58,7 @@
#include "qquickitemchangelistener_p.h"
#include <qqmlincubator.h>
-#include <private/qv4value_p.h>
+#include <private/qv4value_inl_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 410f18e767..54c7527eec 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -323,7 +323,7 @@ void QQuickScreenAttached::screenChanged(QScreen *screen)
this, SIGNAL(orientationChanged()));
connect(screen, SIGNAL(primaryOrientationChanged(Qt::ScreenOrientation)),
this, SIGNAL(primaryOrientationChanged()));
- connect(screen, SIGNAL(virtualGeometryChanged(const QRect &)),
+ connect(screen, SIGNAL(virtualGeometryChanged(QRect)),
this, SIGNAL(desktopGeometryChanged()));
connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)),
this, SIGNAL(logicalPixelDensityChanged()));
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 5b5dd0ef03..ae14a43de0 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -2216,7 +2216,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
else
node = static_cast<QQuickTextNode *>(oldNode);
- node->setUseNativeRenderer(d->renderType == NativeRendering && d->window->devicePixelRatio() <= 1);
+ node->setUseNativeRenderer(d->renderType == NativeRendering);
node->deleteContent();
node->setMatrix(QMatrix4x4());
@@ -2569,7 +2569,7 @@ bool QQuickTextPrivate::isLinkHoveredConnected()
text. The link must be in rich text or HTML format and the \a link
string provides access to the particular link.
- \sa hoveredLink
+ \sa hoveredLink, linkAt()
*/
/*!
@@ -2580,7 +2580,7 @@ bool QQuickTextPrivate::isLinkHoveredConnected()
embedded in the text. The link must be in rich text or HTML format
and the \a hoveredLink string provides access to the particular link.
- \sa onLinkHovered
+ \sa onLinkHovered, linkAt()
*/
QString QQuickText::hoveredLink() const
@@ -2649,9 +2649,6 @@ void QQuickText::hoverLeaveEvent(QHoverEvent *event)
not require advanced features such as transformation of the text. Using such features in
combination with the NativeRendering render type will lend poor and sometimes pixelated
results.
-
- On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
- and QtRendering is always used.
*/
QQuickText::RenderType QQuickText::renderType() const
{
@@ -2683,4 +2680,19 @@ void QQuickText::doLayout()
d->updateSize();
}
+/*!
+ \qmlmethod QtQuick::Text::linkAt(real x, real y)
+ \since 5.3
+
+ Returns the link string at point \a x, \a y in content coordinates,
+ or an empty string if no link exists at that point.
+
+ \sa hoveredLink
+*/
+QString QQuickText::linkAt(qreal x, qreal y) const
+{
+ Q_D(const QQuickText);
+ return d->anchorAt(QPointF(x, y));
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index d55dc7e287..44bd5aa9b0 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -210,6 +210,8 @@ public:
QString hoveredLink() const;
+ Q_REVISION(3) Q_INVOKABLE QString linkAt(qreal x, qreal y) const;
+
Q_SIGNALS:
void textChanged(const QString &text);
void linkActivated(const QString &link);
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index c342c79ce5..810a47cfa8 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -418,9 +418,6 @@ void QQuickTextEdit::setTextFormat(TextFormat format)
not require advanced features such as transformation of the text. Using such features in
combination with the NativeRendering render type will lend poor and sometimes pixelated
results.
-
- On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
- and QtRendering is always used.
*/
QQuickTextEdit::RenderType QQuickTextEdit::renderType() const
{
@@ -2371,7 +2368,7 @@ QQuickTextNode *QQuickTextEditPrivate::createTextNode()
{
Q_Q(QQuickTextEdit);
QQuickTextNode* node = new QQuickTextNode(q);
- node->setUseNativeRenderer(renderType == QQuickTextEdit::NativeRendering && window->devicePixelRatio() <= 1);
+ node->setUseNativeRenderer(renderType == QQuickTextEdit::NativeRendering);
node->initEngine(color, selectedTextColor, selectionColor);
return node;
}
@@ -2518,7 +2515,7 @@ bool QQuickTextEditPrivate::isLinkHoveredConnected()
The link must be in rich text or HTML format and the
\a link string provides access to the particular link.
- \sa hoveredLink
+ \sa hoveredLink, linkAt()
*/
/*!
@@ -2529,7 +2526,7 @@ bool QQuickTextEditPrivate::isLinkHoveredConnected()
embedded in the text. The link must be in rich text or HTML format
and the link string provides access to the particular link.
- \sa onLinkHovered
+ \sa onLinkHovered, linkAt()
*/
QString QQuickTextEdit::hoveredLink() const
@@ -2602,4 +2599,19 @@ void QQuickTextEdit::append(const QString &text)
d->control->updateCursorRectangle(false);
}
+/*!
+ \qmlmethod QtQuick::TextEdit::linkAt(real x, real y)
+ \since 5.3
+
+ Returns the link string at point \a x, \a y in content coordinates,
+ or an empty string if no link exists at that point.
+
+ \sa hoveredLink
+*/
+QString QQuickTextEdit::linkAt(qreal x, qreal y) const
+{
+ Q_D(const QQuickTextEdit);
+ return d->control->anchorAt(QPointF(x, y));
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 8057f76be5..b84552d255 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -258,6 +258,8 @@ public:
QString hoveredLink() const;
+ Q_REVISION(3) Q_INVOKABLE QString linkAt(qreal x, qreal y) const;
+
Q_SIGNALS:
void textChanged();
void contentSizeChanged();
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 1dd1dfa57e..9f155f9cf7 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -155,9 +155,6 @@ void QQuickTextInput::setText(const QString &s)
not require advanced features such as transformation of the text. Using such features in
combination with the NativeRendering render type will lend poor and sometimes pixelated
results.
-
- On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
- and QtRendering is always used.
*/
QQuickTextInput::RenderType QQuickTextInput::renderType() const
{
@@ -1862,7 +1859,7 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
}
}
} else {
- node->setUseNativeRenderer(d->renderType == NativeRendering && d->window->devicePixelRatio() <= 1);
+ node->setUseNativeRenderer(d->renderType == NativeRendering);
node->deleteContent();
node->setMatrix(QMatrix4x4());
diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp
index 18ee1a479d..1133636a74 100644
--- a/src/quick/items/qquicktextnode.cpp
+++ b/src/quick/items/qquicktextnode.cpp
@@ -144,11 +144,9 @@ QSGGlyphNode *QQuickTextNode::addGlyphs(const QPointF &position, const QGlyphRun
{
QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
QRawFont font = glyphs.rawFont();
- bool smoothScalable = QFontDatabase().isSmoothlyScalable(font.familyName(),
- font.styleName());
- QSGGlyphNode *node = m_useNativeRenderer || !smoothScalable
- ? sg->sceneGraphContext()->createNativeGlyphNode(sg)
- : sg->sceneGraphContext()->createGlyphNode(sg);
+ bool smoothScalable = QFontDatabase().isSmoothlyScalable(font.familyName(), font.styleName());
+ bool preferNativeGlyphNode = m_useNativeRenderer || !smoothScalable;
+ QSGGlyphNode *node = sg->sceneGraphContext()->createGlyphNode(sg, preferNativeGlyphNode);
node->setOwnerElement(m_ownerElement);
node->setGlyphs(position + QPointF(0, glyphs.rawFont().ascent()), glyphs);
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index a311971266..6778cf13e9 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -344,6 +344,7 @@ void QQuickWindowPrivate::syncSceneGraph()
mode |= QSGRenderer::ClearColorBuffer;
renderer->setClearMode(mode);
+ renderer->setCustomRenderMode(customRenderMode);
context->endSync();
}
@@ -418,6 +419,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c)
contentItemPrivate->windowRefCount = 1;
contentItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
+ customRenderMode = qgetenv("QSG_VISUALIZE");
windowManager = QSGRenderLoop::instance();
QSGContext *sg = windowManager->sceneGraphContext();
context = windowManager->createRenderContext(sg);
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index d5c7b5d64c..944a320dce 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -57,6 +57,7 @@
#include "qquickwindow.h"
#include <QtQuick/private/qsgcontext_p.h>
+#include <private/qsgbatchrenderer_p.h>
#include <QtCore/qthread.h>
#include <QtCore/qmutex.h>
@@ -200,6 +201,7 @@ public:
QSGRenderContext *context;
QSGRenderer *renderer;
+ QByteArray customRenderMode; // Default renderer supports "clip", "overdraw", "changes", "batches" and blank.
QSGRenderLoop *windowManager;
QQuickAnimatorController *animationController;
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 1a9669f9ab..9de7bb8667 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -42,6 +42,10 @@
#include "qsgbatchrenderer_p.h"
#include <private/qsgshadersourcebuilder_p.h>
+#include <QQuickWindow>
+
+#include <qmath.h>
+
#include <QtCore/QElapsedTimer>
#include <QtGui/QGuiApplication>
@@ -106,7 +110,7 @@ bool qsg_sort_batch_is_valid(Batch *a, Batch *b) { return a->first && !b->first;
bool qsg_sort_batch_increasing_order(Batch *a, Batch *b) { return a->first->order < b->first->order; }
bool qsg_sort_batch_decreasing_order(Batch *a, Batch *b) { return a->first->order > b->first->order; }
-QSGMaterial::Flag QSGMaterial_RequiresFullMatrixBit = (QSGMaterial::Flag) (QSGMaterial::RequiresFullMatrix & ~QSGMaterial::RequiresFullMatrixExceptTranslate);
+QSGMaterial::Flag QSGMaterial_FullMatrix = (QSGMaterial::Flag) (QSGMaterial::RequiresFullMatrix & ~QSGMaterial::RequiresFullMatrixExceptTranslate);
struct QMatrix4x4_Accessor
{
@@ -305,6 +309,9 @@ void Updater::updateStates(QSGNode *n)
qDebug() << " - forceupdate";
}
+ if (Q_UNLIKELY(renderer->m_visualizeMode == Renderer::VisualizeChanges))
+ renderer->visualizeChangesPrepare(sn);
+
visitNode(sn);
}
@@ -760,6 +767,7 @@ Renderer::Renderer(QSGRenderContext *ctx)
, m_currentClip(0)
, m_currentClipType(NoClip)
, m_vao(0)
+ , m_visualizeMode(VisualizeNothing)
{
setNodeUpdater(new Updater(this));
@@ -1668,7 +1676,7 @@ void Renderer::uploadMergedElement(Element *e, int vaOffset, char **vertexData,
*indexCount += iCount;
}
-const QMatrix4x4 &Renderer::matrixForRoot(Node *node)
+static QMatrix4x4 qsg_matrixForRoot(Node *node)
{
if (node->type() == QSGNode::TransformNodeType)
return static_cast<QSGTransformNode *>(node->sgNode)->combinedMatrix();
@@ -1701,14 +1709,12 @@ void Renderer::uploadBatch(Batch *b)
QSGGeometryNode *gn = b->first->node;
QSGGeometry *g = gn->geometry();
-
+ QSGMaterial::Flags flags = gn->activeMaterial()->flags();
bool canMerge = (g->drawingMode() == GL_TRIANGLES || g->drawingMode() == GL_TRIANGLE_STRIP)
&& b->positionAttribute >= 0
&& g->indexType() == GL_UNSIGNED_SHORT
- && (gn->activeMaterial()->flags() & QSGMaterial::CustomCompileStep) == 0
- && (((gn->activeMaterial()->flags() & QSGMaterial::RequiresDeterminant) == 0)
- || (((gn->activeMaterial()->flags() & QSGMaterial_RequiresFullMatrixBit) == 0) && b->isTranslateOnlyToRoot())
- )
+ && (flags & (QSGMaterial::CustomCompileStep | QSGMaterial_FullMatrix)) == 0
+ && ((flags & QSGMaterial::RequiresFullMatrixExceptTranslate) == 0 || b->isTranslateOnlyToRoot())
&& b->isSafeToBatch();
b->merged = canMerge;
@@ -2004,7 +2010,7 @@ void Renderer::renderMergedBatch(const Batch *batch)
// We always have dirty matrix as all batches are at a unique z range.
QSGMaterialShader::RenderState::DirtyStates dirty = QSGMaterialShader::RenderState::DirtyMatrix;
if (batch->root)
- m_current_model_view_matrix = matrixForRoot(batch->root);
+ m_current_model_view_matrix = qsg_matrixForRoot(batch->root);
else
m_current_model_view_matrix.setToIdentity();
m_current_determinant = m_current_model_view_matrix.determinant();
@@ -2133,7 +2139,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
char *iOffset = indexBase + batch->vertexCount * gn->geometry()->sizeOfVertex();
#endif
- QMatrix4x4 rootMatrix = batch->root ? matrixForRoot(batch->root) : QMatrix4x4();
+ QMatrix4x4 rootMatrix = batch->root ? qsg_matrixForRoot(batch->root) : QMatrix4x4();
while (e) {
gn = e->node;
@@ -2358,7 +2364,6 @@ void Renderer::render()
cleanupBatches(&m_opaqueBatches);
cleanupBatches(&m_alphaBatches);
-
if (m_rebuild & BuildBatches) {
prepareOpaqueBatches();
prepareAlphaBatches();
@@ -2408,6 +2413,9 @@ void Renderer::render()
m_rebuild = 0;
+ if (m_visualizeMode != VisualizeNothing)
+ visualize();
+
if (m_vao)
m_vao->release();
}
@@ -2446,7 +2454,7 @@ void Renderer::renderRenderNode(Batch *batch)
QMatrix4x4 matrix;
while (xform != rootNode()) {
if (xform->type() == QSGNode::TransformNodeType) {
- matrix = matrixForRoot(e->root) * static_cast<QSGTransformNode *>(xform)->combinedMatrix();
+ matrix = qsg_matrixForRoot(e->root) * static_cast<QSGTransformNode *>(xform)->combinedMatrix();
break;
}
xform = xform->parent();
@@ -2510,6 +2518,312 @@ void Renderer::renderRenderNode(Batch *batch)
}
+class VisualizeShader : public QOpenGLShaderProgram
+{
+public:
+ int color;
+ int matrix;
+ int rotation;
+ int tweak;
+};
+
+void Renderer::visualizeDrawGeometry(const QSGGeometry *g)
+{
+ if (g->attributeCount() < 1)
+ return;
+ const QSGGeometry::Attribute *a = g->attributes();
+ glVertexAttribPointer(0, a->tupleSize, a->type, false, g->sizeOfVertex(), g->vertexData());
+ if (g->indexCount())
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
+ else
+ glDrawArrays(g->drawingMode(), 0, g->vertexCount());
+
+}
+
+void Renderer::visualizeBatch(Batch *b)
+{
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram);
+
+ if (b->positionAttribute != 0)
+ return;
+
+ QSGGeometryNode *gn = b->first->node;
+ QSGGeometry *g = gn->geometry();
+ const QSGGeometry::Attribute &a = g->attributes()[b->positionAttribute];
+
+ glBindBuffer(GL_ARRAY_BUFFER, b->vbo.id);
+
+ QMatrix4x4 matrix(m_current_projection_matrix);
+ if (b->root)
+ matrix = matrix * qsg_matrixForRoot(b->root);
+
+ QRect viewport = viewportRect();
+ shader->setUniformValue(shader->tweak, viewport.width(), viewport.height(), b->merged ? 0 : 1, 0);
+
+ QColor color = QColor::fromHsvF((rand() & 1023) / 1023.0, 1.0, 1.0);
+ float cr = color.redF();
+ float cg = color.greenF();
+ float cb = color.blueF();
+ shader->setUniformValue(shader->color, cr, cg, cb, 1.0);
+
+ if (b->merged) {
+ shader->setUniformValue(shader->matrix, matrix);
+ for (int ds=0; ds<b->drawSets.size(); ++ds) {
+ const DrawSet &set = b->drawSets.at(ds);
+ glVertexAttribPointer(a.position, 2, a.type, false, g->sizeOfVertex(), (void *) (qintptr) (set.vertices));
+ glDrawElements(g->drawingMode(), set.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (b->vbo.data + set.indices));
+ }
+ } else {
+ Element *e = b->first;
+ int offset = 0;
+ while (e) {
+ gn = e->node;
+ g = gn->geometry();
+ shader->setUniformValue(shader->matrix, matrix * *gn->matrix());
+ glVertexAttribPointer(a.position, a.tupleSize, a.type, false, g->sizeOfVertex(), (void *) (qintptr) offset);
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
+ offset += g->sizeOfVertex() * g->vertexCount();
+ e = e->nextInBatch;
+ }
+ }
+}
+
+
+
+
+void Renderer::visualizeClipping(QSGNode *node)
+{
+ if (node->type() == QSGNode::ClipNodeType) {
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram);
+ QSGClipNode *clipNode = static_cast<QSGClipNode *>(node);
+ QMatrix4x4 matrix = m_current_projection_matrix;
+ if (clipNode->matrix())
+ matrix = matrix * *clipNode->matrix();
+ shader->setUniformValue(shader->matrix, matrix);
+ visualizeDrawGeometry(clipNode->geometry());
+ }
+
+ QSGNODE_TRAVERSE(node) {
+ visualizeClipping(child);
+ }
+}
+
+#define QSGNODE_DIRTY_PARENT (QSGNode::DirtyNodeAdded \
+ | QSGNode::DirtyOpacity \
+ | QSGNode::DirtyMatrix \
+ | QSGNode::DirtyNodeRemoved)
+
+void Renderer::visualizeChangesPrepare(Node *n, uint parentChanges)
+{
+ uint childDirty = (parentChanges | n->dirtyState) & QSGNODE_DIRTY_PARENT;
+ uint selfDirty = n->dirtyState | parentChanges;
+ if (n->type() == QSGNode::GeometryNodeType && selfDirty != 0)
+ m_visualizeChanceSet.insert(n, selfDirty);
+ SHADOWNODE_TRAVERSE(n) {
+ visualizeChangesPrepare(*child, childDirty);
+ }
+}
+
+void Renderer::visualizeChanges(Node *n)
+{
+
+ if (n->type() == QSGNode::GeometryNodeType && m_visualizeChanceSet.contains(n)) {
+ uint dirty = m_visualizeChanceSet.value(n);
+ bool tinted = (dirty & QSGNODE_DIRTY_PARENT) != 0;
+
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram);
+ QColor color = QColor::fromHsvF((rand() & 1023) / 1023.0, 0.3, 1.0);
+ float ca = 0.5;
+ float cr = color.redF() * ca;
+ float cg = color.greenF() * ca;
+ float cb = color.blueF() * ca;
+ shader->setUniformValue(shader->color, cr, cg, cb, ca);
+
+ QRect viewport = viewportRect();
+ shader->setUniformValue(shader->tweak, viewport.width(), viewport.height(), tinted ? 0.5 : 0, 0);
+
+ QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(n->sgNode);
+
+ QMatrix4x4 matrix = m_current_projection_matrix;
+ if (n->element()->batch->root)
+ matrix = matrix * qsg_matrixForRoot(n->element()->batch->root);
+ matrix = matrix * *gn->matrix();
+ shader->setUniformValue(shader->matrix, matrix);
+ visualizeDrawGeometry(gn->geometry());
+
+ // This is because many changes don't propegate their dirty state to the
+ // parent so the node updater will not unset these states. They are
+ // not used for anything so, unsetting it should have no side effects.
+ n->dirtyState = 0;
+ }
+
+ SHADOWNODE_TRAVERSE(n) {
+ visualizeChanges(*child);
+ }
+}
+
+void Renderer::visualizeOverdraw_helper(Node *node)
+{
+ if (node->type() == QSGNode::GeometryNodeType) {
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram);
+ QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(node->sgNode);
+
+ QMatrix4x4 matrix = m_current_projection_matrix;
+ matrix(2, 2) = m_zRange;
+ matrix(2, 3) = 1.0f - node->element()->order * m_zRange;
+
+ if (node->element()->batch->root)
+ matrix = matrix * qsg_matrixForRoot(node->element()->batch->root);
+ matrix = matrix * *gn->matrix();
+ shader->setUniformValue(shader->matrix, matrix);
+
+ QColor color = node->element()->batch->isOpaque ? QColor::fromRgbF(0.3, 1.0, 0.3) : QColor::fromRgbF(1.0, 0.3, 0.3);
+ float ca = 0.33;
+ shader->setUniformValue(shader->color, color.redF() * ca, color.greenF() * ca, color.blueF() * ca, ca);
+
+ visualizeDrawGeometry(gn->geometry());
+ }
+
+ SHADOWNODE_TRAVERSE(node) {
+ visualizeOverdraw_helper(*child);
+ }
+}
+
+void Renderer::visualizeOverdraw()
+{
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram);
+ shader->setUniformValue(shader->color, 0.5, 0.5, 1, 1);
+
+ QRect viewport = viewportRect();
+ shader->setUniformValue(shader->tweak, viewport.width(), viewport.height(), 0, 1);
+
+ glBlendFunc(GL_ONE, GL_ONE);
+
+ static float step = 0;
+ step += M_PI * 2 / 1000.;
+ if (step > M_PI * 2)
+ step = 0;
+ float angle = 80.0 * sin(step);
+
+ QMatrix4x4 xrot; xrot.rotate(20, 1, 0, 0);
+ QMatrix4x4 zrot; zrot.rotate(angle, 0, 0, 1);
+ QMatrix4x4 tx; tx.translate(0, 0, 1);
+
+ QMatrix4x4 m;
+
+// m.rotate(180, 0, 1, 0);
+
+ m.translate(0, 0.5, 4);
+ m.scale(2, 2, 1);
+
+ m.rotate(-30, 1, 0, 0);
+ m.rotate(angle, 0, 1, 0);
+ m.translate(0, 0, -1);
+
+ shader->setUniformValue(shader->rotation, m);
+
+ float box[] = {
+ // lower
+ -1, 1, 0, 1, 1, 0,
+ -1, 1, 0, -1, -1, 0,
+ 1, 1, 0, 1, -1, 0,
+ -1, -1, 0, 1, -1, 0,
+
+ // upper
+ -1, 1, 1, 1, 1, 1,
+ -1, 1, 1, -1, -1, 1,
+ 1, 1, 1, 1, -1, 1,
+ -1, -1, 1, 1, -1, 1,
+
+ // sides
+ -1, -1, 0, -1, -1, 1,
+ 1, -1, 0, 1, -1, 1,
+ -1, 1, 0, -1, 1, 1,
+ 1, 1, 0, 1, 1, 1
+ };
+ glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, box);
+ glLineWidth(2);
+ glDrawArrays(GL_LINES, 0, 24);
+
+ visualizeOverdraw_helper(m_nodes.value(rootNode()));
+
+ // Animate the view...
+ QSurface *surface = QOpenGLContext::currentContext()->surface();
+ if (surface->surfaceClass() == QSurface::Window)
+ if (QQuickWindow *window = qobject_cast<QQuickWindow *>(static_cast<QWindow *>(surface)))
+ window->update();
+}
+
+void Renderer::setCustomRenderMode(const QByteArray &mode)
+{
+ if (mode.isEmpty()) m_visualizeMode = VisualizeNothing;
+ else if (mode == "clip") m_visualizeMode = VisualizeClipping;
+ else if (mode == "overdraw") m_visualizeMode = VisualizeOverdraw;
+ else if (mode == "batches") m_visualizeMode = VisualizeBatches;
+ else if (mode == "changes") m_visualizeMode = VisualizeChanges;
+}
+
+void Renderer::visualize()
+{
+ if (!m_shaderManager->visualizeProgram) {
+ VisualizeShader *prog = new VisualizeShader();
+ QSGShaderSourceBuilder::initializeProgramFromFiles(
+ prog,
+ QStringLiteral(":/scenegraph/shaders/visualization.vert"),
+ QStringLiteral(":/scenegraph/shaders/visualization.frag"));
+ prog->bindAttributeLocation("v", 0);
+ prog->link();
+ prog->bind();
+ prog->color = prog->uniformLocation("color");
+ prog->tweak = prog->uniformLocation("tweak");
+ prog->matrix = prog->uniformLocation("matrix");
+ prog->rotation = prog->uniformLocation("rotation");
+ m_shaderManager->visualizeProgram = prog;
+ } else {
+ m_shaderManager->visualizeProgram->bind();
+ }
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram);
+
+ glDisable(GL_DEPTH_TEST);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glEnableVertexAttribArray(0);
+
+ // Blacken out the actual rendered content...
+ float bgOpacity = 0.8;
+ if (m_visualizeMode == VisualizeBatches)
+ bgOpacity = 1.0;
+ float v[] = { -1, 1, 1, 1, -1, -1, 1, -1 };
+ shader->setUniformValue(shader->color, 0, 0, 0, bgOpacity);
+ shader->setUniformValue(shader->matrix, QMatrix4x4());
+ shader->setUniformValue(shader->rotation, QMatrix4x4());
+ shader->setUniformValue(shader->tweak, 0, 0, 0, 0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, v);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ if (m_visualizeMode == VisualizeBatches) {
+ srand(0); // To force random colors to be roughly the same every time..
+ for (int i=0; i<m_opaqueBatches.size(); ++i) visualizeBatch(m_opaqueBatches.at(i));
+ for (int i=0; i<m_alphaBatches.size(); ++i) visualizeBatch(m_alphaBatches.at(i));
+ } else if (m_visualizeMode == VisualizeClipping) {
+ QRect viewport = viewportRect();
+ shader->setUniformValue(shader->tweak, viewport.width(), viewport.height(), 0.5, 0);
+ shader->setUniformValue(shader->color, 0.2, 0, 0, 0.2);
+ visualizeClipping(rootNode());
+ } else if (m_visualizeMode == VisualizeChanges) {
+ visualizeChanges(m_nodes.value(rootNode()));
+ m_visualizeChanceSet.clear();
+ } else if (m_visualizeMode == VisualizeOverdraw) {
+ visualizeOverdraw();
+ }
+
+ // Reset state back to defaults..
+ glDisable(GL_BLEND);
+ glDisableVertexAttribArray(0);
+ shader->release();
+}
+
QT_END_NAMESPACE
}
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 0aa84da185..d22ab4069e 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -368,7 +368,7 @@ public:
float lastOpacity;
};
- ShaderManager() : blitProgram(0) { }
+ ShaderManager() : blitProgram(0), visualizeProgram(0) { }
~ShaderManager() {
qDeleteAll(rewrittenShaders.values());
qDeleteAll(stockShaders.values());
@@ -385,6 +385,7 @@ public:
QHash<QSGMaterialType *, Shader *> stockShaders;
QOpenGLShaderProgram *blitProgram;
+ QOpenGLShaderProgram *visualizeProgram;
};
class Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer
@@ -393,6 +394,14 @@ public:
Renderer(QSGRenderContext *);
~Renderer();
+ enum VisualizeMode {
+ VisualizeNothing,
+ VisualizeBatches,
+ VisualizeClipping,
+ VisualizeChanges,
+ VisualizeOverdraw
+ };
+
protected:
void nodeChanged(QSGNode *node, QSGNode::DirtyState state);
void preprocess() Q_DECL_OVERRIDE;
@@ -448,6 +457,16 @@ private:
inline Batch *newBatch();
void invalidateAndRecycleBatch(Batch *b);
+ void visualize();
+ void visualizeBatch(Batch *b);
+ void visualizeClipping(QSGNode *node);
+ void visualizeChangesPrepare(Node *n, uint parentChanges = 0);
+ void visualizeChanges(Node *n);
+ void visualizeOverdraw();
+ void visualizeOverdraw_helper(Node *node);
+ void visualizeDrawGeometry(const QSGGeometry *g);
+ void setCustomRenderMode(const QByteArray &mode);
+
QSet<Node *> m_taggedRoots;
QDataBuffer<Element *> m_opaqueRenderList;
QDataBuffer<Element *> m_alphaRenderList;
@@ -484,6 +503,9 @@ private:
// For minimal OpenGL core profile support
QOpenGLVertexArrayObject *m_vao;
+
+ QHash<Node *, uint> m_visualizeChanceSet;
+ VisualizeMode m_visualizeMode;
};
Batch *Renderer::newBatch()
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
index 43811e6d5e..296d6e2cfd 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -132,6 +132,8 @@ public:
void setClearMode(ClearMode mode) { m_clear_mode = mode; }
ClearMode clearMode() const { return m_clear_mode; }
+ virtual void setCustomRenderMode(const QByteArray &) { };
+
Q_SIGNALS:
void sceneGraphChanged(); // Add, remove, ChangeFlags changes...
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index 829d33a0d7..202ae91ac3 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -253,32 +253,14 @@ QSGImageNode *QSGContext::createImageNode()
}
/*!
- Factory function for scene graph backends of the Text elements which supports native
- text rendering. Used in special cases where native look and feel is a main objective.
-*/
-QSGGlyphNode *QSGContext::createNativeGlyphNode(QSGRenderContext *rc)
-{
-#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_ES_2_ANGLE)
- Q_D(QSGContext);
- if (d->distanceFieldDisabled)
- return new QSGDefaultGlyphNode;
- else
- return createGlyphNode(rc);
-#else
- Q_UNUSED(rc);
- return new QSGDefaultGlyphNode;
-#endif
-}
-
-/*!
Factory function for scene graph backends of the Text elements;
*/
-QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc)
+QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode)
{
Q_D(QSGContext);
- if (d->distanceFieldDisabled) {
- return createNativeGlyphNode(rc);
+ if (d->distanceFieldDisabled || preferNativeGlyphNode) {
+ return new QSGDefaultGlyphNode;
} else {
QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(rc);
node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing);
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index c1bf78a018..883287e35d 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -158,8 +158,7 @@ public:
virtual QSGRectangleNode *createRectangleNode();
virtual QSGImageNode *createImageNode();
- virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc);
- virtual QSGGlyphNode *createNativeGlyphNode(QSGRenderContext *rc);
+ virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode);
virtual QAnimationDriver *createAnimationDriver(QObject *parent);
virtual QSize minimumFBOSize() const;
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index 6868e10b90..570d6b92b5 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -160,5 +160,7 @@ OTHER_FILES += \
$$PWD/shaders/textmask_core.vert \
$$PWD/shaders/texture_core.frag \
$$PWD/shaders/vertexcolor_core.frag \
- $$PWD/shaders/vertexcolor_core.vert
+ $$PWD/shaders/vertexcolor_core.vert \
+ scenegraph/shaders/visualization.frag \
+ scenegraph/shaders/visualization.vert
diff --git a/src/quick/scenegraph/scenegraph.qrc b/src/quick/scenegraph/scenegraph.qrc
index 2be8b246d3..e6a90c9120 100644
--- a/src/quick/scenegraph/scenegraph.qrc
+++ b/src/quick/scenegraph/scenegraph.qrc
@@ -64,5 +64,7 @@
<file>shaders/texture_core.frag</file>
<file>shaders/vertexcolor_core.frag</file>
<file>shaders/vertexcolor_core.vert</file>
+ <file>shaders/visualization.vert</file>
+ <file>shaders/visualization.frag</file>
</qresource>
</RCC>
diff --git a/src/quick/scenegraph/shaders/visualization.frag b/src/quick/scenegraph/shaders/visualization.frag
new file mode 100644
index 0000000000..205b726c03
--- /dev/null
+++ b/src/quick/scenegraph/shaders/visualization.frag
@@ -0,0 +1,11 @@
+uniform lowp vec4 color;
+uniform mediump vec4 tweak; // x,y -> width, height; z -> intensity of ;
+
+varying mediump vec2 pos;
+
+void main(void)
+{
+ lowp vec4 c = color;
+ c.xyz += pow(max(sin(pos.x + pos.y), 0.0), 2.0) * tweak.z * 0.1;
+ gl_FragColor = c;
+}
diff --git a/src/quick/scenegraph/shaders/visualization.vert b/src/quick/scenegraph/shaders/visualization.vert
new file mode 100644
index 0000000000..f1892b71da
--- /dev/null
+++ b/src/quick/scenegraph/shaders/visualization.vert
@@ -0,0 +1,22 @@
+attribute highp vec4 v;
+uniform highp mat4 matrix;
+uniform highp mat4 rotation;
+
+// w -> apply 3d rotation and projection
+uniform lowp vec4 tweak;
+
+varying mediump vec2 pos;
+
+void main()
+{
+ vec4 p = matrix * v;
+
+ if (tweak.w > 0.0) {
+ vec4 proj = rotation * p;
+ gl_Position = vec4(proj.x, proj.y, 0, proj.z);
+ } else {
+ gl_Position = p;
+ }
+
+ pos = v.xy * 1.37;
+}
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index d080c59198..e6a2096c80 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -148,9 +148,10 @@ Atlas::Atlas(const QSize &size)
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK)
QString *deviceName =
static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName"));
- static bool wrongfullyReportsBgra8888Support = deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0
- || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0
- || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0;
+ static bool wrongfullyReportsBgra8888Support = deviceName != 0
+ && (deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0
+ || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0
+ || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0);
#else
static bool wrongfullyReportsBgra8888Support = false;
#endif
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index ae1bec3f42..b738896a6c 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -684,9 +684,10 @@ void QSGPlainTexture::bind()
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK)
QString *deviceName =
static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName"));
- static bool wrongfullyReportsBgra8888Support = deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0
- || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0
- || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0;
+ static bool wrongfullyReportsBgra8888Support = deviceName != 0
+ && (deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0
+ || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0
+ || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0);
#else
static bool wrongfullyReportsBgra8888Support = false;
#endif
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index fa6f615649..3bc4cef5b9 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -271,7 +271,7 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
m_helper = new Helper();
m_helper->item = m_target;
m_controller->m_transforms.insert(m_target, m_helper);
- QObject::connect(m_target, SIGNAL(destroyed(QObject *)), m_controller, SLOT(itemDestroyed(QObject*)), Qt::DirectConnection);
+ QObject::connect(m_target, SIGNAL(destroyed(QObject*)), m_controller, SLOT(itemDestroyed(QObject*)), Qt::DirectConnection);
} else {
++m_helper->ref;
// Make sure leftovers from previous runs are being used...