aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp21
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h4
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h1
-rw-r--r--src/qml/compiler/compiler.pri8
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp407
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h138
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator.cpp (renamed from src/qml/jsruntime/qv4debugging.cpp)45
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h746
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp703
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator_p.h87
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp1938
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h269
-rw-r--r--src/qml/compiler/qv4codegen.cpp7
-rw-r--r--src/qml/compiler/qv4compileddata.cpp316
-rw-r--r--src/qml/compiler/qv4compileddata_p.h544
-rw-r--r--src/qml/compiler/qv4compiler.cpp214
-rw-r--r--src/qml/compiler/qv4compiler_p.h11
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h23
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp194
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h18
-rw-r--r--src/qml/compiler/qv4isel_p.cpp3
-rw-r--r--src/qml/compiler/qv4isel_p.h41
-rw-r--r--src/qml/compiler/qv4isel_util_p.h50
-rw-r--r--src/qml/compiler/qv4jsir.cpp331
-rw-r--r--src/qml/compiler/qv4jsir_p.h445
-rw-r--r--src/qml/compiler/qv4ssa.cpp1019
-rw-r--r--src/qml/debugger/debugger.pri26
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter_p.h10
-rw-r--r--src/qml/debugger/qqmldebug.cpp17
-rw-r--r--src/qml/debugger/qqmldebug.h3
-rw-r--r--src/qml/debugger/qqmldebugconnector_p.h25
-rw-r--r--src/qml/debugger/qqmldebugservice.cpp33
-rw-r--r--src/qml/debugger/qqmldebugservice_p.h20
-rw-r--r--src/qml/debugger/qqmldebugserviceinterfaces_p.h57
-rw-r--r--src/qml/debugger/qqmldebugstatesdelegate_p.h7
-rw-r--r--src/qml/debugger/qqmlmemoryprofiler.cpp (renamed from src/qml/qml/qqmlmemoryprofiler.cpp)7
-rw-r--r--src/qml/debugger/qqmlmemoryprofiler_p.h (renamed from src/qml/qml/qqmlmemoryprofiler_p.h)9
-rw-r--r--src/qml/debugger/qqmlprofiler.cpp18
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h94
-rw-r--r--src/qml/debugger/qqmlprofilerdefinitions_p.h4
-rw-r--r--src/qml/doc/snippets/qml/qtLater.qml109
-rw-r--r--src/qml/doc/src/javascript/functionlist.qdoc24
-rw-r--r--src/qml/jit/qv4assembler.cpp70
-rw-r--r--src/qml/jit/qv4assembler_p.h145
-rw-r--r--src/qml/jit/qv4binop.cpp62
-rw-r--r--src/qml/jit/qv4binop_p.h4
-rw-r--r--src/qml/jit/qv4isel_masm.cpp170
-rw-r--r--src/qml/jit/qv4isel_masm_p.h14
-rw-r--r--src/qml/jit/qv4regalloc.cpp83
-rw-r--r--src/qml/jit/qv4unop.cpp43
-rw-r--r--src/qml/jit/qv4unop_p.h4
-rw-r--r--src/qml/jsapi/qjsengine.cpp49
-rw-r--r--src/qml/jsapi/qjsengine.h8
-rw-r--r--src/qml/jsapi/qjsvalue.cpp56
-rw-r--r--src/qml/jsapi/qjsvalue.h2
-rw-r--r--src/qml/jsruntime/jsruntime.pri13
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp24
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp30
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h4
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp2
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp64
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp9
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp22
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h4
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp16
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h15
-rw-r--r--src/qml/jsruntime/qv4engine.cpp55
-rw-r--r--src/qml/jsruntime/qv4engine_p.h50
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp49
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h16
-rw-r--r--src/qml/jsruntime/qv4function.cpp6
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp190
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h28
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp38
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4identifier.cpp23
-rw-r--r--src/qml/jsruntime/qv4identifier_p.h12
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp10
-rw-r--r--src/qml/jsruntime/qv4include.cpp40
-rw-r--r--src/qml/jsruntime/qv4include_p.h11
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp42
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h30
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp84
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp24
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp32
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h6
-rw-r--r--src/qml/jsruntime/qv4object.cpp22
-rw-r--r--src/qml/jsruntime/qv4object_p.h17
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp21
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h4
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h4
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp28
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h123
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp290
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h34
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp52
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp565
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h434
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h315
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h53
-rw-r--r--src/qml/jsruntime/qv4script.cpp58
-rw-r--r--src/qml/jsruntime/qv4script_p.h6
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4string.cpp121
-rw-r--r--src/qml/jsruntime/qv4string_p.h66
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp129
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h7
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp81
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h4
-rw-r--r--src/qml/jsruntime/qv4value_p.h13
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp158
-rw-r--r--src/qml/memory/qv4mm.cpp132
-rw-r--r--src/qml/memory/qv4mm_p.h4
-rw-r--r--src/qml/parser/qqmljsengine_p.cpp2
-rw-r--r--src/qml/qml.pro12
-rw-r--r--src/qml/qml/ftw/ftw.pri1
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp23
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h39
-rw-r--r--src/qml/qml/ftw/qpointervaluepair_p.h194
-rw-r--r--src/qml/qml/qml.pri10
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h12
-rw-r--r--src/qml/qml/qqmlaccessors_p.h7
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp11
-rw-r--r--src/qml/qml/qqmlbinding.cpp305
-rw-r--r--src/qml/qml/qqmlbinding_p.h45
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp19
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp165
-rw-r--r--src/qml/qml/qqmlcompiler_p.h160
-rw-r--r--src/qml/qml/qqmlcomponent.cpp73
-rw-r--r--src/qml/qml/qqmlcomponent.h9
-rw-r--r--src/qml/qml/qqmlcomponent_p.h6
-rw-r--r--src/qml/qml/qqmlcontext.cpp57
-rw-r--r--src/qml/qml/qqmlcontext_p.h13
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp15
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h8
-rw-r--r--src/qml/qml/qqmldata_p.h14
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp215
-rw-r--r--src/qml/qml/qqmldelayedcallqueue_p.h104
-rw-r--r--src/qml/qml/qqmlengine.cpp147
-rw-r--r--src/qml/qml/qqmlengine.h4
-rw-r--r--src/qml/qml/qqmlengine_p.h16
-rw-r--r--src/qml/qml/qqmlexpression.cpp11
-rw-r--r--src/qml/qml/qqmlexpression_p.h3
-rw-r--r--src/qml/qml/qqmlfile.cpp30
-rw-r--r--src/qml/qml/qqmlfile.h2
-rw-r--r--src/qml/qml/qqmlimport.cpp13
-rw-r--r--src/qml/qml/qqmlincubator.cpp32
-rw-r--r--src/qml/qml/qqmlincubator_p.h4
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp73
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h19
-rw-r--r--src/qml/qml/qqmlmetatype.cpp23
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp4
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.h3
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp339
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h21
-rw-r--r--src/qml/qml/qqmlplatform.cpp2
-rw-r--r--src/qml/qml/qqmlproperty.cpp190
-rw-r--r--src/qml/qml/qqmlproperty_p.h18
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp405
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h187
-rw-r--r--src/qml/qml/qqmltypeloader.cpp574
-rw-r--r--src/qml/qml/qqmltypeloader_p.h80
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp2
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding.cpp2
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp34
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h1
-rw-r--r--src/qml/qml/qqmlvme.cpp1
-rw-r--r--src/qml/qml/qqmlvme_p.h4
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp509
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h116
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp31
-rw-r--r--src/qml/qml/qqmlxmlhttprequest_p.h4
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp33
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h4
-rw-r--r--src/qml/qml/v8/qv8engine.cpp7
-rw-r--r--src/qml/qml/v8/qv8engine_p.h11
-rw-r--r--src/qml/qml/v8/v8.pri1
-rw-r--r--src/qml/types/qqmlbind.cpp58
-rw-r--r--src/qml/types/qqmlbind_p.h5
-rw-r--r--src/qml/types/qqmlconnections.cpp11
-rw-r--r--src/qml/types/qqmlconnections_p.h2
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp34
-rw-r--r--src/qml/types/qqmllistmodel.cpp39
-rw-r--r--src/qml/types/qqmllistmodel_p.h4
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h2
-rw-r--r--src/qml/types/qquickworkerscript.cpp30
195 files changed, 10204 insertions, 6955 deletions
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index 4bd02c1934..f7f6939e4b 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -588,8 +588,7 @@ void QAbstractAnimationJob::updateDirection(QAbstractAnimationJob::Direction dir
void QAbstractAnimationJob::finished()
{
//TODO: update this code so it is valid to delete the animation in animationFinished
- for (int i = 0; i < changeListeners.count(); ++i) {
- const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ for (const auto &change : changeListeners) {
if (change.types & QAbstractAnimationJob::Completion) {
RETURN_IF_DELETED(change.listener->animationFinished(this));
}
@@ -603,8 +602,7 @@ void QAbstractAnimationJob::finished()
void QAbstractAnimationJob::stateChanged(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState)
{
- for (int i = 0; i < changeListeners.count(); ++i) {
- const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ for (const auto &change : changeListeners) {
if (change.types & QAbstractAnimationJob::StateChange) {
RETURN_IF_DELETED(change.listener->animationStateChanged(this, newState, oldState));
}
@@ -613,8 +611,7 @@ void QAbstractAnimationJob::stateChanged(QAbstractAnimationJob::State newState,
void QAbstractAnimationJob::currentLoopChanged()
{
- for (int i = 0; i < changeListeners.count(); ++i) {
- const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ for (const auto &change : changeListeners) {
if (change.types & QAbstractAnimationJob::CurrentLoop) {
RETURN_IF_DELETED(change.listener->animationCurrentLoopChanged(this));
}
@@ -625,8 +622,7 @@ void QAbstractAnimationJob::currentTimeChanged(int currentTime)
{
Q_ASSERT(m_hasCurrentTimeChangeListeners);
- for (int i = 0; i < changeListeners.count(); ++i) {
- const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ for (const auto &change : changeListeners) {
if (change.types & QAbstractAnimationJob::CurrentTime) {
RETURN_IF_DELETED(change.listener->animationCurrentTimeChanged(this, currentTime));
}
@@ -638,17 +634,18 @@ void QAbstractAnimationJob::addAnimationChangeListener(QAnimationJobChangeListen
if (changes & QAbstractAnimationJob::CurrentTime)
m_hasCurrentTimeChangeListeners = true;
- changeListeners.append(ChangeListener(listener, changes));
+ changeListeners.push_back(ChangeListener(listener, changes));
}
void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
{
m_hasCurrentTimeChangeListeners = false;
- changeListeners.removeOne(ChangeListener(listener, changes));
+ const auto it = std::find(changeListeners.begin(), changeListeners.end(), ChangeListener(listener, changes));
+ if (it != changeListeners.end())
+ changeListeners.erase(it);
- for (int i = 0; i < changeListeners.count(); ++i) {
- const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ for (const auto &change: changeListeners) {
if (change.types & QAbstractAnimationJob::CurrentTime) {
m_hasCurrentTimeChangeListeners = true;
break;
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index b04f523585..efc86a5823 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -54,7 +54,7 @@
#include <private/qtqmlglobal_p.h>
#include <QtCore/QObject>
#include <QtCore/private/qabstractanimation_p.h>
-#include "private/qpodvector_p.h"
+#include <vector>
QT_BEGIN_NAMESPACE
@@ -164,7 +164,7 @@ protected:
QAbstractAnimationJob::ChangeTypes types;
bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
};
- QPODVector<ChangeListener,1> changeListeners;
+ std::vector<ChangeListener> changeListeners;
QAbstractAnimationJob *m_nextSibling;
QAbstractAnimationJob *m_previousSibling;
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
index 4b94e79d40..9bcd63127a 100644
--- a/src/qml/animations/qanimationgroupjob_p.h
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -52,6 +52,7 @@
//
#include "private/qabstractanimationjob_p.h"
+#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 585fef7603..ad73c26b15 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -26,12 +26,16 @@ SOURCES += \
HEADERS += \
$$PWD/qqmltypecompiler_p.h \
$$PWD/qv4isel_moth_p.h \
- $$PWD/qv4instr_moth_p.h
+ $$PWD/qv4instr_moth_p.h \
+ $$PWD/qqmlpropertycachecreator_p.h \
+ $$PWD/qqmlpropertyvalidator_p.h
SOURCES += \
$$PWD/qqmltypecompiler.cpp \
$$PWD/qv4instr_moth.cpp \
- $$PWD/qv4isel_moth.cpp
+ $$PWD/qv4isel_moth.cpp \
+ $$PWD/qqmlpropertycachecreator.cpp \
+ $$PWD/qqmlpropertyvalidator.cpp
}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index eaf0e72296..f736e04b88 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -49,7 +49,6 @@
#include <private/qqmlglobal_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qqmlcompiler_p.h>
#endif
#ifdef CONST
@@ -72,21 +71,24 @@ using namespace QmlIR;
return false; \
}
-void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQmlJS::AST::SourceLocation &loc)
+void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &loc)
{
inheritedTypeNameIndex = typeNameIndex;
location.line = loc.startLine;
location.column = loc.startColumn;
- idIndex = id;
- indexOfDefaultProperty = -1;
+ idNameIndex = idIndex;
+ id = -1;
+ indexOfDefaultPropertyOrAlias = -1;
+ defaultPropertyIsAlias = false;
+ flags = QV4::CompiledData::Object::NoFlag;
properties = pool->New<PoolList<Property> >();
+ aliases = pool->New<PoolList<Alias> >();
qmlSignals = pool->New<PoolList<Signal> >();
bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >();
functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >();
- runtimeFunctionIndices = 0;
declarationsOverride = 0;
}
@@ -145,15 +147,42 @@ QString Object::appendProperty(Property *prop, const QString &propertyName, bool
const int index = target->properties->append(prop);
if (isDefaultProperty) {
- if (target->indexOfDefaultProperty != -1) {
+ if (target->indexOfDefaultPropertyOrAlias != -1) {
*errorLocation = defaultToken;
return tr("Duplicate default property");
}
- target->indexOfDefaultProperty = index;
+ target->indexOfDefaultPropertyOrAlias = index;
}
return QString(); // no error
}
+QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation)
+{
+ Object *target = declarationsOverride;
+ if (!target)
+ target = this;
+
+ for (Alias *p = target->aliases->first; p; p = p->next)
+ if (p->nameIndex == alias->nameIndex)
+ return tr("Duplicate alias name");
+
+ if (aliasName.constData()->isUpper())
+ return tr("Alias names cannot begin with an upper case letter");
+
+ const int index = target->aliases->append(alias);
+
+ if (isDefaultProperty) {
+ if (target->indexOfDefaultPropertyOrAlias != -1) {
+ *errorLocation = defaultToken;
+ return tr("Duplicate default property");
+ }
+ target->indexOfDefaultPropertyOrAlias = index;
+ target->defaultPropertyIsAlias = true;
+ }
+
+ return QString(); // no error
+}
+
void Object::appendFunction(QmlIR::Function *f)
{
Object *target = declarationsOverride;
@@ -164,7 +193,7 @@ void Object::appendFunction(QmlIR::Function *f)
QString Object::appendBinding(Binding *b, bool isListBinding)
{
- const bool bindingToDefaultProperty = (b->propertyNameIndex == 0);
+ const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
if (!isListBinding && !bindingToDefaultProperty
&& b->type != QV4::CompiledData::Binding::Type_GroupProperty
&& b->type != QV4::CompiledData::Binding::Type_AttachedProperty
@@ -190,7 +219,7 @@ Binding *Object::findBinding(quint32 nameIndex) const
void Object::insertSorted(Binding *b)
{
- Binding *insertionPoint = bindings->findSortedInsertionPoint<QV4::CompiledData::Location, QV4::CompiledData::Binding, &QV4::CompiledData::Binding::valueLocation>(b);
+ Binding *insertionPoint = bindings->findSortedInsertionPoint<quint32, Binding, &Binding::offset>(b);
bindings->insertAfter(insertionPoint, b);
}
@@ -222,32 +251,6 @@ static void replaceWithSpace(QString &str, int idx, int n)
*data++ = space;
}
-void Document::collectTypeReferences()
-{
- foreach (Object *obj, objects) {
- if (obj->inheritedTypeNameIndex != emptyStringIndex) {
- QV4::CompiledData::TypeReference &r = typeReferences.add(obj->inheritedTypeNameIndex, obj->location);
- r.needsCreation = true;
- r.errorWhenNotFound = true;
- }
-
- for (const Property *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.
- QV4::CompiledData::TypeReference &r = typeReferences.add(prop->customTypeNameIndex, obj->location);
- r.needsCreation = true;
- r.errorWhenNotFound = true;
- }
- }
-
- for (const Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
- typeReferences.add(binding->propertyNameIndex, binding->location);
- }
- }
-}
-
void Document::removeScriptPragmas(QString &script)
{
const QLatin1String pragma("pragma");
@@ -637,7 +640,10 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
}
if (node->versionToken.isValid()) {
- extractVersion(textRefAt(node->versionToken), &import->majorVersion, &import->minorVersion);
+ int major, minor;
+ extractVersion(textRefAt(node->versionToken), &major, &minor);
+ import->majorVersion = major;
+ import->minorVersion = minor;
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version"));
return false;
@@ -807,130 +813,87 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
}
} else {
const QStringRef &memberType = node->memberType;
- const QStringRef &name = node->name;
-
- bool typeFound = false;
- QV4::CompiledData::Property::Type type;
-
if (memberType == QLatin1String("alias")) {
- type = QV4::CompiledData::Property::Alias;
- typeFound = true;
- }
+ return appendAlias(node);
+ } else {
+ const QStringRef &name = node->name;
- for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
- const TypeNameToType *t = propTypeNameToTypes + ii;
- if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
- type = t->type;
- typeFound = true;
+ bool typeFound = false;
+ QV4::CompiledData::Property::Type type;
+
+ for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
+ const TypeNameToType *t = propTypeNameToTypes + ii;
+ if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
+ type = t->type;
+ typeFound = true;
+ }
}
- }
- if (!typeFound && memberType.at(0).isUpper()) {
- const QStringRef &typeModifier = node->typeModifier;
+ if (!typeFound && memberType.at(0).isUpper()) {
+ const QStringRef &typeModifier = node->typeModifier;
- if (typeModifier.isEmpty()) {
- type = QV4::CompiledData::Property::Custom;
- } else if (typeModifier == QLatin1String("list")) {
- type = QV4::CompiledData::Property::CustomList;
- } else {
- recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
+ if (typeModifier.isEmpty()) {
+ type = QV4::CompiledData::Property::Custom;
+ } else if (typeModifier == QLatin1String("list")) {
+ type = QV4::CompiledData::Property::CustomList;
+ } else {
+ recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
+ return false;
+ }
+ typeFound = true;
+ } else if (!node->typeModifier.isNull()) {
+ recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Unexpected property type modifier"));
return false;
}
- typeFound = true;
- } else if (!node->typeModifier.isNull()) {
- recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Unexpected property type modifier"));
- return false;
- }
-
- if (!typeFound) {
- recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected property type"));
- return false;
- }
-
- Property *property = New<Property>();
- property->flags = 0;
- if (node->isReadonlyMember)
- property->flags |= QV4::CompiledData::Property::IsReadOnly;
- property->type = type;
- if (type >= QV4::CompiledData::Property::Custom)
- property->customTypeNameIndex = registerString(memberType.toString());
- else
- property->customTypeNameIndex = emptyStringIndex;
- const QString propName = name.toString();
- property->nameIndex = registerString(propName);
-
- QQmlJS::AST::SourceLocation loc = node->firstSourceLocation();
- property->location.line = loc.startLine;
- property->location.column = loc.startColumn;
-
- property->aliasPropertyValueIndex = emptyStringIndex;
-
- if (type == QV4::CompiledData::Property::Alias) {
- if (!node->statement && !node->binding)
- COMPILE_EXCEPTION(loc, tr("No property alias location"));
+ if (!typeFound) {
+ recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected property type"));
+ return false;
+ }
- QQmlJS::AST::SourceLocation rhsLoc;
- if (node->binding)
- rhsLoc = node->binding->firstSourceLocation();
- else if (node->statement)
- rhsLoc = node->statement->firstSourceLocation();
+ Property *property = New<Property>();
+ property->flags = 0;
+ if (node->isReadonlyMember)
+ property->flags |= QV4::CompiledData::Property::IsReadOnly;
+ property->type = type;
+ if (type >= QV4::CompiledData::Property::Custom)
+ property->customTypeNameIndex = registerString(memberType.toString());
else
- rhsLoc = node->semicolonToken;
- property->aliasLocation.line = rhsLoc.startLine;
- property->aliasLocation.column = rhsLoc.startColumn;
-
- QStringList alias;
-
- if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(node->statement)) {
- alias = astNodeToStringList(stmt->expression);
- if (alias.isEmpty()) {
- if (isStatementNodeScript(node->statement)) {
- COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
- } else {
- COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias location"));
- }
- }
- } else {
- COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
- }
+ property->customTypeNameIndex = emptyStringIndex;
- if (alias.count() < 1 || alias.count() > 3)
- COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
+ const QString propName = name.toString();
+ property->nameIndex = registerString(propName);
- property->aliasIdValueIndex = registerString(alias.first());
+ QQmlJS::AST::SourceLocation loc = node->firstSourceLocation();
+ property->location.line = loc.startLine;
+ property->location.column = loc.startColumn;
- QString propertyValue = alias.value(1);
- if (alias.count() == 3) {
- propertyValue += QLatin1Char('.');
- propertyValue += alias.at(2);
- }
- property->aliasPropertyValueIndex = registerString(propertyValue);
- }
- QQmlJS::AST::SourceLocation errorLocation;
- QString error;
+ QQmlJS::AST::SourceLocation errorLocation;
+ QString error;
- if (illegalNames.contains(propName))
- error = tr("Illegal property name");
- else
- error = _object->appendProperty(property, propName, node->isDefaultMember, node->defaultToken, &errorLocation);
+ 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;
+ if (!error.isEmpty()) {
+ if (errorLocation.startLine == 0)
+ errorLocation = node->identifierToken;
- recordError(errorLocation, error);
- return false;
- }
+ recordError(errorLocation, error);
+ return false;
+ }
- qSwap(_propertyDeclaration, property);
- if (node->binding) {
- // process QML-like initializers (e.g. property Object o: Object {})
- QQmlJS::AST::Node::accept(node->binding, this);
- } else if (node->statement && type != QV4::CompiledData::Property::Alias) {
- appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement);
+ qSwap(_propertyDeclaration, property);
+ if (node->binding) {
+ // process QML-like initializers (e.g. property Object o: Object {})
+ QQmlJS::AST::Node::accept(node->binding, this);
+ } else if (node->statement) {
+ if (!isRedundantNullInitializerForPropertyDeclaration(_propertyDeclaration, node->statement))
+ appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement);
+ }
+ qSwap(_propertyDeclaration, property);
}
- qSwap(_propertyDeclaration, property);
}
return false;
@@ -952,6 +915,16 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
f->location.column = loc.startColumn;
f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
+
+ int formalsCount = 0;
+ for (QQmlJS::AST::FormalParameterList *it = funDecl->formals; it; it = it->next)
+ ++formalsCount;
+ f->formals.allocate(pool, formalsCount);
+
+ int i = 0;
+ for (QQmlJS::AST::FormalParameterList *it = funDecl->formals; it; it = it->next, ++i)
+ f->formals[i] = registerString(it->name.toString());
+
_object->appendFunction(f);
} else {
recordError(node->firstSourceLocation(), QCoreApplication::translate("QQmlParser","JavaScript declaration outside Script element"));
@@ -1027,13 +1000,13 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
binding->value.b = false;
} else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) {
binding->type = QV4::CompiledData::Binding::Type_Number;
- binding->value.d = lit->value;
+ binding->setNumberValueInternal(lit->value);
} else {
if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
binding->type = QV4::CompiledData::Binding::Type_Number;
- binding->value.d = -lit->value;
+ binding->setNumberValueInternal(-lit->value);
}
}
}
@@ -1085,6 +1058,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
{
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
+ binding->offset = nameLocation.offset;
binding->location.line = nameLocation.startLine;
binding->location.column = nameLocation.startColumn;
binding->flags = 0;
@@ -1104,6 +1078,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
+ binding->offset = nameLocation.offset;
binding->location.line = nameLocation.startLine;
binding->location.column = nameLocation.startColumn;
@@ -1133,6 +1108,79 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
}
}
+bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node)
+{
+ Alias *alias = New<Alias>();
+ alias->flags = 0;
+ if (node->isReadonlyMember)
+ alias->flags |= QV4::CompiledData::Alias::IsReadOnly;
+
+ const QString propName = node->name.toString();
+ alias->nameIndex = registerString(propName);
+
+ QQmlJS::AST::SourceLocation loc = node->firstSourceLocation();
+ alias->location.line = loc.startLine;
+ alias->location.column = loc.startColumn;
+
+ alias->propertyNameIndex = emptyStringIndex;
+
+ if (!node->statement && !node->binding)
+ COMPILE_EXCEPTION(loc, tr("No property alias location"));
+
+ QQmlJS::AST::SourceLocation rhsLoc;
+ if (node->binding)
+ rhsLoc = node->binding->firstSourceLocation();
+ else if (node->statement)
+ rhsLoc = node->statement->firstSourceLocation();
+ else
+ rhsLoc = node->semicolonToken;
+ alias->referenceLocation.line = rhsLoc.startLine;
+ alias->referenceLocation.column = rhsLoc.startColumn;
+
+ QStringList aliasReference;
+
+ if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(node->statement)) {
+ aliasReference = astNodeToStringList(stmt->expression);
+ if (aliasReference.isEmpty()) {
+ if (isStatementNodeScript(node->statement)) {
+ COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
+ } else {
+ COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias location"));
+ }
+ }
+ } else {
+ COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
+ }
+
+ if (aliasReference.count() < 1 || aliasReference.count() > 3)
+ COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
+
+ alias->idIndex = registerString(aliasReference.first());
+
+ QString propertyValue = aliasReference.value(1);
+ if (aliasReference.count() == 3)
+ propertyValue += QLatin1Char('.') + aliasReference.at(2);
+ alias->propertyNameIndex = registerString(propertyValue);
+
+ QQmlJS::AST::SourceLocation errorLocation;
+ QString error;
+
+ if (illegalNames.contains(propName))
+ error = tr("Illegal property name");
+ else
+ error = _object->appendAlias(alias, propName, node->isDefaultMember, node->defaultToken, &errorLocation);
+
+ if (!error.isEmpty()) {
+ if (errorLocation.startLine == 0)
+ errorLocation = node->identifierToken;
+
+ recordError(errorLocation, error);
+ return false;
+ }
+
+ return false;
+}
+
Object *IRBuilder::bindingsTarget() const
{
if (_propertyDeclaration && _object->declarationsOverride)
@@ -1178,10 +1226,10 @@ bool IRBuilder::setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST
if (illegalNames.contains(idQString))
COMPILE_EXCEPTION(loc, tr( "ID illegally masks global JavaScript property"));
- if (_object->idIndex != emptyStringIndex)
+ if (_object->idNameIndex != emptyStringIndex)
COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times"));
- _object->idIndex = registerString(idQString);
+ _object->idNameIndex = registerString(idQString);
_object->locationOfIdProperty.line = idLocation.startLine;
_object->locationOfIdProperty.column = idLocation.startColumn;
@@ -1202,8 +1250,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
if (import->qualifierIndex != emptyStringIndex
&& stringAt(import->qualifierIndex) == currentName) {
qualifiedIdElement = qualifiedIdElement->next;
- currentName += QLatin1Char('.');
- currentName += qualifiedIdElement->name;
+ currentName += QLatin1Char('.') + qualifiedIdElement->name;
if (!qualifiedIdElement->name.unicode()->isUpper())
COMPILE_EXCEPTION(qualifiedIdElement->firstSourceLocation(), tr("Expected type name"));
@@ -1229,6 +1276,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
if (!binding) {
binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
+ binding->offset = qualifiedIdElement->identifierToken.offset;
binding->location.line = qualifiedIdElement->identifierToken.startLine;
binding->location.column = qualifiedIdElement->identifierToken.startColumn;
binding->valueLocation.line = qualifiedIdElement->next->identifierToken.startLine;
@@ -1300,6 +1348,17 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
return true;
}
+bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement)
+{
+ if (property->type != QV4::CompiledData::Property::Custom)
+ return false;
+ QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
+ if (!exprStmt)
+ return false;
+ QQmlJS::AST::ExpressionNode * const expr = exprStmt->expression;
+ return QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr);
+}
+
QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
{
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = output.javaScriptCompilationUnit;
@@ -1309,12 +1368,12 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count();
const int objectOffsetTableSize = output.objects.count() * sizeof(quint32);
- QHash<Object*, quint32> objectOffsets;
+ QHash<const Object*, quint32> objectOffsets;
int objectsSize = 0;
foreach (Object *o, output.objects) {
objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize);
- objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount());
+ objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
int signalTableSize = 0;
for (const Signal *s = o->firstSignal(); s; s = s->next)
@@ -1354,13 +1413,17 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
// write objects
quint32 *objectTable = reinterpret_cast<quint32*>(data + qmlUnit->offsetToObjects);
char *objectPtr = data + qmlUnit->offsetToObjects + objectOffsetTableSize;
- foreach (Object *o, output.objects) {
+ for (int i = 0; i < output.objects.count(); ++i) {
+ const Object *o = output.objects.at(i);
*objectTable++ = objectOffsets.value(o);
QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
- objectToWrite->indexOfDefaultProperty = o->indexOfDefaultProperty;
- objectToWrite->idIndex = o->idIndex;
+ objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
+ objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias;
+ objectToWrite->flags = o->flags;
+ objectToWrite->idNameIndex = o->idNameIndex;
+ objectToWrite->id = o->id;
objectToWrite->location = o->location;
objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
@@ -1374,6 +1437,10 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
objectToWrite->offsetToProperties = nextOffset;
nextOffset += objectToWrite->nProperties * sizeof(QV4::CompiledData::Property);
+ objectToWrite->nAliases = o->aliasCount();
+ objectToWrite->offsetToAliases = nextOffset;
+ nextOffset += objectToWrite->nAliases * sizeof(QV4::CompiledData::Alias);
+
objectToWrite->nSignals = o->signalCount();
objectToWrite->offsetToSignals = nextOffset;
nextOffset += objectToWrite->nSignals * sizeof(quint32);
@@ -1382,9 +1449,13 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
objectToWrite->offsetToBindings = nextOffset;
nextOffset += objectToWrite->nBindings * sizeof(QV4::CompiledData::Binding);
+ objectToWrite->nNamedObjectsInComponent = o->namedObjectsInComponent.count;
+ objectToWrite->offsetToNamedObjectsInComponent = nextOffset;
+ nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32);
+
quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions);
for (const Function *f = o->firstFunction(); f; f = f->next)
- *functionsTable++ = o->runtimeFunctionIndices->at(f->index);
+ *functionsTable++ = o->runtimeFunctionIndices.at(f->index);
char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
for (const Property *p = o->firstProperty(); p; p = p->next) {
@@ -1393,6 +1464,13 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
propertiesPtr += sizeof(QV4::CompiledData::Property);
}
+ char *aliasesPtr = objectPtr + objectToWrite->offsetToAliases;
+ for (const Alias *a = o->firstAlias(); a; a = a->next) {
+ QV4::CompiledData::Alias *aliasToWrite = reinterpret_cast<QV4::CompiledData::Alias*>(aliasesPtr);
+ *aliasToWrite = *a;
+ aliasesPtr += sizeof(QV4::CompiledData::Alias);
+ }
+
char *bindingPtr = objectPtr + objectToWrite->offsetToBindings;
bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingNoAlias);
bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isSignalHandler);
@@ -1421,7 +1499,12 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
signalPtr += size;
}
- objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount());
+ quint32 *namedObjectInComponentPtr = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToNamedObjectsInComponent);
+ for (int i = 0; i < o->namedObjectsInComponent.count; ++i) {
+ *namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i);
+ }
+
+ objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
objectPtr += signalTableSize;
}
@@ -1438,7 +1521,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
return qmlUnit;
}
-char *QmlUnitGenerator::writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const
+char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const
{
for (const Binding *b = o->firstBinding(); b; b = b->next) {
if (!(b->*(filter))())
@@ -1446,7 +1529,7 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, Object *o, BindingFilter
QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
*bindingToWrite = *b;
if (b->type == QV4::CompiledData::Binding::Type_Script)
- bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices->at(b->value.compiledScriptIndex);
+ bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices.at(b->value.compiledScriptIndex);
bindingPtr += sizeof(QV4::CompiledData::Binding);
}
return bindingPtr;
@@ -1614,7 +1697,7 @@ static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
if (tdata->isComplete()) {
auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
newResolver->owner = resolver->owner;
- initMetaObjectResolver(newResolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId));
+ initMetaObjectResolver(newResolver, qmlEngine->propertyCacheForType(tdata->compilationUnit()->metaTypeId));
newResolver->flags |= AllPropertiesAreFinal;
return newResolver->resolveMember(qmlEngine, newResolver, member);
}
@@ -1822,7 +1905,9 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
// Look for IDs first.
foreach (const IdMapping &mapping, _idObjects)
if (name == mapping.name) {
- _function->idObjectDependencies.insert(mapping.idIndex);
+ if (_function->isQmlBinding)
+ _function->idObjectDependencies.insert(mapping.idIndex);
+
QV4::IR::Expr *s = _block->MEMBER(_block->TEMP(_qmlContextTemp), _function->newString(name), 0, QV4::IR::Member::MemberOfIdObjectsArray, mapping.idIndex);
QV4::IR::Temp *result = _block->TEMP(_block->newTemp());
_block->MOVE(result, s);
@@ -1907,7 +1992,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
#ifndef V4_BOOTSTRAP
-QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, RevisionCheck check)
+QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, RevisionCheck check) const
{
if (notInRevision) *notInRevision = false;
@@ -1926,7 +2011,7 @@ QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRev
}
-QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision)
+QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision) const
{
if (notInRevision) *notInRevision = false;
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 057ed1be9f..821a6bba6d 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -113,7 +113,7 @@ struct PoolList
T *insertPos = 0;
for (T *it = first; it; it = it->next) {
- if (!(it->*sortMember < item->*sortMember))
+ if (!(it->*sortMember <= item->*sortMember))
break;
insertPos = it;
}
@@ -161,6 +161,43 @@ struct PoolList
}
return result;
}
+
+ struct Iterator {
+ T *ptr;
+
+ explicit Iterator(T *p) : ptr(p) {}
+
+ T *operator->() {
+ return ptr;
+ }
+
+ const T *operator->() const {
+ return ptr;
+ }
+
+ T &operator*() {
+ return *ptr;
+ }
+
+ const T &operator*() const {
+ return *ptr;
+ }
+
+ void operator++() {
+ ptr = ptr->next;
+ }
+
+ bool operator==(const Iterator &rhs) const {
+ return ptr == rhs.ptr;
+ }
+
+ bool operator!=(const Iterator &rhs) const {
+ return ptr != rhs.ptr;
+ }
+ };
+
+ Iterator begin() { return Iterator(first); }
+ Iterator end() { return Iterator(nullptr); }
};
template <typename T>
@@ -170,7 +207,18 @@ class FixedPoolArray
public:
int count;
- void init(QQmlJS::MemoryPool *pool, const QVector<T> &vector)
+ FixedPoolArray()
+ : data(0)
+ , count(0)
+ {}
+
+ void allocate(QQmlJS::MemoryPool *pool, int size)
+ {
+ count = size;
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+ }
+
+ void allocate(QQmlJS::MemoryPool *pool, const QVector<T> &vector)
{
count = vector.count();
data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
@@ -183,6 +231,16 @@ public:
}
}
+ template <typename Container>
+ void allocate(QQmlJS::MemoryPool *pool, const Container &container)
+ {
+ count = container.count();
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+ typename Container::ConstIterator it = container.constBegin();
+ for (int i = 0; i < count; ++i)
+ new (data + i) T(*it++);
+ }
+
const T &at(int index) const {
Q_ASSERT(index >= 0 && index < count);
return data[index];
@@ -200,6 +258,9 @@ public:
return i;
return -1;
}
+
+ const T *begin() const { return data; }
+ const T *end() const { return data + count; }
};
struct Object;
@@ -217,6 +278,10 @@ struct Signal
QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const;
+ int parameterCount() const { return parameters->count; }
+ PoolList<SignalParameter>::Iterator parametersBegin() const { return parameters->begin(); }
+ PoolList<SignalParameter>::Iterator parametersEnd() const { return parameters->end(); }
+
Signal *next;
};
@@ -227,16 +292,32 @@ struct Property : public QV4::CompiledData::Property
struct Binding : public QV4::CompiledData::Binding
{
+ // The offset in the source file where the binding appeared. This is used for sorting to ensure
+ // that assignments to list properties are done in the correct order. We use the offset here instead
+ // of Binding::location as the latter has limited precision.
+ quint32 offset;
// Binding's compiledScriptIndex is index in object's functionsAndExpressions
Binding *next;
};
+struct Alias : public QV4::CompiledData::Alias
+{
+ Alias *next;
+};
+
struct Function
{
QQmlJS::AST::FunctionDeclaration *functionDeclaration;
QV4::CompiledData::Location location;
int nameIndex;
quint32 index; // index in parsedQML::functions
+ FixedPoolArray<int> formals;
+
+ // --- QQmlPropertyCacheCreator interface
+ const int *formalsBegin() const { return formals.begin(); }
+ const int *formalsEnd() const { return formals.end(); }
+ // ---
+
Function *next;
};
@@ -265,14 +346,19 @@ struct Q_QML_PRIVATE_EXPORT Object
Q_DECLARE_TR_FUNCTIONS(Object)
public:
quint32 inheritedTypeNameIndex;
- quint32 idIndex;
- int indexOfDefaultProperty;
+ quint32 idNameIndex;
+ int id;
+ int indexOfDefaultPropertyOrAlias;
+ bool defaultPropertyIsAlias;
+ quint32 flags;
QV4::CompiledData::Location location;
QV4::CompiledData::Location locationOfIdProperty;
const Property *firstProperty() const { return properties->first; }
int propertyCount() const { return properties->count; }
+ Alias *firstAlias() const { return aliases->first; }
+ int aliasCount() const { return aliases->count; }
const Signal *firstSignal() const { return qmlSignals->first; }
int signalCount() const { return qmlSignals->count; }
Binding *firstBinding() const { return bindings->first; }
@@ -280,16 +366,28 @@ public:
const Function *firstFunction() const { return functions->first; }
int functionCount() const { return functions->count; }
+ PoolList<Binding>::Iterator bindingsBegin() const { return bindings->begin(); }
+ PoolList<Binding>::Iterator bindingsEnd() const { return bindings->end(); }
+ PoolList<Property>::Iterator propertiesBegin() const { return properties->begin(); }
+ PoolList<Property>::Iterator propertiesEnd() const { return properties->end(); }
+ PoolList<Alias>::Iterator aliasesBegin() const { return aliases->begin(); }
+ PoolList<Alias>::Iterator aliasesEnd() const { return aliases->end(); }
+ PoolList<Signal>::Iterator signalsBegin() const { return qmlSignals->begin(); }
+ PoolList<Signal>::Iterator signalsEnd() const { return qmlSignals->end(); }
+ PoolList<Function>::Iterator functionsBegin() const { return functions->begin(); }
+ PoolList<Function>::Iterator functionsEnd() const { return functions->end(); }
+
// If set, then declarations for this object (and init bindings for these) should go into the
// specified object. Used for declarations inside group properties.
Object *declarationsOverride;
- void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation());
+ void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation());
QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
QString appendSignal(Signal *signal);
QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
+ QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
void appendFunction(QmlIR::Function *f);
QString appendBinding(Binding *b, bool isListBinding);
@@ -299,12 +397,17 @@ public:
QString bindingAsString(Document *doc, int scriptIndex) const;
PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
- FixedPoolArray<int> *runtimeFunctionIndices;
+ FixedPoolArray<int> runtimeFunctionIndices;
+
+ FixedPoolArray<quint32> namedObjectsInComponent;
+ int namedObjectsInComponentCount() const { return namedObjectsInComponent.count; }
+ const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
private:
friend struct IRLoader;
PoolList<Property> *properties;
+ PoolList<Alias> *aliases;
PoolList<Signal> *qmlSignals;
PoolList<Binding> *bindings;
PoolList<Function> *functions;
@@ -330,15 +433,11 @@ struct Q_QML_PRIVATE_EXPORT Document
QList<Pragma*> pragmas;
QQmlJS::AST::UiProgram *program;
int indexOfRootObject;
- QList<Object*> objects;
+ QVector<Object*> objects;
QV4::Compiler::JSUnitGenerator jsGenerator;
quint32 unitFlags;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> javaScriptCompilationUnit;
- QHash<int, QStringList> extraSignalParameters;
-
- QV4::CompiledData::TypeReferenceMap typeReferences;
- void collectTypeReferences();
int registerString(const QString &str) { return jsGenerator.registerString(str); }
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
@@ -410,6 +509,8 @@ public:
void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value);
void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false);
+ bool appendAlias(QQmlJS::AST::UiPublicMember *node);
+
Object *bindingsTarget() const;
bool setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value);
@@ -426,6 +527,7 @@ public:
QString stringAt(int index) const { return jsGenerator->stringForIndex(index); }
static bool isStatementNodeScript(QQmlJS::AST::Statement *statement);
+ static bool isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement);
QList<QQmlJS::DiagnosticMessage> errors;
@@ -433,7 +535,7 @@ public:
QList<const QV4::CompiledData::Import *> _imports;
QList<Pragma*> _pragmas;
- QList<Object*> _objects;
+ QVector<Object*> _objects;
QV4::CompiledData::TypeReferenceMap _typeReferences;
@@ -451,17 +553,17 @@ struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
private:
typedef bool (Binding::*BindingFilter)() const;
- char *writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const;
+ char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const;
};
#ifndef V4_BOOTSTRAP
struct Q_QML_EXPORT PropertyResolver
{
- PropertyResolver(QQmlPropertyCache *cache)
+ PropertyResolver(const QQmlPropertyCache *cache)
: cache(cache)
{}
- QQmlPropertyData *property(int index)
+ QQmlPropertyData *property(int index) const
{
return cache->property(index);
}
@@ -471,12 +573,12 @@ struct Q_QML_EXPORT PropertyResolver
IgnoreRevision
};
- QQmlPropertyData *property(const QString &name, bool *notInRevision = 0, RevisionCheck check = CheckRevision);
+ QQmlPropertyData *property(const QString &name, bool *notInRevision = 0, RevisionCheck check = CheckRevision) const;
// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
- QQmlPropertyData *signal(const QString &name, bool *notInRevision);
+ QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
- QQmlPropertyCache *cache;
+ const QQmlPropertyCache *cache;
};
#endif
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/compiler/qqmlpropertycachecreator.cpp
index 9fcba64038..f8d63ec634 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/compiler/qqmlpropertycachecreator.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -37,24 +37,35 @@
**
****************************************************************************/
-#include "qv4debugging_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4function_p.h"
-#include "qv4instr_moth_p.h"
-#include "qv4runtime_p.h"
-#include "qv4script_p.h"
-#include "qv4identifier_p.h"
-#include "qv4string_p.h"
-#include "qv4objectiterator_p.h"
+#include "qqmlpropertycachecreator_p.h"
-#include <iostream>
-#include <algorithm>
-
-#include <QtCore/QJsonArray>
-#include <QtCore/QJsonDocument>
-#include <QtCore/QJsonValue>
+#include <private/qqmlengine_p.h>
QT_BEGIN_NAMESPACE
+QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0);
+
+QQmlBindingInstantiationContext::QQmlBindingInstantiationContext()
+ : referencingObjectIndex(-1)
+ , instantiatingBinding(nullptr)
+ , instantiatingProperty(nullptr)
+{
+
+}
+
+QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, const QQmlPropertyCache *referencingObjectPropertyCache)
+ : referencingObjectIndex(referencingObjectIndex)
+ , instantiatingBinding(instantiatingBinding)
+ , instantiatingProperty(nullptr)
+{
+ if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ Q_ASSERT(referencingObjectIndex >= 0);
+ Q_ASSERT(referencingObjectPropertyCache);
+ Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
+
+ bool notInRevision = false;
+ instantiatingProperty = QmlIR::PropertyResolver(referencingObjectPropertyCache).property(instantiatingPropertyName, &notInRevision);
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
new file mode 100644
index 0000000000..09a093d911
--- /dev/null
+++ b/src/qml/compiler/qqmlpropertycachecreator_p.h
@@ -0,0 +1,746 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQMLPROPERTYCACHECREATOR_P_H
+#define QQMLPROPERTYCACHECREATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqmltypecompiler_p.h"
+#include <private/qqmlvaluetype_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QQmlBindingInstantiationContext {
+ QQmlBindingInstantiationContext();
+ QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, const QQmlPropertyCache *referencingObjectPropertyCache);
+ int referencingObjectIndex;
+ const QV4::CompiledData::Binding *instantiatingBinding;
+ QQmlPropertyData *instantiatingProperty;
+};
+
+struct QQmlPropertyCacheCreatorBase
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreatorBase)
+public:
+ static QAtomicInt classIndexCounter;
+};
+
+template <typename ObjectContainer>
+class QQmlPropertyCacheCreator : public QQmlPropertyCacheCreatorBase
+{
+public:
+ typedef typename ObjectContainer::CompiledObject CompiledObject;
+
+ QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports);
+
+ QQmlCompileError buildMetaObjects();
+
+protected:
+ QQmlCompileError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
+ QQmlPropertyCache *propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const;
+ QQmlCompileError createMetaObject(int objectIndex, const CompiledObject *obj, QQmlPropertyCache *baseTypeCache);
+
+ QString stringAt(int index) const { return objectContainer->stringAt(index); }
+
+ QQmlEnginePrivate * const enginePrivate;
+ const ObjectContainer * const objectContainer;
+ const QQmlImports * const imports;
+ QQmlPropertyCacheVector *propertyCaches;
+};
+
+template <typename ObjectContainer>
+inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports)
+ : enginePrivate(enginePrivate)
+ , objectContainer(objectContainer)
+ , imports(imports)
+ , propertyCaches(propertyCaches)
+{
+ propertyCaches->resize(objectContainer->objectCount());
+}
+
+template <typename ObjectContainer>
+inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
+{
+ QQmlBindingInstantiationContext context;
+ return buildMetaObjectRecursively(objectContainer->rootObjectIndex(), context);
+}
+
+template <typename ObjectContainer>
+inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
+{
+ const CompiledObject *obj = objectContainer->objectAt(objectIndex);
+
+ bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
+ if (!needVMEMetaObject) {
+ for (auto binding = obj->bindingsBegin(), end = obj->bindingsEnd(); binding != end; ++binding) {
+ if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+ // If the on assignment is inside a group property, we need to distinguish between QObject based
+ // 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 (context.instantiatingProperty && QQmlValueTypeFactory::isValueType(context.instantiatingProperty->propType)) {
+ if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
+ const CompiledObject *obj = objectContainer->objectAt(context.referencingObjectIndex);
+ auto *typeRef = objectContainer->resolvedTypes.value(obj->inheritedTypeNameIndex);
+ Q_ASSERT(typeRef);
+ QQmlPropertyCache *baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ QQmlCompileError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
+ if (error.isSet())
+ return error;
+ }
+ } else {
+ // On assignments are implemented using value interceptors, which require a VME meta object.
+ needVMEMetaObject = true;
+ }
+ break;
+ }
+ }
+ }
+
+ QQmlPropertyCache *baseTypeCache;
+ {
+ QQmlCompileError error;
+ baseTypeCache = propertyCacheForObject(obj, context, &error);
+ if (error.isSet())
+ return error;
+ }
+
+ if (baseTypeCache) {
+ if (needVMEMetaObject) {
+ QQmlCompileError error = createMetaObject(objectIndex, obj, baseTypeCache);
+ if (error.isSet())
+ return error;
+ } else {
+ propertyCaches->set(objectIndex, baseTypeCache);
+ }
+ }
+
+ if (QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex)) {
+ for (auto binding = obj->bindingsBegin(), end = obj->bindingsEnd(); binding != end; ++binding)
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
+ QQmlCompileError error = buildMetaObjectRecursively(binding->value.objectIndex, context);
+ if (error.isSet())
+ return error;
+ }
+ }
+
+ QQmlCompileError noError;
+ return noError;
+}
+
+template <typename ObjectContainer>
+inline QQmlPropertyCache *QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const
+{
+ if (context.instantiatingProperty) {
+ if (context.instantiatingProperty->isQObject()) {
+ return enginePrivate->rawPropertyCacheForType(context.instantiatingProperty->propType);
+ } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(context.instantiatingProperty->propType)) {
+ return enginePrivate->cache(vtmo);
+ }
+ } else if (obj->inheritedTypeNameIndex != 0) {
+ auto *typeRef = objectContainer->resolvedTypes.value(obj->inheritedTypeNameIndex);
+ Q_ASSERT(typeRef);
+
+ if (typeRef->isFullyDynamicType) {
+ if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
+ *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties."));
+ return nullptr;
+ }
+ if (obj->signalCount() > 0) {
+ *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals."));
+ return nullptr;
+ }
+ if (obj->functionCount() > 0) {
+ *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions."));
+ return nullptr;
+ }
+ }
+
+ return typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ } else if (context.instantiatingBinding && context.instantiatingBinding->isAttachedProperty()) {
+ auto *typeRef = objectContainer->resolvedTypes.value(context.instantiatingBinding->propertyNameIndex);
+ Q_ASSERT(typeRef);
+ QQmlType *qmltype = typeRef->type;
+ if (!qmltype) {
+ QString propertyName = stringAt(context.instantiatingBinding->propertyNameIndex);
+ if (imports->resolveType(propertyName, &qmltype, 0, 0, 0)) {
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ auto compilationUnit = tdata->compilationUnit();
+ qmltype = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
+
+ tdata->release();
+ }
+ }
+ }
+
+ const QMetaObject *attachedMo = qmltype ? qmltype->attachedPropertiesType(enginePrivate) : 0;
+ if (!attachedMo) {
+ *error = QQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
+ return nullptr;
+ }
+ return enginePrivate->cache(attachedMo);
+ }
+ return nullptr;
+}
+
+template <typename ObjectContainer>
+inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, QQmlPropertyCache *baseTypeCache)
+{
+ QQmlRefPointer<QQmlPropertyCache> cache;
+ cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
+ obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
+ obj->signalCount() + obj->propertyCount() + obj->aliasCount()));
+
+ propertyCaches->set(objectIndex, cache);
+ propertyCaches->setNeedsVMEMetaObject(objectIndex);
+
+ struct TypeData {
+ QV4::CompiledData::Property::Type dtype;
+ int metaType;
+ } builtinTypes[] = {
+ { QV4::CompiledData::Property::Var, QMetaType::QVariant },
+ { QV4::CompiledData::Property::Variant, QMetaType::QVariant },
+ { QV4::CompiledData::Property::Int, QMetaType::Int },
+ { QV4::CompiledData::Property::Bool, QMetaType::Bool },
+ { QV4::CompiledData::Property::Real, QMetaType::Double },
+ { QV4::CompiledData::Property::String, QMetaType::QString },
+ { QV4::CompiledData::Property::Url, QMetaType::QUrl },
+ { QV4::CompiledData::Property::Color, QMetaType::QColor },
+ { QV4::CompiledData::Property::Font, QMetaType::QFont },
+ { QV4::CompiledData::Property::Time, QMetaType::QTime },
+ { QV4::CompiledData::Property::Date, QMetaType::QDate },
+ { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
+ { QV4::CompiledData::Property::Rect, QMetaType::QRectF },
+ { QV4::CompiledData::Property::Point, QMetaType::QPointF },
+ { QV4::CompiledData::Property::Size, QMetaType::QSizeF },
+ { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
+ { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
+ { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
+ { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
+ { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
+};
+ static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
+
+ QByteArray newClassName;
+
+ if (objectIndex == objectContainer->rootObjectIndex()) {
+ const QString path = objectContainer->url().path();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash > -1) {
+ const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
+ if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
+ newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
+ QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
+ }
+ }
+ if (newClassName.isEmpty()) {
+ newClassName = QQmlMetaObject(baseTypeCache).className();
+ newClassName.append("_QML_");
+ newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
+ }
+
+ cache->_dynamicClassName = newClassName;
+
+ int varPropCount = 0;
+
+ QmlIR::PropertyResolver resolver(baseTypeCache);
+
+ for (auto p = obj->propertiesBegin(), end = obj->propertiesEnd(); p != end; ++p) {
+ if (p->type == QV4::CompiledData::Property::Var)
+ varPropCount++;
+
+ bool notInRevision = false;
+ QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
+ if (d && d->isFinal())
+ return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
+ }
+
+ for (auto a = obj->aliasesBegin(), end = obj->aliasesEnd(); a != end; ++a) {
+ bool notInRevision = false;
+ QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
+ if (d && d->isFinal())
+ return QQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
+ }
+
+ int effectivePropertyIndex = cache->propertyIndexCacheStart;
+ int effectiveMethodIndex = cache->methodIndexCacheStart;
+
+ // For property change signal override detection.
+ // We prepopulate a set of signal names which already exist in the object,
+ // and throw an error if there is a signal/method defined as an override.
+ QSet<QString> seenSignals;
+ seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
+ QQmlPropertyCache *parentCache = cache;
+ while ((parentCache = parentCache->parent())) {
+ if (int pSigCount = parentCache->signalCount()) {
+ int pSigOffset = parentCache->signalOffset();
+ for (int i = pSigOffset; i < pSigCount; ++i) {
+ QQmlPropertyData *currPSig = parentCache->signal(i);
+ // XXX TODO: find a better way to get signal name from the property data :-/
+ for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
+ iter != parentCache->stringCache.end(); ++iter) {
+ if (currPSig == (*iter).second) {
+ seenSignals.insert(iter.key());
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Set up notify signals for properties - first normal, then alias
+ for (auto p = obj->propertiesBegin(), end = obj->propertiesEnd(); p != end; ++p) {
+ quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
+ QQmlPropertyData::IsVMESignal;
+
+ QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
+ seenSignals.insert(changedSigName);
+
+ cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
+ }
+
+ for (auto a = obj->aliasesBegin(), end = obj->aliasesEnd(); a != end; ++a) {
+ quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
+ QQmlPropertyData::IsVMESignal;
+
+ QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
+ seenSignals.insert(changedSigName);
+
+ cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
+ }
+
+ // Dynamic signals
+ for (auto s = obj->signalsBegin(), end = obj->signalsEnd(); s != end; ++s) {
+ const int paramCount = s->parameterCount();
+
+ QList<QByteArray> names;
+ names.reserve(paramCount);
+ QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
+
+ if (paramCount) {
+ paramTypes[0] = paramCount;
+
+ int i = 0;
+ for (auto param = s->parametersBegin(), end = s->parametersEnd(); param != end; ++param, ++i) {
+ names.append(stringAt(param->nameIndex).toUtf8());
+ if (param->type < builtinTypeCount) {
+ // built-in type
+ paramTypes[i + 1] = builtinTypes[param->type].metaType;
+ } else {
+ // lazily resolved type
+ Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
+ const QString customTypeName = stringAt(param->customTypeNameIndex);
+ QQmlType *qmltype = 0;
+ if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0))
+ return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
+
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ auto compilationUnit = tdata->compilationUnit();
+
+ paramTypes[i + 1] = compilationUnit->metaTypeId;
+
+ tdata->release();
+ } else {
+ paramTypes[i + 1] = qmltype->typeId();
+ }
+ }
+ }
+ }
+
+ quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
+ QQmlPropertyData::IsVMESignal;
+ if (paramCount)
+ flags |= QQmlPropertyData::HasArguments;
+
+ QString signalName = stringAt(s->nameIndex);
+ if (seenSignals.contains(signalName))
+ return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
+ seenSignals.insert(signalName);
+
+ cache->appendSignal(signalName, flags, effectiveMethodIndex++,
+ paramCount?paramTypes.constData():0, names);
+ }
+
+
+ // Dynamic slots
+ for (auto function = objectContainer->objectFunctionsBegin(obj), end = objectContainer->objectFunctionsEnd(obj); function != end; ++function) {
+ quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
+
+ const QString slotName = stringAt(function->nameIndex);
+ if (seenSignals.contains(slotName))
+ return QQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal"));
+ // Note: we don't append slotName to the seenSignals list, since we don't
+ // protect against overriding change signals or methods with properties.
+
+ QList<QByteArray> parameterNames;
+ for (auto formal = function->formalsBegin(), end = function->formalsEnd(); formal != end; ++formal) {
+ flags |= QQmlPropertyData::HasArguments;
+ parameterNames << stringAt(*formal).toUtf8();
+ }
+
+ cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
+ }
+
+
+ // Dynamic properties
+ int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
+ int propertyIdx = 0;
+ for (auto p = obj->propertiesBegin(), end = obj->propertiesEnd(); p != end; ++p, ++propertyIdx) {
+ int propertyType = 0;
+ quint32 propertyFlags = 0;
+
+ if (p->type == QV4::CompiledData::Property::Var) {
+ propertyType = QMetaType::QVariant;
+ propertyFlags = QQmlPropertyData::IsVarProperty;
+ } else if (p->type < builtinTypeCount) {
+ propertyType = builtinTypes[p->type].metaType;
+
+ if (p->type == QV4::CompiledData::Property::Variant)
+ propertyFlags |= QQmlPropertyData::IsQVariant;
+ } else {
+ Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
+ p->type == QV4::CompiledData::Property::Custom);
+
+ QQmlType *qmltype = 0;
+ if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) {
+ return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
+ }
+
+ Q_ASSERT(qmltype);
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ auto compilationUnit = tdata->compilationUnit();
+
+ if (p->type == QV4::CompiledData::Property::Custom) {
+ propertyType = compilationUnit->metaTypeId;
+ } else {
+ propertyType = compilationUnit->listMetaTypeId;
+ }
+
+ tdata->release();
+ } else {
+ if (p->type == QV4::CompiledData::Property::Custom) {
+ propertyType = qmltype->typeId();
+ } else {
+ propertyType = qmltype->qListTypeId();
+ }
+ }
+
+ if (p->type == QV4::CompiledData::Property::Custom)
+ propertyFlags |= QQmlPropertyData::IsQObjectDerived;
+ else
+ propertyFlags |= QQmlPropertyData::IsQList;
+ }
+
+ if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
+ propertyFlags |= QQmlPropertyData::IsWritable;
+
+
+ QString propertyName = stringAt(p->nameIndex);
+ if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
+ cache->_defaultPropertyName = propertyName;
+ cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
+ propertyType, effectiveSignalIndex);
+
+ effectiveSignalIndex++;
+ }
+
+ QQmlCompileError noError;
+ return noError;
+}
+
+template <typename ObjectContainer>
+class QQmlPropertyCacheAliasCreator
+{
+public:
+ typedef typename ObjectContainer::CompiledObject CompiledObject;
+
+ QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
+
+ void appendAliasPropertiesToMetaObjects();
+
+ void appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex);
+
+private:
+ void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex);
+ void propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, quint32 *propertyFlags);
+
+ void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
+
+ int objectForId(const CompiledObject &component, int id) const;
+
+ QQmlPropertyCacheVector *propertyCaches;
+ const ObjectContainer *objectContainer;
+};
+
+template <typename ObjectContainer>
+inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
+ : propertyCaches(propertyCaches)
+ , objectContainer(objectContainer)
+{
+
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects()
+{
+ for (int i = 0; i < objectContainer->objectCount(); ++i) {
+ const CompiledObject &component = *objectContainer->objectAt(i);
+ if (!(component.flags & QV4::CompiledData::Object::IsComponent))
+ continue;
+
+ const auto rootBinding = component.bindingsBegin();
+ appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex);
+ }
+
+ const int rootObjectIndex = objectContainer->rootObjectIndex();
+ appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex);
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex)
+{
+ QVector<int> objectsWithAliases;
+ collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
+ if (objectsWithAliases.isEmpty())
+ return;
+
+ const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) {
+ for (auto alias = object.aliasesBegin(), end = object.aliasesEnd(); alias != end; ++alias) {
+ Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+
+ const int targetObjectIndex = objectForId(component, alias->targetObjectId);
+ Q_ASSERT(targetObjectIndex >= 0);
+
+ if (alias->encodedMetaPropertyIndex == -1)
+ continue;
+
+ const QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
+ Q_ASSERT(targetCache);
+
+ int coreIndex;
+ QQmlPropertyData::decodeValueTypePropertyIndex(alias->encodedMetaPropertyIndex, &coreIndex);
+ QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
+ if (!targetProperty)
+ return false;
+ }
+ return true;
+ };
+
+ do {
+ QVector<int> pendingObjects;
+
+ for (int objectIndex: qAsConst(objectsWithAliases)) {
+ const CompiledObject &object = *objectContainer->objectAt(objectIndex);
+
+ if (allAliasTargetsExist(object)) {
+ appendAliasesToPropertyCache(component, objectIndex);
+ } else {
+ pendingObjects.append(objectIndex);
+ }
+
+ }
+ qSwap(objectsWithAliases, pendingObjects);
+ } while (!objectsWithAliases.isEmpty());
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const
+{
+ const CompiledObject &object = *objectContainer->objectAt(objectIndex);
+ if (object.aliasCount() > 0)
+ objectsWithAliases->append(objectIndex);
+
+ // Stop at Component boundary
+ if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != objectContainer->rootObjectIndex())
+ return;
+
+ for (auto binding = object.bindingsBegin(), end = object.bindingsEnd(); binding != end; ++binding) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Object
+ && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
+ && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
+ continue;
+
+ collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
+ }
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, quint32 *propertyFlags)
+{
+ const int targetObjectIndex = objectForId(component, alias.targetObjectId);
+ Q_ASSERT(targetObjectIndex >= 0);
+
+ const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
+
+ *type = 0;
+ bool writable = false;
+ bool resettable = false;
+
+ *propertyFlags = QQmlPropertyData::IsAlias;
+
+ if (alias.aliasToLocalAlias) {
+ auto targetAlias = targetObject.aliasesBegin();
+ for (uint i = 0; i < alias.localAliasIndex; ++i)
+ ++targetAlias;
+ propertyDataForAlias(component, *targetAlias, type, propertyFlags);
+ return;
+ } else if (alias.encodedMetaPropertyIndex == -1) {
+ Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
+ auto *typeRef = objectContainer->resolvedTypes.value(targetObject.inheritedTypeNameIndex);
+ Q_ASSERT(typeRef);
+
+ if (typeRef->type)
+ *type = typeRef->type->typeId();
+ else
+ *type = typeRef->compilationUnit->metaTypeId;
+
+ *propertyFlags |= QQmlPropertyData::IsQObjectDerived;
+ } else {
+ int coreIndex;
+ int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(alias.encodedMetaPropertyIndex, &coreIndex);
+
+ QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
+ Q_ASSERT(targetCache);
+ QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
+ Q_ASSERT(targetProperty);
+
+ *type = targetProperty->propType;
+
+ writable = targetProperty->isWritable();
+ resettable = targetProperty->isResettable();
+
+ if (valueTypeIndex != -1) {
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
+ if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
+ *type = QVariant::Int;
+ else
+ *type = valueTypeMetaObject->property(valueTypeIndex).userType();
+ } else {
+ if (targetProperty->isEnum()) {
+ *type = QVariant::Int;
+ } else {
+ // Copy type flags
+ *propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask;
+
+ if (targetProperty->isVarProperty())
+ *propertyFlags |= QQmlPropertyData::IsQVariant;
+ }
+ }
+ }
+
+ if (!(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable)
+ *propertyFlags |= QQmlPropertyData::IsWritable;
+ else
+ *propertyFlags &= ~QQmlPropertyData::IsWritable;
+
+ if (resettable)
+ *propertyFlags |= QQmlPropertyData::IsResettable;
+ else
+ *propertyFlags &= ~QQmlPropertyData::IsResettable;
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex)
+{
+ const CompiledObject &object = *objectContainer->objectAt(objectIndex);
+ if (!object.aliasCount())
+ return;
+
+ QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
+ Q_ASSERT(propertyCache);
+
+ int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
+ int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
+
+ int aliasIndex = 0;
+ for (auto alias = object.aliasesBegin(), end = object.aliasesEnd(); alias != end; ++alias, ++aliasIndex) {
+ Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+
+ int type = 0;
+ quint32 propertyFlags = 0;
+ propertyDataForAlias(component, *alias, &type, &propertyFlags);
+
+ const QString propertyName = objectContainer->stringAt(alias->nameIndex);
+
+ if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias)
+ propertyCache->_defaultPropertyName = propertyName;
+
+ propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
+ type, effectiveSignalIndex++);
+ }
+}
+
+template <typename ObjectContainer>
+inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const
+{
+ for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
+ const int candidateIndex = component.namedObjectsInComponentTable()[i];
+ const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
+ if (candidate.id == id)
+ return candidateIndex;
+ }
+ return -1;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYCACHECREATOR_P_H
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
new file mode 100644
index 0000000000..c644330e97
--- /dev/null
+++ b/src/qml/compiler/qqmlpropertyvalidator.cpp
@@ -0,0 +1,703 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlpropertyvalidator_p.h"
+
+#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, QV4::CompiledData::CompilationUnit *compilationUnit)
+ : enginePrivate(enginePrivate)
+ , imports(imports)
+ , qmlUnit(compilationUnit->data)
+ , resolvedTypes(compilationUnit->resolvedTypes)
+ , propertyCaches(compilationUnit->propertyCaches)
+ , bindingPropertyDataPerObject(&compilationUnit->bindingPropertyDataPerObject)
+{
+ bindingPropertyDataPerObject->resize(qmlUnit->nObjects);
+}
+
+QVector<QQmlCompileError> QQmlPropertyValidator::validate()
+{
+ return validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0);
+}
+
+typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector;
+
+struct BindingFinder
+{
+ bool operator()(quint32 name, const QV4::CompiledData::Binding *binding) const
+ {
+ return name < binding->propertyNameIndex;
+ }
+ bool operator()(const QV4::CompiledData::Binding *binding, quint32 name) const
+ {
+ return binding->propertyNameIndex < name;
+ }
+ bool operator()(const QV4::CompiledData::Binding *lhs, const QV4::CompiledData::Binding *rhs) const
+ {
+ return lhs->propertyNameIndex < rhs->propertyNameIndex;
+ }
+};
+
+QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
+{
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
+
+ if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ 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);
+ if (!propertyCache)
+ return QVector<QQmlCompileError>();
+
+ QStringList deferredPropertyNames;
+ {
+ const QMetaObject *mo = propertyCache->firstCppMetaObject();
+ const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
+ if (namesIndex != -1) {
+ QMetaClassInfo classInfo = mo->classInfo(namesIndex);
+ deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
+ }
+ }
+
+ QQmlCustomParser *customParser = 0;
+ if (auto typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ if (typeRef->type)
+ customParser = typeRef->type->customParser();
+ }
+
+ QList<const QV4::CompiledData::Binding*> customBindings;
+
+ // Collect group properties first for sanity checking
+ // vector values are sorted by property name string index.
+ GroupPropertyVector groupProperties;
+ const QV4::CompiledData::Binding *binding = obj->bindingTable();
+ for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
+ if (!binding->isGroupProperty())
+ continue;
+
+ if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ continue;
+
+ if (populatingValueTypeGroupProperty) {
+ return recordError(binding->location, tr("Property assignment expected"));
+ }
+
+ GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
+ groupProperties.insert(pos, binding);
+ }
+
+ QmlIR::PropertyResolver propertyResolver(propertyCache);
+
+ QString defaultPropertyName;
+ QQmlPropertyData *defaultProperty = 0;
+ if (obj->indexOfDefaultPropertyOrAlias != -1) {
+ QQmlPropertyCache *cache = propertyCache->parent();
+ defaultPropertyName = cache->defaultPropertyName();
+ defaultProperty = cache->defaultProperty();
+ } else {
+ defaultPropertyName = propertyCache->defaultPropertyName();
+ defaultProperty = propertyCache->defaultProperty();
+ }
+
+ QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
+
+ binding = obj->bindingTable();
+ for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
+ QString name = stringAt(binding->propertyNameIndex);
+
+ if (customParser) {
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
+ customBindings << binding;
+ continue;
+ }
+ } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
+ && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
+ customBindings << binding;
+ continue;
+ }
+ }
+
+ bool bindingToDefaultProperty = false;
+ bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
+
+ bool notInRevision = false;
+ QQmlPropertyData *pd = 0;
+ if (!name.isEmpty()) {
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ pd = propertyResolver.signal(name, &notInRevision);
+ else
+ pd = propertyResolver.property(name, &notInRevision, isGroupProperty ? QmlIR::PropertyResolver::IgnoreRevision : QmlIR::PropertyResolver::CheckRevision);
+
+ if (notInRevision) {
+ QString typeName = stringAt(obj->inheritedTypeNameIndex);
+ auto *objectType = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ if (objectType && objectType->type) {
+ return recordError(binding->location, 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 {
+ return recordError(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
+ }
+ }
+ } else {
+ if (isGroupProperty)
+ return recordError(binding->location, tr("Cannot assign a value directly to a grouped property"));
+
+ pd = defaultProperty;
+ name = defaultPropertyName;
+ bindingToDefaultProperty = true;
+ }
+
+ if (pd)
+ collectedBindingPropertyData[i] = pd;
+
+ if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
+ QQmlType *type = 0;
+ QQmlImportNamespace *typeNamespace = 0;
+ imports.resolveType(stringAt(binding->propertyNameIndex), &type, 0, 0, &typeNamespace);
+ if (typeNamespace)
+ return recordError(binding->location, tr("Invalid use of namespace"));
+ return recordError(binding->location, tr("Invalid attached object assignment"));
+ }
+
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
+ const QVector<QQmlCompileError> subObjectValidatorErrors = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType));
+ if (!subObjectValidatorErrors.isEmpty())
+ return subObjectValidatorErrors;
+ }
+
+ // 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;
+
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
+ return recordError(binding->location, tr("Attached properties cannot be used here"));
+ }
+ continue;
+ }
+
+ if (pd) {
+ GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
+ const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex);
+
+ if (!pd->isWritable()
+ && !pd->isQList()
+ && !binding->isGroupProperty()
+ && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+ ) {
+
+ if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
+ return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
+ return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
+ }
+
+ 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");
+ return recordError(binding->valueLocation, error);
+ }
+
+ if (!bindingToDefaultProperty
+ && !binding->isGroupProperty()
+ && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ && assigningToGroupProperty) {
+ QV4::CompiledData::Location loc = binding->valueLocation;
+ if (loc < (*assignedGroupProperty)->valueLocation)
+ loc = (*assignedGroupProperty)->valueLocation;
+
+ if (pd && QQmlValueTypeFactory::isValueType(pd->propType))
+ return recordError(loc, tr("Property has already been assigned a value"));
+ return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
+ }
+
+ if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ QQmlCompileError bindingError = validateLiteralBinding(propertyCache, pd, binding);
+ if (bindingError.isSet())
+ return recordError(bindingError);
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ QQmlCompileError bindingError = validateObjectBinding(pd, name, binding);
+ if (bindingError.isSet())
+ return recordError(bindingError);
+ } else if (binding->isGroupProperty()) {
+ if (QQmlValueTypeFactory::isValueType(pd->propType)) {
+ if (QQmlValueTypeFactory::metaObjectForMetaType(pd->propType)) {
+ if (!pd->isWritable()) {
+ return recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
+ }
+ } else {
+ return recordError(binding->location, tr("Invalid grouped property access"));
+ }
+ } else {
+ if (!enginePrivate->propertyCacheForType(pd->propType)) {
+ return recordError(binding->location, tr("Invalid grouped property access"));
+ }
+ }
+ }
+ } else {
+ if (customParser) {
+ customBindings << binding;
+ continue;
+ }
+ if (bindingToDefaultProperty) {
+ return recordError(binding->location, tr("Cannot assign to non-existent default property"));
+ } else {
+ return recordError(binding->location, tr("Cannot assign to non-existent property \"%1\"").arg(name));
+ }
+ }
+ }
+
+ if (obj->idNameIndex) {
+ bool notInRevision = false;
+ collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision);
+ }
+
+ if (customParser && !customBindings.isEmpty()) {
+ customParser->clearErrors();
+ customParser->validator = this;
+ customParser->engine = enginePrivate;
+ customParser->imports = &imports;
+ customParser->verifyBindings(qmlUnit, customBindings);
+ customParser->validator = 0;
+ customParser->engine = 0;
+ customParser->imports = (QQmlImports*)0;
+ QVector<QQmlCompileError> parserErrors = customParser->errors();
+ if (!parserErrors.isEmpty())
+ return parserErrors;
+ }
+
+ (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
+
+ QVector<QQmlCompileError> noError;
+ return noError;
+}
+
+QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
+{
+ if (property->isQList()) {
+ return QQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
+ }
+
+ QQmlCompileError noError;
+
+ if (property->isEnum()) {
+ if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
+ return noError;
+
+ QString value = binding->valueAsString(qmlUnit);
+ 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) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
+ }
+ return noError;
+ }
+
+ switch (property->propType) {
+ case QMetaType::QVariant:
+ break;
+ case QVariant::String: {
+ if (!binding->evaluatesToString()) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string expected"));
+ }
+ }
+ break;
+ case QVariant::StringList: {
+ if (!binding->evaluatesToString()) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or string list expected"));
+ }
+ }
+ break;
+ case QVariant::ByteArray: {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: byte array expected"));
+ }
+ }
+ break;
+ case QVariant::Url: {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url expected"));
+ }
+ }
+ break;
+ case QVariant::UInt: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double d = binding->valueAsNumber();
+ if (double(uint(d)) == d)
+ return noError;
+ }
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected"));
+ }
+ break;
+ case QVariant::Int: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double d = binding->valueAsNumber();
+ if (double(int(d)) == d)
+ return noError;
+ }
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: int expected"));
+ }
+ break;
+ case QMetaType::Float: {
+ if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+ }
+ }
+ break;
+ case QVariant::Double: {
+ if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+ }
+ }
+ break;
+ case QVariant::Color: {
+ bool ok = false;
+ QQmlStringConverters::rgbaFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: color expected"));
+ }
+ }
+ break;
+#ifndef QT_NO_DATESTRING
+ case QVariant::Date: {
+ bool ok = false;
+ QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: date expected"));
+ }
+ }
+ break;
+ case QVariant::Time: {
+ bool ok = false;
+ QQmlStringConverters::timeFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: time expected"));
+ }
+ }
+ break;
+ case QVariant::DateTime: {
+ bool ok = false;
+ QQmlStringConverters::dateTimeFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: datetime expected"));
+ }
+ }
+ break;
+#endif // QT_NO_DATESTRING
+ case QVariant::Point: {
+ bool ok = false;
+ QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::PointF: {
+ bool ok = false;
+ QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::Size: {
+ bool ok = false;
+ QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+ }
+ }
+ break;
+ case QVariant::SizeF: {
+ bool ok = false;
+ QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+ }
+ }
+ break;
+ case QVariant::Rect: {
+ bool ok = false;
+ QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: rect expected"));
+ }
+ }
+ break;
+ case QVariant::RectF: {
+ bool ok = false;
+ QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::Bool: {
+ if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: boolean expected"));
+ }
+ }
+ break;
+ case QVariant::Vector2D: {
+ struct {
+ float xp;
+ float yp;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected"));
+ }
+ }
+ break;
+ case QVariant::Vector3D: {
+ struct {
+ float xp;
+ float yp;
+ float zy;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected"));
+ }
+ }
+ break;
+ case QVariant::Vector4D: {
+ struct {
+ float xp;
+ float yp;
+ float zy;
+ float wp;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected"));
+ }
+ }
+ break;
+ case QVariant::Quaternion: {
+ struct {
+ float wp;
+ float xp;
+ float yp;
+ float zp;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: quaternion expected"));
+ }
+ }
+ break;
+ case QVariant::RegExp:
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
+ 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) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number or array of numbers expected"));
+ }
+ 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)
+ return QQmlCompileError(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) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected"));
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected"));
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QList<QString> >()) {
+ if (!binding->evaluatesToString()) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected"));
+ }
+ 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) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType))));
+ }
+ }
+ break;
+ }
+ return noError;
+}
+
+/*!
+ Returns true if from can be assigned to a (QObject) property of type
+ to.
+*/
+bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
+{
+ QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
+
+ while (fromMo) {
+ if (fromMo == toMo)
+ return true;
+ fromMo = fromMo->parent();
+ }
+ return false;
+}
+
+QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
+{
+ QVector<QQmlCompileError> errors;
+ errors.append(QQmlCompileError(location, description));
+ return errors;
+}
+
+QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QQmlCompileError &error) const
+{
+ QVector<QQmlCompileError> errors;
+ errors.append(error);
+ return errors;
+}
+
+QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
+{
+ QQmlCompileError noError;
+
+ 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);
+ if (auto *typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex)) {
+ 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) {
+ return QQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName));
+ }
+
+ return noError;
+ }
+
+ if (QQmlMetaType::isInterface(property->propType)) {
+ // Can only check at instantiation time if the created sub-object successfully casts to the
+ // target interface.
+ return noError;
+ } else if (property->propType == QMetaType::QVariant) {
+ // We can convert everything to QVariant :)
+ return noError;
+ } else if (property->isQList()) {
+ const int listType = enginePrivate->listType(property->propType);
+ if (!QQmlMetaType::isInterface(listType)) {
+ QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
+ if (!canCoerce(listType, source)) {
+ return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
+ }
+ }
+ return noError;
+ } else if (qmlUnit->objectAt(binding->value.objectIndex)->flags & QV4::CompiledData::Object::IsComponent) {
+ return noError;
+ } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
+ return noError;
+ } else if (QQmlValueTypeFactory::isValueType(property->propType)) {
+ return QQmlCompileError(binding->location, tr("Unexpected object assignment"));
+ } else if (property->propType == qMetaTypeId<QQmlScriptString>()) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
+ } 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.at(binding->value.objectIndex);
+ while (c && !isAssignable) {
+ isAssignable |= c == propertyMetaObject;
+ c = c->parent();
+ }
+ }
+
+ if (!isAssignable) {
+ return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to property"));
+ }
+ }
+ return noError;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertyvalidator_p.h b/src/qml/compiler/qqmlpropertyvalidator_p.h
new file mode 100644
index 0000000000..d0bd314461
--- /dev/null
+++ b/src/qml/compiler/qqmlpropertyvalidator_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQMLPROPERTYVALIDATOR_P_H
+#define QQMLPROPERTYVALIDATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltypecompiler_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlPropertyValidator
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
+public:
+ QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, QV4::CompiledData::CompilationUnit *compilationUnit);
+
+ QVector<QQmlCompileError> validate();
+
+private:
+ QVector<QQmlCompileError> validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const;
+ QQmlCompileError validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const;
+ QQmlCompileError validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const;
+
+ bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
+
+ QVector<QQmlCompileError> recordError(const QV4::CompiledData::Location &location, const QString &description) const Q_REQUIRED_RESULT;
+ QVector<QQmlCompileError> recordError(const QQmlCompileError &error) const Q_REQUIRED_RESULT;
+ QString stringAt(int index) const { return qmlUnit->stringAt(index); }
+
+ QQmlEnginePrivate *enginePrivate;
+ const QQmlImports &imports;
+ const QV4::CompiledData::Unit *qmlUnit;
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes;
+ const QQmlPropertyCacheVector &propertyCaches;
+
+ QVector<QV4::CompiledData::BindingPropertyData> * const bindingPropertyDataPerObject;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYVALIDATOR_P_H
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index f49996a3b8..a0b219e28e 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -44,9 +44,10 @@
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmlstringconverters_p.h>
#include <private/qv4ssa_p.h>
+#include "qqmlpropertycachecreator_p.h"
+
#define COMPILE_EXCEPTION(token, desc) \
{ \
recordError((token)->location, desc); \
@@ -55,95 +56,35 @@
QT_BEGIN_NAMESPACE
-QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QmlIR::Document *parsedQML)
- : engine(engine)
- , compiledData(compiledData)
+QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
+ QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
+ : resolvedTypes(resolvedTypeCache)
+ , engine(engine)
, typeData(typeData)
+ , importCache(importCache)
, document(parsedQML)
{
}
-bool QQmlTypeCompiler::compile()
+QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
{
- compiledData->importCache = new QQmlTypeNameCache;
-
- foreach (const QString &ns, typeData->namespaces())
- compiledData->importCache->add(ns);
-
- // Add any Composite Singletons that were used to the import cache
- foreach (const QQmlTypeData::TypeReference &singleton, typeData->compositeSingletons())
- compiledData->importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
-
- typeData->imports().populateCache(compiledData->importCache);
-
- const QHash<int, QQmlTypeData::TypeReference> &resolvedTypes = typeData->resolvedTypeRefs();
- for (QHash<int, QQmlTypeData::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd();
- resolvedType != end; ++resolvedType) {
- QScopedPointer<QQmlCompiledData::TypeReference> ref(new QQmlCompiledData::TypeReference);
- QQmlType *qmlType = resolvedType->type;
- if (resolvedType->typeData) {
- if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) {
- QQmlError error;
- QString reason = tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName());
- error.setDescription(reason);
- error.setColumn(resolvedType->location.column);
- error.setLine(resolvedType->location.line);
- recordError(error);
- return false;
- }
- ref->component = resolvedType->typeData->compiledData();
- ref->component->addref();
- } else if (qmlType) {
- ref->type = qmlType;
- Q_ASSERT(ref->type);
-
- if (resolvedType->needsCreation && !ref->type->isCreatable()) {
- QQmlError error;
- QString reason = ref->type->noCreationReason();
- if (reason.isEmpty())
- reason = tr("Element is not creatable.");
- error.setDescription(reason);
- error.setColumn(resolvedType->location.column);
- error.setLine(resolvedType->location.line);
- recordError(error);
- return false;
- }
-
- if (ref->type->containsRevisionedAttributes()) {
- ref->typePropertyCache = engine->cache(ref->type,
- resolvedType->minorVersion);
- if (!ref->typePropertyCache) {
- QQmlError cacheError;
- cacheError.setColumn(resolvedType->location.column);
- cacheError.setLine(resolvedType->location.line);
- recordError(cacheError);
- return false;
- }
- ref->typePropertyCache->addref();
- }
- }
- ref->majorVersion = resolvedType->majorVersion;
- ref->minorVersion = resolvedType->minorVersion;
- ref->doDynamicTypeCheck();
- compiledData->resolvedTypes.insert(resolvedType.key(), ref.take());
- }
-
// Build property caches and VME meta object data
- for (QHash<int, QQmlCompiledData::TypeReference*>::ConstIterator it = compiledData->resolvedTypes.constBegin(), end = compiledData->resolvedTypes.constEnd();
+ for (auto it = resolvedTypes.constBegin(), end = resolvedTypes.constEnd();
it != end; ++it) {
QQmlCustomParser *customParser = (*it)->type ? (*it)->type->customParser() : 0;
if (customParser)
customParsers.insert(it.key(), customParser);
}
- compiledData->metaObjects.reserve(document->objects.count());
- compiledData->propertyCaches.reserve(document->objects.count());
-
{
- QQmlPropertyCacheCreator propertyCacheBuilder(this);
- if (!propertyCacheBuilder.buildMetaObjects())
- return false;
+ QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, engine, this, imports());
+ QQmlCompileError error = propertyCacheBuilder.buildMetaObjects();
+ if (error.isSet()) {
+ recordError(error);
+ return nullptr;
+ }
}
{
@@ -154,13 +95,13 @@ bool QQmlTypeCompiler::compile()
{
SignalHandlerConverter converter(this);
if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations())
- return false;
+ return nullptr;
}
{
QQmlEnumTypeResolver enumResolver(this);
if (!enumResolver.resolveEnumBindings())
- return false;
+ return nullptr;
}
{
@@ -173,34 +114,19 @@ bool QQmlTypeCompiler::compile()
annotator.annotateBindingsToAliases();
}
- // Collect imported scripts
- const QList<QQmlTypeData::ScriptReference> &scripts = typeData->resolvedScripts();
- compiledData->scripts.reserve(scripts.count());
- for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) {
- const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex);
-
- QStringRef qualifier(&script.qualifier);
- QString enclosingNamespace;
-
- const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
- if (lastDotIndex != -1) {
- enclosingNamespace = qualifier.left(lastDotIndex).toString();
- qualifier = qualifier.mid(lastDotIndex+1);
- }
-
- compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
- QQmlScriptData *scriptData = script.script->scriptData();
- scriptData->addref();
- compiledData->scripts << scriptData;
- }
-
// Resolve component boundaries and aliases
{
// Scan for components, determine their scopes and resolve aliases within the scope.
QQmlComponentAndAliasResolver resolver(this);
if (!resolver.resolve())
- return false;
+ return nullptr;
+ }
+
+ {
+ QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
+ if (!deferredAndCustomParserBindingScanner.scanObject())
+ return nullptr;
}
// Compile JS binding expressions and signal handlers
@@ -212,10 +138,10 @@ bool QQmlTypeCompiler::compile()
sss.scan();
}
- QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, compiledData->importCache, &document->jsGenerator.stringTable);
+ QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, importCache, &document->jsGenerator.stringTable);
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents())
- return false;
+ return nullptr;
QQmlJavaScriptBindingExpressionSimplificationPass pass(this);
pass.reduceTranslationBindings();
@@ -236,64 +162,39 @@ bool QQmlTypeCompiler::compile()
// The js unit owns the data and will free the qml unit.
document->javaScriptCompilationUnit->data = qmlUnit;
- compiledData->compilationUnit = document->javaScriptCompilationUnit;
-
- // Add to type registry of composites
- if (compiledData->isCompositeType())
- engine->registerInternalCompositeType(compiledData);
- else {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
- QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
- if (typeRef->component) {
- compiledData->metaTypeId = typeRef->component->metaTypeId;
- compiledData->listMetaTypeId = typeRef->component->listMetaTypeId;
- } else {
- compiledData->metaTypeId = typeRef->type->typeId();
- compiledData->listMetaTypeId = typeRef->type->qListTypeId();
- }
- }
-
- // Sanity check property bindings
- QQmlPropertyValidator validator(this);
- if (!validator.validate())
- return false;
+ QV4::CompiledData::CompilationUnit *compilationUnit = document->javaScriptCompilationUnit;
+ compilationUnit = document->javaScriptCompilationUnit;
+ compilationUnit->importCache = importCache;
+ compilationUnit->resolvedTypes = resolvedTypes;
+ compilationUnit->propertyCaches = std::move(m_propertyCaches);
+ Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->data->nObjects));
- // Collect some data for instantiation later.
- int bindingCount = 0;
- int parserStatusCount = 0;
- int objectCount = 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;
- }
- ++objectCount;
- if (typeRef->component) {
- bindingCount += typeRef->component->totalBindingsCount;
- parserStatusCount += typeRef->component->totalParserStatusCount;
- objectCount += typeRef->component->totalObjectCount;
- }
- }
- }
- compiledData->totalBindingsCount = bindingCount;
- compiledData->totalParserStatusCount = parserStatusCount;
- compiledData->totalObjectCount = objectCount;
+ if (errors.isEmpty())
+ return compilationUnit;
+ else
+ return nullptr;
+}
- Q_ASSERT(compiledData->propertyCaches.count() == static_cast<int>(compiledData->compilationUnit->data->nObjects));
+void QQmlTypeCompiler::recordError(QQmlError error)
+{
+ error.setUrl(url());
+ errors << error;
+}
- return errors.isEmpty();
+void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
+{
+ QQmlError error;
+ error.setLine(location.line);
+ error.setColumn(location.column);
+ error.setDescription(description);
+ error.setUrl(url());
+ errors << error;
}
-void QQmlTypeCompiler::recordError(const QQmlError &error)
+void QQmlTypeCompiler::recordError(const QQmlCompileError &error)
{
- QQmlError e = error;
- e.setUrl(url());
- errors << e;
+ recordError(error.location, error.description);
}
QString QQmlTypeCompiler::stringAt(int idx) const
@@ -313,7 +214,7 @@ QV4::IR::Module *QQmlTypeCompiler::jsIRModule() const
const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const
{
- return compiledData->compilationUnit->data;
+ return document->javaScriptCompilationUnit->data;
}
const QQmlImports *QQmlTypeCompiler::imports() const
@@ -321,12 +222,7 @@ const QQmlImports *QQmlTypeCompiler::imports() const
return &typeData->imports();
}
-QHash<int, QQmlCompiledData::TypeReference*> *QQmlTypeCompiler::resolvedTypes()
-{
- return &compiledData->resolvedTypes;
-}
-
-QList<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects()
+QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
{
return &document->objects;
}
@@ -336,45 +232,20 @@ int QQmlTypeCompiler::rootObjectIndex() const
return document->indexOfRootObject;
}
-void QQmlTypeCompiler::setPropertyCaches(const QVector<QQmlPropertyCache *> &caches)
+void QQmlTypeCompiler::setPropertyCaches(QQmlPropertyCacheVector &&caches)
{
- compiledData->propertyCaches = caches;
- Q_ASSERT(caches.count() >= document->indexOfRootObject);
- if (compiledData->rootPropertyCache)
- compiledData->rootPropertyCache->release();
- compiledData->rootPropertyCache = caches.at(document->indexOfRootObject);
- compiledData->rootPropertyCache->addref();
+ m_propertyCaches = std::move(caches);
+ Q_ASSERT(m_propertyCaches.count() >= document->indexOfRootObject);
}
-const QVector<QQmlPropertyCache *> &QQmlTypeCompiler::propertyCaches() const
+const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
{
- return compiledData->propertyCaches;
+ return &m_propertyCaches;
}
-void QQmlTypeCompiler::setVMEMetaObjects(const QVector<QByteArray> &metaObjects)
+QQmlPropertyCacheVector &&QQmlTypeCompiler::takePropertyCaches()
{
- Q_ASSERT(compiledData->metaObjects.isEmpty());
- compiledData->metaObjects = metaObjects;
-}
-
-QVector<QByteArray> *QQmlTypeCompiler::vmeMetaObjects() const
-{
- return &compiledData->metaObjects;
-}
-
-QHash<int, int> *QQmlTypeCompiler::objectIndexToIdForRoot()
-{
- return &compiledData->objectIndexToIdForRoot;
-}
-
-QHash<int, QHash<int, int> > *QQmlTypeCompiler::objectIndexToIdPerComponent()
-{
- return &compiledData->objectIndexToIdPerComponent;
-}
-
-QHash<int, QBitArray> *QQmlTypeCompiler::customParserBindings()
-{
- return &compiledData->customParserBindings;
+ return std::move(m_propertyCaches);
}
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
@@ -392,14 +263,9 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
return &document->jsGenerator.stringTable;
}
-void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject)
-{
- compiledData->deferredBindingsPerObject = deferredBindingsPerObject;
-}
-
void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData)
{
- compiledData->compilationUnit->bindingPropertyDataPerObject = propertyData;
+ document->javaScriptCompilationUnit->bindingPropertyDataPerObject = propertyData;
}
QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const
@@ -407,499 +273,34 @@ QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scrip
return object->bindingAsString(document, scriptIndex);
}
-QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
- : compiler(typeCompiler)
-{
-}
-
-void QQmlCompilePass::recordError(const QV4::CompiledData::Location &location, const QString &description) const
-{
- QQmlError error;
- error.setLine(location.line);
- error.setColumn(location.column);
- error.setDescription(description);
- compiler->recordError(error);
-}
-
-static QAtomicInt classIndexCounter(0);
-
-QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , qmlObjects(*typeCompiler->qmlObjects())
- , imports(typeCompiler->imports())
- , resolvedTypes(typeCompiler->resolvedTypes())
-{
-}
-
-QQmlPropertyCacheCreator::~QQmlPropertyCacheCreator()
-{
- for (int i = 0; i < propertyCaches.count(); ++i)
- if (QQmlPropertyCache *cache = propertyCaches.at(i))
- cache->release();
- propertyCaches.clear();
-}
-
-bool QQmlPropertyCacheCreator::buildMetaObjects()
-{
- propertyCaches.resize(qmlObjects.count());
- vmeMetaObjects.resize(qmlObjects.count());
-
- if (!buildMetaObjectRecursively(compiler->rootObjectIndex(), /*referencing object*/-1, /*instantiating binding*/0))
- return false;
-
- compiler->setVMEMetaObjects(vmeMetaObjects);
- compiler->setPropertyCaches(propertyCaches);
- propertyCaches.clear();
-
- return true;
-}
-
-bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding)
+void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion)
{
- const QmlIR::Object *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 notInRevision = false;
- instantiatingProperty = QmlIR::PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), &notInRevision);
- if (instantiatingProperty) {
- if (instantiatingProperty->isQObject()) {
- baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType);
- Q_ASSERT(baseTypeCache);
- } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType)) {
- baseTypeCache = enginePrivate->cache(vtmo);
- Q_ASSERT(baseTypeCache);
- }
- }
- }
-
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
- if (!needVMEMetaObject) {
- for (const QmlIR::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.
- needVMEMetaObject = true;
-
- // If the on assignment is inside a group property, we need to distinguish between QObject based
- // 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 (instantiatingProperty && QQmlValueTypeFactory::isValueType(instantiatingProperty->propType)) {
- needVMEMetaObject = false;
- if (!ensureMetaObject(referencingObjectIndex))
- return false;
- }
- break;
- }
- }
- }
-
- if (obj->inheritedTypeNameIndex != 0) {
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
-
- if (typeRef->isFullyDynamicType) {
- if (obj->propertyCount() > 0) {
- recordError(obj->location, tr("Fully dynamic types cannot declare new properties."));
- return false;
- }
- if (obj->signalCount() > 0) {
- recordError(obj->location, tr("Fully dynamic types cannot declare new signals."));
- return false;
- }
- if (obj->functionCount() > 0) {
- recordError(obj->location, tr("Fully Dynamic types cannot declare new functions."));
- return false;
- }
- }
-
- baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- Q_ASSERT(baseTypeCache);
- } else if (instantiatingBinding && instantiatingBinding->isAttachedProperty()) {
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(instantiatingBinding->propertyNameIndex);
- Q_ASSERT(typeRef);
- QQmlType *qmltype = typeRef->type;
- if (!qmltype) {
- QString propertyName = stringAt(instantiatingBinding->propertyNameIndex);
- if (imports->resolveType(propertyName, &qmltype, 0, 0, 0)) {
- if (qmltype->isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- QQmlCompiledData *data = tdata->compiledData();
- qmltype = QQmlMetaType::qmlType(data->metaTypeId);
-
- tdata->release();
- }
- }
- }
+ const quint32 moduleIdx = registerString(module);
+ const quint32 qualifierIdx = registerString(qualifier);
- const QMetaObject *attachedMo = qmltype ? qmltype->attachedPropertiesType(enginePrivate) : 0;
- if (!attachedMo) {
- recordError(instantiatingBinding->location, tr("Non-existent attached object"));
- return false;
- }
- baseTypeCache = enginePrivate->cache(attachedMo);
- Q_ASSERT(baseTypeCache);
- }
-
- if (baseTypeCache) {
- if (needVMEMetaObject) {
- if (!createMetaObject(objectIndex, obj, baseTypeCache))
- return false;
- } else {
- propertyCaches[objectIndex] = baseTypeCache;
- baseTypeCache->addref();
- }
- }
-
- if (propertyCaches.at(objectIndex)) {
- for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next)
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding))
- return false;
- }
+ for (int i = 0, count = document->imports.count(); i < count; ++i) {
+ const QV4::CompiledData::Import *existingImport = document->imports.at(i);
+ if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
+ && existingImport->uriIndex == moduleIdx
+ && existingImport->qualifierIndex == qualifierIdx)
+ return;
}
-
- return true;
+ auto pool = memoryPool();
+ QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
+ import->type = QV4::CompiledData::Import::ImportLibrary;
+ import->majorVersion = majorVersion;
+ import->minorVersion = minorVersion;
+ import->uriIndex = moduleIdx;
+ import->qualifierIndex = qualifierIdx;
+ document->imports.append(import);
}
-bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex)
+QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
+ : compiler(typeCompiler)
{
- if (!vmeMetaObjects.at(objectIndex).isEmpty())
- return true;
- const QmlIR::Object *obj = qmlObjects.at(objectIndex);
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
- QQmlPropertyCache *baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- return createMetaObject(objectIndex, obj, baseTypeCache);
-}
-
-bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache)
-{
- QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(obj->propertyCount(),
- obj->functionCount() + obj->propertyCount() + obj->signalCount(),
- obj->signalCount() + obj->propertyCount());
- propertyCaches[objectIndex] = cache;
-
- struct TypeData {
- QV4::CompiledData::Property::Type dtype;
- int metaType;
- } builtinTypes[] = {
- { QV4::CompiledData::Property::Var, QMetaType::QVariant },
- { QV4::CompiledData::Property::Variant, QMetaType::QVariant },
- { QV4::CompiledData::Property::Int, QMetaType::Int },
- { QV4::CompiledData::Property::Bool, QMetaType::Bool },
- { QV4::CompiledData::Property::Real, QMetaType::Double },
- { QV4::CompiledData::Property::String, QMetaType::QString },
- { QV4::CompiledData::Property::Url, QMetaType::QUrl },
- { QV4::CompiledData::Property::Color, QMetaType::QColor },
- { QV4::CompiledData::Property::Font, QMetaType::QFont },
- { QV4::CompiledData::Property::Time, QMetaType::QTime },
- { QV4::CompiledData::Property::Date, QMetaType::QDate },
- { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
- { QV4::CompiledData::Property::Rect, QMetaType::QRectF },
- { QV4::CompiledData::Property::Point, QMetaType::QPointF },
- { QV4::CompiledData::Property::Size, QMetaType::QSizeF },
- { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
- { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
- { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
- { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
- { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
- };
- static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
-
- QByteArray newClassName;
-
- if (objectIndex == compiler->rootObjectIndex()) {
- QString path = compiler->url().path();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- if (lastSlash > -1) {
- const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
- if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
- newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
- QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
- }
- }
- if (newClassName.isEmpty()) {
- newClassName = QQmlMetaObject(baseTypeCache).className();
- newClassName.append("_QML_");
- newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
- }
-
- cache->_dynamicClassName = newClassName;
-
- int aliasCount = 0;
- int varPropCount = 0;
-
- QmlIR::PropertyResolver resolver(baseTypeCache);
-
- for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
- if (p->type == QV4::CompiledData::Property::Alias)
- aliasCount++;
- else if (p->type == QV4::CompiledData::Property::Var)
- varPropCount++;
-
- // No point doing this for both the alias and non alias cases
- bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
- if (d && d->isFinal())
- COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
- }
-
- typedef QQmlVMEMetaData VMD;
-
- QByteArray &dynamicData = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData)
- + obj->propertyCount() * sizeof(VMD::PropertyData)
- + obj->functionCount() * sizeof(VMD::MethodData)
- + aliasCount * sizeof(VMD::AliasData), 0);
-
- int effectivePropertyIndex = cache->propertyIndexCacheStart;
- int effectiveMethodIndex = cache->methodIndexCacheStart;
-
- // For property change signal override detection.
- // We prepopulate a set of signal names which already exist in the object,
- // and throw an error if there is a signal/method defined as an override.
- QSet<QString> seenSignals;
- seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
- QQmlPropertyCache *parentCache = cache;
- while ((parentCache = parentCache->parent())) {
- if (int pSigCount = parentCache->signalCount()) {
- int pSigOffset = parentCache->signalOffset();
- for (int i = pSigOffset; i < pSigCount; ++i) {
- QQmlPropertyData *currPSig = parentCache->signal(i);
- // XXX TODO: find a better way to get signal name from the property data :-/
- for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
- iter != parentCache->stringCache.end(); ++iter) {
- if (currPSig == (*iter).second) {
- seenSignals.insert(iter.key());
- break;
- }
- }
- }
- }
- }
-
- // First set up notify signals for properties - first normal, then var, then alias
- enum { NSS_Normal = 0, NSS_Alias = 1 };
- for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
-
- if (ii == NSS_Alias && aliasCount == 0) continue;
-
- for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
- if ((ii == NSS_Normal && p->type == QV4::CompiledData::Property::Alias) ||
- (ii == NSS_Alias && p->type != QV4::CompiledData::Property::Alias))
- continue;
-
- quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
- QQmlPropertyData::IsVMESignal;
-
- QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
-
- cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
- }
- }
-
- // Dynamic signals
- for (const QmlIR::Signal *s = obj->firstSignal(); s; s = s->next) {
- const int paramCount = s->parameters->count;
-
- QList<QByteArray> names;
- names.reserve(paramCount);
- QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
-
- if (paramCount) {
- paramTypes[0] = paramCount;
-
- QmlIR::SignalParameter *param = s->parameters->first;
- for (int i = 0; i < paramCount; ++i, param = param->next) {
- names.append(stringAt(param->nameIndex).toUtf8());
- if (param->type < builtinTypeCount) {
- // built-in type
- paramTypes[i + 1] = builtinTypes[param->type].metaType;
- } else {
- // lazily resolved type
- Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
- const QString customTypeName = stringAt(param->customTypeNameIndex);
- QQmlType *qmltype = 0;
- if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0))
- COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(customTypeName));
-
- if (qmltype->isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- QQmlCompiledData *data = tdata->compiledData();
-
- paramTypes[i + 1] = data->metaTypeId;
-
- tdata->release();
- } else {
- paramTypes[i + 1] = qmltype->typeId();
- }
- }
- }
- }
-
- ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
-
- quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
- QQmlPropertyData::IsVMESignal;
- if (paramCount)
- flags |= QQmlPropertyData::HasArguments;
-
- QString signalName = stringAt(s->nameIndex);
- if (seenSignals.contains(signalName))
- COMPILE_EXCEPTION(s, tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
- seenSignals.insert(signalName);
-
- cache->appendSignal(signalName, flags, effectiveMethodIndex++,
- paramCount?paramTypes.constData():0, names);
- }
-
-
- // Dynamic slots
- for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) {
- QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration;
-
- quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
-
- if (astFunction->formals)
- flags |= QQmlPropertyData::HasArguments;
-
- QString slotName = astFunction->name.toString();
- if (seenSignals.contains(slotName))
- COMPILE_EXCEPTION(s, tr("Duplicate method name: invalid override of property change signal or superclass signal"));
- // Note: we don't append slotName to the seenSignals list, since we don't
- // protect against overriding change signals or methods with properties.
-
- QList<QByteArray> parameterNames;
- QQmlJS::AST::FormalParameterList *param = astFunction->formals;
- while (param) {
- parameterNames << param->name.toUtf8();
- param = param->next;
- }
-
- cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
- }
-
-
- // Dynamic properties (except var and aliases)
- int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
- int propertyIdx = 0;
- for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {
-
- if (p->type == QV4::CompiledData::Property::Alias)
- continue;
-
- int propertyType = 0;
- int vmePropertyType = 0;
- quint32 propertyFlags = 0;
-
- if (p->type == QV4::CompiledData::Property::Var) {
- propertyType = QMetaType::QVariant;
- vmePropertyType = QQmlVMEMetaData::VarPropertyType;
- propertyFlags = QQmlPropertyData::IsVarProperty;
- } else if (p->type < builtinTypeCount) {
- propertyType = builtinTypes[p->type].metaType;
- vmePropertyType = propertyType;
-
- if (p->type == QV4::CompiledData::Property::Variant)
- propertyFlags |= QQmlPropertyData::IsQVariant;
- } else {
- Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
- p->type == QV4::CompiledData::Property::Custom);
-
- QQmlType *qmltype = 0;
- if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) {
- COMPILE_EXCEPTION(p, tr("Invalid property type"));
- }
-
- Q_ASSERT(qmltype);
- if (qmltype->isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- QQmlCompiledData *data = tdata->compiledData();
-
- if (p->type == QV4::CompiledData::Property::Custom) {
- propertyType = data->metaTypeId;
- vmePropertyType = QMetaType::QObjectStar;
- } else {
- propertyType = data->listMetaTypeId;
- vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
- }
-
- tdata->release();
- } else {
- if (p->type == QV4::CompiledData::Property::Custom) {
- propertyType = qmltype->typeId();
- vmePropertyType = QMetaType::QObjectStar;
- } else {
- propertyType = qmltype->qListTypeId();
- vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
- }
- }
-
- if (p->type == QV4::CompiledData::Property::Custom)
- propertyFlags |= QQmlPropertyData::IsQObjectDerived;
- else
- propertyFlags |= QQmlPropertyData::IsQList;
- }
-
- if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
- propertyFlags |= QQmlPropertyData::IsWritable;
-
-
- QString propertyName = stringAt(p->nameIndex);
- if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName;
- cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- propertyType, effectiveSignalIndex);
-
- effectiveSignalIndex++;
-
- VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
- (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
- vmd->propertyCount++;
- }
-
- // Alias property count. Actual data is setup in buildDynamicMetaAliases
- ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
-
- // Dynamic slot data - comes after the property data
- for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) {
- QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration;
- int formalsCount = 0;
- QQmlJS::AST::FormalParameterList *param = astFunction->formals;
- while (param) {
- formalsCount++;
- param = param->next;
- }
-
- VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ###
- formalsCount,
- /* s->location.start.line */0 }; // ###
+}
- VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
- VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
- vmd->methodCount++;
- md = methodData;
- }
- return true;
-}
SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
@@ -907,7 +308,7 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
, qmlObjects(*typeCompiler->qmlObjects())
, imports(typeCompiler->imports())
, customParsers(typeCompiler->customParserCache())
- , resolvedTypes(*typeCompiler->resolvedTypes())
+ , resolvedTypes(typeCompiler->resolvedTypes)
, illegalNames(QV8Engine::get(QQmlEnginePrivate::get(typeCompiler->enginePrivate()))->illegalNames())
, propertyCaches(typeCompiler->propertyCaches())
{
@@ -917,7 +318,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
{
for (int objectIndex = 0; objectIndex < qmlObjects.count(); ++objectIndex) {
const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- QQmlPropertyCache *cache = propertyCaches.at(objectIndex);
+ QQmlPropertyCache *cache = propertyCaches->at(objectIndex);
if (!cache)
continue;
if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
@@ -941,7 +342,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
// Attached property?
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(binding->propertyNameIndex);
+ auto *typeRef = resolvedTypes.value(binding->propertyNameIndex);
QQmlType *type = typeRef ? typeRef->type : 0;
if (!type) {
if (imports->resolveType(propertyName, &type, 0, 0, 0)) {
@@ -950,8 +351,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
- QQmlCompiledData *data = tdata->compiledData();
- type = QQmlMetaType::qmlType(data->metaTypeId);
+ auto compilationUnit = tdata->compilationUnit();
+ type = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
tdata->release();
}
@@ -1014,7 +415,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
const QQmlType *type = typeRef ? typeRef->type : 0;
if (type) {
COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type->module()).arg(type->majorVersion()).arg(type->minorVersion()));
@@ -1118,14 +519,14 @@ QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler)
, qmlObjects(*typeCompiler->qmlObjects())
, propertyCaches(typeCompiler->propertyCaches())
, imports(typeCompiler->imports())
- , resolvedTypes(typeCompiler->resolvedTypes())
+ , resolvedTypes(&typeCompiler->resolvedTypes)
{
}
bool QQmlEnumTypeResolver::resolveEnumBindings()
{
for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches.at(i);
+ QQmlPropertyCache *propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
@@ -1169,7 +570,7 @@ bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QS
COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString()));
}
binding->type = QV4::CompiledData::Binding::Type_Number;
- binding->value.d = (double)enumValue;
+ binding->setNumberValueInternal((double)enumValue);
binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
return true;
}
@@ -1218,7 +619,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
int value = 0;
bool ok = false;
- QQmlCompiledData::TypeReference *tr = resolvedTypes->value(obj->inheritedTypeNameIndex);
+ auto *tr = resolvedTypes->value(obj->inheritedTypeNameIndex);
if (type && tr && tr->type == type) {
QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex);
@@ -1311,20 +712,20 @@ QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
void QQmlAliasAnnotator::annotateBindingsToAliases()
{
for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches.at(i);
+ QQmlPropertyCache *propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
QmlIR::PropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+ QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::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;
+ QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (pd && pd->isAlias())
binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
}
@@ -1343,20 +744,20 @@ void QQmlScriptStringScanner::scan()
{
const int scriptStringMetaType = qMetaTypeId<QQmlScriptString>();
for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches.at(i);
+ QQmlPropertyCache *propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
QmlIR::PropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+ QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Script)
continue;
bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
+ QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (!pd || pd->propType != scriptStringMetaType)
continue;
@@ -1376,13 +777,8 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
, pool(typeCompiler->memoryPool())
, qmlObjects(typeCompiler->qmlObjects())
, indexOfRootObject(typeCompiler->rootObjectIndex())
- , _componentIndex(-1)
- , _objectIndexToIdInScope(0)
- , resolvedTypes(typeCompiler->resolvedTypes())
- , propertyCaches(typeCompiler->propertyCaches())
- , vmeMetaObjectData(typeCompiler->vmeMetaObjects())
- , objectIndexToIdForRoot(typeCompiler->objectIndexToIdForRoot())
- , objectIndexToIdPerComponent(typeCompiler->objectIndexToIdPerComponent())
+ , resolvedTypes(&typeCompiler->resolvedTypes)
+ , propertyCaches(std::move(typeCompiler->takePropertyCaches()))
{
}
@@ -1390,7 +786,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
{
QmlIR::PropertyResolver propertyResolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+ QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Object)
@@ -1399,18 +795,18 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
continue;
const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
- QQmlCompiledData::TypeReference *tr = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
+ auto *tr = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
Q_ASSERT(tr);
if (QQmlType *targetType = tr->type) {
if (targetType->metaObject() == &QQmlComponent::staticMetaObject)
continue;
- } else if (tr->component) {
- if (tr->component->rootPropertyCache->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
+ } else if (tr->compilationUnit) {
+ if (tr->compilationUnit->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
continue;
}
QQmlPropertyData *pd = 0;
- if (binding->propertyNameIndex != 0) {
+ if (binding->propertyNameIndex != quint32(0)) {
bool notInRevision = false;
pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
} else {
@@ -1430,15 +826,20 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
if (!mo)
continue;
+ // emulate "import Qml 2.0 as QmlInternals" and then wrap the component in "QmlInternals.Component {}"
QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
Q_ASSERT(componentType);
+ const QString qualifier = QStringLiteral("QmlInternals");
+
+ compiler->addImport(componentType->module(), qualifier, componentType->majorVersion(), componentType->minorVersion());
QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
- syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString()));
+ syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType->elementName()), compiler->registerString(QString()));
syntheticComponent->location = binding->valueLocation;
+ syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
- QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference;
+ auto typeRef = new QV4::CompiledData::ResolvedTypeReference;
typeRef->type = componentType;
typeRef->majorVersion = componentType->majorVersion();
typeRef->minorVersion = componentType->minorVersion();
@@ -1449,7 +850,6 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
const int componentIndex = qmlObjects->count() - 1;
// Keep property caches symmetric
QQmlPropertyCache *componentCache = enginePrivate->cache(&QQmlComponent::staticMetaObject);
- componentCache->addref();
propertyCaches.append(componentCache);
QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
@@ -1462,7 +862,6 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
binding->value.objectIndex = componentIndex;
componentRoots.append(componentIndex);
- componentBoundaries.append(syntheticBinding->value.objectIndex);
}
}
@@ -1474,7 +873,7 @@ bool QQmlComponentAndAliasResolver::resolve()
// on the left hand side is of QQmlComponent type.
const int objCountWithoutSynthesizedComponents = qmlObjects->count();
for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
- const QmlIR::Object *obj = qmlObjects->at(i);
+ QmlIR::Object *obj = qmlObjects->at(i);
QQmlPropertyCache *cache = propertyCaches.at(i);
if (obj->inheritedTypeNameIndex == 0 && !cache)
continue;
@@ -1482,7 +881,7 @@ bool QQmlComponentAndAliasResolver::resolve()
bool isExplicitComponent = false;
if (obj->inheritedTypeNameIndex) {
- QQmlCompiledData::TypeReference *tref = resolvedTypes->value(obj->inheritedTypeNameIndex);
+ auto *tref = resolvedTypes->value(obj->inheritedTypeNameIndex);
Q_ASSERT(tref);
if (tref->type && tref->type->metaObject() == &QQmlComponent::staticMetaObject)
isExplicitComponent = true;
@@ -1493,11 +892,11 @@ bool QQmlComponentAndAliasResolver::resolve()
continue;
}
- componentRoots.append(i);
+ obj->flags |= QV4::CompiledData::Object::IsComponent;
if (obj->functionCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
- if (obj->propertyCount() > 0)
+ if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
if (obj->signalCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
@@ -1515,65 +914,69 @@ bool QQmlComponentAndAliasResolver::resolve()
if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
- componentBoundaries.append(rootBinding->value.objectIndex);
- }
+ // We are going to collect ids/aliases and resolve them for the root object as a separate
+ // last pass.
+ if (i != indexOfRootObject)
+ componentRoots.append(i);
- std::sort(componentBoundaries.begin(), componentBoundaries.end());
+ }
for (int i = 0; i < componentRoots.count(); ++i) {
- const QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
+ QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
const QmlIR::Binding *rootBinding = component->firstBinding();
- _componentIndex = i;
_idToObjectIndex.clear();
- _objectIndexToIdInScope = &(*objectIndexToIdPerComponent)[componentRoots.at(i)];
-
_objectsWithAliases.clear();
if (!collectIdsAndAliases(rootBinding->value.objectIndex))
return false;
- if (!resolveAliases())
+ component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
+
+ if (!resolveAliases(componentRoots.at(i)))
return false;
}
// Collect ids and aliases for root
- _componentIndex = -1;
_idToObjectIndex.clear();
- _objectIndexToIdInScope = objectIndexToIdForRoot;
_objectsWithAliases.clear();
collectIdsAndAliases(indexOfRootObject);
- resolveAliases();
+ QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject);
+ rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
+
+ if (!resolveAliases(indexOfRootObject))
+ return false;
// Implicit component insertion may have added objects and thus we also need
// to extend the symmetric propertyCaches.
- compiler->setPropertyCaches(propertyCaches);
+ compiler->setPropertyCaches(std::move(propertyCaches));
+ compiler->setComponentRoots(componentRoots);
return true;
}
bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
{
- const QmlIR::Object *obj = qmlObjects->at(objectIndex);
+ QmlIR::Object *obj = qmlObjects->at(objectIndex);
- if (obj->idIndex != 0) {
- if (_idToObjectIndex.contains(obj->idIndex)) {
+ if (obj->idNameIndex != 0) {
+ if (_idToObjectIndex.contains(obj->idNameIndex)) {
recordError(obj->locationOfIdProperty, tr("id is not unique"));
return false;
}
- _idToObjectIndex.insert(obj->idIndex, objectIndex);
- _objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count());
+ obj->id = _idToObjectIndex.count();
+ _idToObjectIndex.insert(obj->idNameIndex, objectIndex);
}
- for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
- if (property->type == QV4::CompiledData::Property::Alias) {
- _objectsWithAliases.append(objectIndex);
- break;
- }
- }
+ if (obj->aliasCount() > 0)
+ _objectsWithAliases.append(objectIndex);
+
+ // Stop at Component boundary
+ if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != compiler->rootObjectIndex())
+ return true;
for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Object
@@ -1581,10 +984,6 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
&& binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
continue;
- // Stop at Component boundary
- if (std::binary_search(componentBoundaries.constBegin(), componentBoundaries.constEnd(), binding->value.objectIndex))
- continue;
-
if (!collectIdsAndAliases(binding->value.objectIndex))
return false;
}
@@ -1592,257 +991,205 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
return true;
}
-bool QQmlComponentAndAliasResolver::resolveAliases()
+bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
{
- foreach (int objectIndex, _objectsWithAliases) {
- const QmlIR::Object *obj = qmlObjects->at(objectIndex);
+ if (_objectsWithAliases.isEmpty())
+ return true;
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
- Q_ASSERT(propertyCache);
+ QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler);
- int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
- int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
- int effectiveAliasIndex = 0;
+ bool atLeastOneAliasResolved;
+ do {
+ atLeastOneAliasResolved = false;
+ QVector<int> pendingObjects;
- const QmlIR::Property *p = obj->firstProperty();
- for (int propertyIndex = 0; propertyIndex < obj->propertyCount(); ++propertyIndex, p = p->next) {
- if (p->type != QV4::CompiledData::Property::Alias)
- continue;
+ for (int objectIndex: qAsConst(_objectsWithAliases)) {
- const int idIndex = p->aliasIdValueIndex;
- const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
- if (targetObjectIndex == -1) {
- recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ QQmlCompileError error;
+ const auto result = resolveAliasesInObject(objectIndex, &error);
+
+ if (error.isSet()) {
+ recordError(error);
return false;
}
- const int targetId = _objectIndexToIdInScope->value(targetObjectIndex, -1);
- Q_ASSERT(targetId != -1);
-
- const QString aliasPropertyValue = stringAt(p->aliasPropertyValueIndex);
-
- QStringRef property;
- QStringRef subProperty;
-
- const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
- if (propertySeparator != -1) {
- property = aliasPropertyValue.leftRef(propertySeparator);
- subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
- } else
- property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
-
- int propIdx = -1;
- int propType = 0;
- int notifySignal = -1;
- int flags = 0;
- int type = 0;
- bool writable = false;
- bool resettable = false;
-
- quint32 propertyFlags = QQmlPropertyData::IsAlias;
-
- if (property.isEmpty()) {
- const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
-
- if (typeRef->type)
- type = typeRef->type->typeId();
- else
- type = typeRef->component->metaTypeId;
-
- flags |= QML_ALIAS_FLAG_PTR;
- propertyFlags |= QQmlPropertyData::IsQObjectDerived;
+
+ if (result == AllAliasesResolved) {
+ aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
+ atLeastOneAliasResolved = true;
+ } else if (result == SomeAliasesResolved) {
+ atLeastOneAliasResolved = true;
+ pendingObjects.append(objectIndex);
} else {
- QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
- Q_ASSERT(targetCache);
- QmlIR::PropertyResolver resolver(targetCache);
+ pendingObjects.append(objectIndex);
+ }
+ }
+ qSwap(_objectsWithAliases, pendingObjects);
+ } while (!_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
- QQmlPropertyData *targetProperty = resolver.property(property.toString());
- if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) {
- recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(property.toString()));
- return false;
- }
+ if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) {
+ const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first());
+ for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
+ if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) {
+ recordError(alias->location, tr("Circular alias reference detected"));
+ return false;
+ }
+ }
+ }
- propIdx = targetProperty->coreIndex;
- type = targetProperty->propType;
+ return true;
+}
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
- notifySignal = targetProperty->notifyIndex;
+QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error)
+{
+ const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
+ if (!obj->aliasCount())
+ return AllAliasesResolved;
- if (!subProperty.isEmpty()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(type);
- if (!valueTypeMetaObject) {
- recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- return false;
- }
+ int numResolvedAliases = 0;
+ bool seenUnresolvedAlias = false;
- propType = type;
+ for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
+ if (alias->flags & QV4::CompiledData::Alias::Resolved)
+ continue;
- int valueTypeIndex =
- valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
- if (valueTypeIndex == -1) {
- recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- return false;
- }
- Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
+ seenUnresolvedAlias = true;
- propIdx = QQmlPropertyData::encodeValueTypePropertyIndex(propIdx, valueTypeIndex);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- type = QVariant::Int;
- else
- type = valueTypeMetaObject->property(valueTypeIndex).userType();
+ const int idIndex = alias->idIndex;
+ const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
+ if (targetObjectIndex == -1) {
+ *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ break;
+ }
- } else {
- if (targetProperty->isEnum()) {
- type = QVariant::Int;
- } else {
- // Copy type flags
- propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask;
+ const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
+ Q_ASSERT(targetObject->id >= 0);
+ alias->targetObjectId = targetObject->id;
+ alias->aliasToLocalAlias = false;
- if (targetProperty->isVarProperty())
- propertyFlags |= QQmlPropertyData::IsQVariant;
+ const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
- if (targetProperty->isQObject())
- flags |= QML_ALIAS_FLAG_PTR;
+ QStringRef property;
+ QStringRef subProperty;
+
+ const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
+ if (propertySeparator != -1) {
+ property = aliasPropertyValue.leftRef(propertySeparator);
+ subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
+ } else
+ property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
+
+ int propIdx = -1;
+
+ if (property.isEmpty()) {
+ alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ } else {
+ QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
+ Q_ASSERT(targetCache);
+ QmlIR::PropertyResolver resolver(targetCache);
+
+ QQmlPropertyData *targetProperty = resolver.property(property.toString());
+
+ // If it's an alias that we haven't resolved yet, try again later.
+ if (!targetProperty) {
+ bool aliasPointsToOtherAlias = false;
+ int localAliasIndex = 0;
+ for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
+ if (stringAt(targetAlias->nameIndex) == property) {
+ aliasPointsToOtherAlias = true;
+ break;
}
}
- }
-
- QQmlVMEMetaData::AliasData aliasData = { targetId, propIdx, propType, flags, notifySignal };
+ if (aliasPointsToOtherAlias) {
+ if (targetObjectIndex == objectIndex) {
+ alias->localAliasIndex = localAliasIndex;
+ alias->aliasToLocalAlias = true;
+ alias->flags |= QV4::CompiledData::Alias::Resolved;
+ ++numResolvedAliases;
+ continue;
+ }
- typedef QQmlVMEMetaData VMD;
- QByteArray &dynamicData = (*vmeMetaObjectData)[objectIndex];
- Q_ASSERT(!dynamicData.isEmpty());
- VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
- *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
+ // Try again later and resolve the target alias first.
+ _objectsWithAliases.append(objectIndex);
+ // restore
+ alias->idIndex = idIndex;
+ break;
+ }
+ }
- Q_ASSERT(dynamicData.isDetached());
+ if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) {
+ *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
+ break;
+ }
- if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable)
- propertyFlags |= QQmlPropertyData::IsWritable;
- else
- propertyFlags &= ~QQmlPropertyData::IsWritable;
+ propIdx = targetProperty->coreIndex;
- if (resettable)
- propertyFlags |= QQmlPropertyData::IsResettable;
- else
- propertyFlags &= ~QQmlPropertyData::IsResettable;
+ if (!subProperty.isEmpty()) {
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType);
+ if (!valueTypeMetaObject) {
+ *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ break;
+ }
- QString propertyName = stringAt(p->nameIndex);
- if (propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName;
- propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- type, effectiveSignalIndex++);
+ int valueTypeIndex =
+ valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
+ if (valueTypeIndex == -1) {
+ *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ break;
+ }
+ Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
+ propIdx = QQmlPropertyData::encodeValueTypePropertyIndex(propIdx, valueTypeIndex);
+ } else {
+ if (targetProperty->isQObject())
+ alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ }
}
+
+ alias->encodedMetaPropertyIndex = propIdx;
+ alias->flags |= QV4::CompiledData::Alias::Resolved;
+ numResolvedAliases++;
}
- return true;
+
+ if (numResolvedAliases == 0)
+ return seenUnresolvedAlias ? NoAliasResolved : AllAliasesResolved;
+
+ return SomeAliasesResolved;
}
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
+QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , qmlUnit(typeCompiler->qmlUnit())
- , resolvedTypes(*typeCompiler->resolvedTypes())
- , customParsers(typeCompiler->customParserCache())
+ , qmlObjects(typeCompiler->qmlObjects())
, propertyCaches(typeCompiler->propertyCaches())
- , objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
- , customParserBindingsPerObject(typeCompiler->customParserBindings())
+ , customParsers(typeCompiler->customParserCache())
, _seenObjectWithId(false)
{
}
-bool QQmlPropertyValidator::validate()
-{
- _bindingPropertyDataPerObject.resize(qmlUnit->nObjects);
- if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0))
- return false;
- compiler->setDeferredBindingsPerObject(_deferredBindingsPerObject);
- compiler->setBindingPropertyDataPerObject(_bindingPropertyDataPerObject);
- return true;
-}
-
-const QQmlImports &QQmlPropertyValidator::imports() const
+bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
{
- return *compiler->imports();
+ return scanObject(compiler->rootObjectIndex());
}
-typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector;
-
-struct BindingFinder
-{
- bool operator()(quint32 name, const QV4::CompiledData::Binding *binding) const
- {
- return name < binding->propertyNameIndex;
- }
- bool operator()(const QV4::CompiledData::Binding *binding, quint32 name) const
- {
- return binding->propertyNameIndex < name;
- }
- bool operator()(const QV4::CompiledData::Binding *lhs, const QV4::CompiledData::Binding *rhs) const
- {
- return lhs->propertyNameIndex < rhs->propertyNameIndex;
- }
-};
-
-bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
+bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
{
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
- if (obj->idIndex != 0)
+ QmlIR::Object *obj = qmlObjects->at(objectIndex);
+ if (obj->idNameIndex != 0)
_seenObjectWithId = true;
- if (isComponent(objectIndex)) {
- Q_ASSERT(obj->nBindings == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
+ if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ Q_ASSERT(obj->bindingCount() == 1);
+ const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- return validateObject(componentBinding->value.objectIndex, componentBinding);
+ return scanObject(componentBinding->value.objectIndex);
}
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
+ QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
if (!propertyCache)
return true;
- QStringList deferredPropertyNames;
- {
- const QMetaObject *mo = propertyCache->firstCppMetaObject();
- const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
- if (namesIndex != -1) {
- QMetaClassInfo classInfo = mo->classInfo(namesIndex);
- deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
- }
- }
-
- QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
- QList<const QV4::CompiledData::Binding*> customBindings;
-
- // Collect group properties first for sanity checking
- // vector values are sorted by property name string index.
- GroupPropertyVector groupProperties;
- const QV4::CompiledData::Binding *binding = obj->bindingTable();
- for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (!binding->isGroupProperty())
- continue;
-
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- continue;
-
- if (populatingValueTypeGroupProperty) {
- recordError(binding->location, tr("Property assignment expected"));
- return false;
- }
-
- GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
- groupProperties.insert(pos, binding);
- }
-
- QBitArray customParserBindings(obj->nBindings);
- QBitArray deferredBindings;
-
- QmlIR::PropertyResolver propertyResolver(propertyCache);
-
QString defaultPropertyName;
QQmlPropertyData *defaultProperty = 0;
- if (obj->indexOfDefaultProperty != -1) {
+ if (obj->indexOfDefaultPropertyOrAlias != -1) {
QQmlPropertyCache *cache = propertyCache->parent();
defaultPropertyName = cache->defaultPropertyName();
defaultProperty = cache->defaultProperty();
@@ -1851,76 +1198,55 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
defaultProperty = propertyCache->defaultProperty();
}
- QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
+ QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
+
+ QmlIR::PropertyResolver propertyResolver(propertyCache);
+
+ QStringList deferredPropertyNames;
+ {
+ const QMetaObject *mo = propertyCache->firstCppMetaObject();
+ const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
+ if (namesIndex != -1) {
+ QMetaClassInfo classInfo = mo->classInfo(namesIndex);
+ deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
+ }
+ }
- binding = obj->bindingTable();
- for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ QQmlPropertyData *pd = 0;
QString name = stringAt(binding->propertyNameIndex);
if (customParser) {
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- customBindings << binding;
- customParserBindings.setBit(i);
+ binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
continue;
}
} else if (QmlIR::IRBuilder::isSignalPropertyName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
- customBindings << binding;
- customParserBindings.setBit(i);
+ obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
+ binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
continue;
}
}
- bool bindingToDefaultProperty = false;
- bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
-
- bool notInRevision = false;
- QQmlPropertyData *pd = 0;
- if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- pd = propertyResolver.signal(name, &notInRevision);
- else
- pd = propertyResolver.property(name, &notInRevision, isGroupProperty ? QmlIR::PropertyResolver::IgnoreRevision : QmlIR::PropertyResolver::CheckRevision);
-
- if (notInRevision) {
- QString typeName = stringAt(obj->inheritedTypeNameIndex);
- QQmlCompiledData::TypeReference *objectType = resolvedTypes.value(obj->inheritedTypeNameIndex);
- 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));
- }
- }
+ if (name.isEmpty()) {
+ pd = defaultProperty;
+ name = defaultPropertyName;
} else {
- if (isGroupProperty)
- COMPILE_EXCEPTION(binding, tr("Cannot assign a value directly to a grouped property"));
-
- pd = defaultProperty;
- name = defaultPropertyName;
- bindingToDefaultProperty = true;
- }
-
- if (pd)
- collectedBindingPropertyData[i] = pd;
+ if (name.constData()->isUpper())
+ continue;
- if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
- QQmlType *type = 0;
- QQmlImportNamespace *typeNamespace = 0;
- compiler->imports()->resolveType(stringAt(binding->propertyNameIndex), &type, 0, 0, &typeNamespace);
- if (typeNamespace)
- recordError(binding->location, tr("Invalid use of namespace"));
- else
- recordError(binding->location, tr("Invalid attached object assignment"));
- return false;
+ bool notInRevision = false;
+ pd = propertyResolver.property(name, &notInRevision, QmlIR::PropertyResolver::CheckRevision);
}
bool seenSubObjectWithId = false;
if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
qSwap(_seenObjectWithId, seenSubObjectWithId);
- const bool subObjectValid = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType));
+ const bool subObjectValid = scanObject(binding->value.objectIndex);
qSwap(_seenObjectWithId, seenSubObjectWithId);
if (!subObjectValid)
return false;
@@ -1930,538 +1256,28 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
if (!seenSubObjectWithId
&& !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
- if (deferredBindings.isEmpty())
- deferredBindings.resize(obj->nBindings);
-
- deferredBindings.setBit(i);
+ binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
+ obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
}
- // 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;
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
- recordError(binding->location, tr("Attached properties cannot be used here"));
- return false;
- }
- continue;
- }
-
- if (pd) {
- GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
- const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex);
-
- if (!pd->isWritable()
- && !pd->isQList()
- && !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
- ) {
-
- if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
- recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
- else
- 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 (!bindingToDefaultProperty
- && !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- && assigningToGroupProperty) {
- QV4::CompiledData::Location loc = binding->valueLocation;
- if (loc < (*assignedGroupProperty)->valueLocation)
- loc = (*assignedGroupProperty)->valueLocation;
-
- if (pd && QQmlValueTypeFactory::isValueType(pd->propType))
- recordError(loc, tr("Property has already been assigned a value"));
- else
- recordError(loc, tr("Cannot assign a value directly to a grouped property"));
- 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 (binding->isGroupProperty()) {
- if (QQmlValueTypeFactory::isValueType(pd->propType)) {
- if (QQmlValueTypeFactory::metaObjectForMetaType(pd->propType)) {
- if (!pd->isWritable()) {
- recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
- return false;
- }
- } else {
- recordError(binding->location, tr("Invalid grouped property access"));
- return false;
- }
- } else {
- if (!enginePrivate->propertyCacheForType(pd->propType)) {
- recordError(binding->location, tr("Invalid grouped property access"));
- return false;
- }
- }
- }
- } else {
+ if (!pd) {
if (customParser) {
- customBindings << binding;
- customParserBindings.setBit(i);
- continue;
- }
- if (bindingToDefaultProperty) {
- COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent default property"));
- } else {
- COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent property \"%1\"").arg(name));
- }
- }
- }
-
- if (obj->idIndex) {
- bool notInRevision = false;
- collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision);
- }
-
- if (customParser && !customBindings.isEmpty()) {
- customParser->clearErrors();
- customParser->validator = this;
- customParser->engine = enginePrivate;
- customParser->imports = compiler->imports();
- customParser->verifyBindings(qmlUnit, customBindings);
- customParser->validator = 0;
- customParser->engine = 0;
- customParser->imports = (QQmlImports*)0;
- customParserBindingsPerObject->insert(objectIndex, customParserBindings);
- const QList<QQmlError> parserErrors = customParser->errors();
- if (!parserErrors.isEmpty()) {
- foreach (const QQmlError &error, parserErrors)
- compiler->recordError(error);
- return false;
- }
- }
-
- if (!deferredBindings.isEmpty())
- _deferredBindingsPerObject.insert(objectIndex, deferredBindings);
-
- _bindingPropertyDataPerObject[objectIndex] = collectedBindingPropertyData;
-
- return true;
-}
-
-bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
-{
- if (property->isQList()) {
- recordError(binding->valueLocation, tr("Cannot assign primitives to lists"));
- return false;
- }
-
- if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
- return true;
-
- QString value = binding->valueAsString(qmlUnit);
- 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->evaluatesToString()) {
- recordError(binding->valueLocation, tr("Invalid property assignment: string expected"));
- return false;
- }
- }
- break;
- case QVariant::StringList: {
- if (!binding->evaluatesToString()) {
- 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), &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), &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), &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), &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), &ok);
- 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), &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), &ok);
- 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), &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), &ok);
- 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), &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::Vector2D: {
- struct {
- float xp;
- float yp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
- recordError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected"));
- return false;
- }
- }
- break;
- case QVariant::Vector3D: {
- struct {
- float xp;
- float yp;
- float zy;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(qmlUnit), &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), &vec, sizeof(vec))) {
- recordError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected"));
- return false;
- }
- }
- break;
- case QVariant::Quaternion: {
- struct {
- float wp;
- float xp;
- float yp;
- float zp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
- recordError(binding->valueLocation, tr("Invalid property assignment: quaternion 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: number or array of numbers 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;
+ obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
+ binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
}
- break;
- } else if (property->propType == qMetaTypeId<QList<QString> >()) {
- if (!binding->evaluatesToString()) {
- 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->valueLocation, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType))));
- return false;
}
}
- break;
- }
- return true;
-}
-
-/*!
- Returns true if from can be assigned to a (QObject) property of type
- to.
-*/
-bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
-{
- QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
-
- while (fromMo) {
- if (fromMo == toMo)
- return true;
- fromMo = fromMo->parent();
- }
- return false;
-}
-bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
-{
- 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 (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()) {
- const int listType = enginePrivate->listType(property->propType);
- if (!QQmlMetaType::isInterface(listType)) {
- QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
- if (!canCoerce(listType, source)) {
- recordError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
- return false;
- }
- }
- return true;
- } else if (isComponent(binding->value.objectIndex)) {
- 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 if (property->propType == qMetaTypeId<QQmlScriptString>()) {
- recordError(binding->valueLocation, tr("Invalid property assignment: script expected"));
- 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.at(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;
}
QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
: QQmlCompilePass(typeCompiler)
- , objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
- , resolvedTypes(*typeCompiler->resolvedTypes())
+ , resolvedTypes(typeCompiler->resolvedTypes)
, customParsers(typeCompiler->customParserCache())
, qmlObjects(*typeCompiler->qmlObjects())
, propertyCaches(typeCompiler->propertyCaches())
@@ -2471,48 +1287,42 @@ QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::
bool QQmlJSCodeGenerator::generateCodeForComponents()
{
- const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent = *compiler->objectIndexToIdPerComponent();
- for (QHash<int, QHash<int, int> >::ConstIterator component = objectIndexToIdPerComponent.constBegin(), end = objectIndexToIdPerComponent.constEnd();
- component != end; ++component) {
- if (!compileComponent(component.key(), component.value()))
+ const QVector<quint32> &componentRoots = compiler->componentRoots();
+ for (int i = 0; i < componentRoots.count(); ++i) {
+ if (!compileComponent(componentRoots.at(i)))
return false;
}
- return compileComponent(compiler->rootObjectIndex(), *compiler->objectIndexToIdForRoot());
+ return compileComponent(compiler->rootObjectIndex());
}
-bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, int> &objectIndexToId)
+bool QQmlJSCodeGenerator::compileComponent(int contextObject)
{
- if (isComponent(contextObject)) {
- const QmlIR::Object *component = qmlObjects.at(contextObject);
- Q_ASSERT(component->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = component->firstBinding();
+ const QmlIR::Object *obj = qmlObjects.at(contextObject);
+ if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ Q_ASSERT(obj->bindingCount() == 1);
+ const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
contextObject = componentBinding->value.objectIndex;
}
QmlIR::JSCodeGen::ObjectIdMapping idMapping;
- if (!objectIndexToId.isEmpty()) {
- idMapping.reserve(objectIndexToId.count());
+ idMapping.reserve(obj->namedObjectsInComponent.count);
+ for (int i = 0; i < obj->namedObjectsInComponent.count; ++i) {
+ const int objectIndex = obj->namedObjectsInComponent.at(i);
+ QmlIR::JSCodeGen::IdMapping m;
+ const QmlIR::Object *obj = qmlObjects.at(objectIndex);
+ m.name = stringAt(obj->idNameIndex);
+ m.idIndex = obj->id;
+ m.type = propertyCaches->at(objectIndex);
- for (QHash<int, int>::ConstIterator idIt = objectIndexToId.constBegin(), end = objectIndexToId.constEnd();
- idIt != end; ++idIt) {
+ auto *tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ if (tref && tref->isFullyDynamicType)
+ m.type = 0;
- const int objectIndex = idIt.key();
- QmlIR::JSCodeGen::IdMapping m;
- const QmlIR::Object *obj = qmlObjects.at(objectIndex);
- m.name = stringAt(obj->idIndex);
- m.idIndex = idIt.value();
- m.type = propertyCaches.at(objectIndex);
-
- QQmlCompiledData::TypeReference *tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
- if (tref && tref->isFullyDynamicType)
- m.type = 0;
-
- idMapping << m;
- }
+ idMapping << m;
}
- v4CodeGen->beginContextScope(idMapping, propertyCaches.at(contextObject));
+ v4CodeGen->beginContextScope(idMapping, propertyCaches->at(contextObject));
if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
return false;
@@ -2522,12 +1332,12 @@ bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, i
bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
{
- if (isComponent(objectIndex))
+ QmlIR::Object *object = qmlObjects.at(objectIndex);
+ if (object->flags & QV4::CompiledData::Object::IsComponent)
return true;
- QmlIR::Object *object = qmlObjects.at(objectIndex);
if (object->functionsAndExpressions->count > 0) {
- QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex);
+ QQmlPropertyCache *scopeObject = propertyCaches->at(scopeObjectIndex);
v4CodeGen->beginObjectScope(scopeObject);
QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
@@ -2546,8 +1356,7 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn
}
QQmlJS::MemoryPool *pool = compiler->memoryPool();
- object->runtimeFunctionIndices = pool->New<QmlIR::FixedPoolArray<int> >();
- object->runtimeFunctionIndices->init(pool, runtimeFunctionIndices);
+ object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
}
for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
@@ -2580,20 +1389,20 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties()
void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
{
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
+ QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
if (!propertyCache)
return;
QmlIR::Object *object = qmlObjects.at(objectIndex);
- QString defaultProperty = object->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
+ QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
QmlIR::Binding *bindingsToReinsert = 0;
QmlIR::Binding *tail = 0;
QmlIR::Binding *previousBinding = 0;
QmlIR::Binding *binding = object->firstBinding();
while (binding) {
- if (binding->propertyNameIndex == 0 || stringAt(binding->propertyNameIndex) != defaultProperty) {
+ if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
previousBinding = binding;
binding = binding->next;
continue;
@@ -2646,7 +1455,7 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBinding
if (binding->type != QV4::CompiledData::Binding::Type_Script)
continue;
- const int irFunctionIndex = obj->runtimeFunctionIndices->at(binding->value.compiledScriptIndex);
+ const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex);
QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex);
if (simplifyBinding(irFunction, binding)) {
irFunctionsToRemove.append(irFunctionIndex);
@@ -2757,7 +1566,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR:
for (QV4::IR::BasicBlock *bb : function->basicBlocks()) {
for (QV4::IR::Stmt *s : bb->statements()) {
- s->accept(this);
+ visit(s);
if (!_canSimplify)
return false;
}
@@ -2927,22 +1736,41 @@ void QQmlIRFunctionCleanser::clean()
foreach (QV4::IR::Function *function, module->functions) {
for (QV4::IR::BasicBlock *block : function->basicBlocks()) {
for (QV4::IR::Stmt *s : block->statements()) {
- s->accept(this);
+ visit(s);
}
}
}
foreach (QmlIR::Object *obj, *compiler->qmlObjects()) {
- if (!obj->runtimeFunctionIndices)
- continue;
- for (int i = 0; i < obj->runtimeFunctionIndices->count; ++i)
- (*obj->runtimeFunctionIndices)[i] = newFunctionIndices[obj->runtimeFunctionIndices->at(i)];
+ for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i)
+ obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)];
+ }
+}
+
+void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s)
+{
+
+ switch (s->stmtKind) {
+ case QV4::IR::Stmt::PhiStmt:
+ // nothing to do
+ break;
+ default:
+ STMT_VISIT_ALL_KINDS(s);
+ break;
}
}
-void QQmlIRFunctionCleanser::visitClosure(QV4::IR::Closure *closure)
+void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e)
{
- closure->value = newFunctionIndices.at(closure->value);
+ switch (e->exprKind) {
+ case QV4::IR::Expr::ClosureExpr: {
+ auto closure = e->asClosure();
+ closure->value = newFunctionIndices.at(closure->value);
+ } break;
+ default:
+ EXPR_VISIT_ALL_KINDS(e);
+ break;
+ }
}
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 273ba01a88..6ad6ad8557 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -53,13 +53,12 @@
#include <qglobal.h>
#include <qqmlerror.h>
#include <qhash.h>
-#include <private/qqmlcompiler_p.h>
+#include <private/qqmltypeloader_p.h>
#include <private/qqmlirbuilder_p.h>
QT_BEGIN_NAMESPACE
class QQmlEnginePrivate;
-class QQmlCompiledData;
class QQmlError;
class QQmlTypeData;
class QQmlImports;
@@ -75,18 +74,40 @@ struct Location;
}
}
+struct QQmlCompileError
+{
+ QQmlCompileError() {}
+ QQmlCompileError(const QV4::CompiledData::Location &location, const QString &description)
+ : location(location), description(description) {}
+ QV4::CompiledData::Location location;
+ QString description;
+
+ bool isSet() const { return !description.isEmpty(); }
+};
+
struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QmlIR::Document *document);
+ QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
+
+ // --- interface used by QQmlPropertyCacheCreator
+ typedef QmlIR::Object CompiledObject;
+ const QmlIR::Object *objectAt(int index) const { return document->objects.at(index); }
+ int objectCount() const { return document->objects.count(); }
+ QString stringAt(int idx) const;
+ QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsBegin(const QmlIR::Object *object) const { return object->functionsBegin(); }
+ QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsEnd(const QmlIR::Object *object) const { return object->functionsEnd(); }
+ QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypes;
+ // ---
- bool compile();
+ QV4::CompiledData::CompilationUnit *compile();
QList<QQmlError> compilationErrors() const { return errors; }
- void recordError(const QQmlError &error);
+ void recordError(QQmlError error);
+ void recordError(const QV4::CompiledData::Location &location, const QString &description);
+ void recordError(const QQmlCompileError &error);
- QString stringAt(int idx) const;
int registerString(const QString &str);
QV4::IR::Module *jsIRModule() const;
@@ -96,70 +117,52 @@ public:
QUrl url() const { return typeData->finalUrl(); }
QQmlEnginePrivate *enginePrivate() const { return engine; }
const QQmlImports *imports() const;
- QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes();
- QList<QmlIR::Object*> *qmlObjects();
+ QVector<QmlIR::Object *> *qmlObjects() const;
int rootObjectIndex() const;
- void setPropertyCaches(const QVector<QQmlPropertyCache *> &caches);
- const QVector<QQmlPropertyCache *> &propertyCaches() const;
- void setVMEMetaObjects(const QVector<QByteArray> &metaObjects);
- QVector<QByteArray> *vmeMetaObjects() const;
- QHash<int, int> *objectIndexToIdForRoot();
- QHash<int, QHash<int, int> > *objectIndexToIdPerComponent();
- QHash<int, QBitArray> *customParserBindings();
+ void setPropertyCaches(QQmlPropertyCacheVector &&caches);
+ const QQmlPropertyCacheVector *propertyCaches() const;
+ QQmlPropertyCacheVector &&takePropertyCaches();
+ void setComponentRoots(const QVector<quint32> &roots) { m_componentRoots = roots; }
+ const QVector<quint32> &componentRoots() const { return m_componentRoots; }
QQmlJS::MemoryPool *memoryPool();
QStringRef newStringRef(const QString &string);
const QV4::Compiler::StringTableGenerator *stringPool() const;
- void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject);
void setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData);
const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const;
+ void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion);
+
private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
- QQmlCompiledData *compiledData;
QQmlTypeData *typeData;
+ QQmlRefPointer<QQmlTypeNameCache> importCache;
QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
QHash<int, QQmlCustomParser*> customParsers;
+
+ // index in first hash is component index, vector inside contains object indices of objects with id property
+ QVector<quint32> m_componentRoots;
+ QQmlPropertyCacheVector m_propertyCaches;
};
struct QQmlCompilePass
{
- virtual ~QQmlCompilePass() {}
-
QQmlCompilePass(QQmlTypeCompiler *typeCompiler);
QString stringAt(int idx) const { return compiler->stringAt(idx); }
protected:
- void recordError(const QV4::CompiledData::Location &location, const QString &description) const;
+ void recordError(const QV4::CompiledData::Location &location, const QString &description) const
+ { compiler->recordError(location, description); }
+ void recordError(const QQmlCompileError &error)
+ { compiler->recordError(error); }
QQmlTypeCompiler *compiler;
};
-class QQmlPropertyCacheCreator : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreator)
-public:
- QQmlPropertyCacheCreator(QQmlTypeCompiler *typeCompiler);
- ~QQmlPropertyCacheCreator();
-
- bool buildMetaObjects();
-protected:
- bool buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding);
- bool ensureMetaObject(int objectIndex);
- bool createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache);
-
- QQmlEnginePrivate *enginePrivate;
- const QList<QmlIR::Object*> &qmlObjects;
- const QQmlImports *imports;
- QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
- QVector<QByteArray> vmeMetaObjects;
- QVector<QQmlPropertyCache*> propertyCaches;
-};
-
// "Converts" signal expressions to full-fleged function declarations with
// parameters taken from the signal declarations
// It also updates the QV4::CompiledData::Binding objects to set the property name
@@ -176,12 +179,12 @@ private:
bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache);
QQmlEnginePrivate *enginePrivate;
- const QList<QmlIR::Object*> &qmlObjects;
+ const QVector<QmlIR::Object*> &qmlObjects;
const QQmlImports *imports;
const QHash<int, QQmlCustomParser*> &customParsers;
- const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes;
const QSet<QString> &illegalNames;
- const QVector<QQmlPropertyCache*> &propertyCaches;
+ const QQmlPropertyCacheVector * const propertyCaches;
};
// ### This will go away when the codegen resolves all enums to constant expressions
@@ -207,10 +210,10 @@ private:
int evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const;
- const QList<QmlIR::Object*> &qmlObjects;
- const QVector<QQmlPropertyCache *> propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
const QQmlImports *imports;
- QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes;
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes;
};
class QQmlCustomParserScriptIndexer: public QQmlCompilePass
@@ -223,7 +226,7 @@ public:
private:
void scanObjectRecursively(int objectIndex, bool annotateScriptBindings = false);
- const QList<QmlIR::Object*> &qmlObjects;
+ const QVector<QmlIR::Object*> &qmlObjects;
const QHash<int, QQmlCustomParser*> &customParsers;
};
@@ -235,8 +238,8 @@ public:
void annotateBindingsToAliases();
private:
- const QList<QmlIR::Object*> &qmlObjects;
- const QVector<QQmlPropertyCache *> propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
};
class QQmlScriptStringScanner : public QQmlCompilePass
@@ -247,8 +250,8 @@ public:
void scan();
private:
- const QList<QmlIR::Object*> &qmlObjects;
- const QVector<QQmlPropertyCache *> propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
};
class QQmlComponentAndAliasResolver : public QQmlCompilePass
@@ -262,64 +265,48 @@ public:
protected:
void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache);
bool collectIdsAndAliases(int objectIndex);
- bool resolveAliases();
+ bool resolveAliases(int componentIndex);
+ void propertyDataForAlias(QmlIR::Alias *alias, int *type, quint32 *propertyFlags);
+
+ enum AliasResolutionResult {
+ NoAliasResolved,
+ SomeAliasesResolved,
+ AllAliasesResolved
+ };
+
+ AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlCompileError *error);
QQmlEnginePrivate *enginePrivate;
QQmlJS::MemoryPool *pool;
- QList<QmlIR::Object*> *qmlObjects;
+ QVector<QmlIR::Object*> *qmlObjects;
const int indexOfRootObject;
// indices of the objects that are actually Component {}
- QVector<int> componentRoots;
- // indices of objects that are the beginning of a new component
- // scope. This is sorted and used for binary search.
- QVector<quint32> componentBoundaries;
+ QVector<quint32> componentRoots;
- int _componentIndex;
QHash<int, int> _idToObjectIndex;
- QHash<int, int> *_objectIndexToIdInScope;
- QList<int> _objectsWithAliases;
-
- QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
- QVector<QQmlPropertyCache *> propertyCaches;
- QVector<QByteArray> *vmeMetaObjectData;
- QHash<int, int> *objectIndexToIdForRoot;
- QHash<int, QHash<int, int> > *objectIndexToIdPerComponent;
+ QVector<int> _objectsWithAliases;
+
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes;
+ QQmlPropertyCacheVector propertyCaches;
};
-class QQmlPropertyValidator : public QQmlCompilePass
+class QQmlDeferredAndCustomParserBindingScanner : public QQmlCompilePass
{
- Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
public:
- QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler);
-
- bool validate();
+ QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler);
- const QQmlImports &imports() const;
- QQmlEnginePrivate *engine() const { return enginePrivate; }
+ bool scanObject();
private:
- bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const;
- bool validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const;
- bool validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const;
-
- bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
-
- bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
+ bool scanObject(int objectIndex);
- QQmlEnginePrivate *enginePrivate;
- const QV4::CompiledData::Unit *qmlUnit;
- const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
+ QVector<QmlIR::Object*> *qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
const QHash<int, QQmlCustomParser*> &customParsers;
- const QVector<QQmlPropertyCache *> &propertyCaches;
- const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
- QHash<int, QBitArray> *customParserBindingsPerObject;
-
- // collected state variables, essentially write-only
- mutable QHash<int, QBitArray> _deferredBindingsPerObject;
- mutable bool _seenObjectWithId;
- mutable QVector<QV4::CompiledData::BindingPropertyData> _bindingPropertyDataPerObject;
+
+ bool _seenObjectWithId;
};
// ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone.
@@ -331,16 +318,13 @@ public:
bool generateCodeForComponents();
private:
- bool compileComponent(int componentRoot, const QHash<int, int> &objectIndexToId);
+ bool compileComponent(int componentRoot);
bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
- bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
-
- const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent;
- const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes;
const QHash<int, QQmlCustomParser*> &customParsers;
- const QList<QmlIR::Object*> &qmlObjects;
- const QVector<QQmlPropertyCache *> &propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
QmlIR::JSCodeGen * const v4CodeGen;
};
@@ -354,11 +338,11 @@ public:
private:
void mergeDefaultProperties(int objectIndex);
- const QList<QmlIR::Object*> &qmlObjects;
- const QVector<QQmlPropertyCache*> &propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
};
-class QQmlJavaScriptBindingExpressionSimplificationPass : public QQmlCompilePass, public QV4::IR::StmtVisitor
+class QQmlJavaScriptBindingExpressionSimplificationPass : public QQmlCompilePass
{
public:
QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler);
@@ -368,12 +352,30 @@ public:
private:
void reduceTranslationBindings(int objectIndex);
- virtual void visitMove(QV4::IR::Move *move);
- virtual void visitJump(QV4::IR::Jump *) {}
- virtual void visitCJump(QV4::IR::CJump *) { discard(); }
- virtual void visitExp(QV4::IR::Exp *) { discard(); }
- virtual void visitPhi(QV4::IR::Phi *) {}
- virtual void visitRet(QV4::IR::Ret *ret);
+ void visit(QV4::IR::Stmt *s)
+ {
+ switch (s->stmtKind) {
+ case QV4::IR::Stmt::MoveStmt:
+ visitMove(s->asMove());
+ break;
+ case QV4::IR::Stmt::RetStmt:
+ visitRet(s->asRet());
+ break;
+ case QV4::IR::Stmt::CJumpStmt:
+ discard();
+ break;
+ case QV4::IR::Stmt::ExpStmt:
+ discard();
+ break;
+ case QV4::IR::Stmt::JumpStmt:
+ break;
+ case QV4::IR::Stmt::PhiStmt:
+ break;
+ }
+ }
+
+ void visitMove(QV4::IR::Move *move);
+ void visitRet(QV4::IR::Ret *ret);
void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target);
@@ -382,7 +384,7 @@ private:
bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding);
bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding);
- const QList<QmlIR::Object*> &qmlObjects;
+ const QVector<QmlIR::Object*> &qmlObjects;
QV4::IR::Module *jsModule;
bool _canSimplify;
@@ -397,8 +399,7 @@ private:
QVector<int> irFunctionsToRemove;
};
-class QQmlIRFunctionCleanser : public QQmlCompilePass, public QV4::IR::StmtVisitor,
- public QV4::IR::ExprVisitor
+class QQmlIRFunctionCleanser : public QQmlCompilePass
{
public:
QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector<int> &functionsToRemove);
@@ -406,51 +407,13 @@ public:
void clean();
private:
- virtual void visitClosure(QV4::IR::Closure *closure);
-
- virtual void visitTemp(QV4::IR::Temp *) {}
- virtual void visitArgLocal(QV4::IR::ArgLocal *) {}
-
virtual void visitMove(QV4::IR::Move *s) {
- s->source->accept(this);
- s->target->accept(this);
- }
-
- virtual void visitConvert(QV4::IR::Convert *e) { e->expr->accept(this); }
- virtual void visitPhi(QV4::IR::Phi *) { }
-
- virtual void visitExp(QV4::IR::Exp *s) { s->expr->accept(this); }
-
- virtual void visitJump(QV4::IR::Jump *) {}
- virtual void visitCJump(QV4::IR::CJump *s) { s->cond->accept(this); }
- virtual void visitRet(QV4::IR::Ret *s) { s->expr->accept(this); }
-
- virtual void visitConst(QV4::IR::Const *) {}
- virtual void visitString(QV4::IR::String *) {}
- virtual void visitRegExp(QV4::IR::RegExp *) {}
- virtual void visitName(QV4::IR::Name *) {}
- virtual void visitUnop(QV4::IR::Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(QV4::IR::Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(QV4::IR::Call *e) {
- e->base->accept(this);
- for (QV4::IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
+ visit(s->source);
+ visit(s->target);
}
- virtual void visitNew(QV4::IR::New *e) {
- e->base->accept(this);
- for (QV4::IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitSubscript(QV4::IR::Subscript *e) {
- e->base->accept(this);
- e->index->accept(this);
- }
-
- virtual void visitMember(QV4::IR::Member *e) {
- e->base->accept(this);
- }
+ void visit(QV4::IR::Stmt *s);
+ void visit(QV4::IR::Expr *e);
private:
QV4::IR::Module *module;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index ad28e4d6d1..4130ad08d7 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2026,6 +2026,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
function->isStrict = _env->isStrict;
function->isNamedExpression = _env->isNamedFunctionExpression;
+ function->isQmlBinding = _env->compilationMode == QmlBinding;
AST::SourceLocation loc = ast->firstSourceLocation();
function->line = loc.startLine;
@@ -2046,7 +2047,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
}
} else {
if (!_env->isStrict) {
- foreach (const QString &inheritedLocal, inheritedLocals) {
+ for (const QString &inheritedLocal : qAsConst(inheritedLocals)) {
function->LOCAL(inheritedLocal);
unsigned tempIndex = entryBlock->newTemp();
Environment::Member member = { Environment::UndefinedMember,
@@ -2088,7 +2089,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_function->RECEIVE(it->name.toString());
}
- foreach (const Environment::Member &member, _env->members) {
+ for (const Environment::Member &member : qAsConst(_env->members)) {
if (member.function) {
const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
member.function->body ? member.function->body->elements : 0);
@@ -2932,7 +2933,7 @@ QList<QQmlError> Codegen::qmlErrors() const
qmlErrors.reserve(_errors.size());
QUrl url(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
- foreach (const QQmlJS::DiagnosticMessage &msg, _errors) {
+ for (const QQmlJS::DiagnosticMessage &msg: qAsConst(_errors)) {
QQmlError e;
e.setUrl(url);
e.setLine(msg.loc.startLine);
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index a63f35152a..2aab1743cc 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -47,6 +47,14 @@
#include <private/qv4lookup_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmlengine_p.h>
+#include <QQmlPropertyMap>
+#include <QDateTime>
+#include <QSaveFile>
+#include <QFile>
+#include <QFileInfo>
+#include <QScopedValueRollback>
#endif
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
@@ -67,11 +75,20 @@ CompilationUnit::CompilationUnit()
, runtimeLookups(0)
, runtimeRegularExpressions(0)
, runtimeClasses(0)
+ , totalBindingsCount(0)
+ , totalParserStatusCount(0)
+ , totalObjectCount(0)
+ , metaTypeId(-1)
+ , listMetaTypeId(-1)
+ , isRegisteredWithEngine(false)
{}
CompilationUnit::~CompilationUnit()
{
unlink();
+ if (data && !(data->flags & QV4::CompiledData::Unit::StaticData))
+ free(const_cast<Unit *>(data));
+ data = 0;
}
QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
@@ -109,7 +126,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
for (uint i = 0; i < data->lookupTableSize; ++i) {
QV4::Lookup *l = runtimeLookups + i;
- Lookup::Type type = Lookup::Type(compiledLookups[i].type_and_flags);
+ Lookup::Type type = Lookup::Type(uint(compiledLookups[i].type_and_flags));
if (type == CompiledData::Lookup::Type_Getter)
l->getter = QV4::Lookup::getterGeneric;
else if (type == CompiledData::Lookup::Type_Setter)
@@ -146,12 +163,6 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
linkBackendToEngine(engine);
-#if 0
- runtimeFunctionsSortedByAddress.resize(runtimeFunctions.size());
- memcpy(runtimeFunctionsSortedByAddress.data(), runtimeFunctions.data(), runtimeFunctions.size() * sizeof(QV4::Function*));
- std::sort(runtimeFunctionsSortedByAddress.begin(), runtimeFunctionsSortedByAddress.end(), functionSortHelper);
-#endif
-
if (data->indexOfRootFunction != -1)
return runtimeFunctions[data->indexOfRootFunction];
else
@@ -162,10 +173,26 @@ void CompilationUnit::unlink()
{
if (engine)
engine->compilationUnits.erase(engine->compilationUnits.find(this));
+
+ if (isRegisteredWithEngine) {
+ Q_ASSERT(data && quint32(propertyCaches.count()) > data->indexOfRootObject && propertyCaches.at(data->indexOfRootObject));
+ QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(propertyCaches.at(data->indexOfRootObject)->engine);
+ qmlEngine->unregisterInternalCompositeType(this);
+ isRegisteredWithEngine = false;
+ }
+
+ propertyCaches.clear();
+
+ for (int ii = 0; ii < dependentScripts.count(); ++ii)
+ dependentScripts.at(ii)->release();
+ dependentScripts.clear();
+
+ importCache = nullptr;
+
+ qDeleteAll(resolvedTypes);
+ resolvedTypes.clear();
+
engine = 0;
- if (data && !(data->flags & QV4::CompiledData::Unit::StaticData))
- free(data);
- data = 0;
free(runtimeStrings);
runtimeStrings = 0;
delete [] runtimeLookups;
@@ -189,6 +216,223 @@ void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
}
}
+void CompilationUnit::destroy()
+{
+ QQmlEngine *qmlEngine = 0;
+ if (engine && engine->v8Engine)
+ qmlEngine = engine->v8Engine->engine();
+ if (qmlEngine)
+ QQmlEnginePrivate::deleteInEngineThread(qmlEngine, this);
+ else
+ delete this;
+}
+
+IdentifierHash<int> CompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
+{
+ auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
+ if (it == namedObjectsPerComponentCache.end()) {
+ IdentifierHash<int> namedObjectCache(engine);
+ const CompiledData::Object *component = data->objectAt(componentObjectIndex);
+ const LEUInt32 *namedObjectIndexPtr = component->namedObjectsInComponentTable();
+ for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
+ const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr);
+ namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
+ }
+ it = namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
+ }
+ return *it;
+}
+
+void CompilationUnit::finalize(QQmlEnginePrivate *engine)
+{
+ // Add to type registry of composites
+ if (propertyCaches.needsVMEMetaObject(data->indexOfRootObject))
+ engine->registerInternalCompositeType(this);
+ else {
+ const QV4::CompiledData::Object *obj = objectAt(data->indexOfRootObject);
+ auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ Q_ASSERT(typeRef);
+ if (typeRef->compilationUnit) {
+ metaTypeId = typeRef->compilationUnit->metaTypeId;
+ listMetaTypeId = typeRef->compilationUnit->listMetaTypeId;
+ } else {
+ metaTypeId = typeRef->type->typeId();
+ listMetaTypeId = typeRef->type->qListTypeId();
+ }
+ }
+
+ // Collect some data for instantiation later.
+ int bindingCount = 0;
+ int parserStatusCount = 0;
+ int objectCount = 0;
+ for (quint32 i = 0; i < data->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = data->objectAt(i);
+ bindingCount += obj->nBindings;
+ if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ if (QQmlType *qmlType = typeRef->type) {
+ if (qmlType->parserStatusCast() != -1)
+ ++parserStatusCount;
+ }
+ ++objectCount;
+ if (typeRef->compilationUnit) {
+ bindingCount += typeRef->compilationUnit->totalBindingsCount;
+ parserStatusCount += typeRef->compilationUnit->totalParserStatusCount;
+ objectCount += typeRef->compilationUnit->totalObjectCount;
+ }
+ }
+ }
+
+ totalBindingsCount = bindingCount;
+ totalParserStatusCount = parserStatusCount;
+ totalObjectCount = objectCount;
+}
+
+bool CompilationUnit::saveToDisk(QString *errorString)
+{
+ errorString->clear();
+
+ const QUrl unitUrl = url();
+ if (!unitUrl.isLocalFile()) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ // Foo.qml -> Foo.qmlc
+ QSaveFile cacheFile(unitUrl.toLocalFile() + QLatin1Char('c'));
+ if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ *errorString = cacheFile.errorString();
+ return false;
+ }
+
+ QByteArray modifiedUnit;
+ modifiedUnit.resize(data->unitSize);
+ memcpy(modifiedUnit.data(), data, data->unitSize);
+ const char *dataPtr = modifiedUnit.data();
+ Unit *unitPtr;
+ memcpy(&unitPtr, &dataPtr, sizeof(unitPtr));
+ unitPtr->flags |= Unit::StaticData;
+
+ prepareCodeOffsetsForDiskStorage(unitPtr);
+
+ qint64 headerWritten = cacheFile.write(modifiedUnit);
+ if (headerWritten != modifiedUnit.size()) {
+ *errorString = cacheFile.errorString();
+ return false;
+ }
+
+ if (!saveCodeToDisk(&cacheFile, unitPtr, errorString))
+ return false;
+
+ if (!cacheFile.commit()) {
+ *errorString = cacheFile.errorString();
+ return false;
+ }
+
+ return true;
+}
+
+bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
+{
+ if (!url.isLocalFile()) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ const QString sourcePath = url.toLocalFile();
+ QScopedPointer<QFile> cacheFile(new QFile(sourcePath + QLatin1Char('c')));
+
+ if (!cacheFile->open(QIODevice::ReadOnly)) {
+ *errorString = cacheFile->errorString();
+ return false;
+ }
+
+ {
+ CompiledData::Unit header;
+ qint64 bytesRead = cacheFile->read(reinterpret_cast<char *>(&header), sizeof(header));
+
+ if (bytesRead != sizeof(header)) {
+ *errorString = QStringLiteral("File too small for the header fields");
+ return false;
+ }
+
+ if (strncmp(header.magic, CompiledData::magic_str, sizeof(header.magic))) {
+ *errorString = QStringLiteral("Magic bytes in the header do not match");
+ return false;
+ }
+
+ if (header.version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
+ *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(header.version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
+ return false;
+ }
+
+ if (header.qtVersion != quint32(QT_VERSION)) {
+ *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(header.qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
+ return false;
+ }
+
+ {
+ QFileInfo sourceCode(sourcePath);
+ if (sourceCode.exists() && sourceCode.lastModified().toMSecsSinceEpoch() != header.sourceTimeStamp) {
+ *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
+ return false;
+ }
+ }
+
+ }
+ // Data structure and qt version matched, so now we can access the rest of the file safely.
+
+ uchar *cacheData = cacheFile->map(/*offset*/0, cacheFile->size());
+ if (!cacheData) {
+ *errorString = cacheFile->errorString();
+ return false;
+ }
+
+ QScopedValueRollback<const Unit *> dataPtrChange(data, reinterpret_cast<const Unit *>(cacheData));
+
+ {
+ const QString foundArchitecture = stringAt(data->architectureIndex);
+ const QString expectedArchitecture = QSysInfo::buildAbi();
+ if (foundArchitecture != expectedArchitecture) {
+ *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
+ return false;
+ }
+ }
+
+ {
+ const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
+ const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
+ if (foundCodeGenerator != expectedCodeGenerator) {
+ *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
+ return false;
+ }
+ }
+
+ if (!memoryMapCode(errorString))
+ return false;
+
+ dataPtrChange.commit();
+ backingFile.reset(cacheFile.take());
+ return true;
+}
+
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
+{
+ Q_UNUSED(unit);
+}
+
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
+{
+ Q_UNUSED(device);
+ Q_UNUSED(unit);
+ *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
+ return false;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ *errorString = QStringLiteral("Missing code mapping backend");
+ return false;
+}
#endif // V4_BOOTSTRAP
Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
@@ -205,7 +449,7 @@ QString Binding::valueAsString(const Unit *unit) const
case Type_Boolean:
return value.b ? QStringLiteral("true") : QStringLiteral("false");
case Type_Number:
- return QString::number(value.d);
+ return QString::number(valueAsNumber());
case Type_Invalid:
return QString();
#ifdef QT_NO_TRANSLATION
@@ -287,6 +531,56 @@ QString Binding::valueAsScriptString(const Unit *unit) const
return valueAsString(unit);
}
+#ifndef V4_BOOTSTRAP
+/*!
+Returns the property cache, if one alread exists. The cache is not referenced.
+*/
+QQmlPropertyCache *ResolvedTypeReference::propertyCache() const
+{
+ if (type)
+ return typePropertyCache;
+ else
+ return compilationUnit->rootPropertyCache();
+}
+
+/*!
+Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
+*/
+QQmlPropertyCache *ResolvedTypeReference::createPropertyCache(QQmlEngine *engine)
+{
+ if (typePropertyCache) {
+ return typePropertyCache;
+ } else if (type) {
+ typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type->metaObject());
+ return typePropertyCache;
+ } else {
+ return compilationUnit->rootPropertyCache();
+ }
+}
+
+template <typename T>
+bool qtTypeInherits(const QMetaObject *mo) {
+ while (mo) {
+ if (mo == &T::staticMetaObject)
+ return true;
+ mo = mo->superClass();
+ }
+ return false;
+}
+
+void ResolvedTypeReference::doDynamicTypeCheck()
+{
+ const QMetaObject *mo = 0;
+ if (typePropertyCache)
+ mo = typePropertyCache->firstCppMetaObject();
+ else if (type)
+ mo = type->metaObject();
+ else if (compilationUnit)
+ mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
+ isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
+}
+#endif
+
}
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 8c617875e0..82e303f27d 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -60,11 +60,26 @@
#include <private/qv4executableallocator_p.h>
#include <private/qqmlrefcount_p.h>
#include <private/qqmlnullablevalue_p.h>
+#include <private/qv4identifier_p.h>
+#include <private/qflagpointer_p.h>
+#include <private/qjson_p.h>
+#ifndef V4_BOOTSTRAP
+#include <private/qqmltypenamecache_p.h>
+#include <private/qqmlpropertycache_p.h>
+#endif
QT_BEGIN_NAMESPACE
+// Bump this whenever the compiler data structures change in an incompatible way.
+#define QV4_DATA_STRUCTURE_VERSION 0x01
+
+class QIODevice;
class QQmlPropertyCache;
class QQmlPropertyData;
+class QQmlTypeNameCache;
+class QQmlScriptData;
+class QQmlType;
+class QQmlEngine;
namespace QmlIR {
struct Document;
@@ -76,25 +91,48 @@ struct Function;
}
struct Function;
+class EvalISelFactory;
namespace CompiledData {
+typedef QJsonPrivate::q_littleendian<qint16> LEInt16;
+typedef QJsonPrivate::q_littleendian<quint16> LEUInt16;
+typedef QJsonPrivate::q_littleendian<quint32> LEUInt32;
+typedef QJsonPrivate::q_littleendian<qint32> LEInt32;
+typedef QJsonPrivate::q_littleendian<quint64> LEUInt64;
+typedef QJsonPrivate::q_littleendian<qint64> LEInt64;
+
struct String;
struct Function;
struct Lookup;
struct RegExp;
struct Unit;
+template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const>
+struct TableIterator
+{
+ TableIterator(const Container *container, int index) : container(container), index(index) {}
+ const Container *container;
+ int index;
+
+ const ItemType *operator->() { return (container->*IndexedGetter)(index); }
+ void operator++() { ++index; }
+ bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
+ bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
+};
+
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
#pragma pack(push, 1)
#endif
struct Location
{
- qint32 line;
- qint32 column;
+ union {
+ QJsonPrivate::qle_bitfield<0, 20> line;
+ QJsonPrivate::qle_bitfield<20, 12> column;
+ };
- Location(): line(-1), column(-1) {}
+ Location() { line = 0; column = 0; }
inline bool operator<(const Location &other) const {
return line < other.line ||
@@ -104,20 +142,22 @@ struct Location
struct RegExp
{
- enum Flags {
+ enum Flags : unsigned int {
RegExp_Global = 0x01,
RegExp_IgnoreCase = 0x02,
RegExp_Multiline = 0x04
};
- quint32 flags;
- quint32 stringIndex;
+ union {
+ QJsonPrivate::qle_bitfield<0, 4> flags;
+ QJsonPrivate::qle_bitfield<4, 28> stringIndex;
+ };
- static int calculateSize() { return sizeof(RegExp); }
+ RegExp() { flags = 0; stringIndex = 0; }
};
struct Lookup
{
- enum Type {
+ enum Type : unsigned int {
Type_Getter = 0x0,
Type_Setter = 0x1,
Type_GlobalGetter = 2,
@@ -125,21 +165,27 @@ struct Lookup
Type_IndexedSetter = 4
};
- quint32 type_and_flags;
- quint32 nameIndex;
+ union {
+ QJsonPrivate::qle_bitfield<0, 4> type_and_flags;
+ QJsonPrivate::qle_bitfield<4, 28> nameIndex;
+ };
- static int calculateSize() { return sizeof(Lookup); }
+ Lookup() { type_and_flags = 0; nameIndex = 0; }
};
struct JSClassMember
{
- uint nameOffset : 31;
- uint isAccessor : 1;
+ union {
+ QJsonPrivate::qle_bitfield<0, 31> nameOffset;
+ QJsonPrivate::qle_bitfield<31, 1> isAccessor;
+ };
+
+ JSClassMember() { nameOffset = 0; isAccessor = 0; }
};
struct JSClass
{
- uint nMembers;
+ LEUInt32 nMembers;
// JSClassMember[nMembers]
static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
@@ -147,8 +193,7 @@ struct JSClass
struct String
{
- quint32 flags; // isArrayIndex
- qint32 size;
+ LEInt32 size;
// uint16 strdata[]
static int calculateSize(const QString &str) {
@@ -158,7 +203,7 @@ struct String
struct Function
{
- enum Flags {
+ enum Flags : unsigned int {
HasDirectEval = 0x1,
UsesArgumentsObject = 0x2,
IsStrict = 0x4,
@@ -166,36 +211,46 @@ struct Function
HasCatchOrWith = 0x10
};
- quint32 index; // in CompilationUnit's function table
- quint32 nameIndex;
- qint64 flags;
- quint32 nFormals;
- quint32 formalsOffset;
- quint32 nLocals;
- quint32 localsOffset;
- quint32 nInnerFunctions;
- quint32 innerFunctionsOffset;
+ LEUInt32 nameIndex;
+ LEUInt32 nFormals;
+ LEUInt32 formalsOffset;
+ LEUInt32 nLocals;
+ LEUInt32 localsOffset;
+ LEUInt32 nInnerFunctions;
Location location;
// Qml Extensions Begin
- quint32 nDependingIdObjects;
- quint32 dependingIdObjectsOffset; // Array of resolved ID objects
- quint32 nDependingContextProperties;
- quint32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
- quint32 nDependingScopeProperties;
- quint32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
+ LEUInt32 nDependingIdObjects;
+ LEUInt32 dependingIdObjectsOffset; // Array of resolved ID objects
+ LEUInt32 nDependingContextProperties;
+ LEUInt32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
+ LEUInt32 nDependingScopeProperties;
+ LEUInt32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
// Qml Extensions End
+ // Absolute offset into file where the code for this function is located. Only used when the function
+ // is serialized.
+ LEUInt64 codeOffset;
+ LEUInt64 codeSize;
+
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
// quint32 offsetForInnerFunctions[nInnerFunctions]
// Function[nInnerFunctions]
- const quint32 *formalsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
- const quint32 *localsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
- const quint32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); }
- const quint32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); }
- const quint32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); }
+ // Keep all unaligned data at the end
+ quint8 flags;
+
+ const LEUInt32 *formalsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
+ const LEUInt32 *localsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
+ const LEUInt32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); }
+ const LEUInt32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); }
+ const LEUInt32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); }
+
+ // --- QQmlPropertyCacheCreator interface
+ const LEUInt32 *formalsBegin() const { return formalsTable(); }
+ const LEUInt32 *formalsEnd() const { return formalsTable() + nFormals; }
+ // ---
inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; }
@@ -207,15 +262,15 @@ struct Function
// Qml data structures
struct Q_QML_EXPORT TranslationData {
- quint32 commentIndex;
- int number;
+ LEUInt32 commentIndex;
+ LEInt32 number;
};
struct Q_QML_PRIVATE_EXPORT Binding
{
- quint32 propertyNameIndex;
+ LEUInt32 propertyNameIndex;
- enum ValueType {
+ enum ValueType : unsigned int {
Type_Invalid,
Type_Boolean,
Type_Number,
@@ -228,26 +283,30 @@ struct Q_QML_PRIVATE_EXPORT Binding
Type_GroupProperty
};
- enum Flags {
+ enum Flags : unsigned int {
IsSignalHandlerExpression = 0x1,
IsSignalHandlerObject = 0x2,
IsOnAssignment = 0x4,
InitializerForReadOnlyDeclaration = 0x8,
IsResolvedEnum = 0x10,
IsListItem = 0x20,
- IsBindingToAlias = 0x40
+ IsBindingToAlias = 0x40,
+ IsDeferredBinding = 0x80,
+ IsCustomParserBinding = 0x100,
};
- quint32 flags : 16;
- quint32 type : 16;
+ union {
+ QJsonPrivate::qle_bitfield<0, 16> flags;
+ QJsonPrivate::qle_bitfield<16, 16> type;
+ };
union {
bool b;
- double d;
- quint32 compiledScriptIndex; // used when Type_Script
- quint32 objectIndex;
+ quint64 doubleValue; // do not access directly, needs endian protected access
+ LEUInt32 compiledScriptIndex; // used when Type_Script
+ LEUInt32 objectIndex;
TranslationData translationData; // used when Type_Translation
} value;
- quint32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings)
+ LEUInt32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings)
Location location;
Location valueLocation;
@@ -307,11 +366,20 @@ struct Q_QML_PRIVATE_EXPORT Binding
QString valueAsScriptString(const Unit *unit) const;
double valueAsNumber() const
{
- if (type == Type_Number)
- return value.d;
- return 0.0;
-
+ if (type != Type_Number)
+ return 0.0;
+ quint64 intval = qFromLittleEndian<quint64>(value.doubleValue);
+ double d;
+ memcpy(&d, &intval, sizeof(double));
+ return d;
}
+ void setNumberValueInternal(double d)
+ {
+ quint64 intval;
+ memcpy(&intval, &d, sizeof(double));
+ value.doubleValue = qToLittleEndian<quint64>(intval);
+ }
+
bool valueAsBoolean() const
{
if (type == Type_Boolean)
@@ -323,17 +391,16 @@ struct Q_QML_PRIVATE_EXPORT Binding
struct Parameter
{
- quint32 nameIndex;
- quint32 type;
- quint32 customTypeNameIndex;
- quint32 reserved;
+ LEUInt32 nameIndex;
+ LEUInt32 type;
+ LEUInt32 customTypeNameIndex;
Location location;
};
struct Signal
{
- quint32 nameIndex;
- quint32 nParameters;
+ LEUInt32 nameIndex;
+ LEUInt32 nParameters;
Location location;
// Parameter parameters[1];
@@ -346,47 +413,95 @@ struct Signal
+ nParameters * sizeof(Parameter)
+ 7) & ~0x7;
}
+
+ // --- QQmlPropertyCacheCceatorInterface
+ const Parameter *parametersBegin() const { return parameterAt(0); }
+ const Parameter *parametersEnd() const { return parameterAt(nParameters); }
+ int parameterCount() const { return nParameters; }
+ // ---
};
struct Property
{
- enum Type { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
+ enum Type : unsigned int { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
Font, Time, Date, DateTime, Rect, Point, Size,
Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion,
- Alias, Custom, CustomList };
+ Custom, CustomList };
- enum Flags {
+ enum Flags : unsigned int {
IsReadOnly = 0x1
};
- quint32 nameIndex;
- quint32 type;
+ LEUInt32 nameIndex;
+ union {
+ QJsonPrivate::qle_bitfield<0, 31> type;
+ QJsonPrivate::qle_bitfield<31, 1> flags; // readonly
+ };
+ LEUInt32 customTypeNameIndex; // If type >= Custom
+ Location location;
+};
+
+struct Alias {
+ enum Flags : unsigned int {
+ IsReadOnly = 0x1,
+ Resolved = 0x2,
+ AliasPointsToPointerObject = 0x4
+ };
+ union {
+ QJsonPrivate::qle_bitfield<0, 29> nameIndex;
+ QJsonPrivate::qle_bitfield<29, 3> flags;
+ };
union {
- quint32 customTypeNameIndex; // If type >= Custom
- quint32 aliasIdValueIndex; // If type == Alias
+ LEUInt32 idIndex; // string index
+ QJsonPrivate::qle_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
+ QJsonPrivate::qle_bitfield<31, 1> aliasToLocalAlias;
+ };
+ union {
+ LEUInt32 propertyNameIndex; // string index
+ LEInt32 encodedMetaPropertyIndex;
+ LEUInt32 localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId)
};
- quint32 aliasPropertyValueIndex;
- quint32 flags; // readonly
Location location;
- Location aliasLocation; // If type == Alias
+ Location referenceLocation;
+
+ bool isObjectAlias() const {
+ Q_ASSERT(flags & Resolved);
+ return encodedMetaPropertyIndex == -1;
+ }
};
struct Object
{
+ enum Flags : unsigned int {
+ NoFlag = 0x0,
+ IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
+ HasDeferredBindings = 0x2, // any of the bindings are deferred
+ HasCustomParserBindings = 0x4
+ };
+
// Depending on the use, this may be the type name to instantiate before instantiating this
// object. For grouped properties the type name will be empty and for attached properties
// it will be the name of the attached type.
- quint32 inheritedTypeNameIndex;
- quint32 idIndex;
- qint32 indexOfDefaultProperty; // -1 means no default property declared in this object
- quint32 nFunctions;
- quint32 offsetToFunctions;
- quint32 nProperties;
- quint32 offsetToProperties;
- quint32 nSignals;
- quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
- quint32 nBindings;
- quint32 offsetToBindings;
+ LEUInt32 inheritedTypeNameIndex;
+ LEUInt32 idNameIndex;
+ union {
+ QJsonPrivate::qle_bitfield<0, 15> flags;
+ QJsonPrivate::qle_bitfield<15, 1> defaultPropertyIsAlias;
+ QJsonPrivate::qle_signedbitfield<16, 16> id;
+ };
+ LEInt32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
+ LEUInt32 nFunctions;
+ LEUInt32 offsetToFunctions;
+ LEUInt32 nProperties;
+ LEUInt32 offsetToProperties;
+ LEUInt32 nAliases;
+ LEUInt32 offsetToAliases;
+ LEUInt32 nSignals;
+ LEUInt32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
+ LEUInt32 nBindings;
+ LEUInt32 offsetToBindings;
+ LEUInt32 nNamedObjectsInComponent;
+ LEUInt32 offsetToNamedObjectsInComponent;
Location location;
Location locationOfIdProperty;
// Function[]
@@ -394,20 +509,22 @@ struct Object
// Signal[]
// Binding[]
- static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nSignals, int nBindings)
+ static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings, int nNamedObjectsInComponent)
{
return ( sizeof(Object)
+ nFunctions * sizeof(quint32)
+ nProperties * sizeof(Property)
+ + nAliases * sizeof(Alias)
+ nSignals * sizeof(quint32)
+ nBindings * sizeof(Binding)
+ + nNamedObjectsInComponent * sizeof(int)
+ 0x7
) & ~0x7;
}
- const quint32 *functionOffsetTable() const
+ const LEUInt32 *functionOffsetTable() const
{
- return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
+ return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
}
const Property *propertyTable() const
@@ -415,6 +532,11 @@ struct Object
return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
}
+ const Alias *aliasTable() const
+ {
+ return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases);
+ }
+
const Binding *bindingTable() const
{
return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
@@ -422,78 +544,111 @@ struct Object
const Signal *signalAt(int idx) const
{
- const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
+ const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
}
+
+ const LEUInt32 *namedObjectsInComponentTable() const
+ {
+ return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
+ }
+
+ // --- QQmlPropertyCacheCreator interface
+ int propertyCount() const { return nProperties; }
+ int aliasCount() const { return nAliases; }
+ int signalCount() const { return nSignals; }
+ int functionCount() const { return nFunctions; }
+
+ const Binding *bindingsBegin() const { return bindingTable(); }
+ const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
+
+ const Property *propertiesBegin() const { return propertyTable(); }
+ const Property *propertiesEnd() const { return propertyTable() + nProperties; }
+
+ const Alias *aliasesBegin() const { return aliasTable(); }
+ const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
+
+ typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator;
+ SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
+ SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
+
+ int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
+ // ---
};
struct Import
{
- enum ImportType {
+ enum ImportType : unsigned int {
ImportLibrary = 0x1,
ImportFile = 0x2,
ImportScript = 0x3
};
- quint32 type;
+ quint8 type;
- quint32 uriIndex;
- quint32 qualifierIndex;
+ LEUInt32 uriIndex;
+ LEUInt32 qualifierIndex;
- qint32 majorVersion;
- qint32 minorVersion;
+ LEInt32 majorVersion;
+ LEInt32 minorVersion;
Location location;
- Import(): type(0), uriIndex(0), qualifierIndex(0), majorVersion(0), minorVersion(0) {}
+ Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; }
};
static const char magic_str[] = "qv4cdata";
struct Unit
{
+ // DO NOT CHANGE THESE FIELDS EVER
char magic[8];
- qint16 architecture;
- qint16 version;
- quint32 unitSize; // Size of the Unit and any depending data.
+ LEUInt32 version;
+ LEUInt32 qtVersion;
+ LEInt64 sourceTimeStamp;
+ LEUInt32 unitSize; // Size of the Unit and any depending data.
+ // END DO NOT CHANGE THESE FIELDS EVER
+
+ LEUInt32 architectureIndex; // string index to QSysInfo::buildAbi()
+ LEUInt32 codeGeneratorIndex;
- enum {
+ enum : unsigned int {
IsJavascript = 0x1,
IsQml = 0x2,
StaticData = 0x4, // Unit data persistent in memory?
IsSingleton = 0x8,
IsSharedLibrary = 0x10 // .pragma shared?
};
- quint32 flags;
- uint stringTableSize;
- uint offsetToStringTable;
- uint functionTableSize;
- uint offsetToFunctionTable;
- uint lookupTableSize;
- uint offsetToLookupTable;
- uint regexpTableSize;
- uint offsetToRegexpTable;
- uint constantTableSize;
- uint offsetToConstantTable;
- uint jsClassTableSize;
- uint offsetToJSClassTable;
- qint32 indexOfRootFunction;
- quint32 sourceFileIndex;
+ LEUInt32 flags;
+ LEUInt32 stringTableSize;
+ LEUInt32 offsetToStringTable;
+ LEUInt32 functionTableSize;
+ LEUInt32 offsetToFunctionTable;
+ LEUInt32 lookupTableSize;
+ LEUInt32 offsetToLookupTable;
+ LEUInt32 regexpTableSize;
+ LEUInt32 offsetToRegexpTable;
+ LEUInt32 constantTableSize;
+ LEUInt32 offsetToConstantTable;
+ LEUInt32 jsClassTableSize;
+ LEUInt32 offsetToJSClassTable;
+ LEInt32 indexOfRootFunction;
+ LEUInt32 sourceFileIndex;
/* QML specific fields */
- quint32 nImports;
- quint32 offsetToImports;
- quint32 nObjects;
- quint32 offsetToObjects;
- quint32 indexOfRootObject;
+ LEUInt32 nImports;
+ LEUInt32 offsetToImports;
+ LEUInt32 nObjects;
+ LEUInt32 offsetToObjects;
+ LEUInt32 indexOfRootObject;
const Import *importAt(int idx) const {
return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
}
const Object *objectAt(int idx) const {
- const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
+ const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
}
@@ -503,22 +658,31 @@ struct Unit
/* end QML specific fields*/
QString stringAt(int idx) const {
- const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
+ const LEUInt32 offset = offsetTable[idx];
const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
if (str->size == 0)
return QString();
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
if (flags & StaticData)
return QString::fromRawData(characters, str->size);
return QString(characters, str->size);
+#else
+ const LEUInt16 *characters = reinterpret_cast<const LEUInt16 *>(str + 1);
+ QString qstr(str->size, Qt::Uninitialized);
+ QChar *ch = qstr.data();
+ for (int i = 0; i < str->size; ++i)
+ ch[i] = QChar(characters[i]);
+ return qstr;
+#endif
}
- const uint *functionOffsetTable() const { return reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
+ const LEUInt32 *functionOffsetTable() const { return reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
const Function *functionAt(int idx) const {
- const uint *offsetTable = functionOffsetTable();
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = functionOffsetTable();
+ const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
}
@@ -531,22 +695,13 @@ struct Unit
}
const JSClassMember *jsClassAt(int idx, int *nMembers) const {
- const uint *offsetTable = reinterpret_cast<const uint *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
+ const LEUInt32 offset = offsetTable[idx];
const char *ptr = reinterpret_cast<const char *>(this) + offset;
const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
*nMembers = klass->nMembers;
return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
}
-
- static int calculateSize(uint nFunctions, uint nRegExps, uint nConstants,
- uint nLookups, uint nClasses) {
- return (sizeof(Unit)
- + (nFunctions + nClasses) * sizeof(uint)
- + nRegExps * RegExp::calculateSize()
- + nConstants * sizeof(QV4::ReturnedValue)
- + nLookups * Lookup::calculateSize()
- + 7) & ~7; }
};
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
@@ -574,7 +729,67 @@ struct TypeReferenceMap : QHash<int, TypeReference>
return *it;
return *insert(nameIndex, loc);
}
+
+ template <typename CompiledObject>
+ void collectFromObject(const CompiledObject *obj)
+ {
+ if (obj->inheritedTypeNameIndex != 0) {
+ TypeReference &r = this->add(obj->inheritedTypeNameIndex, obj->location);
+ r.needsCreation = true;
+ r.errorWhenNotFound = true;
+ }
+
+ for (auto prop = obj->propertiesBegin(), propEnd = obj->propertiesEnd(); prop != propEnd; ++prop) {
+ 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.
+ TypeReference &r = this->add(prop->customTypeNameIndex, obj->location);
+ r.errorWhenNotFound = true;
+ }
+ }
+
+ for (auto binding = obj->bindingsBegin(), bindingEnd = obj->bindingsEnd(); binding != bindingEnd; ++binding) {
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
+ this->add(binding->propertyNameIndex, binding->location);
+ }
+ }
+
+ template <typename Iterator>
+ void collectFromObjects(Iterator it, Iterator end)
+ {
+ for (; it != end; ++it)
+ collectFromObject(*it);
+ }
+};
+
+#ifndef V4_BOOTSTRAP
+struct ResolvedTypeReference
+{
+ ResolvedTypeReference()
+ : type(0)
+ , majorVersion(0)
+ , minorVersion(0)
+ , isFullyDynamicType(false)
+ {}
+
+ QQmlType *type;
+ QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+
+ int majorVersion;
+ int minorVersion;
+ // Types such as QQmlPropertyMap can add properties dynamically at run-time and
+ // therefore cannot have a property cache installed when instantiated.
+ bool isFullyDynamicType;
+
+ QQmlPropertyCache *propertyCache() const;
+ QQmlPropertyCache *createPropertyCache(QQmlEngine *);
+
+ void doDynamicTypeCheck();
};
+// map from name index
+typedef QHash<int, ResolvedTypeReference*> ResolvedTypeReferenceMap;
+#endif
// index is per-object binding index
typedef QVector<QQmlPropertyData*> BindingPropertyData;
@@ -597,7 +812,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
virtual ~CompilationUnit();
#endif
- Unit *data;
+ const Unit *data;
// Called only when building QML, when we build the header for JS first and append QML data
virtual QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument);
@@ -614,20 +829,75 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
QVector<QV4::Function *> runtimeFunctions;
mutable QQmlNullableValue<QUrl> m_url;
+ // QML specific fields
+ QQmlPropertyCacheVector propertyCaches;
+ QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject); }
+
+ QQmlRefPointer<QQmlTypeNameCache> importCache;
+
// index is object index. This allows fast access to the
// property data when initializing bindings, avoiding expensive
// lookups by string (property name).
QVector<BindingPropertyData> bindingPropertyDataPerObject;
+ // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects
+ // this is initialized on-demand by QQmlContextData
+ QHash<int, IdentifierHash<int>> namedObjectsPerComponentCache;
+ IdentifierHash<int> namedObjectsPerComponent(int componentObjectIndex);
+
+ void finalize(QQmlEnginePrivate *engine);
+
+ int totalBindingsCount; // Number of bindings used in this type
+ int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
+ int totalObjectCount; // Number of objects explicitly instantiated
+
+ QVector<QQmlScriptData *> dependentScripts;
+ ResolvedTypeReferenceMap resolvedTypes;
+
+ int metaTypeId;
+ int listMetaTypeId;
+ bool isRegisteredWithEngine;
+
+ QScopedPointer<QIODevice> backingFile;
+
+ // --- interface for QQmlPropertyCacheCreator
+ typedef Object CompiledObject;
+ int objectCount() const { return data->nObjects; }
+ int rootObjectIndex() const { return data->indexOfRootObject; }
+ const Object *objectAt(int index) const { return data->objectAt(index); }
+ QString stringAt(int index) const { return data->stringAt(index); }
+
+ struct FunctionIterator
+ {
+ FunctionIterator(const Unit *unit, const Object *object, int index) : unit(unit), object(object), index(index) {}
+ const Unit *unit;
+ const Object *object;
+ int index;
+
+ const Function *operator->() const { return unit->functionAt(object->functionOffsetTable()[index]); }
+ void operator++() { ++index; }
+ bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
+ bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
+ };
+ FunctionIterator objectFunctionsBegin(const Object *object) const { return FunctionIterator(data, object, 0); }
+ FunctionIterator objectFunctionsEnd(const Object *object) const { return FunctionIterator(data, object, object->nFunctions); }
+ // ---
+
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
void unlink();
- virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int /*functionIndex*/) { return 0; }
-
void markObjects(QV4::ExecutionEngine *e);
+ void destroy() Q_DECL_OVERRIDE;
+
+ bool saveToDisk(QString *errorString);
+ bool loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString);
+
protected:
virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;
+ virtual void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit);
+ virtual bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString);
+ virtual bool memoryMapCode(QString *errorString);
#endif // V4_BOOTSTRAP
};
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 3943642146..768a4ffcd3 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -42,6 +42,7 @@
#include <qv4isel_p.h>
#include <private/qv4string_p.h>
#include <private/qv4value_p.h>
+#include <private/qv4alloca_p.h>
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
@@ -75,16 +76,21 @@ void QV4::Compiler::StringTableGenerator::clear()
void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
- uint *stringTable = reinterpret_cast<uint *>(dataStart + unit->offsetToStringTable);
+ CompiledData::LEUInt32 *stringTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataStart + unit->offsetToStringTable);
char *stringData = dataStart + unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
for (int i = 0; i < strings.size(); ++i) {
stringTable[i] = stringData - dataStart;
const QString &qstr = strings.at(i);
- QV4::CompiledData::String *s = (QV4::CompiledData::String*)(stringData);
- s->flags = 0; // ###
+ QV4::CompiledData::String *s = reinterpret_cast<QV4::CompiledData::String *>(stringData);
s->size = qstr.length();
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
memcpy(s + 1, qstr.constData(), qstr.length()*sizeof(ushort));
+#else
+ ushort *uc = reinterpret_cast<ushort *>(s + 1);
+ for (int i = 0; i < qstr.length(); ++i)
+ uc[i] = qToLittleEndian<ushort>(qstr.at(i).unicode());
+#endif
stringData += QV4::CompiledData::String::calculateSize(qstr);
}
@@ -92,7 +98,6 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::IR::Module *module)
: irModule(module)
- , jsClassDataSize(0)
{
// Make sure the empty string always gets index 0
registerString(QString());
@@ -174,30 +179,32 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg
{
// ### re-use existing class definitions.
- QList<CompiledData::JSClassMember> members;
- members.reserve(count);
+ const int size = CompiledData::JSClass::calculateSize(count);
+ jsClassOffsets.append(jsClassData.size());
+ const int oldSize = jsClassData.size();
+ jsClassData.resize(jsClassData.size() + size);
+ memset(jsClassData.data() + oldSize, 0, size);
- IR::ExprList *it = args;
- for (int i = 0; i < count; ++i, it = it->next) {
- CompiledData::JSClassMember member;
+ CompiledData::JSClass *jsClass = reinterpret_cast<CompiledData::JSClass*>(jsClassData.data() + oldSize);
+ jsClass->nMembers = count;
+ CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
+ IR::ExprList *it = args;
+ for (int i = 0; i < count; ++i, it = it->next, ++member) {
QV4::IR::Name *name = it->expr->asName();
it = it->next;
const bool isData = it->expr->asConst()->value;
it = it->next;
- member.nameOffset = registerString(*name->id);
- member.isAccessor = !isData;
- members << member;
+ member->nameOffset = registerString(*name->id);
+ member->isAccessor = !isData;
if (!isData)
it = it->next;
}
- jsClasses << members;
- jsClassDataSize += CompiledData::JSClass::calculateSize(members.count());
- return jsClasses.size() - 1;
+ return jsClassOffsets.size() - 1;
}
QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
@@ -211,94 +218,45 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
registerString(*f->locals.at(i));
}
- int unitSize = QV4::CompiledData::Unit::calculateSize(irModule->functions.size(), regexps.size(),
- constants.size(), lookups.size(), jsClasses.count());
-
- uint functionDataSize = 0;
- for (int i = 0; i < irModule->functions.size(); ++i) {
- QV4::IR::Function *f = irModule->functions.at(i);
- functionOffsets.insert(f, functionDataSize + unitSize);
+ CompiledData::LEUInt32 *functionOffsets = reinterpret_cast<CompiledData::LEUInt32*>(alloca(irModule->functions.size() * sizeof(CompiledData::LEUInt32)));
+ uint jsClassDataOffset = 0;
- const int qmlIdDepsCount = f->idObjectDependencies.count();
- const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
- functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
+ char *dataPtr;
+ CompiledData::Unit *unit;
+ {
+ QV4::CompiledData::Unit tempHeader = generateHeader(option, functionOffsets, &jsClassDataOffset);
+ dataPtr = reinterpret_cast<char *>(malloc(tempHeader.unitSize));
+ memcpy(&unit, &dataPtr, sizeof(CompiledData::Unit*));
+ memcpy(unit, &tempHeader, sizeof(tempHeader));
}
- const int totalSize = unitSize + functionDataSize + jsClassDataSize + (option == GenerateWithStringTable ? stringTable.sizeOfTableAndData() : 0);
- char *data = (char *)malloc(totalSize);
- memset(data, 0, totalSize);
- QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data;
-
- memcpy(unit->magic, QV4::CompiledData::magic_str, sizeof(unit->magic));
- unit->architecture = 0; // ###
- unit->flags = QV4::CompiledData::Unit::IsJavascript;
- unit->version = 1;
- unit->unitSize = totalSize;
- unit->functionTableSize = irModule->functions.size();
- unit->offsetToFunctionTable = sizeof(*unit);
- unit->lookupTableSize = lookups.count();
- unit->offsetToLookupTable = unit->offsetToFunctionTable + unit->functionTableSize * sizeof(uint);
- unit->regexpTableSize = regexps.size();
- unit->offsetToRegexpTable = unit->offsetToLookupTable + unit->lookupTableSize * CompiledData::Lookup::calculateSize();
- unit->constantTableSize = constants.size();
- unit->offsetToConstantTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
- unit->jsClassTableSize = jsClasses.count();
- unit->offsetToJSClassTable = unit->offsetToConstantTable + unit->constantTableSize * sizeof(ReturnedValue);
- if (option == GenerateWithStringTable) {
- unit->stringTableSize = stringTable.stringCount();
- unit->offsetToStringTable = unitSize + functionDataSize + jsClassDataSize;
- } else {
- unit->stringTableSize = 0;
- unit->offsetToStringTable = 0;
- }
- unit->indexOfRootFunction = -1;
- unit->sourceFileIndex = getStringId(irModule->fileName);
- unit->nImports = 0;
- unit->offsetToImports = 0;
- unit->nObjects = 0;
- unit->offsetToObjects = 0;
- unit->indexOfRootObject = 0;
-
- uint *functionTable = (uint *)(data + unit->offsetToFunctionTable);
- for (int i = 0; i < irModule->functions.size(); ++i)
- functionTable[i] = functionOffsets.value(irModule->functions.at(i));
-
- char *f = data + unitSize;
+ memcpy(dataPtr + unit->offsetToFunctionTable, functionOffsets, unit->functionTableSize * sizeof(CompiledData::LEUInt32));
+
for (int i = 0; i < irModule->functions.size(); ++i) {
QV4::IR::Function *function = irModule->functions.at(i);
if (function == irModule->rootFunction)
unit->indexOfRootFunction = i;
- const int bytes = writeFunction(f, i, function);
- f += bytes;
+ writeFunction(dataPtr + functionOffsets[i], function);
}
- CompiledData::Lookup *lookupsToWrite = (CompiledData::Lookup*)(data + unit->offsetToLookupTable);
+ CompiledData::Lookup *lookupsToWrite = reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
foreach (const CompiledData::Lookup &l, lookups)
*lookupsToWrite++ = l;
- CompiledData::RegExp *regexpTable = (CompiledData::RegExp *)(data + unit->offsetToRegexpTable);
+ CompiledData::RegExp *regexpTable = reinterpret_cast<CompiledData::RegExp *>(dataPtr + unit->offsetToRegexpTable);
memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable));
- ReturnedValue *constantTable = (ReturnedValue *)(data + unit->offsetToConstantTable);
+ ReturnedValue *constantTable = reinterpret_cast<ReturnedValue *>(dataPtr + unit->offsetToConstantTable);
memcpy(constantTable, constants.constData(), constants.size() * sizeof(ReturnedValue));
- // write js classes and js class lookup table
- uint *jsClassTable = (uint*)(data + unit->offsetToJSClassTable);
- char *jsClass = data + unitSize + functionDataSize;
- for (int i = 0; i < jsClasses.count(); ++i) {
- jsClassTable[i] = jsClass - data;
-
- const QList<CompiledData::JSClassMember> members = jsClasses.at(i);
-
- CompiledData::JSClass *c = reinterpret_cast<CompiledData::JSClass*>(jsClass);
- c->nMembers = members.count();
+ {
+ memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
- CompiledData::JSClassMember *memberToWrite = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + sizeof(CompiledData::JSClass));
- foreach (const CompiledData::JSClassMember &member, members)
- *memberToWrite++ = member;
-
- jsClass += CompiledData::JSClass::calculateSize(members.count());
+ // write js classes and js class lookup table
+ CompiledData::LEUInt32 *jsClassOffsetTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataPtr + unit->offsetToJSClassTable);
+ for (int i = 0; i < jsClassOffsets.count(); ++i)
+ jsClassOffsetTable[i] = jsClassDataOffset + jsClassOffsets.at(i);
}
// write strings and string table
@@ -308,13 +266,12 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
return unit;
}
-int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::Function *irFunction)
+void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *irFunction) const
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
quint32 currentOffset = sizeof(QV4::CompiledData::Function);
- function->index = index;
function->nameIndex = getStringId(*irFunction->name);
function->flags = 0;
if (irFunction->hasDirectEval)
@@ -336,8 +293,6 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
currentOffset += function->nLocals * sizeof(quint32);
function->nInnerFunctions = irFunction->nestedFunctions.size();
- function->innerFunctionsOffset = currentOffset;
- currentOffset += function->nInnerFunctions * sizeof(quint32);
function->nDependingIdObjects = 0;
function->nDependingContextProperties = 0;
@@ -364,6 +319,9 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
function->location.line = irFunction->line;
function->location.column = irFunction->column;
+ function->codeOffset = 0;
+ function->codeSize = 0;
+
// write formals
quint32 *formals = (quint32 *)(f + function->formalsOffset);
for (int i = 0; i < irFunction->formals.size(); ++i)
@@ -374,15 +332,12 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
for (int i = 0; i < irFunction->locals.size(); ++i)
locals[i] = getStringId(*irFunction->locals.at(i));
- // write inner functions
- quint32 *innerFunctions = (quint32 *)(f + function->innerFunctionsOffset);
- for (int i = 0; i < irFunction->nestedFunctions.size(); ++i)
- innerFunctions[i] = functionOffsets.value(irFunction->nestedFunctions.at(i));
-
// write QML dependencies
quint32 *writtenDeps = (quint32 *)(f + function->dependingIdObjectsOffset);
- foreach (int id, irFunction->idObjectDependencies)
- *writtenDeps++ = id;
+ for (int id : irFunction->idObjectDependencies) {
+ Q_ASSERT(id >= 0);
+ *writtenDeps++ = static_cast<quint32>(id);
+ }
writtenDeps = (quint32 *)(f + function->dependingContextPropertiesOffset);
for (auto property : irFunction->contextObjectPropertyDependencies) {
@@ -395,7 +350,70 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
*writtenDeps++ = property.key(); // property index
*writtenDeps++ = property.value(); // notify index
}
+}
+
+QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset)
+{
+ CompiledData::Unit unit;
+ memcpy(unit.magic, CompiledData::magic_str, sizeof(unit.magic));
+ unit.flags = QV4::CompiledData::Unit::IsJavascript;
+ unit.version = QV4_DATA_STRUCTURE_VERSION;
+ unit.qtVersion = QT_VERSION;
+ unit.architectureIndex = registerString(QSysInfo::buildAbi());
+ unit.codeGeneratorIndex = registerString(codeGeneratorName);
+
+ quint32 nextOffset = sizeof(CompiledData::Unit);
+
+ unit.functionTableSize = irModule->functions.size();
+ unit.offsetToFunctionTable = nextOffset;
+ nextOffset += unit.functionTableSize * sizeof(uint);
+
+ unit.lookupTableSize = lookups.count();
+ unit.offsetToLookupTable = nextOffset;
+ nextOffset += unit.lookupTableSize * sizeof(CompiledData::Lookup);
+
+ unit.regexpTableSize = regexps.size();
+ unit.offsetToRegexpTable = nextOffset;
+ nextOffset += unit.regexpTableSize * sizeof(CompiledData::RegExp);
+
+ unit.constantTableSize = constants.size();
+ unit.offsetToConstantTable = nextOffset;
+ nextOffset += unit.constantTableSize * sizeof(ReturnedValue);
+
+ unit.jsClassTableSize = jsClassOffsets.count();
+ unit.offsetToJSClassTable = nextOffset;
+ nextOffset += unit.jsClassTableSize * sizeof(uint);
+
+ *jsClassDataOffset = nextOffset;
+ nextOffset += jsClassData.size();
+
+ for (int i = 0; i < irModule->functions.size(); ++i) {
+ QV4::IR::Function *f = irModule->functions.at(i);
+ functionOffsets[i] = nextOffset;
+
+ const int qmlIdDepsCount = f->idObjectDependencies.count();
+ const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
+ nextOffset += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
+ }
+
+ if (option == GenerateWithStringTable) {
+ unit.stringTableSize = stringTable.stringCount();
+ unit.offsetToStringTable = nextOffset;
+ nextOffset += stringTable.sizeOfTableAndData();
+ } else {
+ unit.stringTableSize = 0;
+ unit.offsetToStringTable = 0;
+ }
+ unit.indexOfRootFunction = -1;
+ unit.sourceFileIndex = getStringId(irModule->fileName);
+ unit.sourceTimeStamp = irModule->sourceTimeStamp;
+ unit.nImports = 0;
+ unit.offsetToImports = 0;
+ unit.nObjects = 0;
+ unit.offsetToObjects = 0;
+ unit.indexOfRootObject = 0;
- return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions,
- function->nDependingIdObjects, function->nDependingContextProperties + function->nDependingScopeProperties);
+ unit.unitSize = nextOffset;
+
+ return unit;
}
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 0321a83b4f..49b8664513 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -52,6 +52,7 @@
#include <QtCore/qstring.h>
#include "qv4jsir_p.h"
+#include <private/qjson_p.h>
QT_BEGIN_NAMESPACE
@@ -114,18 +115,20 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
QV4::CompiledData::Unit *generateUnit(GeneratorOption option = GenerateWithStringTable);
// Returns bytes written
- int writeFunction(char *f, int index, IR::Function *irFunction);
+ void writeFunction(char *f, IR::Function *irFunction) const;
StringTableGenerator stringTable;
+ QString codeGeneratorName;
private:
+ CompiledData::Unit generateHeader(GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset);
+
IR::Module *irModule;
- QHash<IR::Function *, uint> functionOffsets;
QList<CompiledData::Lookup> lookups;
QVector<CompiledData::RegExp> regexps;
QVector<ReturnedValue> constants;
- QList<QList<CompiledData::JSClassMember> > jsClasses;
- uint jsClassDataSize;
+ QByteArray jsClassData;
+ QVector<int> jsClassOffsets;
};
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 90010ccf52..20b871c4e8 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -58,10 +58,17 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+#define MOTH_DEBUG_INSTR(F)
+#else
+#define MOTH_DEBUG_INSTR(F) \
+ F(Line, line) \
+ F(Debug, debug)
+#endif
+
#define FOR_EACH_MOTH_INSTR(F) \
F(Ret, ret) \
- F(Line, line) \
- F(Debug, debug) \
+ MOTH_DEBUG_INSTR(F) \
F(LoadRuntimeString, loadRuntimeString) \
F(LoadRegExp, loadRegExp) \
F(LoadClosure, loadClosure) \
@@ -162,7 +169,7 @@ QT_BEGIN_NAMESPACE
#define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QV4::Moth::Instr) - 1)
#ifdef MOTH_THREADED_INTERPRETER
-# define MOTH_INSTR_HEADER void *code;
+# define MOTH_INSTR_HEADER union { quint32 instructionType; void *code; };
#else
# define MOTH_INSTR_HEADER quint32 instructionType;
#endif
@@ -174,6 +181,8 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Moth {
+ // When making changes to the instructions, make sure to bump QV4_DATA_STRUCTURE_VERSION in qv4compileddata_p.h
+
struct Param {
// Params are looked up as follows:
// Constant: 0
@@ -252,6 +261,8 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
+
+#ifndef QT_NO_QML_DEBUGGING
struct instr_line {
MOTH_INSTR_HEADER
qint32 lineNumber;
@@ -260,6 +271,8 @@ union Instr
MOTH_INSTR_HEADER
qint32 lineNumber;
};
+#endif // QT_NO_QML_DEBUGGING
+
struct instr_loadRuntimeString {
MOTH_INSTR_HEADER
int stringId;
@@ -672,7 +685,7 @@ union Instr
};
struct instr_binop {
MOTH_INSTR_HEADER
- QV4::Runtime::BinaryOperation alu;
+ uint alu; // offset inside the runtime methods
Param lhs;
Param rhs;
Param result;
@@ -757,7 +770,7 @@ union Instr
};
struct instr_binopContext {
MOTH_INSTR_HEADER
- QV4::Runtime::BinaryOperationContext alu;
+ uint alu; // offset inside the runtime methods
Param lhs;
Param rhs;
Param result;
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index be10d50e9b..41790c04a9 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -46,6 +46,7 @@
#include <private/qv4regexpobject_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmlengine_p.h>
+#include <wtf/MathExtras.h>
#undef USE_TYPE_INFO
@@ -54,7 +55,7 @@ using namespace QV4::Moth;
namespace {
-inline QV4::Runtime::BinaryOperation aluOpFunction(IR::AluOp op)
+inline uint aluOpFunction(IR::AluOp op)
{
switch (op) {
case IR::OpInvalid:
@@ -70,43 +71,43 @@ inline QV4::Runtime::BinaryOperation aluOpFunction(IR::AluOp op)
case IR::OpCompl:
return 0;
case IR::OpBitAnd:
- return QV4::Runtime::bitAnd;
+ return offsetof(QV4::Runtime, bitAnd);
case IR::OpBitOr:
- return QV4::Runtime::bitOr;
+ return offsetof(QV4::Runtime, bitOr);
case IR::OpBitXor:
- return QV4::Runtime::bitXor;
+ return offsetof(QV4::Runtime, bitXor);
case IR::OpAdd:
return 0;
case IR::OpSub:
- return QV4::Runtime::sub;
+ return offsetof(QV4::Runtime, sub);
case IR::OpMul:
- return QV4::Runtime::mul;
+ return offsetof(QV4::Runtime, mul);
case IR::OpDiv:
- return QV4::Runtime::div;
+ return offsetof(QV4::Runtime, div);
case IR::OpMod:
- return QV4::Runtime::mod;
+ return offsetof(QV4::Runtime, mod);
case IR::OpLShift:
- return QV4::Runtime::shl;
+ return offsetof(QV4::Runtime, shl);
case IR::OpRShift:
- return QV4::Runtime::shr;
+ return offsetof(QV4::Runtime, shr);
case IR::OpURShift:
- return QV4::Runtime::ushr;
+ return offsetof(QV4::Runtime, ushr);
case IR::OpGt:
- return QV4::Runtime::greaterThan;
+ return offsetof(QV4::Runtime, greaterThan);
case IR::OpLt:
- return QV4::Runtime::lessThan;
+ return offsetof(QV4::Runtime, lessThan);
case IR::OpGe:
- return QV4::Runtime::greaterEqual;
+ return offsetof(QV4::Runtime, greaterEqual);
case IR::OpLe:
- return QV4::Runtime::lessEqual;
+ return offsetof(QV4::Runtime, lessEqual);
case IR::OpEqual:
- return QV4::Runtime::equal;
+ return offsetof(QV4::Runtime, equal);
case IR::OpNotEqual:
- return QV4::Runtime::notEqual;
+ return offsetof(QV4::Runtime, notEqual);
case IR::OpStrictEqual:
- return QV4::Runtime::strictEqual;
+ return offsetof(QV4::Runtime, strictEqual);
case IR::OpStrictNotEqual:
- return QV4::Runtime::strictNotEqual;
+ return offsetof(QV4::Runtime, strictNotEqual);
case IR::OpInstanceof:
return 0;
case IR::OpIn:
@@ -250,7 +251,7 @@ protected:
_unhandled.removeLast();
}
- s->accept(this);
+ visit(s);
}
if (IR::Jump *jump = s->asJump()) {
@@ -273,7 +274,7 @@ protected:
moves.order();
QList<IR::Move *> newMoves = moves.insertMoves(_currentBasicBlock, _function, true);
foreach (IR::Move *move, newMoves)
- move->accept(this);
+ visit(move);
}
}
@@ -312,8 +313,8 @@ protected:
};
} // anonymous namespace
-InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- : EvalInstructionSelection(execAllocator, module, jsGenerator)
+InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
+ : EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory)
, qmlEngine(qmlEngine)
, _block(0)
, _codeStart(0)
@@ -411,6 +412,7 @@ void InstructionSelection::run(int functionIndex)
if (s->location.startLine != currentLine) {
blockNeedsDebugInstruction = false;
currentLine = s->location.startLine;
+#ifndef QT_NO_QML_DEBUGGER
if (irModule->debugMode) {
Instruction::Debug debug;
debug.lineNumber = currentLine;
@@ -420,10 +422,11 @@ void InstructionSelection::run(int functionIndex)
line.lineNumber = currentLine;
addInstruction(line);
}
+#endif
}
}
- s->accept(this);
+ visit(s);
}
}
@@ -1040,11 +1043,11 @@ Param InstructionSelection::binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR
if (oper == IR::OpInstanceof || oper == IR::OpIn || oper == IR::OpAdd) {
Instruction::BinopContext binop;
if (oper == IR::OpInstanceof)
- binop.alu = QV4::Runtime::instanceof;
+ binop.alu = offsetof(QV4::Runtime, instanceof);
else if (oper == IR::OpIn)
- binop.alu = QV4::Runtime::in;
+ binop.alu = offsetof(QV4::Runtime, in);
else
- binop.alu = QV4::Runtime::add;
+ binop.alu = offsetof(QV4::Runtime, add);
binop.lhs = getParam(leftSource);
binop.rhs = getParam(rightSource);
binop.result = getResultParam(target);
@@ -1091,6 +1094,17 @@ void InstructionSelection::prepareCallArgs(IR::ExprList *e, quint32 &argc, quint
}
}
+void InstructionSelection::addDebugInstruction()
+{
+#ifndef QT_NO_QML_DEBUGGER
+ if (blockNeedsDebugInstruction) {
+ Instruction::Debug debug;
+ debug.lineNumber = -int(currentLine);
+ addInstruction(debug);
+ }
+#endif
+}
+
void InstructionSelection::visitJump(IR::Jump *s)
{
if (s->target == _nextBlock)
@@ -1098,11 +1112,7 @@ void InstructionSelection::visitJump(IR::Jump *s)
if (_removableJumps.contains(s))
return;
- if (blockNeedsDebugInstruction) {
- Instruction::Debug debug;
- debug.lineNumber = -int(currentLine);
- addInstruction(debug);
- }
+ addDebugInstruction();
Instruction::Jump jump;
jump.offset = 0;
@@ -1113,11 +1123,7 @@ void InstructionSelection::visitJump(IR::Jump *s)
void InstructionSelection::visitCJump(IR::CJump *s)
{
- if (blockNeedsDebugInstruction) {
- Instruction::Debug debug;
- debug.lineNumber = -int(currentLine);
- addInstruction(debug);
- }
+ addDebugInstruction();
Param condition;
if (IR::Temp *t = s->cond->asTemp()) {
@@ -1152,12 +1158,8 @@ void InstructionSelection::visitCJump(IR::CJump *s)
void InstructionSelection::visitRet(IR::Ret *s)
{
- if (blockNeedsDebugInstruction) {
- // this is required so stepOut will always be guaranteed to stop in every stack frame
- Instruction::Debug debug;
- debug.lineNumber = -int(currentLine);
- addInstruction(debug);
- }
+ // this is required so stepOut will always be guaranteed to stop in every stack frame
+ addDebugInstruction();
Instruction::Ret ret;
ret.result = getParam(s->expr);
@@ -1493,12 +1495,7 @@ void QV4::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
int instructionSize = Instr::size(type);
if (_codeEnd - _codeNext < instructionSize) {
@@ -1584,6 +1581,29 @@ CompilationUnit::~CompilationUnit()
void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
{
+#ifdef MOTH_THREADED_INTERPRETER
+ // link byte code against addresses of instructions
+ for (int i = 0; i < codeRefs.count(); ++i) {
+ QByteArray &codeRef = codeRefs[i];
+ char *code = codeRef.data();
+ int index = 0;
+ while (index < codeRef.size()) {
+ Instr *genericInstr = reinterpret_cast<Instr *>(code + index);
+
+ switch (genericInstr->common.instructionType) {
+#define LINK_INSTRUCTION(InstructionType, Member) \
+ case Instr::InstructionType: \
+ genericInstr->common.code = VME::instructionJumpTable()[static_cast<int>(genericInstr->common.instructionType)]; \
+ index += InstrMeta<(int)Instr::InstructionType>::Size; \
+ break;
+
+ FOR_EACH_MOTH_INSTR(LINK_INSTRUCTION)
+
+ }
+ }
+ }
+#endif
+
runtimeFunctions.resize(data->functionTableSize);
runtimeFunctions.fill(0);
for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
@@ -1594,3 +1614,81 @@ void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
runtimeFunctions[i] = runtimeFunction;
}
}
+
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
+{
+ const int codeAlignment = 16;
+ quint64 offset = WTF::roundUpToMultipleOf(codeAlignment, unit->unitSize);
+ Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
+ for (int i = 0; i < codeRefs.size(); ++i) {
+ CompiledData::Function *compiledFunction = const_cast<CompiledData::Function *>(unit->functionAt(i));
+ compiledFunction->codeOffset = offset;
+ compiledFunction->codeSize = codeRefs.at(i).size();
+ offset = WTF::roundUpToMultipleOf(codeAlignment, offset + compiledFunction->codeSize);
+ }
+}
+
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString)
+{
+ Q_ASSERT(device->pos() == unit->unitSize);
+ Q_ASSERT(device->atEnd());
+ Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
+
+ QByteArray padding;
+
+ for (int i = 0; i < codeRefs.size(); ++i) {
+ const CompiledData::Function *compiledFunction = unit->functionAt(i);
+
+ if (device->pos() > qint64(compiledFunction->codeOffset)) {
+ *errorString = QStringLiteral("Invalid state of cache file to write.");
+ return false;
+ }
+
+ const quint64 paddingSize = compiledFunction->codeOffset - device->pos();
+ padding.fill(0, paddingSize);
+ qint64 written = device->write(padding);
+ if (written != padding.size()) {
+ *errorString = device->errorString();
+ return false;
+ }
+
+ const void *codePtr = codeRefs.at(i).constData();
+ written = device->write(reinterpret_cast<const char *>(codePtr), compiledFunction->codeSize);
+ if (written != qint64(compiledFunction->codeSize)) {
+ *errorString = device->errorString();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ Q_ASSERT(codeRefs.isEmpty());
+ codeRefs.reserve(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ const char *codePtr = const_cast<const char *>(reinterpret_cast<const char *>(basePtr + compiledFunction->codeOffset));
+#ifdef MOTH_THREADED_INTERPRETER
+ // for the threaded interpreter we need to make a copy of the data because it needs to be
+ // modified for the instruction handler addresses.
+ QByteArray code(codePtr, compiledFunction->codeSize);
+#else
+ QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
+#endif
+ codeRefs.append(code);
+ }
+
+ return true;
+}
+
+QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
+{
+ QQmlRefPointer<CompiledData::CompilationUnit> result;
+ result.adopt(new Moth::CompilationUnit);
+ return result;
+}
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index 29d117af38..2d2bb91228 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -66,7 +66,10 @@ namespace Moth {
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
- virtual void linkBackendToEngine(QV4::ExecutionEngine *engine);
+ void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
+ bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
QVector<QByteArray> codeRefs;
@@ -77,7 +80,7 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory);
~InstructionSelection();
virtual void run(int functionIndex);
@@ -174,6 +177,8 @@ private:
template <int Instr>
inline ptrdiff_t addInstruction(const InstrData<Instr> &data);
+ inline void addDebugInstruction();
+
ptrdiff_t addInstructionHelper(Instr::Type type, Instr &instr);
void patchJumpAddresses();
QByteArray squeezeCode() const;
@@ -202,11 +207,14 @@ private:
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
+ ISelFactory() : EvalISelFactory(QStringLiteral("moth")) {}
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); }
- virtual bool jitCompileRegexps() const
+ EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) Q_DECL_OVERRIDE Q_DECL_FINAL
+ { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator, this); }
+ bool jitCompileRegexps() const Q_DECL_OVERRIDE Q_DECL_FINAL
{ return false; }
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> createUnitForLoading() Q_DECL_OVERRIDE;
+
};
template<int InstrT>
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 0ae08160ab..d97eec5e1d 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -52,7 +52,7 @@
using namespace QV4;
using namespace QV4::IR;
-EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
: useFastLookups(true)
, useTypeInference(true)
, executableAllocator(execAllocator)
@@ -67,6 +67,7 @@ EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *exe
Q_ASSERT(execAllocator);
#endif
Q_ASSERT(module);
+ jsGenerator->codeGeneratorName = iselFactory->codeGeneratorName;
}
EvalInstructionSelection::~EvalInstructionSelection()
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 88d2071c52..a3fa80b6f0 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -65,13 +65,14 @@ class QQmlEnginePrivate;
namespace QV4 {
+class EvalISelFactory;
class ExecutableAllocator;
struct Function;
class Q_QML_PRIVATE_EXPORT EvalInstructionSelection
{
public:
- EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory);
virtual ~EvalInstructionSelection() = 0;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compile(bool generateUnitData = true);
@@ -104,23 +105,44 @@ protected:
class Q_QML_PRIVATE_EXPORT EvalISelFactory
{
public:
+ EvalISelFactory(const QString &codeGeneratorName) : codeGeneratorName(codeGeneratorName) {}
virtual ~EvalISelFactory() = 0;
virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) = 0;
virtual bool jitCompileRegexps() const = 0;
+ virtual QQmlRefPointer<QV4::CompiledData::CompilationUnit> createUnitForLoading() = 0;
+
+ const QString codeGeneratorName;
};
namespace IR {
-class Q_QML_PRIVATE_EXPORT IRDecoder: protected IR::StmtVisitor
+class Q_QML_PRIVATE_EXPORT IRDecoder
{
public:
IRDecoder() : _function(0) {}
virtual ~IRDecoder() = 0;
- virtual void visitPhi(IR::Phi *) {}
-
-public: // visitor methods for StmtVisitor:
- virtual void visitMove(IR::Move *s);
- virtual void visitExp(IR::Exp *s);
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto j = s->asJump()) {
+ visitJump(j);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+private: // visitor methods for StmtVisitor:
+ void visitMove(IR::Move *s);
+ void visitExp(IR::Exp *s);
public: // to implement by subclasses:
virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) = 0;
@@ -178,6 +200,11 @@ public: // to implement by subclasses:
virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) = 0;
protected:
+ virtual void visitJump(IR::Jump *) = 0;
+ virtual void visitCJump(IR::CJump *) = 0;
+ virtual void visitRet(IR::Ret *) = 0;
+ virtual void visitPhi(IR::Phi *) {}
+
virtual void callBuiltin(IR::Call *c, IR::Expr *result);
IR::Function *_function; // subclass needs to set
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index 674fc01623..1755193d32 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -104,7 +104,7 @@ inline Primitive convertToValue(IR::Const *c)
return Primitive::undefinedValue();
}
-class ConvertTemps: protected IR::StmtVisitor, protected IR::ExprVisitor
+class ConvertTemps
{
void renumber(IR::Temp *t)
{
@@ -132,7 +132,7 @@ protected:
virtual void process(IR::Stmt *s)
{
- s->accept(this);
+ visit(s);
}
public:
@@ -157,34 +157,28 @@ public:
}
protected:
- virtual void visitConst(IR::Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(IR::Name *) {}
- virtual void visitTemp(IR::Temp *e) { renumber(e); }
- virtual void visitArgLocal(IR::ArgLocal *) {}
- virtual void visitClosure(IR::Closure *) {}
- virtual void visitConvert(IR::Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(IR::Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(IR::Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(IR::Call *e) {
- e->base->accept(this);
- for (IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
+ void visit(IR::Stmt *s) {
+ switch (s->stmtKind) {
+ case IR::Stmt::PhiStmt:
+ visitPhi(s->asPhi());
+ break;
+ default:
+ STMT_VISIT_ALL_KINDS(s);
+ break;
+ }
}
- virtual void visitNew(IR::New *e) {
- e->base->accept(this);
- for (IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
+
+ virtual void visitPhi(IR::Phi *)
+ { Q_UNREACHABLE(); }
+
+private:
+ void visit(IR::Expr *e) {
+ if (auto temp = e->asTemp()) {
+ renumber(temp);
+ } else {
+ EXPR_VISIT_ALL_KINDS(e);
+ }
}
- virtual void visitSubscript(IR::Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(IR::Member *e) { e->base->accept(this); }
- virtual void visitExp(IR::Exp *s) { s->expr->accept(this); }
- virtual void visitMove(IR::Move *s) { s->target->accept(this); s->source->accept(this); }
- virtual void visitJump(IR::Jump *) {}
- virtual void visitCJump(IR::CJump *s) { s->cond->accept(this); }
- virtual void visitRet(IR::Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(IR::Phi *) { Q_UNREACHABLE(); }
};
} // namespace QV4
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index b28db59190..b6c5226894 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -157,12 +157,13 @@ AluOp binaryOperator(int op)
}
}
-struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
+class RemoveSharedExpressions
{
CloneExpr clone;
std::vector<Expr *> subexpressions; // contains all the non-cloned subexpressions in the given function. sorted using std::lower_bound.
Expr *uniqueExpr;
+public:
RemoveSharedExpressions(): uniqueExpr(0) {}
void operator()(IR::Function *function)
@@ -176,11 +177,12 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
clone.setBasicBlock(block);
for (Stmt *s : block->statements()) {
- s->accept(this);
+ visit(s);
}
}
}
+private:
template <typename Expr_>
Expr_ *cleanup(Expr_ *expr)
{
@@ -189,7 +191,7 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
subexpressions.insert(it, expr);
IR::Expr *e = expr;
qSwap(uniqueExpr, e);
- expr->accept(this);
+ visit(expr);
qSwap(uniqueExpr, e);
return static_cast<Expr_ *>(e);
}
@@ -199,83 +201,45 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
return clone(expr);
}
- // statements
- virtual void visitExp(Exp *s)
+ void visit(Stmt *s)
{
- s->expr = cleanup(s->expr);
- }
-
- virtual void visitMove(Move *s)
- {
- s->target = cleanup(s->target);
- s->source = cleanup(s->source);
- }
-
- virtual void visitJump(Jump *)
- {
- // nothing to do for Jump statements
- }
-
- virtual void visitCJump(CJump *s)
- {
- s->cond = cleanup(s->cond);
- }
-
- virtual void visitRet(Ret *s)
- {
- s->expr = cleanup(s->expr);
- }
-
- virtual void visitPhi(IR::Phi *) { Q_UNIMPLEMENTED(); }
-
- // expressions
- virtual void visitConst(Const *) {}
- virtual void visitString(String *) {}
- virtual void visitRegExp(RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
-
- virtual void visitConvert(Convert *e)
- {
- e->expr = cleanup(e->expr);
- }
-
- virtual void visitUnop(Unop *e)
- {
- e->expr = cleanup(e->expr);
- }
-
- virtual void visitBinop(Binop *e)
- {
- e->left = cleanup(e->left);
- e->right = cleanup(e->right);
- }
-
- virtual void visitCall(Call *e)
- {
- e->base = cleanup(e->base);
- for (IR::ExprList *it = e->args; it; it = it->next)
- it->expr = cleanup(it->expr);
- }
-
- virtual void visitNew(New *e)
- {
- e->base = cleanup(e->base);
- for (IR::ExprList *it = e->args; it; it = it->next)
- it->expr = cleanup(it->expr);
- }
-
- virtual void visitSubscript(Subscript *e)
- {
- e->base = cleanup(e->base);
- e->index = cleanup(e->index);
+ if (auto e = s->asExp()) {
+ e->expr = cleanup(e->expr);
+ } else if (auto m = s->asMove()) {
+ m->target = cleanup(m->target);
+ m->source = cleanup(m->source);
+ } else if (auto c = s->asCJump()) {
+ c->cond = cleanup(c->cond);
+ } else if (auto r = s->asRet()) {
+ r->expr = cleanup(r->expr);
+ }
}
- virtual void visitMember(Member *e)
+ void visit(Expr *e)
{
- e->base = cleanup(e->base);
+ if (auto c = e->asConvert()) {
+ c->expr = cleanup(c->expr);
+ } else if (auto u = e->asUnop()) {
+ u->expr = cleanup(u->expr);
+ } else if (auto b = e->asBinop()) {
+ b->left = cleanup(b->left);
+ b->right = cleanup(b->right);
+ } else if (auto c = e->asCall()) {
+ c->base = cleanup(c->base);
+ for (IR::ExprList *it = c->args; it; it = it->next) {
+ it->expr = cleanup(it->expr);
+ }
+ } else if (auto n = e->asNew()) {
+ n->base = cleanup(n->base);
+ for (IR::ExprList *it = n->args; it; it = it->next) {
+ it->expr = cleanup(it->expr);
+ }
+ } else if (auto s = e->asSubscript()) {
+ s->base = cleanup(s->base);
+ s->index = cleanup(s->index);
+ } else if (auto m = e->asMember()) {
+ m->base = cleanup(m->base);
+ }
}
};
@@ -404,9 +368,10 @@ Function::Function(Module *module, Function *outer, const QString &name)
, isNamedExpression(false)
, hasTry(false)
, hasWith(false)
+ , isQmlBinding(false)
, unused(0)
- , line(-1)
- , column(-1)
+ , line(0)
+ , column(0)
, _allBasicBlocks(0)
, _statementCount(0)
{
@@ -548,75 +513,39 @@ ExprList *CloneExpr::clone(ExprList *list)
return clonedList;
}
-void CloneExpr::visitConst(Const *e)
-{
- cloned = cloneConst(e, block->function);
-}
-
-void CloneExpr::visitString(String *e)
-{
- cloned = block->STRING(e->value);
-}
-
-void CloneExpr::visitRegExp(RegExp *e)
-{
- cloned = block->REGEXP(e->value, e->flags);
-}
-
-void CloneExpr::visitName(Name *e)
-{
- cloned = cloneName(e, block->function);
-}
-
-void CloneExpr::visitTemp(Temp *e)
-{
- cloned = cloneTemp(e, block->function);
-}
-
-void CloneExpr::visitArgLocal(ArgLocal *e)
-{
- cloned = cloneArgLocal(e, block->function);
-}
-
-void CloneExpr::visitClosure(Closure *e)
-{
- cloned = block->CLOSURE(e->value);
-}
-
-void CloneExpr::visitConvert(Convert *e)
-{
- cloned = block->CONVERT(clone(e->expr), e->type);
-}
-
-void CloneExpr::visitUnop(Unop *e)
-{
- cloned = block->UNOP(e->op, clone(e->expr));
-}
-
-void CloneExpr::visitBinop(Binop *e)
-{
- cloned = block->BINOP(e->op, clone(e->left), clone(e->right));
-}
-
-void CloneExpr::visitCall(Call *e)
-{
- cloned = block->CALL(clone(e->base), clone(e->args));
-}
-
-void CloneExpr::visitNew(New *e)
-{
- cloned = block->NEW(clone(e->base), clone(e->args));
-}
-
-void CloneExpr::visitSubscript(Subscript *e)
-{
- cloned = block->SUBSCRIPT(clone(e->base), clone(e->index));
-}
-
-void CloneExpr::visitMember(Member *e)
-{
- Expr *clonedBase = clone(e->base);
- cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->idIndex);
+void CloneExpr::visit(Expr *e)
+{
+ if (auto c = e->asConst()) {
+ cloned = cloneConst(c, block->function);
+ } else if (auto s = e->asString()) {
+ cloned = block->STRING(s->value);
+ } else if (auto r = e->asRegExp()) {
+ cloned = block->REGEXP(r->value, r->flags);
+ } else if (auto n = e->asName()) {
+ cloned = cloneName(n, block->function);
+ } else if (auto t = e->asTemp()) {
+ cloned = cloneTemp(t, block->function);
+ } else if (auto a = e->asArgLocal()) {
+ cloned = cloneArgLocal(a, block->function);
+ } else if (auto c = e->asClosure()) {
+ cloned = block->CLOSURE(c->value);
+ } else if (auto c = e->asConvert()) {
+ cloned = block->CONVERT(clone(c->expr), c->type);
+ } else if (auto u = e->asUnop()) {
+ cloned = block->UNOP(u->op, clone(u->expr));
+ } else if (auto b = e->asBinop()) {
+ cloned = block->BINOP(b->op, clone(b->left), clone(b->right));
+ } else if (auto c = e->asCall()) {
+ cloned = block->CALL(clone(c->base), clone(c->args));
+ } else if (auto n = e->asNew()) {
+ cloned = block->NEW(clone(n->base), clone(n->args));
+ } else if (auto s = e->asSubscript()) {
+ cloned = block->SUBSCRIPT(clone(s->base), clone(s->index));
+ } else if (auto m = e->asMember()) {
+ cloned = block->MEMBER(clone(m->base), m->name, m->property, m->kind, m->idIndex);
+ } else {
+ Q_UNREACHABLE();
+ }
}
IRPrinter::IRPrinter(QTextStream *out)
@@ -632,17 +561,17 @@ IRPrinter::~IRPrinter()
void IRPrinter::print(Stmt *s)
{
- s->accept(this);
+ visit(s);
}
void IRPrinter::print(const Expr &e)
{
- const_cast<Expr *>(&e)->accept(this);
+ visit(const_cast<Expr *>(&e));
}
void IRPrinter::print(Expr *e)
{
- e->accept(this);
+ visit(e);
}
void IRPrinter::print(Function *f)
@@ -696,7 +625,7 @@ void IRPrinter::print(BasicBlock *bb)
QTextStream *prevOut = &os;
std::swap(out, prevOut);
addStmtNr(s);
- s->accept(this);
+ visit(s);
if (s->location.startLine) {
out->flush();
for (int i = 58 - str.length(); i > 0; --i)
@@ -713,10 +642,29 @@ void IRPrinter::print(BasicBlock *bb)
std::swap(currentBB, bb);
}
+void IRPrinter::visit(Stmt *s)
+{
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto j = s->asJump()) {
+ visitJump(j);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ } else {
+ Q_UNREACHABLE();
+ }
+}
+
void IRPrinter::visitExp(Exp *s)
{
*out << "void ";
- s->expr->accept(this);
+ visit(s->expr);
}
void IRPrinter::visitMove(Move *s)
@@ -725,13 +673,13 @@ void IRPrinter::visitMove(Move *s)
if (!s->swap && targetTemp->type != UnknownType)
*out << typeName(targetTemp->type) << ' ';
- s->target->accept(this);
+ visit(s->target);
*out << ' ';
if (s->swap)
*out << "<=> ";
else
*out << "= ";
- s->source->accept(this);
+ visit(s->source);
}
void IRPrinter::visitJump(Jump *s)
@@ -742,7 +690,7 @@ void IRPrinter::visitJump(Jump *s)
void IRPrinter::visitCJump(CJump *s)
{
*out << "if ";
- s->cond->accept(this);
+ visit(s->cond);
*out << " goto L" << s->iftrue->index()
<< " else goto L" << s->iffalse->index();
}
@@ -752,7 +700,7 @@ void IRPrinter::visitRet(Ret *s)
*out << "return";
if (s->expr) {
*out << ' ';
- s->expr->accept(this);
+ visit(s->expr);
}
}
@@ -761,7 +709,7 @@ void IRPrinter::visitPhi(Phi *s)
if (s->targetTemp->type != UnknownType)
*out << typeName(s->targetTemp->type) << ' ';
- s->targetTemp->accept(this);
+ visit(s->targetTemp);
*out << " = phi ";
for (int i = 0, ei = s->incoming.size(); i < ei; ++i) {
if (i > 0)
@@ -769,7 +717,42 @@ void IRPrinter::visitPhi(Phi *s)
if (currentBB)
*out << 'L' << currentBB->in.at(i)->index() << ": ";
if (s->incoming[i])
- s->incoming[i]->accept(this);
+ visit(s->incoming[i]);
+ }
+}
+
+void IRPrinter::visit(Expr *e)
+{
+ if (auto c = e->asConst()) {
+ visitConst(c);
+ } else if (auto s = e->asString()) {
+ visitString(s);
+ } else if (auto r = e->asRegExp()) {
+ visitRegExp(r);
+ } else if (auto n = e->asName()) {
+ visitName(n);
+ } else if (auto t = e->asTemp()) {
+ visitTemp(t);
+ } else if (auto a = e->asArgLocal()) {
+ visitArgLocal(a);
+ } else if (auto c = e->asClosure()) {
+ visitClosure(c);
+ } else if (auto c = e->asConvert()) {
+ visitConvert(c);
+ } else if (auto u = e->asUnop()) {
+ visitUnop(u);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ } else {
+ Q_UNREACHABLE();
}
}
@@ -867,32 +850,32 @@ void IRPrinter::visitClosure(Closure *e)
void IRPrinter::visitConvert(Convert *e)
{
*out << "convert " << typeName(e->expr->type) << " to " << typeName(e->type) << ' ';
- e->expr->accept(this);
+ visit(e->expr);
}
void IRPrinter::visitUnop(Unop *e)
{
*out << opname(e->op) << ' ';
- e->expr->accept(this);
+ visit(e->expr);
}
void IRPrinter::visitBinop(Binop *e)
{
*out << opname(e->op) << ' ';
- e->left->accept(this);
+ visit(e->left);
*out << ", ";
- e->right->accept(this);
+ visit(e->right);
}
void IRPrinter::visitCall(Call *e)
{
*out << "call ";
- e->base->accept(this);
+ visit(e->base);
*out << '(';
for (ExprList *it = e->args; it; it = it->next) {
if (it != e->args)
*out << ", ";
- it->expr->accept(this);
+ visit(it->expr);
}
*out << ')';
}
@@ -900,21 +883,21 @@ void IRPrinter::visitCall(Call *e)
void IRPrinter::visitNew(New *e)
{
*out << "new ";
- e->base->accept(this);
+ visit(e->base);
*out << '(';
for (ExprList *it = e->args; it; it = it->next) {
if (it != e->args)
*out << ", ";
- it->expr->accept(this);
+ visit(it->expr);
}
*out << ')';
}
void IRPrinter::visitSubscript(Subscript *e)
{
- e->base->accept(this);
+ visit(e->base);
*out << '[';
- e->index->accept(this);
+ visit(e->index);
*out << ']';
}
@@ -924,7 +907,7 @@ void IRPrinter::visitMember(Member *e)
&& e->attachedPropertiesId != 0 && !e->base->asTemp())
*out << "[[attached property from " << e->attachedPropertiesId << "]]";
else
- e->base->accept(this);
+ visit(e->base);
*out << '.' << *e->name;
#ifndef V4_BOOTSTRAP
if (e->property)
@@ -942,15 +925,15 @@ QString IRPrinter::escape(const QString &s)
for (int i = 0; i < s.length(); ++i) {
const QChar ch = s.at(i);
if (ch == QLatin1Char('\n'))
- r += QStringLiteral("\\n");
+ r += QLatin1String("\\n");
else if (ch == QLatin1Char('\r'))
- r += QStringLiteral("\\r");
+ r += QLatin1String("\\r");
else if (ch == QLatin1Char('\\'))
- r += QStringLiteral("\\\\");
+ r += QLatin1String("\\\\");
else if (ch == QLatin1Char('"'))
- r += QStringLiteral("\\\"");
+ r += QLatin1String("\\\"");
else if (ch == QLatin1Char('\''))
- r += QStringLiteral("\\'");
+ r += QLatin1String("\\'");
else
r += ch;
}
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 94fa65cf71..51b8797862 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -192,7 +192,7 @@ enum AluOp {
AluOp binaryOperator(int op);
const char *opname(IR::AluOp op);
-enum Type {
+enum Type : quint16 {
UnknownType = 0,
MissingType = 1 << 0,
@@ -217,34 +217,6 @@ inline bool strictlyEqualTypes(Type t1, Type t2)
QString typeName(Type t);
-struct ExprVisitor {
- virtual ~ExprVisitor() {}
- virtual void visitConst(Const *) = 0;
- virtual void visitString(String *) = 0;
- virtual void visitRegExp(RegExp *) = 0;
- virtual void visitName(Name *) = 0;
- virtual void visitTemp(Temp *) = 0;
- virtual void visitArgLocal(ArgLocal *) = 0;
- virtual void visitClosure(Closure *) = 0;
- virtual void visitConvert(Convert *) = 0;
- virtual void visitUnop(Unop *) = 0;
- virtual void visitBinop(Binop *) = 0;
- virtual void visitCall(Call *) = 0;
- virtual void visitNew(New *) = 0;
- virtual void visitSubscript(Subscript *) = 0;
- virtual void visitMember(Member *) = 0;
-};
-
-struct StmtVisitor {
- virtual ~StmtVisitor() {}
- virtual void visitExp(Exp *) = 0;
- virtual void visitMove(Move *) = 0;
- virtual void visitJump(Jump *) = 0;
- virtual void visitCJump(CJump *) = 0;
- virtual void visitRet(Ret *) = 0;
- virtual void visitPhi(Phi *) = 0;
-};
-
struct MemberExpressionResolver;
struct DiscoveredType {
@@ -288,28 +260,129 @@ struct MemberExpressionResolver
};
struct Q_AUTOTEST_EXPORT Expr {
+ enum ExprKind : quint8 {
+ NameExpr,
+ TempExpr,
+ ArgLocalExpr,
+ SubscriptExpr,
+ MemberExpr,
+
+ LastLValue = MemberExpr,
+
+ ConstExpr,
+ StringExpr,
+ RegExpExpr,
+ ClosureExpr,
+ ConvertExpr,
+ UnopExpr,
+ BinopExpr,
+ CallExpr,
+ NewExpr
+ };
+
Type type;
+ const ExprKind exprKind;
+
+ Expr &operator=(const Expr &other) {
+ Q_ASSERT(exprKind == other.exprKind);
+ type = other.type;
+ return *this;
+ }
+
+ template <typename To>
+ inline bool isa() const {
+ return To::classof(this);
+ }
- Expr(): type(UnknownType) {}
- virtual ~Expr() {}
- virtual void accept(ExprVisitor *) = 0;
- virtual bool isLValue() { return false; }
- virtual Const *asConst() { return 0; }
- virtual String *asString() { return 0; }
- virtual RegExp *asRegExp() { return 0; }
- virtual Name *asName() { return 0; }
- virtual Temp *asTemp() { return 0; }
- virtual ArgLocal *asArgLocal() { return 0; }
- virtual Closure *asClosure() { return 0; }
- virtual Convert *asConvert() { return 0; }
- virtual Unop *asUnop() { return 0; }
- virtual Binop *asBinop() { return 0; }
- virtual Call *asCall() { return 0; }
- virtual New *asNew() { return 0; }
- virtual Subscript *asSubscript() { return 0; }
- virtual Member *asMember() { return 0; }
+ template <typename To>
+ inline To *as() {
+ if (isa<To>()) {
+ return static_cast<To *>(this);
+ } else {
+ return nullptr;
+ }
+ }
+
+ template <typename To>
+ inline const To *as() const {
+ if (isa<To>()) {
+ return static_cast<const To *>(this);
+ } else {
+ return nullptr;
+ }
+ }
+
+ Expr(ExprKind exprKind): type(UnknownType), exprKind(exprKind) {}
+ bool isLValue() const;
+
+ Const *asConst() { return as<Const>(); }
+ String *asString() { return as<String>(); }
+ RegExp *asRegExp() { return as<RegExp>(); }
+ Name *asName() { return as<Name>(); }
+ Temp *asTemp() { return as<Temp>(); }
+ ArgLocal *asArgLocal() { return as<ArgLocal>(); }
+ Closure *asClosure() { return as<Closure>(); }
+ Convert *asConvert() { return as<Convert>(); }
+ Unop *asUnop() { return as<Unop>(); }
+ Binop *asBinop() { return as<Binop>(); }
+ Call *asCall() { return as<Call>(); }
+ New *asNew() { return as<New>(); }
+ Subscript *asSubscript() { return as<Subscript>(); }
+ Member *asMember() { return as<Member>(); }
};
+#define EXPR_VISIT_ALL_KINDS(e) \
+ switch (e->exprKind) { \
+ case QV4::IR::Expr::ConstExpr: \
+ break; \
+ case QV4::IR::Expr::StringExpr: \
+ break; \
+ case QV4::IR::Expr::RegExpExpr: \
+ break; \
+ case QV4::IR::Expr::NameExpr: \
+ break; \
+ case QV4::IR::Expr::TempExpr: \
+ break; \
+ case QV4::IR::Expr::ArgLocalExpr: \
+ break; \
+ case QV4::IR::Expr::ClosureExpr: \
+ break; \
+ case QV4::IR::Expr::ConvertExpr: { \
+ auto casted = e->asConvert(); \
+ visit(casted->expr); \
+ } break; \
+ case QV4::IR::Expr::UnopExpr: { \
+ auto casted = e->asUnop(); \
+ visit(casted->expr); \
+ } break; \
+ case QV4::IR::Expr::BinopExpr: { \
+ auto casted = e->asBinop(); \
+ visit(casted->left); \
+ visit(casted->right); \
+ } break; \
+ case QV4::IR::Expr::CallExpr: { \
+ auto casted = e->asCall(); \
+ visit(casted->base); \
+ for (QV4::IR::ExprList *it = casted->args; it; it = it->next) \
+ visit(it->expr); \
+ } break; \
+ case QV4::IR::Expr::NewExpr: { \
+ auto casted = e->asNew(); \
+ visit(casted->base); \
+ for (QV4::IR::ExprList *it = casted->args; it; it = it->next) \
+ visit(it->expr); \
+ } break; \
+ case QV4::IR::Expr::SubscriptExpr: { \
+ auto casted = e->asSubscript(); \
+ visit(casted->base); \
+ visit(casted->index); \
+ } break; \
+ case QV4::IR::Expr::MemberExpr: { \
+ auto casted = e->asMember(); \
+ visit(casted->base); \
+ } break; \
+ }
+
struct ExprList {
Expr *expr;
ExprList *next;
@@ -326,26 +399,28 @@ struct ExprList {
struct Const: Expr {
double value;
+ Const(): Expr(ConstExpr) {}
+
void init(Type type, double value)
{
this->type = type;
this->value = value;
}
- virtual void accept(ExprVisitor *v) { v->visitConst(this); }
- virtual Const *asConst() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == ConstExpr; }
};
struct String: Expr {
const QString *value;
+ String(): Expr(StringExpr) {}
+
void init(const QString *value)
{
this->value = value;
}
- virtual void accept(ExprVisitor *v) { v->visitString(this); }
- virtual String *asString() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == StringExpr; }
};
struct RegExp: Expr {
@@ -359,14 +434,15 @@ struct RegExp: Expr {
const QString *value;
int flags;
+ RegExp(): Expr(RegExpExpr) {}
+
void init(const QString *value, int flags)
{
this->value = value;
this->flags = flags;
}
- virtual void accept(ExprVisitor *v) { v->visitRegExp(this); }
- virtual RegExp *asRegExp() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == RegExpExpr; }
};
struct Name: Expr {
@@ -399,13 +475,13 @@ struct Name: Expr {
quint32 line;
quint32 column;
+ Name(): Expr(NameExpr) {}
+
void initGlobal(const QString *id, quint32 line, quint32 column);
void init(const QString *id, quint32 line, quint32 column);
void init(Builtin builtin, quint32 line, quint32 column);
- virtual void accept(ExprVisitor *v) { v->visitName(this); }
- virtual bool isLValue() { return true; }
- virtual Name *asName() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == NameExpr; }
};
struct Q_AUTOTEST_EXPORT Temp: Expr {
@@ -424,7 +500,8 @@ struct Q_AUTOTEST_EXPORT Temp: Expr {
MemberExpressionResolver *memberResolver;
Temp()
- : index((1 << 28) - 1)
+ : Expr(TempExpr)
+ , index((1 << 28) - 1)
, isReadOnly(0)
, kind(Invalid)
, memberResolver(0)
@@ -438,9 +515,8 @@ struct Q_AUTOTEST_EXPORT Temp: Expr {
}
bool isInvalid() const { return kind == Invalid; }
- virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
- virtual bool isLValue() { return !isReadOnly; }
- virtual Temp *asTemp() { return this; }
+
+ static bool classof(const Expr *c) { return c->exprKind == TempExpr; }
};
inline bool operator==(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
@@ -479,44 +555,48 @@ struct Q_AUTOTEST_EXPORT ArgLocal: Expr {
this->isArgumentsOrEval = false;
}
- virtual void accept(ExprVisitor *v) { v->visitArgLocal(this); }
- virtual bool isLValue() { return true; }
- virtual ArgLocal *asArgLocal() { return this; }
+ ArgLocal(): Expr(ArgLocalExpr) {}
bool operator==(const ArgLocal &other) const
{ return index == other.index && scope == other.scope && kind == other.kind; }
+
+ static bool classof(const Expr *c) { return c->exprKind == ArgLocalExpr; }
};
struct Closure: Expr {
int value; // index in _module->functions
const QString *functionName;
+ Closure(): Expr(ClosureExpr) {}
+
void init(int functionInModule, const QString *functionName)
{
this->value = functionInModule;
this->functionName = functionName;
}
- virtual void accept(ExprVisitor *v) { v->visitClosure(this); }
- virtual Closure *asClosure() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == ClosureExpr; }
};
struct Convert: Expr {
Expr *expr;
+ Convert(): Expr(ConvertExpr) {}
+
void init(Expr *expr, Type type)
{
this->expr = expr;
this->type = type;
}
- virtual void accept(ExprVisitor *v) { v->visitConvert(this); }
- virtual Convert *asConvert() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == ConvertExpr; }
};
struct Unop: Expr {
- AluOp op;
Expr *expr;
+ AluOp op;
+
+ Unop(): Expr(UnopExpr) {}
void init(AluOp op, Expr *expr)
{
@@ -524,14 +604,15 @@ struct Unop: Expr {
this->expr = expr;
}
- virtual void accept(ExprVisitor *v) { v->visitUnop(this); }
- virtual Unop *asUnop() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == UnopExpr; }
};
struct Binop: Expr {
- AluOp op;
Expr *left; // Temp or Const
Expr *right; // Temp or Const
+ AluOp op;
+
+ Binop(): Expr(BinopExpr) {}
void init(AluOp op, Expr *left, Expr *right)
{
@@ -540,14 +621,15 @@ struct Binop: Expr {
this->right = right;
}
- virtual void accept(ExprVisitor *v) { v->visitBinop(this); }
- virtual Binop *asBinop() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == BinopExpr; }
};
struct Call: Expr {
Expr *base; // Name, Member, Temp
ExprList *args; // List of Temps
+ Call(): Expr(CallExpr) {}
+
void init(Expr *base, ExprList *args)
{
this->base = base;
@@ -560,14 +642,15 @@ struct Call: Expr {
return 0;
}
- virtual void accept(ExprVisitor *v) { v->visitCall(this); }
- virtual Call *asCall() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == CallExpr; }
};
struct New: Expr {
Expr *base; // Name, Member, Temp
ExprList *args; // List of Temps
+ New(): Expr(NewExpr) {}
+
void init(Expr *base, ExprList *args)
{
this->base = base;
@@ -580,23 +663,22 @@ struct New: Expr {
return 0;
}
- virtual void accept(ExprVisitor *v) { v->visitNew(this); }
- virtual New *asNew() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == NewExpr; }
};
struct Subscript: Expr {
Expr *base;
Expr *index;
+ Subscript(): Expr(SubscriptExpr) {}
+
void init(Expr *base, Expr *index)
{
this->base = base;
this->index = index;
}
- virtual void accept(ExprVisitor *v) { v->visitSubscript(this); }
- virtual bool isLValue() { return true; }
- virtual Subscript *asSubscript() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == SubscriptExpr; }
};
struct Member: Expr {
@@ -628,6 +710,8 @@ struct Member: Expr {
uchar kind: 3; // MemberKind
+ Member(): Expr(MemberExpr) {}
+
void setEnumValue(int value) {
kind = MemberOfEnum;
enumValue = value;
@@ -649,35 +733,52 @@ struct Member: Expr {
this->kind = kind;
}
- virtual void accept(ExprVisitor *v) { v->visitMember(this); }
- virtual bool isLValue() { return true; }
- virtual Member *asMember() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == MemberExpr; }
};
+inline bool Expr::isLValue() const {
+ if (auto t = as<Temp>())
+ return !t->isReadOnly;
+ return exprKind <= LastLValue;
+}
+
struct Stmt {
+ enum StmtKind: quint8 {
+ MoveStmt,
+ ExpStmt,
+ JumpStmt,
+ CJumpStmt,
+ RetStmt,
+ PhiStmt
+ };
+
+ template <typename To>
+ inline bool isa() const {
+ return To::classof(this);
+ }
+
+ template <typename To>
+ inline To *as() {
+ if (isa<To>())
+ return static_cast<To *>(this);
+ else
+ return nullptr;
+ }
+
enum { InvalidId = -1 };
QQmlJS::AST::SourceLocation location;
- explicit Stmt(int id): _id(id) {}
+ explicit Stmt(int id, StmtKind stmtKind): _id(id), stmtKind(stmtKind) {}
- virtual ~Stmt()
- {
-#ifdef Q_CC_MSVC
- // MSVC complains about potential memory leaks if a destructor never returns.
-#else
- Q_UNREACHABLE();
-#endif
- }
- virtual Stmt *asTerminator() { return 0; }
+ Stmt *asTerminator();
- virtual void accept(StmtVisitor *) = 0;
- virtual Exp *asExp() { return 0; }
- virtual Move *asMove() { return 0; }
- virtual Jump *asJump() { return 0; }
- virtual CJump *asCJump() { return 0; }
- virtual Ret *asRet() { return 0; }
- virtual Phi *asPhi() { return 0; }
+ Exp *asExp() { return as<Exp>(); }
+ Move *asMove() { return as<Move>(); }
+ Jump *asJump() { return as<Jump>(); }
+ CJump *asCJump() { return as<CJump>(); }
+ Ret *asRet() { return as<Ret>(); }
+ Phi *asPhi() { return as<Phi>(); }
int id() const { return _id; }
@@ -687,21 +788,52 @@ private: // For memory management in BasicBlock
private:
friend struct Function;
int _id;
+
+public:
+ const StmtKind stmtKind;
};
+#define STMT_VISIT_ALL_KINDS(s) \
+ switch (s->stmtKind) { \
+ case QV4::IR::Stmt::MoveStmt: { \
+ auto casted = s->asMove(); \
+ visit(casted->target); \
+ visit(casted->source); \
+ } break; \
+ case QV4::IR::Stmt::ExpStmt: { \
+ auto casted = s->asExp(); \
+ visit(casted->expr); \
+ } break; \
+ case QV4::IR::Stmt::JumpStmt: \
+ break; \
+ case QV4::IR::Stmt::CJumpStmt: { \
+ auto casted = s->asCJump(); \
+ visit(casted->cond); \
+ } break; \
+ case QV4::IR::Stmt::RetStmt: { \
+ auto casted = s->asRet(); \
+ visit(casted->expr); \
+ } break; \
+ case QV4::IR::Stmt::PhiStmt: { \
+ auto casted = s->asPhi(); \
+ visit(casted->targetTemp); \
+ for (auto *e : casted->incoming) { \
+ visit(e); \
+ } \
+ } break; \
+ }
+
struct Exp: Stmt {
Expr *expr;
- Exp(int id): Stmt(id) {}
+ Exp(int id): Stmt(id, ExpStmt) {}
void init(Expr *expr)
{
this->expr = expr;
}
- virtual void accept(StmtVisitor *v) { v->visitExp(this); }
- virtual Exp *asExp() { return this; }
-
+ static bool classof(const Stmt *c) { return c->stmtKind == ExpStmt; }
};
struct Move: Stmt {
@@ -709,7 +841,7 @@ struct Move: Stmt {
Expr *source;
bool swap;
- Move(int id): Stmt(id) {}
+ Move(int id): Stmt(id, MoveStmt) {}
void init(Expr *target, Expr *source)
{
@@ -718,25 +850,20 @@ struct Move: Stmt {
this->swap = false;
}
- virtual void accept(StmtVisitor *v) { v->visitMove(this); }
- virtual Move *asMove() { return this; }
-
+ static bool classof(const Stmt *c) { return c->stmtKind == MoveStmt; }
};
struct Jump: Stmt {
BasicBlock *target;
- Jump(int id): Stmt(id) {}
+ Jump(int id): Stmt(id, JumpStmt) {}
void init(BasicBlock *target)
{
this->target = target;
}
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitJump(this); }
- virtual Jump *asJump() { return this; }
+ static bool classof(const Stmt *c) { return c->stmtKind == JumpStmt; }
};
struct CJump: Stmt {
@@ -745,7 +872,7 @@ struct CJump: Stmt {
BasicBlock *iffalse;
BasicBlock *parent;
- CJump(int id): Stmt(id) {}
+ CJump(int id): Stmt(id, CJumpStmt) {}
void init(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse, BasicBlock *parent)
{
@@ -755,26 +882,20 @@ struct CJump: Stmt {
this->parent = parent;
}
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitCJump(this); }
- virtual CJump *asCJump() { return this; }
+ static bool classof(const Stmt *c) { return c->stmtKind == CJumpStmt; }
};
struct Ret: Stmt {
Expr *expr;
- Ret(int id): Stmt(id) {}
+ Ret(int id): Stmt(id, RetStmt) {}
void init(Expr *expr)
{
this->expr = expr;
}
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitRet(this); }
- virtual Ret *asRet() { return this; }
+ static bool classof(const Stmt *c) { return c->stmtKind == RetStmt; }
};
// Phi nodes can only occur at the start of a basic block. If there are any, they need to be
@@ -785,30 +906,52 @@ struct Phi: Stmt {
Temp *targetTemp;
VarLengthArray<Expr *, 4> incoming;
- Phi(int id): Stmt(id) {}
+ Phi(int id): Stmt(id, PhiStmt) {}
- virtual void accept(StmtVisitor *v) { v->visitPhi(this); }
- virtual Phi *asPhi() { return this; }
+ static bool classof(const Stmt *c) { return c->stmtKind == PhiStmt; }
void destroyData()
{ incoming.~VarLengthArray(); }
};
+inline Stmt *Stmt::asTerminator()
+{
+ if (auto s = asJump()) {
+ return s;
+ } else if (auto s = asCJump()) {
+ return s;
+ } else if (auto s = asRet()) {
+ return s;
+ } else {
+ return nullptr;
+ }
+}
+
struct Q_QML_PRIVATE_EXPORT Module {
QQmlJS::MemoryPool pool;
QVector<Function *> functions;
Function *rootFunction;
QString fileName;
+ qint64 sourceTimeStamp;
bool isQmlModule; // implies rootFunction is always 0
+#ifdef QT_NO_QML_DEBUGGER
+ static const bool debugMode = false;
+#else
bool debugMode;
+#endif
Function *newFunction(const QString &name, Function *outer);
Module(bool debugMode)
: rootFunction(0)
+ , sourceTimeStamp(0)
, isQmlModule(false)
+#ifndef QT_NO_QML_DEBUGGER
, debugMode(debugMode)
{}
+#else
+ { Q_UNUSED(debugMode); }
+#endif
~Module();
void setFileName(const QString &name);
@@ -1060,6 +1203,20 @@ private:
unsigned _isRemoved : 1;
};
+template <typename T>
+class SmallSet: public QVarLengthArray<T, 8>
+{
+public:
+ void insert(int value)
+ {
+ for (auto it : *this) {
+ if (it == value)
+ return;
+ }
+ this->append(value);
+ }
+};
+
// Map from meta property index (existence implies dependency) to notify signal index
struct KeyValuePair
{
@@ -1125,14 +1282,15 @@ struct Function {
uint isNamedExpression : 1;
uint hasTry: 1;
uint hasWith: 1;
- uint unused : 25;
+ uint isQmlBinding: 1;
+ uint unused : 24;
- // Location of declaration in source code (-1 if not specified)
- int line;
- int column;
+ // Location of declaration in source code (0 if not specified)
+ uint line;
+ uint column;
// Qml extension:
- QSet<int> idObjectDependencies;
+ SmallSet<int> idObjectDependencies;
PropertyDependencyMap contextObjectPropertyDependencies;
PropertyDependencyMap scopeObjectPropertyDependencies;
@@ -1192,7 +1350,7 @@ private:
int _statementCount;
};
-class CloneExpr: protected IR::ExprVisitor
+class CloneExpr
{
public:
explicit CloneExpr(IR::BasicBlock *block = 0);
@@ -1210,7 +1368,7 @@ public:
{
Expr *c = expr;
qSwap(cloned, c);
- expr->accept(this);
+ visit(expr);
qSwap(cloned, c);
return static_cast<ExprSubclass *>(c);
}
@@ -1253,23 +1411,10 @@ public:
return newArgLocal;
}
-protected:
+private:
IR::ExprList *clone(IR::ExprList *list);
- virtual void visitConst(Const *);
- virtual void visitString(String *);
- virtual void visitRegExp(RegExp *);
- virtual void visitName(Name *);
- virtual void visitTemp(Temp *);
- virtual void visitArgLocal(ArgLocal *);
- virtual void visitClosure(Closure *);
- virtual void visitConvert(Convert *);
- virtual void visitUnop(Unop *);
- virtual void visitBinop(Binop *);
- virtual void visitCall(Call *);
- virtual void visitNew(New *);
- virtual void visitSubscript(Subscript *);
- virtual void visitMember(Member *);
+ void visit(Expr *e);
protected:
IR::BasicBlock *block;
@@ -1278,7 +1423,7 @@ private:
IR::Expr *cloned;
};
-class Q_AUTOTEST_EXPORT IRPrinter: public StmtVisitor, public ExprVisitor
+class Q_AUTOTEST_EXPORT IRPrinter
{
public:
IRPrinter(QTextStream *out);
@@ -1291,6 +1436,7 @@ public:
virtual void print(Function *f);
virtual void print(BasicBlock *bb);
+ void visit(Stmt *s);
virtual void visitExp(Exp *s);
virtual void visitMove(Move *s);
virtual void visitJump(Jump *s);
@@ -1298,6 +1444,7 @@ public:
virtual void visitRet(Ret *s);
virtual void visitPhi(Phi *s);
+ void visit(Expr *e);
virtual void visitConst(Const *e);
virtual void visitString(String *e);
virtual void visitRegExp(RegExp *e);
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index f021e1f760..283fb24897 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -642,7 +642,7 @@ public:
qout << from;
else
qout << "(none)";
- qout << " -> " << to->index() << endl;
+ qout << " dominates " << to->index() << endl;
}
qDebug("%s", buf.data().constData());
}
@@ -740,6 +740,21 @@ public:
return order;
}
+ void mergeIntoPredecessor(BasicBlock *successor)
+ {
+ int succIdx = successor->index();
+ if (succIdx == InvalidBasicBlockIndex) {
+ return;
+ }
+
+ int succDom = idom[unsigned(succIdx)];
+ for (BasicBlockIndex &idx : idom) {
+ if (idx == succIdx) {
+ idx = succDom;
+ }
+ }
+ }
+
private:
bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const {
// dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
@@ -898,7 +913,7 @@ private:
}
};
-class VariableCollector: public StmtVisitor, ExprVisitor {
+class VariableCollector {
std::vector<Temp> _allTemps;
std::vector<BasicBlockSet> _defsites;
std::vector<std::vector<int> > A_orig;
@@ -946,7 +961,7 @@ public:
currentBB = bb;
killed.assign(function->tempCount, false);
for (Stmt *s : bb->statements())
- s->accept(this);
+ visit(s);
}
}
@@ -971,62 +986,45 @@ public:
return nonLocals.at(var.index);
}
-protected:
- virtual void visitPhi(Phi *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
-
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(Member *e) { e->base->accept(this); }
- virtual void visitExp(Exp *s) { s->expr->accept(this); }
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
-
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
+private:
+ void visit(Stmt *s)
+ {
+ if (s->asPhi()) {
+ // nothing to do
+ } else if (auto move = s->asMove()) {
+ visit(move->source);
- virtual void visitMove(Move *s) {
- s->source->accept(this);
+ if (Temp *t = move->target->asTemp()) {
+ addTemp(t);
- if (Temp *t = s->target->asTemp()) {
- addTemp(t);
+ if (isCollectable(t)) {
+ _defsites[t->index].insert(currentBB);
+ addDefInCurrentBlock(t);
- if (isCollectable(t)) {
- _defsites[t->index].insert(currentBB);
- addDefInCurrentBlock(t);
-
- // For semi-pruned SSA:
- killed.setBit(t->index);
+ // For semi-pruned SSA:
+ killed.setBit(t->index);
+ }
+ } else {
+ visit(move->target);
}
} else {
- s->target->accept(this);
+ STMT_VISIT_ALL_KINDS(s)
}
}
- virtual void visitTemp(Temp *t)
+ void visit(Expr *e)
{
- addTemp(t);
+ if (auto t = e->asTemp()) {
+ addTemp(t);
- if (isCollectable(t))
- if (!killed.at(t->index))
- nonLocals.setBit(t->index);
+ if (isCollectable(t)) {
+ if (!killed.at(t->index)) {
+ nonLocals.setBit(t->index);
+ }
+ }
+ } else {
+ EXPR_VISIT_ALL_KINDS(e);
+ }
}
};
@@ -1192,6 +1190,15 @@ public:
return _defUses[variable.index].blockOfStatement;
}
+ void replaceBasicBlock(BasicBlock *from, BasicBlock *to)
+ {
+ for (auto &du : _defUses) {
+ if (du.blockOfStatement == from) {
+ du.blockOfStatement = to;
+ }
+ }
+ }
+
void removeUse(Stmt *usingStmt, const Temp &var)
{
Q_ASSERT(static_cast<unsigned>(var.index) < _defUses.size());
@@ -1345,7 +1352,7 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) {
//
// Undo(t, c) =
// mapping[t] = c
-class VariableRenamer: public StmtVisitor, public ExprVisitor
+class VariableRenamer
{
Q_DISABLE_COPY(VariableRenamer)
@@ -1466,7 +1473,7 @@ private:
for (Stmt *s : bb->statements()) {
currentStmt = s;
- s->accept(this);
+ visit(s);
}
for (BasicBlock *Y : bb->out) {
@@ -1532,23 +1539,35 @@ private:
return newIndex;
}
-protected:
- virtual void visitTemp(Temp *e) { // only called for uses, not defs
-// qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top();
- e->index = currentNumber(*e);
- e->kind = Temp::VirtualRegister;
- defUses.addUse(*e, currentStmt);
- }
+private:
+ void visit(Stmt *s)
+ {
+ if (auto move = s->asMove()) {
+ // uses:
+ visit(move->source);
- virtual void visitMove(Move *s) {
- // uses:
- s->source->accept(this);
+ // defs:
+ if (Temp *t = move->target->asTemp()) {
+ renameTemp(t);
+ } else {
+ visit(move->target);
+ }
+ } else if (auto phi = s->asPhi()) {
+ renameTemp(phi->targetTemp);
+ } else {
+ STMT_VISIT_ALL_KINDS(s);
+ }
+ }
- // defs:
- if (Temp *t = s->target->asTemp())
- renameTemp(t);
- else
- s->target->accept(this);
+ void visit(Expr *e)
+ {
+ if (auto temp = e->asTemp()) {
+ temp->index = currentNumber(*temp);
+ temp->kind = Temp::VirtualRegister;
+ defUses.addUse(*temp, currentStmt);
+ } else {
+ EXPR_VISIT_ALL_KINDS(e);
+ }
}
void renameTemp(Temp *t) { // only called for defs, not uses
@@ -1558,44 +1577,6 @@ protected:
t->index = newIdx;
defUses.addDef(t, currentStmt, currentBB);
}
-
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitPhi(Phi *s) { renameTemp(s->targetTemp); }
-
- virtual void visitExp(Exp *s) { s->expr->accept(this); }
-
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
-
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitSubscript(Subscript *e) {
- e->base->accept(this);
- e->index->accept(this);
- }
-
- virtual void visitMember(Member *e) {
- e->base->accept(this);
- }
};
// This function converts the IR to semi-pruned SSA form. For details about SSA and the algorightm,
@@ -1922,7 +1903,7 @@ private:
}
};
-class SideEffectsChecker: public ExprVisitor
+class SideEffectsChecker
{
bool _sideEffect;
@@ -1931,11 +1912,14 @@ public:
: _sideEffect(false)
{}
+ ~SideEffectsChecker()
+ {}
+
bool hasSideEffects(Expr *expr)
{
bool sideEffect = false;
qSwap(_sideEffect, sideEffect);
- expr->accept(this);
+ visit(expr);
qSwap(_sideEffect, sideEffect);
return sideEffect;
}
@@ -1948,12 +1932,35 @@ protected:
bool seenSideEffects() const { return _sideEffect; }
-protected:
- void visitConst(Const *) Q_DECL_OVERRIDE {}
- void visitString(IR::String *) Q_DECL_OVERRIDE {}
- void visitRegExp(IR::RegExp *) Q_DECL_OVERRIDE {}
+ void visit(Expr *e)
+ {
+ if (auto n = e->asName()) {
+ visitName(n);
+ } else if (auto t = e->asTemp()) {
+ visitTemp(t);
+ } else if (auto c = e->asClosure()) {
+ visitClosure(c);
+ } else if (auto c = e->asConvert()) {
+ visitConvert(c);
+ } else if (auto u = e->asUnop()) {
+ visitUnop(u);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ }
+ }
+
+ virtual void visitTemp(Temp *) {}
- void visitName(Name *e) Q_DECL_OVERRIDE {
+private:
+ void visitName(Name *e) {
if (e->freeOfSideEffects)
return;
// TODO: maybe we can distinguish between built-ins of which we know that they do not have
@@ -1962,15 +1969,12 @@ protected:
markAsSideEffect();
}
- void visitTemp(Temp *) Q_DECL_OVERRIDE {}
- void visitArgLocal(ArgLocal *) Q_DECL_OVERRIDE {}
-
- void visitClosure(Closure *) Q_DECL_OVERRIDE {
+ void visitClosure(Closure *) {
markAsSideEffect();
}
- void visitConvert(Convert *e) Q_DECL_OVERRIDE {
- e->expr->accept(this);
+ void visitConvert(Convert *e) {
+ visit(e->expr);
switch (e->expr->type) {
case QObjectType:
@@ -1983,8 +1987,8 @@ protected:
}
}
- void visitUnop(Unop *e) Q_DECL_OVERRIDE {
- e->expr->accept(this);
+ void visitUnop(Unop *e) {
+ visit(e->expr);
switch (e->op) {
case OpUPlus:
@@ -2001,7 +2005,7 @@ protected:
}
}
- void visitBinop(Binop *e) Q_DECL_OVERRIDE {
+ void visitBinop(Binop *e) {
// TODO: prune parts that don't have a side-effect. For example, in:
// function f(x) { +x+1; return 0; }
// we can prune the binop and leave the unop/conversion.
@@ -2013,30 +2017,30 @@ protected:
markAsSideEffect();
}
- void visitSubscript(Subscript *e) Q_DECL_OVERRIDE {
- e->base->accept(this);
- e->index->accept(this);
+ void visitSubscript(Subscript *e) {
+ visit(e->base);
+ visit(e->index);
markAsSideEffect();
}
- void visitMember(Member *e) Q_DECL_OVERRIDE {
- e->base->accept(this);
+ void visitMember(Member *e) {
+ visit(e->base);
if (e->freeOfSideEffects)
return;
markAsSideEffect();
}
- void visitCall(Call *e) Q_DECL_OVERRIDE {
- e->base->accept(this);
+ void visitCall(Call *e) {
+ visit(e->base);
for (ExprList *args = e->args; args; args = args->next)
- args->expr->accept(this);
+ visit(args->expr);
markAsSideEffect(); // TODO: there are built-in functions that have no side effect.
}
- void visitNew(New *e) Q_DECL_OVERRIDE {
- e->base->accept(this);
+ void visitNew(New *e) {
+ visit(e->base);
for (ExprList *args = e->args; args; args = args->next)
- args->expr->accept(this);
+ visit(args->expr);
markAsSideEffect(); // TODO: there are built-in types that have no side effect.
}
};
@@ -2045,21 +2049,19 @@ class EliminateDeadCode: public SideEffectsChecker
{
DefUses &_defUses;
StatementWorklist &_worklist;
- QVector<Temp *> _collectedTemps;
+ QVarLengthArray<Temp *, 8> _collectedTemps;
public:
EliminateDeadCode(DefUses &defUses, StatementWorklist &worklist)
: _defUses(defUses)
, _worklist(worklist)
- {
- _collectedTemps.reserve(8);
- }
+ {}
void run(Expr *&expr, Stmt *stmt) {
_collectedTemps.clear();
if (!hasSideEffects(expr)) {
expr = 0;
- foreach (Temp *t, _collectedTemps) {
+ for (Temp *t : _collectedTemps) {
_defUses.removeUse(stmt, *t);
_worklist += _defUses.defStmt(*t);
}
@@ -2067,13 +2069,13 @@ public:
}
protected:
- void visitTemp(Temp *e) Q_DECL_OVERRIDE
+ void visitTemp(Temp *e) Q_DECL_OVERRIDE Q_DECL_FINAL
{
_collectedTemps.append(e);
}
};
-class PropagateTempTypes: public StmtVisitor, ExprVisitor
+class PropagateTempTypes
{
const DefUses &defUses;
UntypedTemp theTemp;
@@ -2089,64 +2091,31 @@ public:
newType = type;
theTemp = temp;
if (Stmt *defStmt = defUses.defStmt(temp.temp))
- defStmt->accept(this);
+ visit(defStmt);
foreach (Stmt *use, defUses.uses(temp.temp))
- use->accept(this);
+ visit(use);
}
-protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *e) {
- if (theTemp == UntypedTemp(*e)) {
- e->type = static_cast<Type>(newType.type);
- e->memberResolver = newType.memberResolver;
- }
- }
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
-
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitSubscript(Subscript *e) {
- e->base->accept(this);
- e->index->accept(this);
- }
-
- virtual void visitMember(Member *e) {
- e->base->accept(this);
- }
-
- virtual void visitExp(Exp *s) {s->expr->accept(this);}
- virtual void visitMove(Move *s) {
- s->source->accept(this);
- s->target->accept(this);
+private:
+ void visit(Stmt *s)
+ {
+ STMT_VISIT_ALL_KINDS(s);
}
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(Phi *s) {
- s->targetTemp->accept(this);
- foreach (Expr *e, s->incoming)
- e->accept(this);
+ void visit(Expr *e)
+ {
+ if (auto temp = e->asTemp()) {
+ if (theTemp == UntypedTemp(*temp)) {
+ temp->type = static_cast<Type>(newType.type);
+ temp->memberResolver = newType.memberResolver;
+ }
+ } else {
+ EXPR_VISIT_ALL_KINDS(e);
+ }
}
};
-class TypeInference: public StmtVisitor, public ExprVisitor
+class TypeInference
{
enum { DebugTypeInference = 0 };
@@ -2248,7 +2217,7 @@ private:
TypingResult ty;
std::swap(_ty, ty);
std::swap(_currentStmt, s);
- _currentStmt->accept(this);
+ visit(_currentStmt);
std::swap(_currentStmt, s);
std::swap(_ty, ty);
return ty.fullyTyped;
@@ -2257,7 +2226,7 @@ private:
TypingResult run(Expr *e) {
TypingResult ty;
std::swap(_ty, ty);
- e->accept(this);
+ visit(e);
std::swap(_ty, ty);
if (ty.type != UnknownType)
@@ -2299,39 +2268,74 @@ private:
}
}
-protected:
- virtual void visitConst(Const *e) {
- if (e->type & NumberType) {
- if (canConvertToSignedInteger(e->value))
+private:
+ void visit(Expr *e)
+ {
+ if (auto c = e->asConst()) {
+ visitConst(c);
+ } else if (auto s = e->asString()) {
+ visitString(s);
+ } else if (auto r = e->asRegExp()) {
+ visitRegExp(r);
+ } else if (auto n = e->asName()) {
+ visitName(n);
+ } else if (auto t = e->asTemp()) {
+ visitTemp(t);
+ } else if (auto a = e->asArgLocal()) {
+ visitArgLocal(a);
+ } else if (auto c = e->asClosure()) {
+ visitClosure(c);
+ } else if (auto c = e->asConvert()) {
+ visitConvert(c);
+ } else if (auto u = e->asUnop()) {
+ visitUnop(u);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ void visitConst(Const *c) {
+ if (c->type & NumberType) {
+ if (canConvertToSignedInteger(c->value))
_ty = TypingResult(SInt32Type);
- else if (canConvertToUnsignedInteger(e->value))
+ else if (canConvertToUnsignedInteger(c->value))
_ty = TypingResult(UInt32Type);
else
- _ty = TypingResult(e->type);
+ _ty = TypingResult(c->type);
} else
- _ty = TypingResult(e->type);
+ _ty = TypingResult(c->type);
}
- virtual void visitString(IR::String *) { _ty = TypingResult(StringType); }
- virtual void visitRegExp(IR::RegExp *) { _ty = TypingResult(VarType); }
- virtual void visitName(Name *) { _ty = TypingResult(VarType); }
- virtual void visitTemp(Temp *e) {
+ void visitString(IR::String *) { _ty = TypingResult(StringType); }
+ void visitRegExp(IR::RegExp *) { _ty = TypingResult(VarType); }
+ void visitName(Name *) { _ty = TypingResult(VarType); }
+ void visitTemp(Temp *e) {
if (e->memberResolver && e->memberResolver->isValid())
_ty = TypingResult(e->memberResolver);
else
_ty = TypingResult(_tempTypes[e->index]);
setType(e, _ty.type);
}
- virtual void visitArgLocal(ArgLocal *e) {
+ void visitArgLocal(ArgLocal *e) {
_ty = TypingResult(VarType);
setType(e, _ty.type);
}
- virtual void visitClosure(Closure *) { _ty = TypingResult(VarType); }
- virtual void visitConvert(Convert *e) {
+ void visitClosure(Closure *) { _ty = TypingResult(VarType); }
+ void visitConvert(Convert *e) {
_ty = TypingResult(e->type);
}
- virtual void visitUnop(Unop *e) {
+ void visitUnop(Unop *e) {
_ty = run(e->expr);
switch (e->op) {
case OpUPlus: _ty.type = DoubleType; return;
@@ -2348,7 +2352,7 @@ protected:
}
}
- virtual void visitBinop(Binop *e) {
+ void visitBinop(Binop *e) {
TypingResult leftTy = run(e->left);
TypingResult rightTy = run(e->right);
_ty.fullyTyped = leftTy.fullyTyped && rightTy.fullyTyped;
@@ -2406,24 +2410,24 @@ protected:
}
}
- virtual void visitCall(Call *e) {
+ void visitCall(Call *e) {
_ty = run(e->base);
for (ExprList *it = e->args; it; it = it->next)
_ty.fullyTyped &= run(it->expr).fullyTyped;
_ty.type = VarType;
}
- virtual void visitNew(New *e) {
+ void visitNew(New *e) {
_ty = run(e->base);
for (ExprList *it = e->args; it; it = it->next)
_ty.fullyTyped &= run(it->expr).fullyTyped;
_ty.type = VarType;
}
- virtual void visitSubscript(Subscript *e) {
+ void visitSubscript(Subscript *e) {
_ty.fullyTyped = run(e->base).fullyTyped && run(e->index).fullyTyped;
_ty.type = VarType;
}
- virtual void visitMember(Member *e) {
+ void visitMember(Member *e) {
_ty = run(e->base);
if (_ty.fullyTyped && _ty.type.memberResolver && _ty.type.memberResolver->isValid()) {
@@ -2433,8 +2437,27 @@ protected:
_ty.type = VarType;
}
- virtual void visitExp(Exp *s) { _ty = run(s->expr); }
- virtual void visitMove(Move *s) {
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto j = s->asJump()) {
+ visitJump(j);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ void visitExp(Exp *s) { _ty = run(s->expr); }
+ void visitMove(Move *s) {
if (Temp *t = s->target->asTemp()) {
if (Name *n = s->source->asName()) {
if (n->builtin == Name::builtin_qml_context) {
@@ -2455,10 +2478,10 @@ protected:
_ty.fullyTyped &= sourceTy.fullyTyped;
}
- virtual void visitJump(Jump *) { _ty = TypingResult(MissingType); }
- virtual void visitCJump(CJump *s) { _ty = run(s->cond); }
- virtual void visitRet(Ret *s) { _ty = run(s->expr); }
- virtual void visitPhi(Phi *s) {
+ void visitJump(Jump *) { _ty = TypingResult(MissingType); }
+ void visitCJump(CJump *s) { _ty = run(s->cond); }
+ void visitRet(Ret *s) { _ty = run(s->expr); }
+ void visitPhi(Phi *s) {
_ty = run(s->incoming[0]);
for (int i = 1, ei = s->incoming.size(); i != ei; ++i) {
TypingResult ty = run(s->incoming[i]);
@@ -2677,14 +2700,15 @@ void convertConst(Const *c, Type targetType)
c->type = targetType;
}
-class TypePropagation: public StmtVisitor, public ExprVisitor {
+class TypePropagation
+{
DefUses &_defUses;
Type _ty;
IR::Function *_f;
bool run(Expr *&e, Type requestedType = UnknownType, bool insertConversion = true) {
qSwap(_ty, requestedType);
- e->accept(this);
+ visit(e);
qSwap(_ty, requestedType);
if (requestedType != UnknownType) {
@@ -2731,7 +2755,7 @@ public:
for (Stmt *s : bb->statements()) {
_currStmt = s;
- s->accept(this);
+ visit(s);
}
foreach (const Conversion &conversion, _conversions) {
@@ -2817,8 +2841,29 @@ public:
}
}
-protected:
- virtual void visitConst(Const *c) {
+private:
+ void visit(Expr *e)
+ {
+ if (auto c = e->asConst()) {
+ visitConst(c);
+ } else if (auto c = e->asConvert()) {
+ run(c->expr, c->type);
+ } else if (auto u = e->asUnop()) {
+ run(u->expr, u->type);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ }
+ }
+
+ void visitConst(Const *c) {
if (_ty & NumberType && c->type & NumberType) {
if (_ty == SInt32Type)
c->value = QV4::Primitive::toInt32(c->value);
@@ -2828,15 +2873,7 @@ protected:
}
}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { run(e->expr, e->type); }
- virtual void visitUnop(Unop *e) { run(e->expr, e->type); }
- virtual void visitBinop(Binop *e) {
+ void visitBinop(Binop *e) {
// FIXME: This routine needs more tuning!
switch (e->op) {
case OpAdd:
@@ -2887,20 +2924,36 @@ protected:
Q_UNREACHABLE();
}
}
- virtual void visitCall(Call *e) {
+ void visitCall(Call *e) {
run(e->base);
for (ExprList *it = e->args; it; it = it->next)
run(it->expr);
}
- virtual void visitNew(New *e) {
+ void visitNew(New *e) {
run(e->base);
for (ExprList *it = e->args; it; it = it->next)
run(it->expr);
}
- virtual void visitSubscript(Subscript *e) { run(e->base); run(e->index); }
- virtual void visitMember(Member *e) { run(e->base); }
- virtual void visitExp(Exp *s) { run(s->expr); }
- virtual void visitMove(Move *s) {
+ void visitSubscript(Subscript *e) { run(e->base); run(e->index); }
+ void visitMember(Member *e) { run(e->base); }
+
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ }
+ }
+
+ void visitExp(Exp *s) { run(s->expr); }
+ void visitMove(Move *s) {
if (s->source->asConvert())
return; // this statement got inserted for a phi-node type conversion
@@ -2925,12 +2978,11 @@ protected:
run(s->source, s->target->type, !inhibitConversion);
}
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) {
+ void visitCJump(CJump *s) {
run(s->cond, BoolType);
}
- virtual void visitRet(Ret *s) { run(s->expr); }
- virtual void visitPhi(Phi *s) {
+ void visitRet(Ret *s) { run(s->expr); }
+ void visitPhi(Phi *s) {
Type ty = s->targetTemp->type;
for (int i = 0, ei = s->incoming.size(); i != ei; ++i)
run(s->incoming[i], ty);
@@ -3299,6 +3351,15 @@ class BlockScheduler
// this is a loop, where there in -> candidate edge is the jump back to the top of the loop.
continue;
+ if (in == candidate)
+ // this is a very tight loop, e.g.:
+ // L1: ...
+ // goto L1
+ // This can happen when, for example, the basic-block merging gets rid of the empty
+ // body block. In this case, we can safely schedule this block (if all other
+ // incoming edges are either loop-back edges, or have been scheduled already).
+ continue;
+
return false; // an incoming edge that is not yet emitted, and is not a back-edge
}
@@ -3504,7 +3565,7 @@ static Expr *clone(Expr *e, IR::Function *function) {
}
}
-class ExprReplacer: public StmtVisitor, public ExprVisitor
+class ExprReplacer
{
DefUses &_defUses;
IR::Function* _function;
@@ -3535,7 +3596,7 @@ public:
// qout << " " << uses.size() << " uses:"<<endl;
foreach (Stmt *use, uses) {
// qout<<" ";use->dump(qout);qout<<"\n";
- use->accept(this);
+ visit(use);
// qout<<" -> ";use->dump(qout);qout<<"\n";
W += use;
if (newUses)
@@ -3546,45 +3607,101 @@ public:
qSwap(_toReplace, toReplace);
}
-protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { check(e->expr); }
- virtual void visitUnop(Unop *e) { check(e->expr); }
- virtual void visitBinop(Binop *e) { check(e->left); check(e->right); }
- virtual void visitCall(Call *e) {
+private:
+ void visit(Expr *e)
+ {
+ if (auto c = e->asConst()) {
+ visitConst(c);
+ } else if (auto s = e->asString()) {
+ visitString(s);
+ } else if (auto r = e->asRegExp()) {
+ visitRegExp(r);
+ } else if (auto n = e->asName()) {
+ visitName(n);
+ } else if (auto t = e->asTemp()) {
+ visitTemp(t);
+ } else if (auto a = e->asArgLocal()) {
+ visitArgLocal(a);
+ } else if (auto c = e->asClosure()) {
+ visitClosure(c);
+ } else if (auto c = e->asConvert()) {
+ visitConvert(c);
+ } else if (auto u = e->asUnop()) {
+ visitUnop(u);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ void visitConst(Const *) {}
+ void visitString(IR::String *) {}
+ void visitRegExp(IR::RegExp *) {}
+ void visitName(Name *) {}
+ void visitTemp(Temp *) {}
+ void visitArgLocal(ArgLocal *) {}
+ void visitClosure(Closure *) {}
+ void visitConvert(Convert *e) { check(e->expr); }
+ void visitUnop(Unop *e) { check(e->expr); }
+ void visitBinop(Binop *e) { check(e->left); check(e->right); }
+ void visitCall(Call *e) {
check(e->base);
for (ExprList *it = e->args; it; it = it->next)
check(it->expr);
}
- virtual void visitNew(New *e) {
+ void visitNew(New *e) {
check(e->base);
for (ExprList *it = e->args; it; it = it->next)
check(it->expr);
}
- virtual void visitSubscript(Subscript *e) { check(e->base); check(e->index); }
- virtual void visitMember(Member *e) { check(e->base); }
- virtual void visitExp(Exp *s) { check(s->expr); }
- virtual void visitMove(Move *s) { check(s->target); check(s->source); }
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { check(s->cond); }
- virtual void visitRet(Ret *s) { check(s->expr); }
- virtual void visitPhi(Phi *s) {
+ void visitSubscript(Subscript *e) { check(e->base); check(e->index); }
+ void visitMember(Member *e) { check(e->base); }
+
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto j = s->asJump()) {
+ visitJump(j);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ void visitExp(Exp *s) { check(s->expr); }
+ void visitMove(Move *s) { check(s->target); check(s->source); }
+ void visitJump(Jump *) {}
+ void visitCJump(CJump *s) { check(s->cond); }
+ void visitRet(Ret *s) { check(s->expr); }
+ void visitPhi(Phi *s) {
for (int i = 0, ei = s->incoming.size(); i != ei; ++i)
check(s->incoming[i]);
}
private:
void check(Expr *&e) {
- if (equals(e, _toReplace))
+ if (equals(e, _toReplace)) {
e = clone(_replacement, _function);
- else
- e->accept(this);
+ } else {
+ visit(e);
+ }
}
// This only calculates equality for everything needed by constant propagation
@@ -3625,6 +3742,8 @@ namespace {
void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUses,
StatementWorklist &W, DominatorTree &dt)
{
+ enum { DebugUnlinking = 0 };
+
struct Util {
static void removeIncomingEdge(BasicBlock *from, BasicBlock *to, DefUses &defUses, StatementWorklist &W)
{
@@ -3663,11 +3782,17 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
}
};
+ Q_ASSERT(!from->isRemoved());
+ Q_ASSERT(!to->isRemoved());
+
// don't purge blocks that are entry points for catch statements. They might not be directly
// connected, but are required anyway
if (to->isExceptionHandler())
return;
+ if (DebugUnlinking)
+ qDebug("Unlinking L%d -> L%d...", from->index(), to->index());
+
// First, unlink the edge
from->out.removeOne(to);
Util::removeIncomingEdge(from, to, defUses, W);
@@ -3677,8 +3802,12 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
// Check if the target is still reachable...
if (Util::isReachable(to, dt)) { // yes, recalculate the immediate dominator, and we're done.
+ if (DebugUnlinking)
+ qDebug(".. L%d is still reachable, recalulate idom.", to->index());
dt.collectSiblings(to, siblings);
} else {
+ if (DebugUnlinking)
+ qDebug(".. L%d is unreachable, purging it:", to->index());
// The target is unreachable, so purge it:
QVector<BasicBlock *> toPurge;
toPurge.reserve(8);
@@ -3686,6 +3815,8 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
while (!toPurge.isEmpty()) {
BasicBlock *bb = toPurge.first();
toPurge.removeFirst();
+ if (DebugUnlinking)
+ qDebug("... purging L%d", bb->index());
if (bb->isRemoved())
continue;
@@ -3729,6 +3860,8 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
}
dt.recalculateIDoms(siblings);
+ if (DebugUnlinking)
+ qDebug("Unlinking done.");
}
bool tryOptimizingComparison(Expr *&expr)
@@ -3748,42 +3881,42 @@ bool tryOptimizingComparison(Expr *&expr)
switch (b->op) {
case OpGt:
- leftConst->value = Runtime::compareGreaterThan(l, r);
+ leftConst->value = Runtime::method_compareGreaterThan(l, r);
leftConst->type = BoolType;
expr = leftConst;
return true;
case OpLt:
- leftConst->value = Runtime::compareLessThan(l, r);
+ leftConst->value = Runtime::method_compareLessThan(l, r);
leftConst->type = BoolType;
expr = leftConst;
return true;
case OpGe:
- leftConst->value = Runtime::compareGreaterEqual(l, r);
+ leftConst->value = Runtime::method_compareGreaterEqual(l, r);
leftConst->type = BoolType;
expr = leftConst;
return true;
case OpLe:
- leftConst->value = Runtime::compareLessEqual(l, r);
+ leftConst->value = Runtime::method_compareLessEqual(l, r);
leftConst->type = BoolType;
expr = leftConst;
return true;
case OpStrictEqual:
- leftConst->value = Runtime::compareStrictEqual(l, r);
+ leftConst->value = Runtime::method_compareStrictEqual(l, r);
leftConst->type = BoolType;
expr = leftConst;
return true;
case OpEqual:
- leftConst->value = Runtime::compareEqual(l, r);
+ leftConst->value = Runtime::method_compareEqual(l, r);
leftConst->type = BoolType;
expr = leftConst;
return true;
case OpStrictNotEqual:
- leftConst->value = Runtime::compareStrictNotEqual(l, r);
+ leftConst->value = Runtime::method_compareStrictNotEqual(l, r);
leftConst->type = BoolType;
expr = leftConst;
return true;
case OpNotEqual:
- leftConst->value = Runtime::compareNotEqual(l, r);
+ leftConst->value = Runtime::method_compareNotEqual(l, r);
leftConst->type = BoolType;
expr = leftConst;
return true;
@@ -4153,7 +4286,8 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df)
}
//### TODO: use DefUses from the optimizer, because it already has all this information
-class InputOutputCollector: protected StmtVisitor, protected ExprVisitor {
+class InputOutputCollector
+{
void setOutput(Temp *out)
{
Q_ASSERT(!output);
@@ -4170,48 +4304,33 @@ public:
void collect(Stmt *s) {
inputs.resize(0);
output = 0;
- s->accept(this);
+ visit(s);
}
-protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *e) {
- inputs.push_back(e);
- }
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(Member *e) { e->base->accept(this); }
- virtual void visitExp(Exp *s) { s->expr->accept(this); }
- virtual void visitMove(Move *s) {
- s->source->accept(this);
- if (Temp *t = s->target->asTemp()) {
- setOutput(t);
+private:
+ void visit(Expr *e)
+ {
+ if (auto t = e->asTemp()) {
+ inputs.push_back(t);
} else {
- s->target->accept(this);
+ EXPR_VISIT_ALL_KINDS(e);
}
}
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(Phi *) {
- // Handled separately
+
+ void visit(Stmt *s)
+ {
+ if (auto m = s->asMove()) {
+ visit(m->source);
+ if (Temp *t = m->target->asTemp()) {
+ setOutput(t);
+ } else {
+ visit(m->target);
+ }
+ } else if (s->asPhi()) {
+ // Handled separately
+ } else {
+ STMT_VISIT_ALL_KINDS(s);
+ }
}
};
@@ -4381,7 +4500,7 @@ void removeUnreachleBlocks(IR::Function *function)
function->renumberBasicBlocks();
}
-class ConvertArgLocals: protected StmtVisitor, protected ExprVisitor
+class ConvertArgLocals
{
public:
ConvertArgLocals(IR::Function *function)
@@ -4419,10 +4538,13 @@ public:
}
}
- for (BasicBlock *bb : function->basicBlocks())
- if (!bb->isRemoved())
- for (Stmt *s : bb->statements())
- s->accept(this);
+ for (BasicBlock *bb : function->basicBlocks()) {
+ if (!bb->isRemoved()) {
+ for (Stmt *s : bb->statements()) {
+ visit(s);
+ }
+ }
+ }
if (convertArgs && function->formals.size() > 0)
function->basicBlock(0)->prependStatements(extraMoves);
@@ -4430,39 +4552,45 @@ public:
function->locals.clear();
}
-protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { check(e->expr); }
- virtual void visitUnop(Unop *e) { check(e->expr); }
- virtual void visitBinop(Binop *e) { check(e->left); check(e->right); }
- virtual void visitCall(Call *e) {
- check(e->base);
- for (ExprList *it = e->args; it; it = it->next)
- check(it->expr);
- }
- virtual void visitNew(New *e) {
- check(e->base);
- for (ExprList *it = e->args; it; it = it->next)
- check(it->expr);
+private:
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ check(e->expr);
+ } else if (auto m = s->asMove()) {
+ check(m->target); check(m->source);
+ } else if (auto c = s->asCJump()) {
+ check(c->cond);
+ } else if (auto r = s->asRet()) {
+ check(r->expr);
+ }
}
- virtual void visitSubscript(Subscript *e) { check(e->base); check(e->index); }
- virtual void visitMember(Member *e) { check(e->base); }
- virtual void visitExp(Exp *s) { check(s->expr); }
- virtual void visitMove(Move *s) { check(s->target); check(s->source); }
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { check(s->cond); }
- virtual void visitRet(Ret *s) { check(s->expr); }
- virtual void visitPhi(Phi *) {
- Q_UNREACHABLE();
+
+ void visit(Expr *e)
+ {
+ if (auto c = e->asConvert()) {
+ check(c->expr);
+ } else if (auto u = e->asUnop()) {
+ check(u->expr);
+ } else if (auto b = e->asBinop()) {
+ check(b->left); check(b->right);
+ } else if (auto c = e->asCall()) {
+ check(c->base);
+ for (ExprList *it = c->args; it; it = it->next) {
+ check(it->expr);
+ }
+ } else if (auto n = e->asNew()) {
+ check(n->base);
+ for (ExprList *it = n->args; it; it = it->next) {
+ check(it->expr);
+ }
+ } else if (auto s = e->asSubscript()) {
+ check(s->base); check(s->index);
+ } else if (auto m = e->asMember()) {
+ check(m->base);
+ }
}
-private:
void check(Expr *&e) {
if (ArgLocal *al = e->asArgLocal()) {
if (al->kind == ArgLocal::Local) {
@@ -4475,7 +4603,7 @@ private:
e = t;
}
} else {
- e->accept(this);
+ visit(e);
}
}
@@ -4498,7 +4626,7 @@ private:
std::vector<int> tempForLocal;
};
-class CloneBasicBlock: protected IR::StmtVisitor, protected CloneExpr
+class CloneBasicBlock: protected CloneExpr
{
public:
BasicBlock *operator()(IR::BasicBlock *originalBlock)
@@ -4506,38 +4634,37 @@ public:
block = new BasicBlock(originalBlock->function, 0);
for (Stmt *s : originalBlock->statements()) {
- s->accept(this);
+ visit(s);
clonedStmt->location = s->location;
}
return block;
}
-protected:
- virtual void visitExp(Exp *stmt)
- { clonedStmt = block->EXP(clone(stmt->expr)); }
-
- virtual void visitMove(Move *stmt)
- { clonedStmt = block->MOVE(clone(stmt->target), clone(stmt->source)); }
-
- virtual void visitJump(Jump *stmt)
- { clonedStmt = block->JUMP(stmt->target); }
-
- virtual void visitCJump(CJump *stmt)
- { clonedStmt = block->CJUMP(clone(stmt->cond), stmt->iftrue, stmt->iffalse); }
-
- virtual void visitRet(Ret *stmt)
- { clonedStmt = block->RET(clone(stmt->expr)); }
-
- virtual void visitPhi(Phi *stmt)
+private:
+ void visit(Stmt *s)
{
- Phi *phi = block->function->NewStmt<Phi>();
- clonedStmt = phi;
-
- phi->targetTemp = clone(stmt->targetTemp);
- foreach (Expr *in, stmt->incoming)
- phi->incoming.append(clone(in));
- block->appendStatement(phi);
+ if (auto e = s->asExp()) {
+ clonedStmt = block->EXP(clone(e->expr));
+ } else if (auto m = s->asMove()) {
+ clonedStmt = block->MOVE(clone(m->target), clone(m->source));
+ } else if (auto j = s->asJump()) {
+ clonedStmt = block->JUMP(j->target);
+ } else if (auto c = s->asCJump()) {
+ clonedStmt = block->CJUMP(clone(c->cond), c->iftrue, c->iffalse);
+ } else if (auto r = s->asRet()) {
+ clonedStmt = block->RET(clone(r->expr));
+ } else if (auto p = s->asPhi()) {
+ Phi *phi = block->function->NewStmt<Phi>();
+ clonedStmt = phi;
+
+ phi->targetTemp = clone(p->targetTemp);
+ foreach (Expr *in, p->incoming)
+ phi->incoming.append(clone(in));
+ block->appendStatement(phi);
+ } else {
+ Q_UNREACHABLE();
+ }
}
private:
@@ -4706,13 +4833,20 @@ static void verifyCFG(IR::Function *function)
Q_ASSERT(function->basicBlock(bb->index()) == bb);
// Check the terminators:
- if (Jump *jump = bb->terminator()->asJump()) {
+ Stmt *terminator = bb->terminator();
+ if (terminator == nullptr) {
+ Stmt *last = bb->statements().last();
+ Call *call = last->asExp()->expr->asCall();
+ Name *baseName = call->base->asName();
+ Q_ASSERT(baseName->builtin == Name::builtin_rethrow);
+ Q_UNUSED(baseName);
+ } else if (Jump *jump = terminator->asJump()) {
Q_UNUSED(jump);
Q_ASSERT(jump->target);
Q_ASSERT(!jump->target->isRemoved());
Q_ASSERT(bb->out.size() == 1);
Q_ASSERT(bb->out.first() == jump->target);
- } else if (CJump *cjump = bb->terminator()->asCJump()) {
+ } else if (CJump *cjump = terminator->asCJump()) {
Q_UNUSED(cjump);
Q_ASSERT(bb->out.size() == 2);
Q_ASSERT(cjump->iftrue);
@@ -4721,7 +4855,7 @@ static void verifyCFG(IR::Function *function)
Q_ASSERT(cjump->iffalse);
Q_ASSERT(!cjump->iffalse->isRemoved());
Q_ASSERT(cjump->iffalse == bb->out[1]);
- } else if (bb->terminator()->asRet()) {
+ } else if (terminator->asRet()) {
Q_ASSERT(bb->out.size() == 0);
} else {
Q_UNREACHABLE();
@@ -4769,7 +4903,7 @@ static void verifyNoPointerSharing(IR::Function *function)
if (!DoVerification)
return;
- class : public StmtVisitor, public ExprVisitor {
+ class {
public:
void operator()(IR::Function *f)
{
@@ -4777,44 +4911,23 @@ static void verifyNoPointerSharing(IR::Function *function)
if (bb->isRemoved())
continue;
- for (Stmt *s : bb->statements())
- s->accept(this);
+ for (Stmt *s : bb->statements()) {
+ visit(s);
+ }
}
}
- protected:
- virtual void visitExp(Exp *s) { check(s); s->expr->accept(this); }
- virtual void visitMove(Move *s) { check(s); s->target->accept(this); s->source->accept(this); }
- virtual void visitJump(Jump *s) { check(s); }
- virtual void visitCJump(CJump *s) { check(s); s->cond->accept(this); }
- virtual void visitRet(Ret *s) { check(s); s->expr->accept(this); }
- virtual void visitPhi(Phi *s)
+ private:
+ void visit(Stmt *s)
{
check(s);
- s->targetTemp->accept(this);
- foreach (Expr *e, s->incoming)
- e->accept(this);
- }
-
- virtual void visitConst(Const *e) { check(e); }
- virtual void visitString(IR::String *e) { check(e); }
- virtual void visitRegExp(IR::RegExp *e) { check(e); }
- virtual void visitName(Name *e) { check(e); }
- virtual void visitTemp(Temp *e) { check(e); }
- virtual void visitArgLocal(ArgLocal *e) { check(e); }
- virtual void visitClosure(Closure *e) { check(e); }
- virtual void visitConvert(Convert *e) { check(e); e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { check(e); e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { check(e); e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(Call *e) { check(e); e->base->accept(this); check(e->args); }
- virtual void visitNew(New *e) { check(e); e->base->accept(this); check(e->args); }
- virtual void visitSubscript(Subscript *e) { check(e); e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(Member *e) { check(e); e->base->accept(this); }
-
- void check(ExprList *l)
+ STMT_VISIT_ALL_KINDS(s);
+ }
+
+ void visit(Expr *e)
{
- for (ExprList *it = l; it; it = it->next)
- check(it->expr);
+ check(e);
+ EXPR_VISIT_ALL_KINDS(e);
}
private:
@@ -4836,7 +4949,7 @@ static void verifyNoPointerSharing(IR::Function *function)
V(function);
}
-class RemoveLineNumbers: public SideEffectsChecker, public StmtVisitor
+class RemoveLineNumbers: private SideEffectsChecker
{
public:
static void run(IR::Function *function)
@@ -4854,21 +4967,88 @@ public:
}
private:
+ ~RemoveLineNumbers() {}
+
static bool hasSideEffects(Stmt *stmt)
{
RemoveLineNumbers checker;
- stmt->accept(&checker);
+ if (auto e = stmt->asExp()) {
+ checker.visit(e->expr);
+ } else if (auto m = stmt->asMove()) {
+ checker.visit(m->source);
+ if (!checker.seenSideEffects()) {
+ checker.visit(m->target);
+ }
+ } else if (auto c = stmt->asCJump()) {
+ checker.visit(c->cond);
+ } else if (auto r = stmt->asRet()) {
+ checker.visit(r->expr);
+ }
return checker.seenSideEffects();
}
- void visitExp(Exp *s) Q_DECL_OVERRIDE { s->expr->accept(this); }
- void visitMove(Move *s) Q_DECL_OVERRIDE { s->source->accept(this); s->target->accept(this); }
- void visitJump(Jump *) Q_DECL_OVERRIDE {}
- void visitCJump(CJump *s) Q_DECL_OVERRIDE { s->cond->accept(this); }
- void visitRet(Ret *s) Q_DECL_OVERRIDE { s->expr->accept(this); }
- void visitPhi(Phi *) Q_DECL_OVERRIDE {}
+ void visitTemp(Temp *) Q_DECL_OVERRIDE Q_DECL_FINAL {}
};
+void mergeBasicBlocks(IR::Function *function, DefUses *du, DominatorTree *dt)
+{
+ enum { DebugBlockMerging = 0 };
+
+ if (function->hasTry)
+ return;
+
+ showMeTheCode(function, "Before basic block merging");
+
+ // Now merge a basic block with its successor when there is one outgoing edge, and the
+ // successor has one incoming edge.
+ for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
+ BasicBlock *bb = function->basicBlock(i);
+
+ bb->nextLocation = QQmlJS::AST::SourceLocation(); // make sure appendStatement doesn't mess with the line info
+
+ if (bb->isRemoved()) continue; // the block has been removed, so ignore it
+ if (bb->out.size() != 1) continue; // more than one outgoing edge
+ BasicBlock *successor = bb->out.first();
+ if (successor->in.size() != 1) continue; // more than one incoming edge
+
+ // Ok, we can merge the two basic blocks.
+ if (DebugBlockMerging) {
+ qDebug("Merging L%d into L%d", successor->index(), bb->index());
+ }
+ Q_ASSERT(bb->terminator()->asJump());
+ bb->removeStatement(bb->statementCount() - 1); // remove the terminator, and replace it with:
+ for (Stmt *s : successor->statements()) {
+ bb->appendStatement(s); // add all statements from the successor to the current basic block
+ if (auto cjump = s->asCJump())
+ cjump->parent = bb;
+ }
+ bb->out = successor->out; // set the outgoing edges to the successor's so they're now in sync with our new terminator
+ for (auto newSuccessor : bb->out) {
+ for (auto &backlink : newSuccessor->in) {
+ if (backlink == successor) {
+ backlink = bb; // for all successors of our successor: set the incoming edges to come from bb, because we'll now jump there.
+ }
+ }
+ }
+ if (du) {
+ // all statements in successor have moved to bb, so make sure that the containing blocks
+ // stored in DefUses get updated (meaning: point to bb)
+ du->replaceBasicBlock(successor, bb);
+ }
+ if (dt) {
+ // update the immediate dominators to: any block that was dominated by the successor
+ // will now need to point to bb's immediate dominator. The reason is that bb itself
+ // won't be anyones immediate dominator, because it had just one outgoing edge.
+ dt->mergeIntoPredecessor(successor);
+ }
+ function->removeBasicBlock(successor);
+ --i; // re-run on the current basic-block, so any chain gets collapsed.
+ }
+
+ showMeTheCode(function, "After basic block merging");
+ verifyCFG(function);
+}
+
} // anonymous namespace
void LifeTimeInterval::setFrom(int from) {
@@ -5103,6 +5283,8 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA && statementCount <= 300) {
// qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
+ mergeBasicBlocks(function, nullptr, nullptr);
+
ConvertArgLocals(function).toTemps();
showMeTheCode(function, "After converting arguments to locals");
@@ -5178,6 +5360,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
}
verifyNoPointerSharing(function);
+ mergeBasicBlocks(function, &defUses, &df);
// Basic-block cycles that are unreachable (i.e. for loops in a then-part where the
// condition is calculated to be always false) are not yet removed. This will choke the
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri
index 30a44eedd1..74dcb250a8 100644
--- a/src/qml/debugger/debugger.pri
+++ b/src/qml/debugger/debugger.pri
@@ -1,21 +1,27 @@
-contains(QT_CONFIG, no-qml-debug):DEFINES += QT_NO_QML_DEBUGGER
+contains(QT_CONFIG, no-qml-debug) {
+ DEFINES += QT_NO_QML_DEBUGGER
+} else {
+ HEADERS += \
+ $$PWD/qqmldebugpluginmanager_p.h \
+ $$PWD/qqmldebugservicefactory_p.h
-SOURCES += \
- $$PWD/qqmldebug.cpp \
- $$PWD/qqmldebugconnector.cpp \
- $$PWD/qqmldebugservice.cpp \
- $$PWD/qqmldebugserviceinterfaces.cpp \
- $$PWD/qqmlabstractprofileradapter.cpp \
- $$PWD/qqmlprofiler.cpp
+ SOURCES += \
+ $$PWD/qqmldebug.cpp \
+ $$PWD/qqmldebugconnector.cpp \
+ $$PWD/qqmldebugservice.cpp \
+ $$PWD/qqmlabstractprofileradapter.cpp \
+ $$PWD/qqmlmemoryprofiler.cpp \
+ $$PWD/qqmlprofiler.cpp \
+ $$PWD/qqmldebugserviceinterfaces.cpp
+}
HEADERS += \
$$PWD/qqmldebugconnector_p.h \
- $$PWD/qqmldebugpluginmanager_p.h \
$$PWD/qqmldebugservice_p.h \
- $$PWD/qqmldebugservicefactory_p.h \
$$PWD/qqmldebugserviceinterfaces_p.h \
$$PWD/qqmldebugstatesdelegate_p.h \
$$PWD/qqmldebug.h \
+ $$PWD/qqmlmemoryprofiler_p.h \
$$PWD/qqmlprofilerdefinitions_p.h \
$$PWD/qqmlabstractprofileradapter_p.h \
$$PWD/qqmlprofiler_p.h
diff --git a/src/qml/debugger/qqmlabstractprofileradapter_p.h b/src/qml/debugger/qqmlabstractprofileradapter_p.h
index 1104608055..6a05a80f37 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter_p.h
+++ b/src/qml/debugger/qqmlabstractprofileradapter_p.h
@@ -59,6 +59,8 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QML_DEBUGGER
+
class QQmlProfilerService;
class Q_QML_PRIVATE_EXPORT QQmlAbstractProfilerAdapter : public QObject, public QQmlProfilerDefinitions {
Q_OBJECT
@@ -71,13 +73,13 @@ public:
virtual ~QQmlAbstractProfilerAdapter() {}
void setService(QQmlProfilerService *new_service) { service = new_service; }
- virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages) = 0;
+ virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages, bool trackLocations) = 0;
void startProfiling(quint64 features);
void stopProfiling();
- void reportData() { emit dataRequested(); }
+ void reportData(bool trackLocations) { emit dataRequested(trackLocations); }
void stopWaiting() { waiting = false; }
void startWaiting() { waiting = true; }
@@ -94,7 +96,7 @@ signals:
void profilingDisabled();
void profilingDisabledWhileWaiting();
- void dataRequested();
+ void dataRequested(bool trackLocations);
void referenceTimeKnown(const QElapsedTimer &timer);
protected:
@@ -114,6 +116,8 @@ public:
#define QQmlAbstractProfilerAdapterFactory_iid "org.qt-project.Qt.QQmlAbstractProfilerAdapterFactory"
+#endif // QT_NO_QML_DEBUGGER
+
QT_END_NAMESPACE
#endif // QQMLABSTRACTPROFILERADAPTER_P_H
diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp
index 9276bd0544..386fb60b3a 100644
--- a/src/qml/debugger/qqmldebug.cpp
+++ b/src/qml/debugger/qqmldebug.cpp
@@ -47,15 +47,11 @@ QT_BEGIN_NAMESPACE
QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
{
-#ifndef QQML_NO_DEBUG_PROTOCOL
if (!QQmlEnginePrivate::qml_debugging_enabled
&& printWarning) {
qDebug("QML debugging is enabled. Only use this in a safe environment.");
}
QQmlEnginePrivate::qml_debugging_enabled = true;
-#else
- Q_UNUSED(printWarning);
-#endif
}
/*!
@@ -105,11 +101,7 @@ QStringList QQmlDebuggingEnabler::profilerServices()
*/
void QQmlDebuggingEnabler::setServices(const QStringList &services)
{
-#ifndef QQML_NO_DEBUG_PROTOCOL
QQmlDebugConnector::setServices(services);
-#else
- Q_UNUSED(services);
-#endif
}
/*!
@@ -172,16 +164,9 @@ bool QQmlDebuggingEnabler::connectToLocalDebugger(const QString &socketFileName,
bool QQmlDebuggingEnabler::startDebugConnector(const QString &pluginName,
const QVariantHash &configuration)
{
-#ifndef QQML_NO_DEBUG_PROTOCOL
QQmlDebugConnector::setPluginKey(pluginName);
QQmlDebugConnector *connector = QQmlDebugConnector::instance();
- if (connector)
- return connector->open(configuration);
-#else
- Q_UNUSED(pluginName);
- Q_UNUSED(configuration);
-#endif
- return false;
+ return connector ? connector->open(configuration) : false;
}
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h
index 660b9e4d46..fb41039867 100644
--- a/src/qml/debugger/qqmldebug.h
+++ b/src/qml/debugger/qqmldebug.h
@@ -46,6 +46,7 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QML_DEBUGGER
struct Q_QML_EXPORT QQmlDebuggingEnabler
{
@@ -77,6 +78,8 @@ static QQmlDebuggingEnabler qQmlEnableDebuggingHelper(false);
static QQmlDebuggingEnabler qQmlEnableDebuggingHelper(true);
#endif
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUG_H
diff --git a/src/qml/debugger/qqmldebugconnector_p.h b/src/qml/debugger/qqmldebugconnector_p.h
index 05755250bd..0d3e2e2e47 100644
--- a/src/qml/debugger/qqmldebugconnector_p.h
+++ b/src/qml/debugger/qqmldebugconnector_p.h
@@ -59,6 +59,29 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugConnector
+{
+public:
+ static QQmlDebugConnector *instance() { return nullptr; }
+
+ template<class Service>
+ static Service *service() { return nullptr; }
+
+ bool hasEngine(QJSEngine *) const { return false; }
+ void addEngine(QJSEngine *) {}
+ void removeEngine(QJSEngine *) {}
+
+ bool open(const QVariantHash &configuration = QVariantHash())
+ {
+ Q_UNUSED(configuration);
+ return false;
+ }
+};
+
+#else
+
class QQmlDebugService;
class Q_QML_PRIVATE_EXPORT QQmlDebugConnector : public QObject
{
@@ -106,6 +129,8 @@ public:
#define QQmlDebugConnectorFactory_iid "org.qt-project.Qt.QQmlDebugConnectorFactory"
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUGCONNECTOR_H
diff --git a/src/qml/debugger/qqmldebugservice.cpp b/src/qml/debugger/qqmldebugservice.cpp
index b780735f48..b576c3bb85 100644
--- a/src/qml/debugger/qqmldebugservice.cpp
+++ b/src/qml/debugger/qqmldebugservice.cpp
@@ -132,7 +132,6 @@ public:
int nextId;
-private slots:
void remove(QObject *obj);
};
}
@@ -163,7 +162,7 @@ int QQmlDebugService::idForObject(QObject *object)
int id = hash->nextId++;
hash->ids.insert(id, object);
iter = hash->objects.insert(object, id);
- connect(object, SIGNAL(destroyed(QObject*)), hash, SLOT(remove(QObject*)));
+ connect(object, &QObject::destroyed, hash, &ObjectReferenceHash::remove);
}
return iter.value();
}
@@ -176,36 +175,6 @@ const QHash<int, QObject *> &QQmlDebugService::objectsForIds()
return objectReferenceHash()->ids;
}
-void QQmlDebugService::stateAboutToBeChanged(State)
-{
-}
-
-void QQmlDebugService::stateChanged(State)
-{
-}
-
-void QQmlDebugService::messageReceived(const QByteArray &)
-{
-}
-
-void QQmlDebugService::engineAboutToBeAdded(QJSEngine *engine)
-{
- emit attachedToEngine(engine);
-}
-
-void QQmlDebugService::engineAboutToBeRemoved(QJSEngine *engine)
-{
- emit detachedFromEngine(engine);
-}
-
-void QQmlDebugService::engineAdded(QJSEngine *)
-{
-}
-
-void QQmlDebugService::engineRemoved(QJSEngine *)
-{
-}
-
QT_END_NAMESPACE
#include "qqmldebugservice.moc"
diff --git a/src/qml/debugger/qqmldebugservice_p.h b/src/qml/debugger/qqmldebugservice_p.h
index 9ddc692ecc..42a57a39f2 100644
--- a/src/qml/debugger/qqmldebugservice_p.h
+++ b/src/qml/debugger/qqmldebugservice_p.h
@@ -58,6 +58,8 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QML_DEBUGGER
+
class QJSEngine;
class QQmlDebugServicePrivate;
@@ -65,7 +67,6 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugService : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlDebugService)
- Q_DISABLE_COPY(QQmlDebugService)
public:
~QQmlDebugService();
@@ -77,14 +78,15 @@ public:
State state() const;
void setState(State newState);
- virtual void stateAboutToBeChanged(State);
- virtual void stateChanged(State);
- virtual void messageReceived(const QByteArray &);
+ virtual void stateAboutToBeChanged(State) {}
+ virtual void stateChanged(State) {}
+ virtual void messageReceived(const QByteArray &) {}
+
+ virtual void engineAboutToBeAdded(QJSEngine *engine) { emit attachedToEngine(engine); }
+ virtual void engineAboutToBeRemoved(QJSEngine *engine) { emit detachedFromEngine(engine); }
- virtual void engineAboutToBeAdded(QJSEngine *);
- virtual void engineAboutToBeRemoved(QJSEngine *);
- virtual void engineAdded(QJSEngine *);
- virtual void engineRemoved(QJSEngine *);
+ virtual void engineAdded(QJSEngine *) {}
+ virtual void engineRemoved(QJSEngine *) {}
static const QHash<int, QObject *> &objectsForIds();
static int idForObject(QObject *);
@@ -101,6 +103,8 @@ signals:
void messagesToClient(const QString &name, const QList<QByteArray> &messages);
};
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUGSERVICE_H
diff --git a/src/qml/debugger/qqmldebugserviceinterfaces_p.h b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
index 8f66779872..ca6293c3ec 100644
--- a/src/qml/debugger/qqmldebugserviceinterfaces_p.h
+++ b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
@@ -62,7 +62,46 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QV4DebugService : protected QQmlDebugService
+class QWindow;
+class QQuickWindow;
+
+#ifdef QT_NO_QML_DEBUGGER
+
+struct QV4DebugService
+{
+ void signalEmitted(const QString &) {}
+};
+
+struct QQmlProfilerService
+{
+ void startProfiling(QJSEngine *engine, quint64 features = std::numeric_limits<quint64>::max())
+ {
+ Q_UNUSED(engine);
+ Q_UNUSED(features);
+ }
+
+ void stopProfiling(QJSEngine *) {}
+};
+
+struct QQmlEngineDebugService
+{
+ void objectCreated(QJSEngine *, QObject *) {}
+ virtual void setStatesDelegate(QQmlDebugStatesDelegate *) {}
+};
+
+struct QQmlInspectorService {
+ void addWindow(QQuickWindow *) {}
+ void setParentWindow(QQuickWindow *, QWindow *) {}
+ void removeWindow(QQuickWindow *) {}
+};
+
+struct QDebugMessageService {};
+struct QQmlEngineControlService {};
+struct QQmlNativeDebugService {};
+
+#else
+
+class Q_QML_PRIVATE_EXPORT QV4DebugService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -77,7 +116,7 @@ protected:
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QQmlProfilerService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlProfilerService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -99,7 +138,7 @@ protected:
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QQmlEngineDebugService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlEngineDebugService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -117,9 +156,7 @@ protected:
QQmlBoundSignal *nextSignal(QQmlBoundSignal *prev) { return prev->m_nextSignal; }
};
-class QWindow;
-class QQuickWindow;
-class Q_QML_PRIVATE_EXPORT QQmlInspectorService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlInspectorService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -136,7 +173,7 @@ protected:
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QDebugMessageService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QDebugMessageService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -151,7 +188,7 @@ protected:
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QQmlEngineControlService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlEngineControlService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -165,7 +202,7 @@ protected:
};
-class Q_QML_PRIVATE_EXPORT QQmlNativeDebugService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlNativeDebugService : public QQmlDebugService
{
Q_OBJECT
@@ -178,6 +215,8 @@ protected:
static const QString s_key;
};
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUGSERVICEINTERFACES_P_H
diff --git a/src/qml/debugger/qqmldebugstatesdelegate_p.h b/src/qml/debugger/qqmldebugstatesdelegate_p.h
index 42c4e94b50..95f727fb2d 100644
--- a/src/qml/debugger/qqmldebugstatesdelegate_p.h
+++ b/src/qml/debugger/qqmldebugstatesdelegate_p.h
@@ -57,6 +57,11 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+class QQmlDebugStatesDelegate {};
+
+#else
class QQmlContext;
class QQmlProperty;
@@ -90,6 +95,8 @@ private:
Q_DISABLE_COPY(QQmlDebugStatesDelegate)
};
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUGSTATESDELEGATE_P_H
diff --git a/src/qml/qml/qqmlmemoryprofiler.cpp b/src/qml/debugger/qqmlmemoryprofiler.cpp
index d9e121bb1b..60f6d96eaf 100644
--- a/src/qml/qml/qqmlmemoryprofiler.cpp
+++ b/src/qml/debugger/qqmlmemoryprofiler.cpp
@@ -97,12 +97,9 @@ static bool openLibrary()
return state == Loaded;
}
-QQmlMemoryScope::QQmlMemoryScope(const QUrl &url) : pushed(false)
+QQmlMemoryScope::QQmlMemoryScope(const QUrl &url)
+ : QQmlMemoryScope(url.path().toUtf8().constData())
{
- if (openLibrary() && memprofile_is_enabled()) {
- memprofile_push_location(url.path().toUtf8().constData(), 0);
- pushed = true;
- }
}
QQmlMemoryScope::QQmlMemoryScope(const char *string) : pushed(false)
diff --git a/src/qml/qml/qqmlmemoryprofiler_p.h b/src/qml/debugger/qqmlmemoryprofiler_p.h
index 4b0ba823ba..59f08704ca 100644
--- a/src/qml/qml/qqmlmemoryprofiler_p.h
+++ b/src/qml/debugger/qqmlmemoryprofiler_p.h
@@ -55,6 +55,13 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+#define QML_MEMORY_SCOPE_URL(url)
+#define QML_MEMORY_SCOPE_STRING(s)
+
+#else
+
class QUrl;
class Q_QML_PRIVATE_EXPORT QQmlMemoryScope
@@ -83,5 +90,7 @@ public:
#define QML_MEMORY_SCOPE_URL(url) QQmlMemoryScope _qml_memory_scope(url)
#define QML_MEMORY_SCOPE_STRING(s) QQmlMemoryScope _qml_memory_scope(s)
+#endif
+
QT_END_NAMESPACE
#endif // QQMLMEMORYPROFILER_H
diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp
index 629d5cb7b8..ffba731b13 100644
--- a/src/qml/debugger/qqmlprofiler.cpp
+++ b/src/qml/debugger/qqmlprofiler.cpp
@@ -59,19 +59,21 @@ void QQmlProfiler::startProfiling(quint64 features)
void QQmlProfiler::stopProfiling()
{
featuresEnabled = false;
- reportData();
+ reportData(true);
+ m_locations.clear();
}
-void QQmlProfiler::reportData()
+void QQmlProfiler::reportData(bool trackLocations)
{
LocationHash resolved;
resolved.reserve(m_locations.size());
- for (auto it = m_locations.constBegin(), end = m_locations.constEnd(); it != end; ++it)
- resolved.insert(it.key(), it.value());
-
- // This unrefs all the objects. We have to make sure we do this in the GUI thread. Also, it's
- // a good idea to release the memory before creating the packets to be sent.
- m_locations.clear();
+ for (auto it = m_locations.begin(), end = m_locations.end(); it != end; ++it) {
+ if (!trackLocations || !it->sent) {
+ resolved.insert(it.key(), it.value());
+ if (trackLocations)
+ it->sent = true;
+ }
+ }
QVector<QQmlProfilerData> data;
data.swap(m_data);
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 1380599fb7..6643695d11 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -55,7 +55,6 @@
#include <private/qqmlboundsignal_p.h>
#include <private/qfinitestack_p.h>
#include <private/qqmlbinding_p.h>
-#include <private/qqmlcompiler_p.h>
#include "qqmlprofilerdefinitions_p.h"
#include "qqmlabstractprofileradapter_p.h"
@@ -64,6 +63,54 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+#define Q_QML_PROFILE_IF_ENABLED(feature, profiler, Code)
+#define Q_QML_PROFILE(feature, profiler, Method)
+#define Q_QML_OC_PROFILE(member, Code)
+
+struct QQmlProfiler {};
+
+struct QQmlBindingProfiler
+{
+ QQmlBindingProfiler(quintptr, QQmlBinding *, QV4::FunctionObject *) {}
+};
+
+struct QQmlHandlingSignalProfiler
+{
+ QQmlHandlingSignalProfiler(quintptr, QQmlBoundSignalExpression *) {}
+};
+
+struct QQmlCompilingProfiler
+{
+ QQmlCompilingProfiler(quintptr, QQmlDataBlob *) {}
+};
+
+struct QQmlVmeProfiler {
+ QQmlVmeProfiler() {}
+
+ void init(quintptr, int) {}
+
+ const QV4::CompiledData::Object *pop() { return nullptr; }
+ void push(const QV4::CompiledData::Object *) {}
+
+ static const quintptr profiler = 0;
+};
+
+struct QQmlObjectCreationProfiler
+{
+ QQmlObjectCreationProfiler(quintptr, const QV4::CompiledData::Object *) {}
+ void update(QV4::CompiledData::CompilationUnit *, const QV4::CompiledData::Object *,
+ const QString &, const QUrl &) {}
+};
+
+struct QQmlObjectCompletionProfiler
+{
+ QQmlObjectCompletionProfiler(QQmlVmeProfiler *) {}
+};
+
+#else
+
#define Q_QML_PROFILE_IF_ENABLED(feature, profiler, Code)\
if (profiler && (profiler->featuresEnabled & (1 << feature))) {\
Code;\
@@ -73,6 +120,9 @@ QT_BEGIN_NAMESPACE
#define Q_QML_PROFILE(feature, profiler, Method)\
Q_QML_PROFILE_IF_ENABLED(feature, profiler, profiler->Method)
+#define Q_QML_OC_PROFILE(member, Code)\
+ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, member.profiler, Code)
+
// This struct is somewhat dangerous to use:
// The messageType is a bit field. You can pack multiple messages into
// one object, e.g. RangeStart and RangeLocation. Each one will be read
@@ -95,7 +145,7 @@ struct Q_AUTOTEST_EXPORT QQmlProfilerData : public QQmlProfilerDefinitions
Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE);
-class QQmlProfiler : public QObject, public QQmlProfilerDefinitions {
+class Q_QML_PRIVATE_EXPORT QQmlProfiler : public QObject, public QQmlProfilerDefinitions {
Q_OBJECT
public:
@@ -146,26 +196,27 @@ public:
// Unfortunately we have to resolve the locations right away because the QML context might not
// be available anymore when we send the data.
struct RefLocation : public Location {
- RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr)
+ RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr), sent(false)
{}
RefLocation(QQmlBinding *binding, QV4::FunctionObject *function) :
Location(function->sourceLocation()), locationType(Binding),
- ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt)
+ ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt), sent(false)
{}
- RefLocation(QQmlCompiledData *ref, const QUrl &url, const QV4::CompiledData::Object *obj,
+ RefLocation(QV4::CompiledData::CompilationUnit *ref, const QUrl &url, const QV4::CompiledData::Object *obj,
const QString &type) :
Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url),
- locationType(Creating), ref(ref)
+ locationType(Creating), ref(ref), sent(false)
{}
RefLocation(QQmlBoundSignalExpression *ref) :
- Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref)
+ Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref), sent(false)
{}
RefLocation(QQmlDataBlob *ref) :
- Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref)
+ Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref),
+ sent(false)
{}
bool isValid() const
@@ -175,6 +226,7 @@ public:
RangeType locationType;
QQmlRefPointer<QQmlRefCount> ref;
+ bool sent;
};
typedef QHash<quintptr, Location> LocationHash;
@@ -217,11 +269,6 @@ public:
location = RefLocation(expression);
}
- void startCreating()
- {
- m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, Creating));
- }
-
void startCreating(const QV4::CompiledData::Object *obj)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
@@ -229,14 +276,10 @@ public:
Creating, id(obj)));
}
- void updateCreating(const QV4::CompiledData::Object *obj, QQmlCompiledData *ref,
+ void updateCreating(const QV4::CompiledData::Object *obj, QV4::CompiledData::CompilationUnit *ref,
const QUrl &url, const QString &type)
{
quintptr locationId(id(obj));
- m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
- (1 << RangeLocation | 1 << RangeData),
- Creating, locationId));
-
RefLocation &location = m_locations[locationId];
if (!location.isValid())
location = RefLocation(ref, url, obj, type);
@@ -258,10 +301,9 @@ public:
return reinterpret_cast<quintptr>(pointer);
}
-public slots:
void startProfiling(quint64 features);
void stopProfiling();
- void reportData();
+ void reportData(bool trackLocations);
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
@@ -357,15 +399,13 @@ private:
QFiniteStack<const QV4::CompiledData::Object *> ranges;
};
-#define Q_QML_OC_PROFILE(member, Code)\
- Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, member.profiler, Code)
-
class QQmlObjectCreationProfiler {
public:
- QQmlObjectCreationProfiler(QQmlProfiler *profiler) : profiler(profiler)
+ QQmlObjectCreationProfiler(QQmlProfiler *profiler, const QV4::CompiledData::Object *obj)
+ : profiler(profiler)
{
- Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, startCreating());
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, startCreating(obj));
}
~QQmlObjectCreationProfiler()
@@ -373,7 +413,7 @@ public:
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, endRange<QQmlProfilerDefinitions::Creating>());
}
- void update(QQmlCompiledData *ref, const QV4::CompiledData::Object *obj,
+ void update(QV4::CompiledData::CompilationUnit *ref, const QV4::CompiledData::Object *obj,
const QString &typeName, const QUrl &url)
{
profiler->updateCreating(obj, ref, url, typeName);
@@ -406,4 +446,6 @@ QT_END_NAMESPACE
Q_DECLARE_METATYPE(QVector<QQmlProfilerData>)
Q_DECLARE_METATYPE(QQmlProfiler::LocationHash)
+#endif // QT_NO_QML_DEBUGGER
+
#endif // QQMLPROFILER_P_H
diff --git a/src/qml/debugger/qqmlprofilerdefinitions_p.h b/src/qml/debugger/qqmlprofilerdefinitions_p.h
index 2b2eda22e1..c6ae4593a9 100644
--- a/src/qml/debugger/qqmlprofilerdefinitions_p.h
+++ b/src/qml/debugger/qqmlprofilerdefinitions_p.h
@@ -56,6 +56,8 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QML_DEBUGGER
+
struct QQmlProfilerDefinitions {
enum Message {
Event,
@@ -161,6 +163,8 @@ struct QQmlProfilerDefinitions {
};
};
+#endif // QT_NO_QML_DEBUGGER
+
QT_END_NAMESPACE
#endif
diff --git a/src/qml/doc/snippets/qml/qtLater.qml b/src/qml/doc/snippets/qml/qtLater.qml
new file mode 100644
index 0000000000..e2bc02edb4
--- /dev/null
+++ b/src/qml/doc/snippets/qml/qtLater.qml
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+
+Rectangle {
+ width: 480
+ height: 320
+
+ property int callsToUpdateMinimumWidth: 0
+ property bool optimize: true
+
+ property int currentTextModel: 0
+ property var columnTexts: [
+ ["Click on either", "rectangle above", "and note how the counter", "below updates", "significantly faster using the", "regular (non-optimized)", "implementation"],
+ ["The width", "of this column", "is", "no wider than the", "widest item"],
+ ["Note how using Qt.callLater()", "the minimum width is", "calculated a bare-minimum", "number", "of times"]
+ ]
+
+ Text {
+ x: 20; y: 280
+ text: "Times minimum width has been calculated: " + callsToUpdateMinimumWidth
+ }
+
+ Row {
+ y: 25; spacing: 30; anchors.horizontalCenter: parent.horizontalCenter
+ Rectangle {
+ width: 200; height: 50; color: "lightgreen"
+ Text { text: "Optimized behavior\nusing Qt.callLater()"; anchors.centerIn: parent }
+ MouseArea { anchors.fill: parent; onClicked: { optimize = true; currentTextModel++ } }
+ }
+ Rectangle {
+ width: 200; height: 50; color: "lightblue"
+ Text { text: "Regular behavior"; anchors.centerIn: parent}
+ MouseArea { anchors.fill: parent; onClicked: { optimize = false; currentTextModel++ } }
+ }
+ }
+
+ Column {
+ id: column
+ anchors.centerIn: parent
+
+ onChildrenChanged: optimize ? Qt.callLater(updateMinimumWidth) : updateMinimumWidth()
+
+ property int widestChild
+ function updateMinimumWidth() {
+ callsToUpdateMinimumWidth++
+ var w = 0;
+ for (var i in children) {
+ var child = children[i];
+ if (child.implicitWidth > w) {
+ w = child.implicitWidth;
+ }
+ }
+
+ widestChild = w;
+ }
+
+ Repeater {
+ id: repeater
+ model: columnTexts[currentTextModel%3]
+ delegate: Text {
+ color: "white"
+ text: modelData
+ width: column.widestChild
+ horizontalAlignment: Text.Center
+ Rectangle { anchors.fill: parent; z: -1; color: index%2 ? "gray" : "darkgray" }
+ }
+ }
+ }
+}
+//![0]
diff --git a/src/qml/doc/src/javascript/functionlist.qdoc b/src/qml/doc/src/javascript/functionlist.qdoc
index 7f0e844b65..b9a25a2440 100644
--- a/src/qml/doc/src/javascript/functionlist.qdoc
+++ b/src/qml/doc/src/javascript/functionlist.qdoc
@@ -174,6 +174,8 @@
\li charAt(pos)
\li charCodeAt(pos)
\li concat([string1 [, string2 [, ...]]])
+ \li endsWith(searchString [, endPosition ]) // ECMAScript 6: Added in Qt 5.8
+ \li includes(searchString [, position ]) // ECMAScript 6: Added in 5.8
\li indexOf(searchString ,position)
\li lastIndexOf(searchString, position)
\li localeCompare(that)
@@ -182,6 +184,7 @@
\li search(regexp)
\li slice(start, end)
\li split(separator, limit)
+ \li startsWith(searchString [, position ]) // ECMAScript 6: Added in Qt 5.8
\li substring(start, end)
\li toLowerCase()
\li toLocaleLowerCase()
@@ -228,6 +231,26 @@
\li \l {Number::toLocaleString}{toLocaleString(locale, format, precision)}
\endlist
+ \section2 The Number Object
+
+ \section3 Value Properties
+
+ \list
+ \li NaN
+ \li NEGATIVE_INFINITY
+ \li POSITIVE_INFINITY
+ \li MAX_VALUE
+ \li MIN_VALUE
+ \li EPSILON // ECMAScript 6: Added in Qt 5.8
+ \endlist
+
+ \section3 Function Properties
+
+ \list
+ \li isFinite(x) // ECMAScript 6: Added in Qt 5.8
+ \li isNaN(x) // ECMAScript 6: Added in Qt 5.8
+ \endlist
+
\section1 The Math Object
\section2 Value Properties
@@ -261,6 +284,7 @@
\li pow(x, y)
\li random()
\li round(x)
+ \li sign(x) // ECMAScript 6: Added in Qt 5.8
\li sin(x)
\li sqrt(x)
\li tan(x)
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 3da1aaa010..08e4f0a8c0 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -79,14 +79,70 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
}
}
-QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int functionIndex)
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
{
- if (functionIndex < 0 || functionIndex >= codeRefs.count())
- return 0;
- JSC::ExecutableMemoryHandle *handle = codeRefs[functionIndex].executableMemory();
- if (!handle)
- return 0;
- return handle->chunk();
+ const int codeAlignment = 16;
+ quint64 offset = WTF::roundUpToMultipleOf(codeAlignment, unit->unitSize);
+ Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
+ for (int i = 0; i < codeRefs.size(); ++i) {
+ CompiledData::Function *compiledFunction = const_cast<CompiledData::Function *>(unit->functionAt(i));
+ compiledFunction->codeOffset = offset;
+ compiledFunction->codeSize = codeRefs.at(i).size();
+ offset = WTF::roundUpToMultipleOf(codeAlignment, offset + compiledFunction->codeSize);
+ }
+}
+
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString)
+{
+ Q_ASSERT(device->pos() == unit->unitSize);
+ Q_ASSERT(device->atEnd());
+ Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
+
+ QByteArray padding;
+
+ for (int i = 0; i < codeRefs.size(); ++i) {
+ const CompiledData::Function *compiledFunction = unit->functionAt(i);
+
+ if (device->pos() > qint64(compiledFunction->codeOffset)) {
+ *errorString = QStringLiteral("Invalid state of cache file to write.");
+ return false;
+ }
+
+ const quint64 paddingSize = compiledFunction->codeOffset - device->pos();
+ padding.fill(0, paddingSize);
+ qint64 written = device->write(padding);
+ if (written != padding.size()) {
+ *errorString = device->errorString();
+ return false;
+ }
+
+ const void *undecoratedCodePtr = codeRefs.at(i).code().dataLocation();
+ written = device->write(reinterpret_cast<const char *>(undecoratedCodePtr), compiledFunction->codeSize);
+ if (written != qint64(compiledFunction->codeSize)) {
+ *errorString = device->errorString();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ Q_ASSERT(codeRefs.isEmpty());
+ codeRefs.reserve(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
+ JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
+ JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
+ codeRefs.append(codeRef);
+ }
+
+ return true;
}
const Assembler::VoidType Assembler::Void;
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index a5028bc683..669b0b2ff4 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -63,6 +63,8 @@
#include <config.h>
#include <wtf/Vector.h>
+#include <climits>
+
#if ENABLE(ASSEMBLER)
#include <assembler/MacroAssembler.h>
@@ -73,20 +75,16 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-#define OP(op) \
- { isel_stringIfy(op), op, 0, 0, 0 }
-#define OPCONTEXT(op) \
- { isel_stringIfy(op), 0, op, 0, 0 }
-
class InstructionSelection;
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
- virtual void linkBackendToEngine(QV4::ExecutionEngine *engine);
-
- virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int functionIndex);
+ void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
+ bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString);
// Coderef + execution engine
@@ -94,14 +92,6 @@ struct CompilationUnit : public QV4::CompiledData::CompilationUnit
QList<QVector<QV4::Primitive> > constantValues;
};
-struct RelativeCall {
- JSC::MacroAssembler::Address addr;
-
- explicit RelativeCall(const JSC::MacroAssembler::Address &addr)
- : addr(addr)
- {}
-};
-
struct LookupCall {
JSC::MacroAssembler::Address addr;
uint getterSetterOffset;
@@ -112,6 +102,13 @@ struct LookupCall {
{}
};
+struct RuntimeCall {
+ JSC::MacroAssembler::Address addr;
+
+ inline RuntimeCall(uint offset = uint(INT_MIN));
+ bool isValid() const { return addr.offset >= 0; }
+};
+
template <typename T>
struct ExceptionCheck {
enum { NeedsCheck = 1 };
@@ -321,12 +318,12 @@ public:
typedef JSC::FunctionPtr FunctionPtr;
- struct CallToLink {
- Call call;
- FunctionPtr externalFunction;
+#ifndef QT_NO_DEBUG
+ struct CallInfo {
Label label;
const char* functionName;
};
+#endif
struct PointerToValue {
PointerToValue(IR::Expr *value)
: value(value)
@@ -344,32 +341,23 @@ public:
IR::Expr *value;
};
- struct ReentryBlock {
- ReentryBlock(IR::BasicBlock *b) : block(b) {}
- IR::BasicBlock *block;
- };
-
- void callAbsolute(const char* functionName, FunctionPtr function) {
- CallToLink ctl;
- ctl.call = call();
- ctl.externalFunction = function;
- ctl.functionName = functionName;
- ctl.label = label();
- _callsToLink.append(ctl);
- }
-
- void callAbsolute(const char* /*functionName*/, Address addr) {
- call(addr);
- }
-
- void callAbsolute(const char* /*functionName*/, const RelativeCall &relativeCall)
+ void callAbsolute(const char* /*functionName*/, const LookupCall &lookupCall)
{
- call(relativeCall.addr);
+ call(lookupCall.addr);
}
- void callAbsolute(const char* /*functionName*/, const LookupCall &lookupCall)
+ void callAbsolute(const char *functionName, const RuntimeCall &runtimeCall)
{
- call(lookupCall.addr);
+ call(runtimeCall.addr);
+#ifndef QT_NO_DEBUG
+ // the code below is to get proper function names in the disassembly
+ CallInfo info;
+ info.functionName = functionName;
+ info.label = label();
+ _callInfos.append(info);
+#else
+ Q_UNUSED(functionName)
+#endif
}
void registerBlock(IR::BasicBlock*, IR::BasicBlock *nextBlock);
@@ -441,13 +429,6 @@ public:
move(source, dest);
}
- void loadArgumentInRegister(TrustedImmPtr ptr, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- move(TrustedImmPtr(ptr), dest);
- }
-
void loadArgumentInRegister(const Pointer& ptr, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
@@ -457,7 +438,7 @@ public:
void loadArgumentInRegister(PointerToValue temp, RegisterID dest, int argumentNumber)
{
if (!temp.value) {
- loadArgumentInRegister(TrustedImmPtr(0), dest, argumentNumber);
+ move(TrustedImmPtr(0), dest);
} else {
Pointer addr = toAddress(dest, temp.value, argumentNumber);
loadArgumentInRegister(addr, dest, argumentNumber);
@@ -476,15 +457,6 @@ public:
loadArgumentInRegister(addr, dest, argumentNumber);
}
- void loadArgumentInRegister(ReentryBlock block, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- Q_ASSERT(block.block);
- DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), dest);
- addPatch(patch, block.block);
- }
-
#ifdef VALUE_FITS_IN_REGISTER
void loadArgumentInRegister(IR::Temp* temp, RegisterID dest, int argumentNumber)
{
@@ -544,11 +516,6 @@ public:
}
#endif
- void loadArgumentInRegister(QV4::String* string, RegisterID dest, int argumentNumber)
- {
- loadArgumentInRegister(TrustedImmPtr(string), dest, argumentNumber);
- }
-
void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
@@ -705,34 +672,6 @@ public:
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
}
- template <int StackSlot>
- void loadArgumentOnStack(ReentryBlock block, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- Q_ASSERT(block.block);
- DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), ScratchRegister);
- poke(ScratchRegister, StackSlot);
- addPatch(patch, block.block);
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(TrustedImmPtr ptr, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- move(TrustedImmPtr(ptr), ScratchRegister);
- poke(ScratchRegister, StackSlot);
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(QV4::String* name, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- poke(TrustedImmPtr(name), StackSlot);
- }
-
void loadDouble(IR::Expr *source, FPRegisterID dest)
{
IR::Temp *sourceTemp = source->asTemp();
@@ -1154,9 +1093,8 @@ public:
// it's not in signed int range, so load it as a double, and truncate it down
loadDouble(addr, FPGpr0);
- static const double magic = double(INT_MAX) + 1;
- move(TrustedImmPtr(&magic), scratchReg);
- subDouble(Address(scratchReg, 0), FPGpr0);
+ Address inversionAddress = constantTable().loadValueAddress(QV4::Primitive::fromDouble(double(INT_MAX) + 1), scratchReg);
+ subDouble(inversionAddress, FPGpr0);
Jump canNeverHappen = branchTruncateDoubleToUint32(FPGpr0, scratchReg);
canNeverHappen.link(this);
or32(TrustedImm32(1 << 31), scratchReg);
@@ -1184,7 +1122,9 @@ private:
IR::Function *_function;
QHash<IR::BasicBlock *, Label> _addrs;
QHash<IR::BasicBlock *, QVector<Jump> > _patches;
- QList<CallToLink> _callsToLink;
+#ifndef QT_NO_DEBUG
+ QVector<CallInfo> _callInfos;
+#endif
struct DataLabelPatch {
DataLabelPtr dataLabel;
@@ -1245,24 +1185,21 @@ void Assembler::copyValue(Result result, IR::Expr* source)
}
}
+inline RuntimeCall::RuntimeCall(uint offset)
+ : addr(Assembler::EngineRegister, offset + qOffsetOf(QV4::ExecutionEngine, runtime))
+{
+}
+
template <typename T> inline bool prepareCall(T &, Assembler *)
{ return true; }
-template <> inline bool prepareCall(RelativeCall &relativeCall, Assembler *as)
-{
- as->loadPtr(Assembler::Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- as->loadPtr(Assembler::Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)),
- relativeCall.addr.base);
- return true;
-}
-
template <> inline bool prepareCall(LookupCall &lookupCall, Assembler *as)
{
// IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details!
- // same as prepareCall(RelativeCall ....) : load the table from the context
+ // load the table from the context
as->loadPtr(Assembler::Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
as->loadPtr(Assembler::Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)),
lookupCall.addr.base);
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index 50b6cec975..c09fc6fdca 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -45,14 +45,14 @@ using namespace QV4;
using namespace JIT;
#define OP(op) \
- { isel_stringIfy(op), op, 0, 0, 0 }
+ { "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, 0, 0 }
#define OPCONTEXT(op) \
- { isel_stringIfy(op), 0, op, 0, 0 }
+ { "Runtime::" isel_stringIfy(op), INT_MIN, offsetof(QV4::Runtime, op), 0, 0 }
#define INLINE_OP(op, memOp, immOp) \
- { isel_stringIfy(op), op, 0, memOp, immOp }
+ { "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, memOp, immOp }
#define INLINE_OPCONTEXT(op, memOp, immOp) \
- { isel_stringIfy(op), 0, op, memOp, immOp }
+ { "Runtime::" isel_stringIfy(op), INT_MIN, offsetof(QV4::Runtime, op), memOp, immOp }
#define NULL_OP \
{ 0, 0, 0, 0, 0 }
@@ -67,32 +67,32 @@ const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
NULL_OP, // OpIncrement
NULL_OP, // OpDecrement
- INLINE_OP(Runtime::bitAnd, &Binop::inline_and32, &Binop::inline_and32), // OpBitAnd
- INLINE_OP(Runtime::bitOr, &Binop::inline_or32, &Binop::inline_or32), // OpBitOr
- INLINE_OP(Runtime::bitXor, &Binop::inline_xor32, &Binop::inline_xor32), // OpBitXor
+ INLINE_OP(bitAnd, &Binop::inline_and32, &Binop::inline_and32), // OpBitAnd
+ INLINE_OP(bitOr, &Binop::inline_or32, &Binop::inline_or32), // OpBitOr
+ INLINE_OP(bitXor, &Binop::inline_xor32, &Binop::inline_xor32), // OpBitXor
- INLINE_OPCONTEXT(Runtime::add, &Binop::inline_add32, &Binop::inline_add32), // OpAdd
- INLINE_OP(Runtime::sub, &Binop::inline_sub32, &Binop::inline_sub32), // OpSub
- INLINE_OP(Runtime::mul, &Binop::inline_mul32, &Binop::inline_mul32), // OpMul
+ INLINE_OPCONTEXT(add, &Binop::inline_add32, &Binop::inline_add32), // OpAdd
+ INLINE_OP(sub, &Binop::inline_sub32, &Binop::inline_sub32), // OpSub
+ INLINE_OP(mul, &Binop::inline_mul32, &Binop::inline_mul32), // OpMul
- OP(Runtime::div), // OpDiv
- OP(Runtime::mod), // OpMod
+ OP(div), // OpDiv
+ OP(mod), // OpMod
- INLINE_OP(Runtime::shl, &Binop::inline_shl32, &Binop::inline_shl32), // OpLShift
- INLINE_OP(Runtime::shr, &Binop::inline_shr32, &Binop::inline_shr32), // OpRShift
- INLINE_OP(Runtime::ushr, &Binop::inline_ushr32, &Binop::inline_ushr32), // OpURShift
+ INLINE_OP(shl, &Binop::inline_shl32, &Binop::inline_shl32), // OpLShift
+ INLINE_OP(shr, &Binop::inline_shr32, &Binop::inline_shr32), // OpRShift
+ INLINE_OP(ushr, &Binop::inline_ushr32, &Binop::inline_ushr32), // OpURShift
- OP(Runtime::greaterThan), // OpGt
- OP(Runtime::lessThan), // OpLt
- OP(Runtime::greaterEqual), // OpGe
- OP(Runtime::lessEqual), // OpLe
- OP(Runtime::equal), // OpEqual
- OP(Runtime::notEqual), // OpNotEqual
- OP(Runtime::strictEqual), // OpStrictEqual
- OP(Runtime::strictNotEqual), // OpStrictNotEqual
+ OP(greaterThan), // OpGt
+ OP(lessThan), // OpLt
+ OP(greaterEqual), // OpGe
+ OP(lessEqual), // OpLe
+ OP(equal), // OpEqual
+ OP(notEqual), // OpNotEqual
+ OP(strictEqual), // OpStrictEqual
+ OP(strictNotEqual), // OpStrictNotEqual
- OPCONTEXT(Runtime::instanceof), // OpInstanceof
- OPCONTEXT(Runtime::in), // OpIn
+ OPCONTEXT(instanceof), // OpInstanceof
+ OPCONTEXT(in), // OpIn
NULL_OP, // OpAnd
NULL_OP // OpOr
@@ -121,16 +121,18 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
if (op == IR::OpAdd &&
(lhs->type == IR::StringType || rhs->type == IR::StringType)) {
- const Binop::OpInfo stringAdd = OPCONTEXT(Runtime::addString);
+ const Binop::OpInfo stringAdd = OPCONTEXT(addString);
info = stringAdd;
}
- if (info.fallbackImplementation) {
- as->generateFunctionCallImp(target, info.name, info.fallbackImplementation,
+ RuntimeCall fallBack(info.fallbackImplementation);
+ RuntimeCall context(info.contextImplementation);
+ if (fallBack.isValid()) {
+ as->generateFunctionCallImp(target, info.name, fallBack,
Assembler::PointerToValue(lhs),
Assembler::PointerToValue(rhs));
- } else if (info.contextImplementation) {
- as->generateFunctionCallImp(target, info.name, info.contextImplementation,
+ } else if (context.isValid()) {
+ as->generateFunctionCallImp(target, info.name, context,
Assembler::EngineRegister,
Assembler::PointerToValue(lhs),
Assembler::PointerToValue(rhs));
diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h
index 791e335970..c246ee43b0 100644
--- a/src/qml/jit/qv4binop_p.h
+++ b/src/qml/jit/qv4binop_p.h
@@ -77,8 +77,8 @@ struct Binop {
struct OpInfo {
const char *name;
- QV4::Runtime::BinaryOperation fallbackImplementation;
- QV4::Runtime::BinaryOperationContext contextImplementation;
+ int fallbackImplementation; // offsetOf(Runtime,...)
+ int contextImplementation; // offsetOf(Runtime,...)
MemRegOp inlineMemRegOp;
ImmRegOp inlineImmRegOp;
};
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index bf658fe689..4066ab213c 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -159,12 +159,6 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
JSC::JSGlobalData dummy(_executableAllocator);
JSC::LinkBuffer linkBuffer(dummy, this, 0);
- QHash<void*, const char*> functions;
- foreach (CallToLink ctl, _callsToLink) {
- linkBuffer.link(ctl.call, ctl.externalFunction);
- functions[linkBuffer.locationOf(ctl.label).dataLocation()] = ctl.functionName;
- }
-
foreach (const DataLabelPatch &p, _dataLabelPatches)
linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
@@ -193,6 +187,12 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM");
if (showCode) {
+ QHash<void*, const char*> functions;
+#ifndef QT_NO_DEBUG
+ foreach (CallInfo call, _callInfos)
+ functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName;
+#endif
+
QBuffer buf;
buf.open(QIODevice::WriteOnly);
WTF::setDataFile(new QIODevicePrintStream(&buf));
@@ -258,8 +258,8 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
return codeRef;
}
-InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator)
- : EvalInstructionSelection(execAllocator, module, jsGenerator)
+InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
+ : EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory)
, _block(0)
, _as(0)
, compilationUnit(new CompilationUnit)
@@ -353,7 +353,7 @@ void InstructionSelection::run(int functionIndex)
lastLine = s->location.startLine;
}
}
- s->accept(this);
+ visit(s);
}
}
@@ -393,12 +393,12 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
- generateFunctionCall(result, Runtime::callGlobalLookup,
+ generateRuntimeCall(result, callGlobalLookup,
Assembler::EngineRegister,
Assembler::TrustedImm32(index),
baseAddressForCallData());
} else {
- generateFunctionCall(result, Runtime::callActivationProperty,
+ generateRuntimeCall(result, callActivationProperty,
Assembler::EngineRegister,
Assembler::StringToIndex(*func->id),
baseAddressForCallData());
@@ -410,11 +410,11 @@ void InstructionSelection::callBuiltinTypeofQmlContextProperty(IR::Expr *base,
int propertyIndex, IR::Expr *result)
{
if (kind == IR::Member::MemberOfQmlScopeObject) {
- generateFunctionCall(result, Runtime::typeofScopeObjectProperty, Assembler::EngineRegister,
+ generateRuntimeCall(result, typeofScopeObjectProperty, Assembler::EngineRegister,
Assembler::PointerToValue(base),
Assembler::TrustedImm32(propertyIndex));
} else if (kind == IR::Member::MemberOfQmlContextObject) {
- generateFunctionCall(result, Runtime::typeofContextObjectProperty,
+ generateRuntimeCall(result, typeofContextObjectProperty,
Assembler::EngineRegister, Assembler::PointerToValue(base),
Assembler::TrustedImm32(propertyIndex));
} else {
@@ -425,46 +425,46 @@ void InstructionSelection::callBuiltinTypeofQmlContextProperty(IR::Expr *base,
void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
IR::Expr *result)
{
- generateFunctionCall(result, Runtime::typeofMember, Assembler::EngineRegister,
+ generateRuntimeCall(result, typeofMember, Assembler::EngineRegister,
Assembler::PointerToValue(base), Assembler::StringToIndex(name));
}
void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
IR::Expr *result)
{
- generateFunctionCall(result, Runtime::typeofElement,
+ generateRuntimeCall(result, typeofElement,
Assembler::EngineRegister,
Assembler::PointerToValue(base), Assembler::PointerToValue(index));
}
void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Expr *result)
{
- generateFunctionCall(result, Runtime::typeofName, Assembler::EngineRegister,
+ generateRuntimeCall(result, typeofName, Assembler::EngineRegister,
Assembler::StringToIndex(name));
}
void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
{
- generateFunctionCall(result, Runtime::typeofValue, Assembler::EngineRegister,
+ generateRuntimeCall(result, typeofValue, Assembler::EngineRegister,
Assembler::PointerToValue(value));
}
void InstructionSelection::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
{
- generateFunctionCall(result, Runtime::deleteMember, Assembler::EngineRegister,
+ generateRuntimeCall(result, deleteMember, Assembler::EngineRegister,
Assembler::Reference(base), Assembler::StringToIndex(name));
}
void InstructionSelection::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
IR::Expr *result)
{
- generateFunctionCall(result, Runtime::deleteElement, Assembler::EngineRegister,
+ generateRuntimeCall(result, deleteElement, Assembler::EngineRegister,
Assembler::Reference(base), Assembler::PointerToValue(index));
}
void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Expr *result)
{
- generateFunctionCall(result, Runtime::deleteName, Assembler::EngineRegister,
+ generateRuntimeCall(result, deleteName, Assembler::EngineRegister,
Assembler::StringToIndex(name));
}
@@ -475,7 +475,7 @@ void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result)
void InstructionSelection::callBuiltinThrow(IR::Expr *arg)
{
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::throwException, Assembler::EngineRegister,
+ generateRuntimeCall(Assembler::ReturnValueRegister, throwException, Assembler::EngineRegister,
Assembler::PointerToValue(arg));
}
@@ -486,13 +486,13 @@ void InstructionSelection::callBuiltinReThrow()
void InstructionSelection::callBuiltinUnwindException(IR::Expr *result)
{
- generateFunctionCall(result, Runtime::unwindException, Assembler::EngineRegister);
+ generateRuntimeCall(result, unwindException, Assembler::EngineRegister);
}
void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName)
{
- generateFunctionCall(Assembler::Void, Runtime::pushCatchScope, Assembler::EngineRegister, Assembler::StringToIndex(exceptionName));
+ generateRuntimeCall(Assembler::Void, pushCatchScope, Assembler::EngineRegister, Assembler::StringToIndex(exceptionName));
}
void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
@@ -500,7 +500,7 @@ void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::E
Q_ASSERT(arg);
Q_ASSERT(result);
- generateFunctionCall(result, Runtime::foreachIterator, Assembler::EngineRegister, Assembler::PointerToValue(arg));
+ generateRuntimeCall(result, foreachIterator, Assembler::EngineRegister, Assembler::PointerToValue(arg));
}
void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
@@ -508,24 +508,24 @@ void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR:
Q_ASSERT(arg);
Q_ASSERT(result);
- generateFunctionCall(result, Runtime::foreachNextPropertyName, Assembler::Reference(arg));
+ generateRuntimeCall(result, foreachNextPropertyName, Assembler::Reference(arg));
}
void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg)
{
Q_ASSERT(arg);
- generateFunctionCall(Assembler::Void, Runtime::pushWithScope, Assembler::Reference(arg), Assembler::EngineRegister);
+ generateRuntimeCall(Assembler::Void, pushWithScope, Assembler::Reference(arg), Assembler::EngineRegister);
}
void InstructionSelection::callBuiltinPopScope()
{
- generateFunctionCall(Assembler::Void, Runtime::popScope, Assembler::EngineRegister);
+ generateRuntimeCall(Assembler::Void, popScope, Assembler::EngineRegister);
}
void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
{
- generateFunctionCall(Assembler::Void, Runtime::declareVar, Assembler::EngineRegister,
+ generateRuntimeCall(Assembler::Void, declareVar, Assembler::EngineRegister,
Assembler::TrustedImm32(deletable), Assembler::StringToIndex(name));
}
@@ -534,7 +534,7 @@ void InstructionSelection::callBuiltinDefineArray(IR::Expr *result, IR::ExprList
Q_ASSERT(result);
int length = prepareVariableArguments(args);
- generateFunctionCall(result, Runtime::arrayLiteral, Assembler::EngineRegister,
+ generateRuntimeCall(result, arrayLiteral, Assembler::EngineRegister,
baseAddressForCallArguments(), Assembler::TrustedImm32(length));
}
@@ -614,19 +614,19 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int
it = it->next;
}
- generateFunctionCall(result, Runtime::objectLiteral, Assembler::EngineRegister,
+ generateRuntimeCall(result, objectLiteral, Assembler::EngineRegister,
baseAddressForCallArguments(), Assembler::TrustedImm32(classId),
Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
}
void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result)
{
- generateFunctionCall(result, Runtime::setupArgumentsObject, Assembler::EngineRegister);
+ generateRuntimeCall(result, setupArgumentsObject, Assembler::EngineRegister);
}
void InstructionSelection::callBuiltinConvertThisToObject()
{
- generateFunctionCall(Assembler::Void, Runtime::convertThisToObject, Assembler::EngineRegister);
+ generateRuntimeCall(Assembler::Void, convertThisToObject, Assembler::EngineRegister);
}
void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
@@ -635,11 +635,11 @@ void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Ex
prepareCallData(args, 0);
if (value->asConst())
- generateFunctionCall(result, Runtime::callValue, Assembler::EngineRegister,
+ generateRuntimeCall(result, callValue, Assembler::EngineRegister,
Assembler::PointerToValue(value),
baseAddressForCallData());
else
- generateFunctionCall(result, Runtime::callValue, Assembler::EngineRegister,
+ generateRuntimeCall(result, callValue, Assembler::EngineRegister,
Assembler::Reference(value),
baseAddressForCallData());
}
@@ -659,17 +659,17 @@ void InstructionSelection::loadThisObject(IR::Expr *temp)
void InstructionSelection::loadQmlContext(IR::Expr *temp)
{
- generateFunctionCall(temp, Runtime::getQmlContext, Assembler::EngineRegister);
+ generateRuntimeCall(temp, getQmlContext, Assembler::EngineRegister);
}
void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp)
{
- generateFunctionCall(temp, Runtime::getQmlImportedScripts, Assembler::EngineRegister);
+ generateRuntimeCall(temp, getQmlImportedScripts, Assembler::EngineRegister);
}
void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *temp)
{
- generateFunctionCall(temp, Runtime::getQmlSingleton, Assembler::EngineRegister, Assembler::StringToIndex(name));
+ generateRuntimeCall(temp, getQmlSingleton, Assembler::EngineRegister, Assembler::StringToIndex(name));
}
void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target)
@@ -716,7 +716,7 @@ void InstructionSelection::loadString(const QString &str, IR::Expr *target)
void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
{
int id = registerRegExp(sourceRegexp);
- generateFunctionCall(target, Runtime::regexpLiteral, Assembler::EngineRegister, Assembler::TrustedImm32(id));
+ generateRuntimeCall(target, regexpLiteral, Assembler::EngineRegister, Assembler::TrustedImm32(id));
}
void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target)
@@ -726,20 +726,20 @@ void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr
generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), Assembler::EngineRegister, Assembler::Void);
return;
}
- generateFunctionCall(target, Runtime::getActivationProperty, Assembler::EngineRegister, Assembler::StringToIndex(*name->id));
+ generateRuntimeCall(target, getActivationProperty, Assembler::EngineRegister, Assembler::StringToIndex(*name->id));
}
void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName)
{
// ### should use a lookup call here
- generateFunctionCall(Assembler::Void, Runtime::setActivationProperty,
+ generateRuntimeCall(Assembler::Void, setActivationProperty,
Assembler::EngineRegister, Assembler::StringToIndex(targetName), Assembler::PointerToValue(source));
}
void InstructionSelection::initClosure(IR::Closure *closure, IR::Expr *target)
{
int id = closure->value;
- generateFunctionCall(target, Runtime::closure, Assembler::EngineRegister, Assembler::TrustedImm32(id));
+ generateRuntimeCall(target, closure, Assembler::EngineRegister, Assembler::TrustedImm32(id));
}
void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
@@ -748,7 +748,7 @@ void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::
uint index = registerGetterLookup(name);
generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::Void);
} else {
- generateFunctionCall(target, Runtime::getProperty, Assembler::EngineRegister,
+ generateRuntimeCall(target, getProperty, Assembler::EngineRegister,
Assembler::PointerToValue(base), Assembler::StringToIndex(name));
}
}
@@ -756,11 +756,11 @@ void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::
void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, IR::Expr *target)
{
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateFunctionCall(target, Runtime::getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
+ generateRuntimeCall(target, getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateFunctionCall(target, Runtime::getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
+ generateRuntimeCall(target, getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
else if (kind == IR::Member::MemberOfIdObjectsArray)
- generateFunctionCall(target, Runtime::getQmlIdObject, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
+ generateRuntimeCall(target, getQmlIdObject, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
else
Q_ASSERT(false);
}
@@ -768,12 +768,12 @@ void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::Mem
void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
{
if (attachedPropertiesId != 0)
- generateFunctionCall(target, Runtime::getQmlAttachedProperty, Assembler::EngineRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(target, getQmlAttachedProperty, Assembler::EngineRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
else if (isSingleton)
- generateFunctionCall(target, Runtime::getQmlSingletonQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
+ generateRuntimeCall(target, getQmlSingletonQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
Assembler::TrustedImm32(captureRequired));
else
- generateFunctionCall(target, Runtime::getQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
+ generateRuntimeCall(target, getQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
Assembler::TrustedImm32(captureRequired));
}
@@ -787,7 +787,7 @@ void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase,
Assembler::PointerToValue(targetBase),
Assembler::PointerToValue(source));
} else {
- generateFunctionCall(Assembler::Void, Runtime::setProperty, Assembler::EngineRegister,
+ generateRuntimeCall(Assembler::Void, setProperty, Assembler::EngineRegister,
Assembler::PointerToValue(targetBase), Assembler::StringToIndex(targetName),
Assembler::PointerToValue(source));
}
@@ -796,10 +796,10 @@ void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase,
void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex)
{
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateFunctionCall(Assembler::Void, Runtime::setQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
+ generateRuntimeCall(Assembler::Void, setQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateFunctionCall(Assembler::Void, Runtime::setQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
+ generateRuntimeCall(Assembler::Void, setQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
else
Q_ASSERT(false);
@@ -807,7 +807,7 @@ void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *tar
void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex)
{
- generateFunctionCall(Assembler::Void, Runtime::setQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
+ generateRuntimeCall(Assembler::Void, setQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
}
@@ -821,7 +821,7 @@ void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr
return;
}
- generateFunctionCall(target, Runtime::getElement, Assembler::EngineRegister,
+ generateRuntimeCall(target, getElement, Assembler::EngineRegister,
Assembler::PointerToValue(base), Assembler::PointerToValue(index));
}
@@ -834,7 +834,7 @@ void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, IR
Assembler::PointerToValue(source));
return;
}
- generateFunctionCall(Assembler::Void, Runtime::setElement, Assembler::EngineRegister,
+ generateRuntimeCall(Assembler::Void, setElement, Assembler::EngineRegister,
Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
Assembler::PointerToValue(source));
}
@@ -981,9 +981,9 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
}
#define setOp(op, opName, operation) \
- do { op = operation; opName = isel_stringIfy(operation); } while (0)
+ do { op = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); } while (0)
#define setOpContext(op, opName, operation) \
- do { opContext = operation; opName = isel_stringIfy(operation); } while (0)
+ do { opContext = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); } while (0)
void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
{
@@ -1003,12 +1003,12 @@ void InstructionSelection::callQmlContextProperty(IR::Expr *base, IR::Member::Me
prepareCallData(args, base);
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateFunctionCall(result, Runtime::callQmlScopeObjectProperty,
+ generateRuntimeCall(result, callQmlScopeObjectProperty,
Assembler::EngineRegister,
Assembler::TrustedImm32(propertyIndex),
baseAddressForCallData());
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateFunctionCall(result, Runtime::callQmlContextObjectProperty,
+ generateRuntimeCall(result, callQmlContextObjectProperty,
Assembler::EngineRegister,
Assembler::TrustedImm32(propertyIndex),
baseAddressForCallData());
@@ -1025,12 +1025,12 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR:
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateFunctionCall(result, Runtime::callPropertyLookup,
+ generateRuntimeCall(result, callPropertyLookup,
Assembler::EngineRegister,
Assembler::TrustedImm32(index),
baseAddressForCallData());
} else {
- generateFunctionCall(result, Runtime::callProperty, Assembler::EngineRegister,
+ generateRuntimeCall(result, callProperty, Assembler::EngineRegister,
Assembler::StringToIndex(name),
baseAddressForCallData());
}
@@ -1042,7 +1042,7 @@ void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::Ex
Q_ASSERT(base != 0);
prepareCallData(args, base);
- generateFunctionCall(result, Runtime::callElement, Assembler::EngineRegister,
+ generateRuntimeCall(result, callElement, Assembler::EngineRegister,
Assembler::PointerToValue(index),
baseAddressForCallData());
}
@@ -1118,7 +1118,7 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe
Assembler::TrustedImm32(Value::NotDouble_Mask));
#endif
- generateFunctionCall(target, Runtime::toDouble, Assembler::PointerToValue(source));
+ generateRuntimeCall(target, toDouble, Assembler::PointerToValue(source));
Assembler::Jump noDoubleDone = _as->jump();
// it is a double:
@@ -1183,7 +1183,7 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
case IR::StringType:
case IR::VarType:
default:
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toBoolean,
+ generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
Assembler::PointerToValue(source));
_as->storeBool(Assembler::ReturnValueRegister, target);
break;
@@ -1215,7 +1215,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *targe
// not an int:
fallback.link(_as);
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt,
+ generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
_as->loadAddress(Assembler::ScratchRegister, source));
isInt.link(_as);
@@ -1253,7 +1253,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *targe
// not an int:
fallback.link(_as);
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt,
+ generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
_as->loadAddress(Assembler::ScratchRegister, source));
_as->storeInt32(Assembler::ReturnValueRegister, target);
@@ -1266,7 +1266,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *targe
_as->branchTruncateDoubleToInt32(_as->toDoubleRegister(source),
Assembler::ReturnValueRegister,
Assembler::BranchIfTruncateSuccessful);
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::doubleToInt,
+ generateRuntimeCall(Assembler::ReturnValueRegister, doubleToInt,
Assembler::PointerToValue(source));
success.link(_as);
_as->storeInt32(Assembler::ReturnValueRegister, target);
@@ -1284,7 +1284,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *targe
break;
case IR::StringType:
default:
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt,
+ generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
_as->loadAddress(Assembler::ScratchRegister, source));
_as->storeInt32(Assembler::ReturnValueRegister, target);
break;
@@ -1309,7 +1309,7 @@ void InstructionSelection::convertTypeToUInt32(IR::Expr *source, IR::Expr *targe
// not an int:
isNoInt.link(_as);
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toUInt,
+ generateRuntimeCall(Assembler::ReturnValueRegister, toUInt,
_as->loadAddress(Assembler::ScratchRegister, source));
_as->storeInt32(Assembler::ReturnValueRegister, target);
@@ -1320,7 +1320,7 @@ void InstructionSelection::convertTypeToUInt32(IR::Expr *source, IR::Expr *targe
Assembler::Jump success =
_as->branchTruncateDoubleToUint32(reg, Assembler::ReturnValueRegister,
Assembler::BranchIfTruncateSuccessful);
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::doubleToUInt,
+ generateRuntimeCall(Assembler::ReturnValueRegister, doubleToUInt,
Assembler::PointerToValue(source));
success.link(_as);
_as->storeUInt32(Assembler::ReturnValueRegister, target);
@@ -1331,7 +1331,7 @@ void InstructionSelection::convertTypeToUInt32(IR::Expr *source, IR::Expr *targe
_as->storeUInt32(Assembler::ReturnValueRegister, target);
break;
case IR::StringType:
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toUInt,
+ generateRuntimeCall(Assembler::ReturnValueRegister, toUInt,
Assembler::PointerToValue(source));
_as->storeUInt32(Assembler::ReturnValueRegister, target);
break;
@@ -1351,13 +1351,13 @@ void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprL
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
- generateFunctionCall(result, Runtime::constructGlobalLookup,
+ generateRuntimeCall(result, constructGlobalLookup,
Assembler::EngineRegister,
Assembler::TrustedImm32(index), baseAddressForCallData());
return;
}
- generateFunctionCall(result, Runtime::constructActivationProperty,
+ generateRuntimeCall(result, constructActivationProperty,
Assembler::EngineRegister,
Assembler::StringToIndex(*func->id),
baseAddressForCallData());
@@ -1369,14 +1369,14 @@ void InstructionSelection::constructProperty(IR::Expr *base, const QString &name
prepareCallData(args, base);
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateFunctionCall(result, Runtime::constructPropertyLookup,
+ generateRuntimeCall(result, constructPropertyLookup,
Assembler::EngineRegister,
Assembler::TrustedImm32(index),
baseAddressForCallData());
return;
}
- generateFunctionCall(result, Runtime::constructProperty, Assembler::EngineRegister,
+ generateRuntimeCall(result, constructProperty, Assembler::EngineRegister,
Assembler::StringToIndex(name),
baseAddressForCallData());
}
@@ -1386,7 +1386,7 @@ void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, I
Q_ASSERT(value != 0);
prepareCallData(args, 0);
- generateFunctionCall(result, Runtime::constructValue,
+ generateRuntimeCall(result, constructValue,
Assembler::EngineRegister,
Assembler::Reference(value),
baseAddressForCallData());
@@ -1422,7 +1422,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
booleanConversion.link(_as);
reg = Assembler::ReturnValueRegister;
- generateFunctionCall(reg, Runtime::toBoolean, Assembler::Reference(s->cond));
+ generateRuntimeCall(reg, toBoolean, Assembler::Reference(s->cond));
testBoolean.link(_as);
}
@@ -1432,7 +1432,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
} else if (IR::Const *c = s->cond->asConst()) {
// TODO: SSA optimization for constant condition evaluation should remove this.
// See also visitCJump() in RegAllocInfo.
- generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toBoolean,
+ generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
Assembler::PointerToValue(c));
_as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, s->iftrue, s->iffalse);
return;
@@ -1454,8 +1454,8 @@ void InstructionSelection::visitCJump(IR::CJump *s)
return;
}
- Runtime::CompareOperation op = 0;
- Runtime::CompareOperationContext opContext = 0;
+ RuntimeCall op;
+ RuntimeCall opContext;
const char *opName = 0;
switch (b->op) {
default: Q_UNREACHABLE(); Q_ASSERT(!"todo"); break;
@@ -1476,7 +1476,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
// if (true === true) .....
// Of course, after folding the CJUMP to a JUMP, dead-code (dead-basic-block)
// elimination (which isn't there either) would remove the whole else block.
- if (opContext)
+ if (opContext.isValid())
_as->generateFunctionCallImp(Assembler::ReturnValueRegister, opName, opContext,
Assembler::EngineRegister,
Assembler::PointerToValue(b->left),
@@ -1800,7 +1800,7 @@ void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *tr
IR::Expr *left = binop->left;
IR::Expr *right = binop->right;
- _as->generateFunctionCallImp(Assembler::ReturnValueRegister, "Runtime::compareStrictEqual", Runtime::compareStrictEqual,
+ generateRuntimeCall(Assembler::ReturnValueRegister, compareStrictEqual,
Assembler::PointerToValue(left), Assembler::PointerToValue(right));
_as->generateCJumpOnCompare(binop->op == IR::OpStrictEqual ? Assembler::NotEqual : Assembler::Equal,
Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
@@ -1954,12 +1954,18 @@ void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *tru
IR::Expr *left = binop->left;
IR::Expr *right = binop->right;
- _as->generateFunctionCallImp(Assembler::ReturnValueRegister, "Runtime::compareEqual", Runtime::compareEqual,
+ generateRuntimeCall(Assembler::ReturnValueRegister, compareEqual,
Assembler::PointerToValue(left), Assembler::PointerToValue(right));
_as->generateCJumpOnCompare(binop->op == IR::OpEqual ? Assembler::NotEqual : Assembler::Equal,
Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
_block, trueBlock, falseBlock);
}
+QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
+{
+ QQmlRefPointer<CompiledData::CompilationUnit> result;
+ result.adopt(new JIT::CompilationUnit);
+ return result;
+}
#endif // ENABLE(ASSEMBLER)
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 366d510072..4b35a72e01 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -76,7 +76,7 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory);
~InstructionSelection();
virtual void run(int functionIndex);
@@ -244,8 +244,8 @@ private:
#define isel_stringIfyx(s) #s
#define isel_stringIfy(s) isel_stringIfyx(s)
- #define generateFunctionCall(t, function, ...) \
- _as->generateFunctionCallImp(t, isel_stringIfy(function), function, __VA_ARGS__)
+ #define generateRuntimeCall(t, function, ...) \
+ _as->generateFunctionCallImp(t, "Runtime::" isel_stringIfy(function), RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
int prepareVariableArguments(IR::ExprList* args);
int prepareCallData(IR::ExprList* args, IR::Expr *thisObject);
@@ -285,11 +285,13 @@ private:
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
+ ISelFactory() : EvalISelFactory(QStringLiteral("jit")) {}
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); }
- virtual bool jitCompileRegexps() const
+ EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) Q_DECL_OVERRIDE Q_DECL_FINAL
+ { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator, this); }
+ bool jitCompileRegexps() const Q_DECL_OVERRIDE Q_DECL_FINAL
{ return true; }
+ QQmlRefPointer<CompiledData::CompilationUnit> createUnitForLoading() Q_DECL_OVERRIDE Q_DECL_FINAL;
};
} // end of namespace JIT
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index c21f52ecd3..deef719b67 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -87,7 +87,7 @@ public:
{}
protected:
- void addStmtNr(Stmt *s)
+ void addStmtNr(Stmt *s) Q_DECL_OVERRIDE Q_DECL_FINAL
{
addJustifiedNr(intervals->positionForStatement(s));
}
@@ -115,7 +115,7 @@ public:
}
protected:
- void visitTemp(Temp *e)
+ void visitTemp(Temp *e) Q_DECL_OVERRIDE Q_DECL_FINAL
{
switch (e->kind) {
case Temp::PhysicalRegister: {
@@ -184,7 +184,7 @@ public:
_currentBB = bb;
for (Stmt *s : bb->statements()) {
_currentStmt = s;
- s->accept(this);
+ visit(s);
}
}
}
@@ -809,7 +809,8 @@ using namespace QT_PREPEND_NAMESPACE(QV4::IR);
using namespace QT_PREPEND_NAMESPACE(QV4);
namespace {
-class ResolutionPhase: protected StmtVisitor, protected ExprVisitor {
+class ResolutionPhase
+{
Q_DISABLE_COPY(ResolutionPhase)
LifeTimeIntervals::Ptr _intervals;
@@ -892,7 +893,7 @@ private:
addNewIntervals(usePosition(_currentStmt));
else
addNewIntervals(defPosition(_currentStmt));
- _currentStmt->accept(this);
+ visit(_currentStmt);
for (Move *load : _loads)
newStatements.append(load);
if (_currentStmt->asPhi())
@@ -1179,8 +1180,20 @@ private:
return load;
}
-protected:
- virtual void visitTemp(Temp *t)
+private:
+ void visit(Expr *e)
+ {
+ switch (e->exprKind) {
+ case Expr::TempExpr:
+ visitTemp(e->asTemp());
+ break;
+ default:
+ EXPR_VISIT_ALL_KINDS(e);
+ break;
+ }
+ }
+
+ void visitTemp(Temp *t)
{
if (t->kind != Temp::VirtualRegister)
return;
@@ -1210,47 +1223,25 @@ protected:
}
}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(Member *e) { e->base->accept(this); }
-
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitExp(Exp *s) { s->expr->accept(this); }
-
- virtual void visitMove(Move *s)
+ void visit(Stmt *s)
{
- if (Temp *t = s->target->asTemp())
- maybeGenerateSpill(t);
+ switch (s->stmtKind) {
+ case Stmt::MoveStmt: {
+ auto m = s->asMove();
+ if (Temp *t = m->target->asTemp())
+ maybeGenerateSpill(t);
- s->source->accept(this);
- s->target->accept(this);
- }
-
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(Phi *s)
- {
- maybeGenerateSpill(s->targetTemp);
+ visit(m->source);
+ visit(m->target);
+ } break;
+ case Stmt::PhiStmt: {
+ auto p = s->asPhi();
+ maybeGenerateSpill(p->targetTemp);
+ } break;
+ default:
+ STMT_VISIT_ALL_KINDS(s);
+ break;
+ }
}
};
} // anonymous namespace
diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp
index cb9131d731..6a32069ac4 100644
--- a/src/qml/jit/qv4unop.cpp
+++ b/src/qml/jit/qv4unop.cpp
@@ -47,11 +47,11 @@ using namespace JIT;
#define stringIfyx(s) #s
#define stringIfy(s) stringIfyx(s)
#define setOp(operation) \
- do { call = operation; name = stringIfy(operation); } while (0)
+ do { call = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); } while (0)
void Unop::generate(IR::Expr *source, IR::Expr *target)
{
- Runtime::UnaryOperation call = 0;
+ RuntimeCall call;
const char *name = 0;
switch (op) {
case IR::OpNot:
@@ -60,19 +60,18 @@ void Unop::generate(IR::Expr *source, IR::Expr *target)
case IR::OpUMinus:
generateUMinus(source, target);
return;
- case IR::OpUPlus: setOp(Runtime::uPlus); break;
+ case IR::OpUPlus: setOp(uPlus); break;
case IR::OpCompl:
generateCompl(source, target);
return;
- case IR::OpIncrement: setOp(Runtime::increment); break;
- case IR::OpDecrement: setOp(Runtime::decrement); break;
+ case IR::OpIncrement: setOp(increment); break;
+ case IR::OpDecrement: setOp(decrement); break;
default:
Q_UNREACHABLE();
} // switch
- if (call) {
- as->generateFunctionCallImp(target, name, call, Assembler::PointerToValue(source));
- }
+ Q_ASSERT(call.isValid());
+ _as->generateFunctionCallImp(target, name, call, Assembler::PointerToValue(source));
}
void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
@@ -82,15 +81,15 @@ void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
Assembler::RegisterID tReg = Assembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
tReg = (Assembler::RegisterID) targetTemp->index;
- Assembler::RegisterID sReg = as->toInt32Register(source, tReg);
- as->move(sReg, tReg);
- as->neg32(tReg);
+ Assembler::RegisterID sReg = _as->toInt32Register(source, tReg);
+ _as->move(sReg, tReg);
+ _as->neg32(tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
- as->storeInt32(tReg, target);
+ _as->storeInt32(tReg, target);
return;
}
- as->generateFunctionCallImp(target, "Runtime::uMinus", Runtime::uMinus, Assembler::PointerToValue(source));
+ generateRuntimeCall(target, uMinus, Assembler::PointerToValue(source));
}
void Unop::generateNot(IR::Expr *source, IR::Expr *target)
@@ -100,26 +99,26 @@ void Unop::generateNot(IR::Expr *source, IR::Expr *target)
Assembler::RegisterID tReg = Assembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
tReg = (Assembler::RegisterID) targetTemp->index;
- as->xor32(Assembler::TrustedImm32(0x1), as->toInt32Register(source, tReg), tReg);
+ _as->xor32(Assembler::TrustedImm32(0x1), _as->toInt32Register(source, tReg), tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
- as->storeBool(tReg, target);
+ _as->storeBool(tReg, target);
return;
} else if (source->type == IR::SInt32Type) {
Assembler::RegisterID tReg = Assembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
tReg = (Assembler::RegisterID) targetTemp->index;
- as->compare32(Assembler::Equal,
- as->toInt32Register(source, Assembler::ScratchRegister), Assembler::TrustedImm32(0),
+ _as->compare32(Assembler::Equal,
+ _as->toInt32Register(source, Assembler::ScratchRegister), Assembler::TrustedImm32(0),
tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
- as->storeBool(tReg, target);
+ _as->storeBool(tReg, target);
return;
} else if (source->type == IR::DoubleType) {
// ###
}
// ## generic implementation testing for int/bool
- as->generateFunctionCallImp(target, "Runtime::uNot", Runtime::uNot, Assembler::PointerToValue(source));
+ generateRuntimeCall(target, uNot, Assembler::PointerToValue(source));
}
void Unop::generateCompl(IR::Expr *source, IR::Expr *target)
@@ -129,12 +128,12 @@ void Unop::generateCompl(IR::Expr *source, IR::Expr *target)
Assembler::RegisterID tReg = Assembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
tReg = (Assembler::RegisterID) targetTemp->index;
- as->xor32(Assembler::TrustedImm32(0xffffffff), as->toInt32Register(source, tReg), tReg);
+ _as->xor32(Assembler::TrustedImm32(0xffffffff), _as->toInt32Register(source, tReg), tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
- as->storeInt32(tReg, target);
+ _as->storeInt32(tReg, target);
return;
}
- as->generateFunctionCallImp(target, "Runtime::complement", Runtime::complement, Assembler::PointerToValue(source));
+ generateRuntimeCall(target, complement, Assembler::PointerToValue(source));
}
#endif
diff --git a/src/qml/jit/qv4unop_p.h b/src/qml/jit/qv4unop_p.h
index f0b5b9c223..1141a84913 100644
--- a/src/qml/jit/qv4unop_p.h
+++ b/src/qml/jit/qv4unop_p.h
@@ -64,7 +64,7 @@ class Assembler;
struct Unop {
Unop(Assembler *assembler, IR::AluOp operation)
- : as(assembler)
+ : _as(assembler)
, op(operation)
{}
@@ -74,7 +74,7 @@ struct Unop {
void generateNot(IR::Expr *source, IR::Expr *target);
void generateCompl(IR::Expr *source, IR::Expr *target);
- Assembler *as;
+ Assembler *_as;
IR::AluOp op;
};
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 9c952f0d42..4404a5d79f 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -166,6 +166,17 @@ Q_DECLARE_METATYPE(QList<int>)
properties of the proxy object. No binding code is needed because it
is done dynamically using the Qt meta object system.
+ Use newQMetaObject() to wrap a QMetaObject; this gives you a
+ "script representation" of a QObject-based class. newQMetaObject()
+ returns a proxy script object; enum values of the class are available
+ as properties of the proxy object.
+
+ Constructors exposed to the meta-object system ( using Q_INVOKABLE ) can be
+ called from the script to create a new QObject instance with
+ JavaScriptOwnership.
+
+
+
\snippet code/src_script_qjsengine.cpp 5
\section1 Extensions
@@ -261,12 +272,8 @@ static void checkForApplicationInstance()
\l{ECMA-262}, Section 15.1.
*/
QJSEngine::QJSEngine()
- : QObject(*new QJSEnginePrivate, 0)
- , d(new QV8Engine(this))
+ : QJSEngine(nullptr)
{
- checkForApplicationInstance();
-
- QJSEnginePrivate::addToDebugServer(this);
}
/*!
@@ -515,6 +522,38 @@ QJSValue QJSEngine::newQObject(QObject *object)
}
/*!
+ \since 5.8
+
+ Creates a JavaScript object that wraps the given QMetaObject
+ The metaObject must outlive the script engine. It is recommended to only
+ use this method with static metaobjects.
+
+
+ When called as a constructor, a new instance of the class will be created.
+ Only constructors exposed by Q_INVOKABLE will be visible from the script engine.
+
+ \sa newQObject()
+*/
+
+QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) {
+ Q_D(QJSEngine);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(d);
+ QV4::Scope scope(v4);
+ QV4::ScopedValue v(scope, QV4::QMetaObjectWrapper::create(v4, metaObject));
+ return QJSValue(v4, v->asReturnedValue());
+}
+
+/*! \fn QJSValue QJSEngine::newQMetaObject<T>()
+
+ \since 5.8
+ Creates a JavaScript object that wraps the static QMetaObject associated
+ with class \c{T}.
+
+ \sa newQObject()
+*/
+
+
+/*!
Returns this engine's Global Object.
By default, the Global Object contains the built-in objects that are
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 6ecd0c7ec0..41c4b81270 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -74,6 +74,14 @@ public:
QJSValue newQObject(QObject *object);
+ QJSValue newQMetaObject(const QMetaObject* metaObject);
+
+ template <typename T>
+ QJSValue newQMetaObject()
+ {
+ return newQMetaObject(&T::staticMetaObject);
+ }
+
template <typename T>
inline QJSValue toScriptValue(const T &value)
{
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index ec7848aba2..e5c1dcdb80 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -663,11 +663,11 @@ QJSValue QJSValue::call(const QJSValueList &args)
callData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
}
- ScopedValue result(scope, f->call(callData));
+ f->call(scope, callData);
if (engine->hasException)
- result = engine->catchException();
+ scope.result = engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValue(engine, scope.result.asReturnedValue());
}
/*!
@@ -719,11 +719,11 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
callData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
}
- ScopedValue result(scope, f->call(callData));
+ f->call(scope, callData);
if (engine->hasException)
- result = engine->catchException();
+ scope.result = engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValue(engine, scope.result.asReturnedValue());
}
/*!
@@ -767,11 +767,11 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
callData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
}
- ScopedValue result(scope, f->construct(callData));
+ f->construct(scope, callData);
if (engine->hasException)
- result = engine->catchException();
+ scope.result = engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValue(engine, scope.result.asReturnedValue());
}
#ifdef QT_DEPRECATED
@@ -938,7 +938,7 @@ bool QJSValue::equals(const QJSValue& other) const
if (!ov)
return other.equals(*this);
- return Runtime::compareEqual(*v, *ov);
+ return Runtime::method_compareEqual(*v, *ov);
}
/*!
@@ -1234,6 +1234,28 @@ QObject *QJSValue::toQObject() const
}
/*!
+ \since 5.8
+
+ * If this QJSValue is a QMetaObject, returns the QMetaObject pointer
+ * that the QJSValue represents; otherwise, returns 0.
+ *
+ * \sa isQMetaObject()
+ */
+const QMetaObject *QJSValue::toQMetaObject() const
+{
+ QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
+ if (!engine)
+ return 0;
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::QMetaObjectWrapper> wrapper(scope, QJSValuePrivate::getValue(this));
+ if (!wrapper)
+ return 0;
+
+ return wrapper->metaObject();
+}
+
+
+/*!
Returns a QDateTime representation of this value, in local time.
If this QJSValue is not a date, or the value of the date is NaN
(Not-a-Number), an invalid QDateTime is returned.
@@ -1286,4 +1308,18 @@ bool QJSValue::isQObject() const
return val && val->as<QV4::QObjectWrapper>() != 0;
}
+/*!
+ \since 5.8
+
+ Returns true if this QJSValue is a QMetaObject; otherwise returns
+ false.
+
+ \sa toQMetaObject(), QJSEngine::newQMetaObject()
+*/
+bool QJSValue::isQMetaObject() const
+{
+ QV4::Value *val = QJSValuePrivate::getValue(this);
+ return val && val->as<QV4::QMetaObjectWrapper>() != 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index e207e1b099..ab20a2607d 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -98,6 +98,7 @@ public:
bool isUndefined() const;
bool isVariant() const;
bool isQObject() const;
+ bool isQMetaObject() const;
bool isObject() const;
bool isDate() const;
bool isRegExp() const;
@@ -111,6 +112,7 @@ public:
bool toBool() const;
QVariant toVariant() const;
QObject *toQObject() const;
+ const QMetaObject *toQMetaObject() const;
QDateTime toDateTime() const;
bool equals(const QJSValue &other) const;
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 038b23e8d3..cf434ee2ed 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -6,7 +6,6 @@ SOURCES += \
$$PWD/qv4engine.cpp \
$$PWD/qv4context.cpp \
$$PWD/qv4persistent.cpp \
- $$PWD/qv4debugging.cpp \
$$PWD/qv4lookup.cpp \
$$PWD/qv4identifier.cpp \
$$PWD/qv4identifiertable.cpp \
@@ -40,11 +39,16 @@ SOURCES += \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
$$PWD/qv4vme_moth.cpp \
- $$PWD/qv4profiling.cpp \
$$PWD/qv4arraybuffer.cpp \
$$PWD/qv4typedarray.cpp \
$$PWD/qv4dataview.cpp
+!contains(QT_CONFIG, no-qml-debug) {
+ SOURCES += $$PWD/qv4profiling.cpp
+} else {
+ DEFINES += QT_NO_QML_DEBUGGER
+}
+
HEADERS += \
$$PWD/qv4global_p.h \
$$PWD/qv4engine_p.h \
@@ -99,6 +103,7 @@ HEADERS += \
HEADERS += \
$$PWD/qv4runtime_p.h \
+ $$PWD/qv4runtimeapi_p.h \
$$PWD/qv4value_p.h \
$$PWD/qv4string_p.h \
$$PWD/qv4value_p.h
@@ -111,3 +116,7 @@ SOURCES += \
valgrind {
DEFINES += V4_USE_VALGRIND
}
+
+heaptrack {
+ DEFINES += V4_USE_HEAPTRACK
+}
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 94f418cae1..b55494823c 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -134,7 +134,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
ScopedCallData callData(scope, 1);
callData->thisObject = this->asReturnedValue();
callData->args[0] = desc->value;
- setter->call(callData);
+ setter->call(scope, callData);
if (attrs.isWritable()) {
setArrayAttributes(index, mapAttrs);
@@ -203,33 +203,35 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction);
-ReturnedValue ArgumentsGetterFunction::call(const Managed *getter, CallData *callData)
+void ArgumentsGetterFunction::call(const Managed *getter, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine();
- Scope scope(v4);
Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
- if (!o)
- return v4->throwTypeError();
+ if (!o) {
+ scope.result = v4->throwTypeError();
+ return;
+ }
Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->callData->argc));
- return o->context()->callData->args[g->index()].asReturnedValue();
+ scope.result = o->context()->callData->args[g->index()];
}
DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction);
-ReturnedValue ArgumentsSetterFunction::call(const Managed *setter, CallData *callData)
+void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine();
- Scope scope(v4);
Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
- if (!o)
- return v4->throwTypeError();
+ if (!o) {
+ scope.result = v4->throwTypeError();
+ return;
+ }
Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->callData->argc));
o->context()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined();
- return Encode::undefined();
+ scope.result = Encode::undefined();
}
void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index eeedcaf995..6ccfd89fd4 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -88,7 +88,7 @@ struct ArgumentsGetterFunction: FunctionObject
V4_OBJECT2(ArgumentsGetterFunction, FunctionObject)
uint index() const { return d()->index; }
- static ReturnedValue call(const Managed *that, CallData *d);
+ static void call(const Managed *that, Scope &scope, CallData *d);
};
inline
@@ -103,7 +103,7 @@ struct ArgumentsSetterFunction: FunctionObject
V4_OBJECT2(ArgumentsSetterFunction, FunctionObject)
uint index() const { return d()->index; }
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
inline
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index d170bde0e8..e006773c9e 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -51,29 +51,34 @@ Heap::ArrayBufferCtor::ArrayBufferCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue ArrayBufferCtor::construct(const Managed *m, CallData *callData)
+void ArrayBufferCtor::construct(const Managed *m, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const Object *>(m)->engine();
- Scope scope(v4);
ScopedValue l(scope, callData->argument(0));
double dl = l->toInteger();
- if (v4->hasException)
- return Encode::undefined();
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
uint len = (uint)qBound(0., dl, (double)UINT_MAX);
- if (len != dl)
- return v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length"));
+ if (len != dl) {
+ scope.result = v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length"));
+ return;
+ }
Scoped<ArrayBuffer> a(scope, v4->newArrayBuffer(len));
- if (scope.engine->hasException)
- return Encode::undefined();
- return a.asReturnedValue();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ } else {
+ scope.result = a->asReturnedValue();
+ }
}
-ReturnedValue ArrayBufferCtor::call(const Managed *that, CallData *callData)
+void ArrayBufferCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx)
@@ -184,7 +189,8 @@ ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx)
ScopedCallData callData(scope, 1);
double newLen = qMax(final - first, 0.);
callData->args[0] = QV4::Encode(newLen);
- QV4::Scoped<ArrayBuffer> newBuffer(scope, constructor->construct(callData));
+ constructor->construct(scope, callData);
+ QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result.asReturnedValue());
if (!newBuffer || newBuffer->d()->data->size < (int)newLen)
return scope.engine->throwTypeError();
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index 0413d2f28d..d079aeb9f7 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -78,8 +78,8 @@ struct ArrayBufferCtor: FunctionObject
{
V4_OBJECT2(ArrayBufferCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
static ReturnedValue method_isView(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 62ece57c41..f4afe46fcb 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -682,7 +682,7 @@ bool ArrayElementLessThan::operator()(Value v1, Value v2) const
callData->thisObject = Primitive::undefinedValue();
callData->args[0] = v1;
callData->args[1] = v2;
- result = Runtime::callValue(scope.engine, m_comparefn, callData);
+ result = scope.engine->runtime.callValue(scope.engine, m_comparefn, callData);
return result->toNumber() < 0;
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 3521673461..4d15c6c137 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -54,18 +54,19 @@ Heap::ArrayCtor::ArrayCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue ArrayCtor::construct(const Managed *m, CallData *callData)
+void ArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const ArrayCtor *>(m)->engine();
- Scope scope(v4);
ScopedArrayObject a(scope, v4->newArrayObject());
uint len;
if (callData->argc == 1 && callData->args[0].isNumber()) {
bool ok;
len = callData->args[0].asArrayLength(&ok);
- if (!ok)
- return v4->throwRangeError(callData->args[0]);
+ if (!ok) {
+ scope.result = v4->throwRangeError(callData->args[0]);
+ return;
+ }
if (len < 0x1000)
a->arrayReserve(len);
@@ -76,12 +77,12 @@ ReturnedValue ArrayCtor::construct(const Managed *m, CallData *callData)
}
a->setArrayLengthUnchecked(len);
- return a.asReturnedValue();
+ scope.result = a.asReturnedValue();
}
-ReturnedValue ArrayCtor::call(const Managed *that, CallData *callData)
+void ArrayCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -132,7 +133,8 @@ ReturnedValue ArrayPrototype::method_toString(CallContext *ctx)
if (!!f) {
ScopedCallData d(scope, 0);
d->thisObject = ctx->thisObject();
- return f->call(d);
+ f->call(scope, d);
+ return scope.result.asReturnedValue();
}
return ObjectPrototype::method_toString(ctx);
}
@@ -704,7 +706,6 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
ScopedCallData callData(scope, 3);
callData->args[2] = instance;
callData->thisObject = ctx->argument(1);
- ScopedValue r(scope);
ScopedValue v(scope);
bool ok = true;
@@ -716,8 +717,8 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- r = callback->call(callData);
- ok = r->toBoolean();
+ callback->call(scope, callData);
+ ok = scope.result.toBoolean();
}
return Encode(ok);
}
@@ -740,7 +741,6 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
callData->args[2] = instance;
ScopedValue v(scope);
- ScopedValue r(scope);
for (uint k = 0; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
@@ -749,8 +749,8 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- r = callback->call(callData);
- if (r->toBoolean())
+ callback->call(scope, callData);
+ if (scope.result.toBoolean())
return Encode(true);
}
return Encode(false);
@@ -782,7 +782,7 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- callback->call(callData);
+ callback->call(scope, callData);
}
return Encode::undefined();
}
@@ -804,7 +804,6 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
a->arrayReserve(len);
a->setArrayLengthUnchecked(len);
- ScopedValue mapped(scope);
ScopedCallData callData(scope, 3);
callData->thisObject = ctx->argument(1);
callData->args[2] = instance;
@@ -818,8 +817,8 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- mapped = callback->call(callData);
- a->arraySet(k, mapped);
+ callback->call(scope, callData);
+ a->arraySet(k, scope.result);
}
return a.asReturnedValue();
}
@@ -840,7 +839,6 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject());
a->arrayReserve(len);
- ScopedValue selected(scope);
ScopedCallData callData(scope, 3);
callData->thisObject = ctx->argument(1);
callData->args[2] = instance;
@@ -856,8 +854,8 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- selected = callback->call(callData);
- if (selected->toBoolean()) {
+ callback->call(scope, callData);
+ if (scope.result.toBoolean()) {
a->arraySet(to, v);
++to;
}
@@ -879,17 +877,16 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
return ctx->engine()->throwTypeError();
uint k = 0;
- ScopedValue acc(scope);
ScopedValue v(scope);
if (ctx->argc() > 1) {
- acc = ctx->argument(1);
+ scope.result = ctx->argument(1);
} else {
bool kPresent = false;
while (k < len && !kPresent) {
v = instance->getIndexed(k, &kPresent);
if (kPresent)
- acc = v;
+ scope.result = v;
++k;
}
if (!kPresent)
@@ -898,21 +895,21 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
ScopedCallData callData(scope, 4);
callData->thisObject = Primitive::undefinedValue();
- callData->args[0] = acc;
+ callData->args[0] = scope.result;
callData->args[3] = instance;
while (k < len) {
bool kPresent;
v = instance->getIndexed(k, &kPresent);
if (kPresent) {
- callData->args[0] = acc;
+ callData->args[0] = scope.result;
callData->args[1] = v;
callData->args[2] = Primitive::fromDouble(k);
- acc = callback->call(callData);
+ callback->call(scope, callData);
}
++k;
}
- return acc->asReturnedValue();
+ return scope.result.asReturnedValue();
}
ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
@@ -935,16 +932,15 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
}
uint k = len;
- ScopedValue acc(scope);
ScopedValue v(scope);
if (ctx->argc() > 1) {
- acc = ctx->argument(1);
+ scope.result = ctx->argument(1);
} else {
bool kPresent = false;
while (k > 0 && !kPresent) {
v = instance->getIndexed(k - 1, &kPresent);
if (kPresent)
- acc = v;
+ scope.result = v;
--k;
}
if (!kPresent)
@@ -959,13 +955,13 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
bool kPresent;
v = instance->getIndexed(k - 1, &kPresent);
if (kPresent) {
- callData->args[0] = acc;
+ callData->args[0] = scope.result;
callData->args[1] = v;
callData->args[2] = Primitive::fromDouble(k - 1);
- acc = callback->call(callData);
+ callback->call(scope, callData);
}
--k;
}
- return acc->asReturnedValue();
+ return scope.result.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index bae5f9e0da..f49ed76b02 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -70,8 +70,8 @@ struct ArrayCtor: FunctionObject
{
V4_OBJECT2(ArrayCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct ArrayPrototype: ArrayObject
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index d9da7d7754..57c54e15c4 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -50,17 +50,16 @@ Heap::BooleanCtor::BooleanCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue BooleanCtor::construct(const Managed *m, CallData *callData)
+void BooleanCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const BooleanCtor *>(m)->engine());
bool n = callData->argc ? callData->args[0].toBoolean() : false;
- return Encode(scope.engine->newBooleanObject(n));
+ scope.result = Encode(scope.engine->newBooleanObject(n));
}
-ReturnedValue BooleanCtor::call(const Managed *, CallData *callData)
+void BooleanCtor::call(const Managed *, Scope &scope, CallData *callData)
{
bool value = callData->argc ? callData->args[0].toBoolean() : 0;
- return Encode(value);
+ scope.result = Encode(value);
}
void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor)
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index eedafa6126..17543e33e0 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -70,8 +70,8 @@ struct BooleanCtor: FunctionObject
{
V4_OBJECT2(BooleanCtor, FunctionObject)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct BooleanPrototype: BooleanObject
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index f296ffd71e..fac3d5316c 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -54,32 +54,34 @@ Heap::DataViewCtor::DataViewCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue DataViewCtor::construct(const Managed *m, CallData *callData)
+void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const Object *>(m)->engine());
Scoped<ArrayBuffer> buffer(scope, callData->argument(0));
- if (!buffer)
- return scope.engine->throwTypeError();
+ if (!buffer) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
double bo = callData->argc > 1 ? callData->args[1].toNumber() : 0;
uint byteOffset = (uint)bo;
uint bufferLength = buffer->d()->data->size;
double bl = callData->argc < 3 || callData->args[2].isUndefined() ? (bufferLength - bo) : callData->args[2].toNumber();
uint byteLength = (uint)bl;
- if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength)
- return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
+ if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) {
+ scope.result = scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
+ return;
+ }
Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>());
a->d()->buffer = buffer->d();
a->d()->byteLength = byteLength;
a->d()->byteOffset = byteOffset;
- return a.asReturnedValue();
-
+ scope.result = a.asReturnedValue();
}
-ReturnedValue DataViewCtor::call(const Managed *that, CallData *callData)
+void DataViewCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 2e8e94cecd..f996a4c2f1 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -76,8 +76,8 @@ struct DataViewCtor: FunctionObject
{
V4_OBJECT2(DataViewCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct DataView : Object
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 5397ad43c5..df648ba9ee 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -466,7 +466,7 @@ static inline double ParseString(const QString &s)
if (format < Minute || format >= TimezoneHour)
error = true;
format = TimezoneHour;
- } else if (*ch == 'Z' || *ch == 0) {
+ } else if (*ch == 'Z' || ch->unicode() == 0) {
format = Done;
}
current = 0;
@@ -565,7 +565,7 @@ static inline QString ToString(double t)
{
if (std::isnan(t))
return QStringLiteral("Invalid Date");
- QString str = ToDateTime(t, Qt::LocalTime).toString() + QStringLiteral(" GMT");
+ QString str = ToDateTime(t, Qt::LocalTime).toString() + QLatin1String(" GMT");
double tzoffset = LocalTZA + DaylightSavingTA(t);
if (tzoffset) {
int hours = static_cast<int>(::fabs(tzoffset) / 1000 / 60 / 60);
@@ -651,9 +651,8 @@ Heap::DateCtor::DateCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue DateCtor::construct(const Managed *m, CallData *callData)
+void DateCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const DateCtor *>(m)->engine());
double t = 0;
if (callData->argc == 0)
@@ -687,13 +686,13 @@ ReturnedValue DateCtor::construct(const Managed *m, CallData *callData)
t = TimeClip(UTC(t));
}
- return Encode(scope.engine->newDateObject(Primitive::fromDouble(t)));
+ scope.result = Encode(scope.engine->newDateObject(Primitive::fromDouble(t)));
}
-ReturnedValue DateCtor::call(const Managed *m, CallData *)
+void DateCtor::call(const Managed *m, Scope &scope, CallData *)
{
double t = currentTime();
- return static_cast<const DateCtor *>(m)->engine()->newString(ToString(t))->asReturnedValue();
+ scope.result = static_cast<const DateCtor *>(m)->engine()->newString(ToString(t));
}
void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -1311,7 +1310,8 @@ ReturnedValue DatePrototype::method_toJSON(CallContext *ctx)
ScopedCallData callData(scope);
callData->thisObject = ctx->thisObject();
- return toIso->call(callData);
+ toIso->call(scope, callData);
+ return scope.result.asReturnedValue();
}
void DatePrototype::timezoneUpdated()
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index e3615d76a7..13e9e04040 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -104,8 +104,8 @@ struct DateCtor: FunctionObject
{
V4_OBJECT2(DateCtor, FunctionObject)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *);
};
struct DatePrototype: DateObject
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 9dca7e9979..3b589a41f1 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -59,6 +59,19 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Debugging {
+#ifdef QT_NO_QML_DEBUGGER
+
+struct Debugger
+{
+ bool pauseAtNextOpportunity() const { return false; }
+ void maybeBreakAtInstruction() {}
+ void enteringFunction() {}
+ void leavingFunction(const ReturnedValue &) {}
+ void aboutToThrow() {}
+};
+
+#else
+
class Q_QML_EXPORT Debugger : public QObject
{
Q_OBJECT
@@ -72,6 +85,8 @@ public:
virtual void aboutToThrow() = 0;
};
+#endif // QT_NO_QML_DEBUGGING
+
} // namespace Debugging
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 15a4ed2e56..f5bae4b258 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -136,8 +136,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, currentContext(0)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
- , debugger(0)
- , profiler(0)
, globalCode(0)
, v8Engine(0)
, argumentsAccessors(0)
@@ -145,6 +143,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
, regExpCache(0)
, m_multiplyWrappedQObjects(0)
+#ifndef QT_NO_QML_DEBUGGER
+ , m_debugger(0)
+ , m_profiler(0)
+#endif
{
if (maxCallDepth == -1) {
bool ok = false;
@@ -442,10 +444,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
ExecutionEngine::~ExecutionEngine()
{
- delete debugger;
- debugger = 0;
- delete profiler;
- profiler = 0;
+#ifndef QT_NO_QML_DEBUGGER
+ delete m_debugger;
+ m_debugger = 0;
+ delete m_profiler;
+ m_profiler = 0;
+#endif
delete m_multiplyWrappedQObjects;
m_multiplyWrappedQObjects = 0;
delete identifierTable;
@@ -467,17 +471,19 @@ ExecutionEngine::~ExecutionEngine()
delete [] argumentsAccessors;
}
-void ExecutionEngine::setDebugger(Debugging::Debugger *debugger_)
+#ifndef QT_NO_QML_DEBUGGER
+void ExecutionEngine::setDebugger(Debugging::Debugger *debugger)
{
- Q_ASSERT(!debugger);
- debugger = debugger_;
+ Q_ASSERT(!m_debugger);
+ m_debugger = debugger;
}
-void ExecutionEngine::enableProfiler()
+void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
{
- Q_ASSERT(!profiler);
- profiler = new QV4::Profiling::Profiler(this);
+ Q_ASSERT(!m_profiler);
+ m_profiler = profiler;
}
+#endif // QT_NO_QML_DEBUGGER
void ExecutionEngine::initRootContext()
{
@@ -910,8 +916,8 @@ ReturnedValue ExecutionEngine::throwError(const Value &value)
else
exceptionStackTrace = stackTrace();
- if (debugger)
- debugger->aboutToThrow();
+ if (QV4::Debugging::Debugger *debug = debugger())
+ debug->aboutToThrow();
return Encode::undefined();
}
@@ -969,7 +975,7 @@ ReturnedValue ExecutionEngine::throwReferenceError(const Value &value)
{
Scope scope(this);
ScopedString s(scope, value.toString(this));
- QString msg = s->toQString() + QStringLiteral(" is not defined");
+ QString msg = s->toQString() + QLatin1String(" is not defined");
ScopedObject error(scope, newReferenceErrorObject(msg));
return throwError(error);
}
@@ -993,7 +999,7 @@ ReturnedValue ExecutionEngine::throwRangeError(const Value &value)
{
Scope scope(this);
ScopedString s(scope, value.toString(this));
- QString msg = s->toQString() + QStringLiteral(" out of range");
+ QString msg = s->toQString() + QLatin1String(" out of range");
ScopedObject error(scope, newRangeErrorObject(msg));
return throwError(error);
}
@@ -1137,7 +1143,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return ld->d()->locale;
if (const QV4::DateObject *d = value.as<DateObject>())
return d->toQDateTime();
- if (const QV4::ArrayBuffer *d = value.as<ArrayBuffer>())
+ if (const ArrayBuffer *d = value.as<ArrayBuffer>())
return d->asByteArray();
// NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
@@ -1265,6 +1271,8 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::Encode(*reinterpret_cast<const double*>(ptr));
case QMetaType::QString:
return newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
+ case QMetaType::QByteArray:
+ return newArrayBuffer(*reinterpret_cast<const QByteArray*>(ptr))->asReturnedValue();
case QMetaType::Float:
return QV4::Encode(*reinterpret_cast<const float*>(ptr));
case QMetaType::Short:
@@ -1441,6 +1449,8 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
return QV4::Encode(*reinterpret_cast<const double*>(data));
case QMetaType::QString:
return newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
+ case QMetaType::QByteArray:
+ return newArrayBuffer(*reinterpret_cast<const QByteArray*>(data))->asReturnedValue();
case QMetaType::Float:
return QV4::Encode(*reinterpret_cast<const float*>(data));
case QMetaType::Short:
@@ -1502,6 +1512,11 @@ void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject)
Q_UNUSED(baseObject);
}
+void ExecutionEngine::failStackLimitCheck(Scope &scope)
+{
+ scope.result = throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
+}
+
// Converts a JS value to a meta-type.
// data must point to a place that can store a value of the given type.
// Returns true if conversion succeeded, false otherwise.
@@ -1533,6 +1548,12 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
else
*reinterpret_cast<QString*>(data) = value->toQString();
return true;
+ case QMetaType::QByteArray:
+ if (const ArrayBuffer *ab = value->as<ArrayBuffer>())
+ *reinterpret_cast<QByteArray*>(data) = ab->asByteArray();
+ else
+ *reinterpret_cast<QByteArray*>(data) = QByteArray();
+ return true;
case QMetaType::Float:
*reinterpret_cast<float*>(data) = value->toNumber();
return true;
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index aeb2533d35..f42f727295 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -54,7 +54,7 @@
#include "private/qv4isel_p.h"
#include "qv4managed_p.h"
#include "qv4context_p.h"
-#include "qv4internalclass_p.h"
+#include "qv4runtimeapi_p.h"
#include <private/qintrusivelist_p.h>
#ifndef V4_BOOTSTRAP
@@ -85,6 +85,9 @@ namespace CompiledData {
struct CompilationUnit;
}
+struct InternalClass;
+struct InternalClassPool;
+
struct Q_QML_EXPORT ExecutionEngine
{
private:
@@ -109,6 +112,8 @@ public:
Value *jsStackLimit;
+ Runtime runtime;
+
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
enum { JSStackLimit = 4*1024*1024 };
@@ -132,9 +137,6 @@ public:
IdentifierTable *identifierTable;
- QV4::Debugging::Debugger *debugger;
- QV4::Profiling::Profiler *profiler;
-
Object *globalObject;
Function *globalCode;
@@ -377,8 +379,19 @@ public:
ExecutionEngine(EvalISelFactory *iselFactory = 0);
~ExecutionEngine();
+#ifdef QT_NO_QML_DEBUGGER
+ QV4::Debugging::Debugger *debugger() const { return nullptr; }
+ QV4::Profiling::Profiler *profiler() const { return nullptr; }
+
+ void setDebugger(Debugging::Debugger *) {}
+ void setProfiler(Profiling::Profiler *) {}
+#else
+ QV4::Debugging::Debugger *debugger() const { return m_debugger; }
+ QV4::Profiling::Profiler *profiler() const { return m_profiler; }
+
void setDebugger(Debugging::Debugger *debugger);
- void enableProfiler();
+ void setProfiler(Profiling::Profiler *profiler);
+#endif // QT_NO_QML_DEBUGGER
ExecutionContext *pushGlobalContext();
void pushContext(Heap::ExecutionContext *context);
@@ -475,9 +488,28 @@ public:
void assertObjectBelongsToEngine(const Heap::Base &baseObject);
- bool checkStackLimits(ReturnedValue &exception);
+ bool checkStackLimits(Scope &scope);
+
+private:
+ void failStackLimitCheck(Scope &scope);
+
+#ifndef QT_NO_QML_DEBUGGER
+ QV4::Debugging::Debugger *m_debugger;
+ QV4::Profiling::Profiler *m_profiler;
+#endif
};
+// This is a trick to tell the code generators that functions taking a NoThrowContext won't
+// throw exceptions and therefore don't need a check after the call.
+#ifndef V4_BOOTSTRAP
+struct NoThrowEngine : public ExecutionEngine
+{
+};
+#else
+struct NoThrowEngine;
+#endif
+
+
inline void ExecutionEngine::pushContext(Heap::ExecutionContext *context)
{
Q_ASSERT(currentContext && context);
@@ -557,7 +589,7 @@ inline void Value::mark(ExecutionEngine *e)
o->mark(e);
}
-#define CHECK_STACK_LIMITS(v4) { ReturnedValue e; if ((v4)->checkStackLimits(e)) return e; } \
+#define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \
ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
struct ExecutionEngineCallDepthRecorder
@@ -568,10 +600,10 @@ struct ExecutionEngineCallDepthRecorder
~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
};
-inline bool ExecutionEngine::checkStackLimits(ReturnedValue &exception)
+inline bool ExecutionEngine::checkStackLimits(Scope &scope)
{
if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) {
- exception = throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
+ failStackLimitCheck(scope);
return true;
}
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 9f1e6b613b..3763bf2613 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -160,13 +160,9 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx)
if (i > 0)
trace += QLatin1Char('\n');
const StackFrame &frame = This->d()->stackTrace[i];
- trace += frame.function;
- trace += QLatin1Char('@');
- trace += frame.source;
- if (frame.line >= 0) {
- trace += QLatin1Char(':');
- trace += QString::number(frame.line);
- }
+ trace += frame.function + QLatin1Char('@') + frame.source;
+ if (frame.line >= 0)
+ trace += QLatin1Char(':') + QString::number(frame.line);
}
This->d()->stack = ctx->d()->engine->newString(trace);
}
@@ -243,16 +239,15 @@ Heap::ErrorCtor::ErrorCtor(QV4::ExecutionContext *scope, const QString &name)
{
}
-ReturnedValue ErrorCtor::construct(const Managed *m, CallData *callData)
+void ErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const ErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<ErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<ErrorObject>(scope.engine, v);
}
-ReturnedValue ErrorCtor::call(const Managed *that, CallData *callData)
+void ErrorCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return static_cast<const Object *>(that)->construct(callData);
+ static_cast<const Object *>(that)->construct(scope, callData);
}
Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope)
@@ -260,11 +255,10 @@ Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue EvalErrorCtor::construct(const Managed *m, CallData *callData)
+void EvalErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const EvalErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<EvalErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<EvalErrorObject>(scope.engine, v);
}
Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope)
@@ -272,11 +266,10 @@ Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue RangeErrorCtor::construct(const Managed *m, CallData *callData)
+void RangeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const RangeErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<RangeErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<RangeErrorObject>(scope.engine, v);
}
Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope)
@@ -284,11 +277,10 @@ Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue ReferenceErrorCtor::construct(const Managed *m, CallData *callData)
+void ReferenceErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const ReferenceErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<ReferenceErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<ReferenceErrorObject>(scope.engine, v);
}
Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope)
@@ -296,11 +288,10 @@ Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue SyntaxErrorCtor::construct(const Managed *m, CallData *callData)
+void SyntaxErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const SyntaxErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<SyntaxErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<SyntaxErrorObject>(scope.engine, v);
}
Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope)
@@ -308,11 +299,10 @@ Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue TypeErrorCtor::construct(const Managed *m, CallData *callData)
+void TypeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const TypeErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<TypeErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<TypeErrorObject>(scope.engine, v);
}
Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope)
@@ -320,11 +310,10 @@ Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue URIErrorCtor::construct(const Managed *m, CallData *callData)
+void URIErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const URIErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<URIErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<URIErrorObject>(scope.engine, v);
}
void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t)
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 1ca2fedd7b..42a3d05d9f 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -221,50 +221,50 @@ struct ErrorCtor: FunctionObject
{
V4_OBJECT2(ErrorCtor, FunctionObject)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct EvalErrorCtor: ErrorCtor
{
V4_OBJECT2(EvalErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
struct RangeErrorCtor: ErrorCtor
{
V4_OBJECT2(RangeErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
};
struct ReferenceErrorCtor: ErrorCtor
{
V4_OBJECT2(ReferenceErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
struct SyntaxErrorCtor: ErrorCtor
{
V4_OBJECT2(SyntaxErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
struct TypeErrorCtor: ErrorCtor
{
V4_OBJECT2(TypeErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
struct URIErrorCtor: ErrorCtor
{
V4_OBJECT2(URIErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index f314e20863..caabee322a 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -59,7 +59,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
Q_UNUSED(engine);
internalClass = engine->emptyClass;
- const quint32 *formalsIndices = compiledFunction->formalsTable();
+ const CompiledData::LEUInt32 *formalsIndices = compiledFunction->formalsTable();
// iterate backwards, so we get the right ordering for duplicate names
Scope scope(engine);
ScopedString arg(scope);
@@ -78,7 +78,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
}
nFormals = compiledFunction->nFormals;
- const quint32 *localsIndices = compiledFunction->localsTable();
+ const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
@@ -110,7 +110,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
}
nFormals = parameters.size();
- const quint32 *localsIndices = compiledFunction->localsTable();
+ const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 5d2c57a2ba..6b9c552350 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -166,14 +166,6 @@ ReturnedValue FunctionObject::name() const
return get(scope()->engine->id_name());
}
-
-ReturnedValue FunctionObject::newInstance()
-{
- Scope scope(internalClass()->engine);
- ScopedCallData callData(scope);
- return construct(callData);
-}
-
ReturnedValue FunctionObject::construct(const Managed *that, CallData *)
{
return static_cast<const FunctionObject *>(that)->engine()->throwTypeError();
@@ -251,9 +243,8 @@ Heap::FunctionCtor::FunctionCtor(QV4::ExecutionContext *scope)
}
// 15.3.2
-ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData)
+void FunctionCtor::construct(const Managed *that, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const Object *>(that)->engine());
Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that));
QString arguments;
@@ -266,8 +257,10 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData)
}
body = callData->args[callData->argc - 1].toQString();
}
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1Char('}');
@@ -278,15 +271,19 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData)
const bool parsed = parser.parseExpression();
- if (!parsed)
- return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ if (!parsed) {
+ scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ return;
+ }
using namespace QQmlJS::AST;
FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
- if (!fe)
- return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ if (!fe) {
+ scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ return;
+ }
- IR::Module module(scope.engine->debugger != 0);
+ IR::Module module(scope.engine->debugger() != 0);
QQmlJS::RuntimeCodegen cg(scope.engine, f->strictMode());
cg.generateFromFunctionExpression(QString(), function, fe, &module);
@@ -297,13 +294,13 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData)
Function *vmf = compilationUnit->linkToEngine(scope.engine);
ExecutionContext *global = scope.engine->rootContext();
- return FunctionObject::createScriptFunction(global, vmf)->asReturnedValue();
+ scope.result = FunctionObject::createScriptFunction(global, vmf);
}
// 15.3.1: This is equivalent to new Function(...)
-ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData)
+void FunctionCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
DEFINE_OBJECT_VTABLE(FunctionPrototype);
@@ -376,7 +373,8 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
}
callData->thisObject = ctx->argument(0);
- return o->call(callData);
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
@@ -393,7 +391,9 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
callData->args[i - 1] = ctx->args()[i];
}
callData->thisObject = ctx->argument(0);
- return o->call(callData);
+
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
@@ -422,19 +422,20 @@ Heap::ScriptFunction::ScriptFunction(QV4::ExecutionContext *scope, Function *fun
{
}
-ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData)
+void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
- InternalClass *ic = scope.engine->emptyClass;
+ InternalClass *ic = v4->emptyClass;
ScopedObject proto(scope, f->protoForConstructor());
ScopedObject obj(scope, v4->newObject(ic, proto));
@@ -442,39 +443,37 @@ ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData)
Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData));
v4->pushContext(ctx);
- ScopedValue result(scope, Q_V4_PROFILE(v4, f->function()));
+ scope.result = Q_V4_PROFILE(v4, f->function());
if (f->function()->compiledFunction->hasQmlDependencies())
- QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction);
-
- if (v4->hasException)
- return Encode::undefined();
+ QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
- if (result->isObject())
- return result->asReturnedValue();
- return obj.asReturnedValue();
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ } else if (!scope.result.isObject()) {
+ scope.result = obj.asReturnedValue();
+ }
}
-ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData)
+void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData));
v4->pushContext(ctx);
- ScopedValue result(scope, Q_V4_PROFILE(v4, f->function()));
+ scope.result = Q_V4_PROFILE(v4, f->function());
if (f->function()->compiledFunction->hasQmlDependencies())
- QQmlPropertyCapture::registerQmlDependencies(scope.engine, f->function()->compiledFunction);
-
- return result->asReturnedValue();
+ QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
}
DEFINE_OBJECT_VTABLE(SimpleScriptFunction);
@@ -511,14 +510,15 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F
}
}
-ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *callData)
+void SimpleScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that));
@@ -542,24 +542,24 @@ ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *cal
v4->pushContext(&ctx);
Q_ASSERT(v4->current == &ctx);
- ScopedObject result(scope, Q_V4_PROFILE(v4, f->function()));
+ scope.result = Q_V4_PROFILE(v4, f->function());
if (f->function()->compiledFunction->hasQmlDependencies())
- QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction);
+ QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
- if (!result)
- return callData->thisObject.asReturnedValue();
- return result.asReturnedValue();
+ if (!scope.result.isManaged() || !scope.result.managed())
+ scope.result = callData->thisObject;
}
-ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData)
+void SimpleScriptFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const SimpleScriptFunction *>(that)->internalClass()->engine;
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that));
@@ -579,12 +579,10 @@ ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData
v4->pushContext(&ctx);
Q_ASSERT(v4->current == &ctx);
- ScopedValue result(scope, Q_V4_PROFILE(v4, f->function()));
+ scope.result = Q_V4_PROFILE(v4, f->function());
if (f->function()->compiledFunction->hasQmlDependencies())
- QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction);
-
- return result->asReturnedValue();
+ QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
}
Heap::Object *SimpleScriptFunction::protoForConstructor()
@@ -606,20 +604,21 @@ Heap::BuiltinFunction::BuiltinFunction(QV4::ExecutionContext *scope, QV4::String
{
}
-ReturnedValue BuiltinFunction::construct(const Managed *f, CallData *)
+void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
{
- return static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
+ scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
}
-ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData)
+void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that);
- ExecutionEngine *v4 = f->internalClass()->engine;
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
CallContext::Data ctx(v4);
@@ -630,18 +629,19 @@ ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData)
v4->pushContext(&ctx);
Q_ASSERT(v4->current == &ctx);
- return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext));
+ scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext));
}
-ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData)
+void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that);
- ExecutionEngine *v4 = f->internalClass()->engine;
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
CallContext::Data ctx(v4);
@@ -652,7 +652,7 @@ ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callDa
v4->pushContext(&ctx);
Q_ASSERT(v4->current == &ctx);
- return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index);
+ scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index);
}
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
@@ -685,12 +685,13 @@ Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionOb
f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
-ReturnedValue BoundFunction::call(const Managed *that, CallData *dd)
+void BoundFunction::call(const Managed *that, Scope &scope, CallData *dd)
{
const BoundFunction *f = static_cast<const BoundFunction *>(that);
- Scope scope(f->engine());
- if (scope.hasException())
- return Encode::undefined();
+ if (scope.hasException()) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<MemberData> boundArgs(scope, f->boundArgs());
ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc);
@@ -702,15 +703,16 @@ ReturnedValue BoundFunction::call(const Managed *that, CallData *dd)
}
memcpy(argp, dd->args, dd->argc*sizeof(Value));
ScopedFunctionObject t(scope, f->target());
- return t->call(callData);
+ t->call(scope, callData);
}
-ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd)
+void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd)
{
const BoundFunction *f = static_cast<const BoundFunction *>(that);
- Scope scope(f->engine());
- if (scope.hasException())
- return Encode::undefined();
+ if (scope.hasException()) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<MemberData> boundArgs(scope, f->boundArgs());
ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc);
@@ -721,7 +723,7 @@ ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd)
}
memcpy(argp, dd->args, dd->argc*sizeof(Value));
ScopedFunctionObject t(scope, f->target());
- return t->construct(callData);
+ t->construct(scope, callData);
}
void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 4a4545eca4..be80b87873 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -145,8 +145,6 @@ struct Q_QML_EXPORT FunctionObject: Object {
void init(String *name, bool createProto);
- ReturnedValue newInstance();
-
using Object::construct;
using Object::call;
static ReturnedValue construct(const Managed *that, CallData *);
@@ -178,8 +176,8 @@ struct FunctionCtor: FunctionObject
{
V4_OBJECT2(FunctionCtor, FunctionObject)
- static ReturnedValue construct(const Managed *that, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *that, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct FunctionPrototype: FunctionObject
@@ -202,20 +200,20 @@ struct Q_QML_EXPORT BuiltinFunction: FunctionObject {
return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code);
}
- static ReturnedValue construct(const Managed *, CallData *);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct IndexedBuiltinFunction: FunctionObject
{
V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *)
+ static void construct(const Managed *m, Scope &scope, CallData *)
{
- return static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError();
+ scope.result = static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError();
}
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scope, uint index,
@@ -231,8 +229,8 @@ struct SimpleScriptFunction: FunctionObject {
V4_OBJECT2(SimpleScriptFunction, FunctionObject)
V4_INTERNALCLASS(simpleScriptFunctionClass)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
Heap::Object *protoForConstructor();
};
@@ -240,8 +238,8 @@ struct SimpleScriptFunction: FunctionObject {
struct ScriptFunction: SimpleScriptFunction {
V4_OBJECT2(ScriptFunction, FunctionObject)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
@@ -257,8 +255,8 @@ struct BoundFunction: FunctionObject {
Value boundThis() const { return d()->boundThis; }
Heap::MemberData *boundArgs() const { return d()->boundArgs; }
- static ReturnedValue construct(const Managed *, CallData *d);
- static ReturnedValue call(const Managed *that, CallData *dd);
+ static void construct(const Managed *, Scope &scope, CallData *d);
+ static void call(const Managed *that, Scope &scope, CallData *dd);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 2c767e3302..b88e271a26 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -338,13 +338,14 @@ Heap::EvalFunction::EvalFunction(QV4::ExecutionContext *scope)
f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1));
}
-ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const
+void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) const
{
- if (callData->argc < 1)
- return Encode::undefined();
+ if (callData->argc < 1) {
+ scope.result = Encode::undefined();
+ return;
+ }
ExecutionEngine *v4 = engine();
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
ExecutionContext *currentContext = v4->currentContext;
@@ -356,8 +357,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const
ctx = v4->pushGlobalContext();
}
- if (!callData->args[0].isString())
- return callData->args[0].asReturnedValue();
+ if (!callData->args[0].isString()) {
+ scope.result = callData->args[0].asReturnedValue();
+ return;
+ }
const QString code = callData->args[0].stringValue()->toQString();
bool inheritContext = !ctx->d()->strictMode;
@@ -366,18 +369,23 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const
script.strictMode = (directCall && currentContext->d()->strictMode);
script.inheritContext = inheritContext;
script.parse();
- if (v4->hasException)
- return Encode::undefined();
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
Function *function = script.function();
- if (!function)
- return Encode::undefined();
+ if (!function) {
+ scope.result = Encode::undefined();
+ return;
+ }
if (function->isStrict() || (ctx->d()->strictMode)) {
ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function));
ScopedCallData callData(scope, 0);
callData->thisObject = ctx->thisObject();
- return e->call(callData);
+ e->call(scope, callData);
+ return;
}
ContextStateSaver stateSaver(scope, ctx);
@@ -386,14 +394,14 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const
ctx->d()->strictMode = false;
ctx->d()->compilationUnit = function->compilationUnit;
- return Q_V4_PROFILE(ctx->engine(), function);
+ scope.result = Q_V4_PROFILE(ctx->engine(), function);
}
-ReturnedValue EvalFunction::call(const Managed *that, CallData *callData)
+void EvalFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
// indirect call
- return static_cast<const EvalFunction *>(that)->evalCall(callData, false);
+ static_cast<const EvalFunction *>(that)->evalCall(scope, callData, false);
}
@@ -512,7 +520,7 @@ ReturnedValue GlobalFunctions::method_parseFloat(CallContext *ctx)
if (trimmed.startsWith(QLatin1String("Infinity"))
|| trimmed.startsWith(QLatin1String("+Infinity")))
return Encode(Q_INFINITY);
- if (trimmed.startsWith(QStringLiteral("-Infinity")))
+ if (trimmed.startsWith(QLatin1String("-Infinity")))
return Encode(-Q_INFINITY);
QByteArray ba = trimmed.toLatin1();
bool ok;
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index ea7a3b06ce..403639f8c1 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -69,9 +69,9 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject
{
V4_OBJECT2(EvalFunction, FunctionObject)
- ReturnedValue evalCall(CallData *callData, bool directCall) const;
+ void evalCall(Scope &scope, CallData *callData, bool directCall) const;
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct GlobalFunctions
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp
index c8d66b1254..6260fd0cc8 100644
--- a/src/qml/jsruntime/qv4identifier.cpp
+++ b/src/qml/jsruntime/qv4identifier.cpp
@@ -64,12 +64,33 @@ IdentifierHashData::IdentifierHashData(int numBits)
memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
}
+IdentifierHashData::IdentifierHashData(IdentifierHashData *other)
+ : size(other->size)
+ , numBits(other->numBits)
+ , identifierTable(other->identifierTable)
+{
+ refCount.store(1);
+ alloc = other->alloc;
+ entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
+ memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry));
+}
+
IdentifierHashBase::IdentifierHashBase(ExecutionEngine *engine)
{
d = new IdentifierHashData(3);
d->identifierTable = engine->identifierTable;
}
+void IdentifierHashBase::detach()
+{
+ if (!d || d->refCount == 1)
+ return;
+ IdentifierHashData *newData = new IdentifierHashData(d);
+ if (d && !d->refCount.deref())
+ delete d;
+ d = newData;
+}
+
IdentifierHashEntry *IdentifierHashBase::addEntry(const Identifier *identifier)
{
@@ -131,7 +152,7 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(const QString &str) const
return 0;
Q_ASSERT(d->entries);
- uint hash = String::createHashValue(str.constData(), str.length());
+ uint hash = String::createHashValue(str.constData(), str.length(), Q_NULLPTR);
uint idx = hash % d->alloc;
while (1) {
if (!d->entries[idx].identifier)
diff --git a/src/qml/jsruntime/qv4identifier_p.h b/src/qml/jsruntime/qv4identifier_p.h
index a3abfd8e13..2695bbc875 100644
--- a/src/qml/jsruntime/qv4identifier_p.h
+++ b/src/qml/jsruntime/qv4identifier_p.h
@@ -85,6 +85,7 @@ struct IdentifierHashEntry {
struct IdentifierHashData
{
IdentifierHashData(int numBits);
+ explicit IdentifierHashData(IdentifierHashData *other);
~IdentifierHashData() {
free(entries);
}
@@ -115,6 +116,8 @@ struct IdentifierHashBase
bool contains(const QString &str) const;
bool contains(String *str) const;
+ void detach();
+
protected:
IdentifierHashEntry *addEntry(const Identifier *i);
const IdentifierHashEntry *lookup(const Identifier *identifier) const;
@@ -141,6 +144,7 @@ struct IdentifierHash : public IdentifierHashBase
}
void add(const QString &str, const T &value);
+ void add(Heap::String *str, const T &value);
inline T value(const QString &str) const;
inline T value(String *str) const;
@@ -198,6 +202,13 @@ void IdentifierHash<T>::add(const QString &str, const T &value)
}
template<typename T>
+void IdentifierHash<T>::add(Heap::String *str, const T &value)
+{
+ IdentifierHashEntry *e = addEntry(toIdentifier(str));
+ e->value = value;
+}
+
+template<typename T>
inline T IdentifierHash<T>::value(const QString &str) const
{
return IdentifierHashEntry::get(lookup(str), (T*)0);
@@ -223,7 +234,6 @@ QString IdentifierHash<T>::findId(T value) const
return QString();
}
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index 5adb17b4ea..3def6defbf 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -118,7 +118,8 @@ void IdentifierTable::addEntry(Heap::String *str)
Heap::String *IdentifierTable::insertString(const QString &s)
{
- uint hash = String::createHashValue(s.constData(), s.length());
+ uint subtype;
+ uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
uint idx = hash % alloc;
while (Heap::String *e = entries[idx]) {
if (e->stringHash == hash && e->toQString() == s)
@@ -128,6 +129,8 @@ Heap::String *IdentifierTable::insertString(const QString &s)
}
Heap::String *str = engine->newString(s);
+ str->stringHash = hash;
+ str->subtype = subtype;
addEntry(str);
return str;
}
@@ -178,7 +181,8 @@ Identifier *IdentifierTable::identifier(const QString &s)
Identifier *IdentifierTable::identifier(const char *s, int len)
{
- uint hash = String::createHashValue(s, len);
+ uint subtype;
+ uint hash = String::createHashValue(s, len, &subtype);
if (hash == UINT_MAX)
return identifier(QString::fromUtf8(s, len));
@@ -192,6 +196,8 @@ Identifier *IdentifierTable::identifier(const char *s, int len)
}
Heap::String *str = engine->newString(QString::fromLatin1(s, len));
+ str->stringHash = hash;
+ str->subtype = subtype;
addEntry(str);
return str->identifier;
}
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 29f83da522..c33d2cad11 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -41,8 +41,10 @@
#include "qv4scopedvalue_p.h"
#include <QtQml/qjsengine.h>
+#ifndef QT_NO_NETWORK
#include <QtNetwork/qnetworkrequest.h>
#include <QtNetwork/qnetworkreply.h>
+#endif
#include <QtCore/qfile.h>
#include <QtQml/qqmlfile.h>
@@ -57,7 +59,10 @@ QT_BEGIN_NAMESPACE
QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine,
QV4::QmlContext *qmlContext, const QV4::Value &callback)
- : v4(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0)
+ : v4(engine), m_url(url)
+#ifndef QT_NO_NETWORK
+ , m_redirectCount(0), m_network(0) , m_reply(0)
+#endif
{
if (qmlContext)
m_qmlContext.set(engine, *qmlContext);
@@ -66,6 +71,7 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine,
m_resultObject.set(v4, resultValue(v4));
+#ifndef QT_NO_NETWORK
m_network = engine->v8Engine->networkAccessManager();
QNetworkRequest request;
@@ -73,11 +79,17 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine,
m_reply = m_network->get(request);
QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+#else
+ finished();
+#endif
}
QV4Include::~QV4Include()
{
- delete m_reply; m_reply = 0;
+#ifndef QT_NO_NETWORK
+ delete m_reply;
+ m_reply = 0;
+#endif
}
QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status status)
@@ -110,7 +122,7 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status)
QV4::ScopedCallData callData(scope, 1);
callData->thisObject = v4->globalObject->asReturnedValue();
callData->args[0] = status;
- f->call(callData);
+ f->call(scope, callData);
if (scope.hasException())
scope.engine->catchException();
}
@@ -123,6 +135,7 @@ QV4::ReturnedValue QV4Include::result()
#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
void QV4Include::finished()
{
+#ifndef QT_NO_NETWORK
m_redirectCount++;
if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
@@ -166,6 +179,12 @@ void QV4Include::finished()
} else {
resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError)));
}
+#else
+ QV4::Scope scope(v4);
+ QV4::ScopedObject resultObj(scope, m_resultObject.value());
+ QV4::ScopedString status(scope, v4->newString(QStringLiteral("status")));
+ resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError)));
+#endif //QT_NO_NETWORK
QV4::ScopedValue cb(scope, m_callbackFunction.value());
callback(cb, resultObj);
@@ -188,14 +207,15 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
if (!context || !context->isJSContext)
V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
- QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow()));
- if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor())
- url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile);
-
QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue());
if (ctx->argc() >= 2 && ctx->args()[1].as<QV4::FunctionObject>())
callbackFunction = ctx->args()[1];
+#ifndef QT_NO_NETWORK
+ QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow()));
+ if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor())
+ url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile);
+
QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
QV4::ScopedValue result(scope);
@@ -243,6 +263,12 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
}
return result->asReturnedValue();
+#else
+ QV4::ScopedValue result(scope);
+ result = resultValue(scope.engine, NetworkError);
+ callback(callbackFunction, result);
+ return result->asReturnedValue();
+#endif
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h
index 257dc05e65..1750e6a7e1 100644
--- a/src/qml/jsruntime/qv4include_p.h
+++ b/src/qml/jsruntime/qv4include_p.h
@@ -62,7 +62,9 @@
QT_BEGIN_NAMESPACE
class QQmlEngine;
+#ifndef QT_NO_NETWORK
class QNetworkAccessManager;
+#endif
class QNetworkReply;
class QV4Include : public QObject
{
@@ -90,15 +92,16 @@ private:
static void callback(const QV4::Value &callback, const QV4::Value &status);
QV4::ExecutionEngine *v4;
- QNetworkAccessManager *m_network;
- QPointer<QNetworkReply> m_reply;
-
QUrl m_url;
+
+#ifndef QT_NO_NETWORK
int m_redirectCount;
+ QNetworkAccessManager *m_network;
+ QPointer<QNetworkReply> m_reply;
+#endif
QV4::PersistentValue m_callbackFunction;
QV4::PersistentValue m_resultObject;
-
QV4::PersistentValue m_qmlContext;
};
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index af359bc0d3..bac45e18c8 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -101,20 +101,6 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
++d->size;
}
-uint PropertyHash::lookup(const Identifier *identifier) const
-{
- Q_ASSERT(d->entries);
-
- uint idx = identifier->hashValue % d->alloc;
- while (1) {
- if (d->entries[idx].identifier == identifier)
- return d->entries[idx].index;
- if (!d->entries[idx].identifier)
- return UINT_MAX;
- ++idx;
- idx %= d->alloc;
- }
-}
InternalClass::InternalClass(ExecutionEngine *engine)
: engine(engine)
@@ -360,18 +346,6 @@ void InternalClass::removeMember(Object *object, Identifier *id)
Q_ASSERT(t.lookup);
}
-uint InternalClass::find(const String *string)
-{
- engine->identifierTable->identifier(string);
- const Identifier *id = string->d()->identifier;
-
- uint index = propertyTable.lookup(id);
- if (index < size)
- return index;
-
- return UINT_MAX;
-}
-
uint InternalClass::find(const Identifier *id)
{
uint index = propertyTable.lookup(id);
@@ -429,11 +403,13 @@ InternalClass *InternalClass::propertiesFrozen() const
void InternalClass::destroy()
{
- QList<InternalClass *> destroyStack;
- destroyStack.append(this);
+ std::vector<InternalClass *> destroyStack;
+ destroyStack.reserve(64);
+ destroyStack.push_back(this);
- while (!destroyStack.isEmpty()) {
- InternalClass *next = destroyStack.takeLast();
+ while (!destroyStack.empty()) {
+ InternalClass *next = destroyStack.back();
+ destroyStack.pop_back();
if (!next->engine)
continue;
next->engine = 0;
@@ -441,13 +417,13 @@ void InternalClass::destroy()
next->nameMap.~SharedInternalClassData<Identifier *>();
next->propertyData.~SharedInternalClassData<PropertyAttributes>();
if (next->m_sealed)
- destroyStack.append(next->m_sealed);
+ destroyStack.push_back(next->m_sealed);
if (next->m_frozen)
- destroyStack.append(next->m_frozen);
+ destroyStack.push_back(next->m_frozen);
for (size_t i = 0; i < next->transitions.size(); ++i) {
Q_ASSERT(next->transitions.at(i).lookup);
- destroyStack.append(next->transitions.at(i).lookup);
+ destroyStack.push_back(next->transitions.at(i).lookup);
}
next->transitions.~vector<Transition>();
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index c10af4ce01..dcda949c97 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -54,6 +54,8 @@
#include <QHash>
#include <private/qqmljsmemorypool_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4identifiertable_p.h>
QT_BEGIN_NAMESPACE
@@ -117,6 +119,20 @@ inline PropertyHash::~PropertyHash()
delete d;
}
+inline uint PropertyHash::lookup(const Identifier *identifier) const
+{
+ Q_ASSERT(d->entries);
+
+ uint idx = identifier->hashValue % d->alloc;
+ while (1) {
+ if (d->entries[idx].identifier == identifier)
+ return d->entries[idx].index;
+ if (!d->entries[idx].identifier)
+ return UINT_MAX;
+ ++idx;
+ idx %= d->alloc;
+ }
+}
template <typename T>
struct SharedInternalClassData {
@@ -245,7 +261,7 @@ struct InternalClass : public QQmlJS::Managed {
InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0);
static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0);
static void removeMember(Object *object, Identifier *id);
- uint find(const String *s);
+ uint find(const String *string);
uint find(const Identifier *id);
InternalClass *sealed();
@@ -261,6 +277,18 @@ private:
InternalClass(const InternalClass &other);
};
+inline uint InternalClass::find(const String *string)
+{
+ engine->identifierTable->identifier(string);
+ const Identifier *id = string->d()->identifier;
+
+ uint index = propertyTable.lookup(id);
+ if (index < size)
+ return index;
+
+ return UINT_MAX;
+}
+
struct InternalClassPool : public QQmlJS::MemoryPool
{
void markObjects(ExecutionEngine *engine);
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index a211d46153..5b665d8836 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -590,8 +590,7 @@ bool JsonParser::parseString(QString *string)
return false;
}
if (QChar::requiresSurrogates(ch)) {
- *string += QChar(QChar::highSurrogate(ch));
- *string += QChar(QChar::lowSurrogate(ch));
+ *string += QChar(QChar::highSurrogate(ch)) + QChar(QChar::lowSurrogate(ch));
} else {
*string += QChar(ch);
}
@@ -644,36 +643,39 @@ struct Stringify
static QString quote(const QString &str)
{
- QString product = QStringLiteral("\"");
- for (int i = 0; i < str.length(); ++i) {
+ QString product;
+ const int length = str.length();
+ product.reserve(length + 2);
+ product += QLatin1Char('"');
+ for (int i = 0; i < length; ++i) {
QChar c = str.at(i);
switch (c.unicode()) {
case '"':
- product += QStringLiteral("\\\"");
+ product += QLatin1String("\\\"");
break;
case '\\':
- product += QStringLiteral("\\\\");
+ product += QLatin1String("\\\\");
break;
case '\b':
- product += QStringLiteral("\\b");
+ product += QLatin1String("\\b");
break;
case '\f':
- product += QStringLiteral("\\f");
+ product += QLatin1String("\\f");
break;
case '\n':
- product += QStringLiteral("\\n");
+ product += QLatin1String("\\n");
break;
case '\r':
- product += QStringLiteral("\\r");
+ product += QLatin1String("\\r");
break;
case '\t':
- product += QStringLiteral("\\t");
+ product += QLatin1String("\\t");
break;
default:
if (c.unicode() <= 0x1f) {
- product += QStringLiteral("\\u00");
- product += c.unicode() > 0xf ? QLatin1Char('1') : QLatin1Char('0');
- product += QLatin1Char("0123456789abcdef"[c.unicode() & 0xf]);
+ product += QLatin1String("\\u00");
+ product += (c.unicode() > 0xf ? QLatin1Char('1') : QLatin1Char('0')) +
+ QLatin1Char("0123456789abcdef"[c.unicode() & 0xf]);
} else {
product += c;
}
@@ -686,53 +688,53 @@ static QString quote(const QString &str)
QString Stringify::Str(const QString &key, const Value &v)
{
Scope scope(v4);
+ scope.result = v;
- ScopedValue value(scope, v);
- ScopedObject o(scope, value);
+ ScopedObject o(scope, scope.result);
if (o) {
ScopedString s(scope, v4->newString(QStringLiteral("toJSON")));
ScopedFunctionObject toJSON(scope, o->get(s));
if (!!toJSON) {
ScopedCallData callData(scope, 1);
- callData->thisObject = value;
+ callData->thisObject = scope.result;
callData->args[0] = v4->newString(key);
- value = toJSON->call(callData);
+ toJSON->call(scope, callData);
}
}
if (replacerFunction) {
ScopedObject holder(scope, v4->newObject());
- holder->put(scope.engine, QString(), value);
+ holder->put(scope.engine, QString(), scope.result);
ScopedCallData callData(scope, 2);
callData->args[0] = v4->newString(key);
- callData->args[1] = value;
+ callData->args[1] = scope.result;
callData->thisObject = holder;
- value = replacerFunction->call(callData);
+ replacerFunction->call(scope, callData);
}
- o = value->asReturnedValue();
+ o = scope.result.asReturnedValue();
if (o) {
if (NumberObject *n = o->as<NumberObject>())
- value = Encode(n->value());
+ scope.result = Encode(n->value());
else if (StringObject *so = o->as<StringObject>())
- value = so->d()->string;
+ scope.result = so->d()->string;
else if (BooleanObject *b = o->as<BooleanObject>())
- value = Encode(b->value());
+ scope.result = Encode(b->value());
}
- if (value->isNull())
+ if (scope.result.isNull())
return QStringLiteral("null");
- if (value->isBoolean())
- return value->booleanValue() ? QStringLiteral("true") : QStringLiteral("false");
- if (value->isString())
- return quote(value->stringValue()->toQString());
-
- if (value->isNumber()) {
- double d = value->toNumber();
- return std::isfinite(d) ? value->toQString() : QStringLiteral("null");
+ if (scope.result.isBoolean())
+ return scope.result.booleanValue() ? QStringLiteral("true") : QStringLiteral("false");
+ if (scope.result.isString())
+ return quote(scope.result.stringValue()->toQString());
+
+ if (scope.result.isNumber()) {
+ double d = scope.result.toNumber();
+ return std::isfinite(d) ? scope.result.toQString() : QStringLiteral("null");
}
- o = value->asReturnedValue();
+ o = scope.result.asReturnedValue();
if (o) {
if (!o->as<FunctionObject>()) {
if (o->as<ArrayObject>()) {
@@ -807,10 +809,10 @@ QString Stringify::JO(Object *o)
if (partial.isEmpty()) {
result = QStringLiteral("{}");
} else if (gap.isEmpty()) {
- result = QStringLiteral("{") + partial.join(QLatin1Char(',')) + QLatin1Char('}');
+ result = QLatin1Char('{') + partial.join(QLatin1Char(',')) + QLatin1Char('}');
} else {
- QString separator = QStringLiteral(",\n") + indent;
- result = QStringLiteral("{\n") + indent + partial.join(separator) + QLatin1Char('\n')
+ QString separator = QLatin1String(",\n") + indent;
+ result = QLatin1String("{\n") + indent + partial.join(separator) + QLatin1Char('\n')
+ stepback + QLatin1Char('}');
}
@@ -853,10 +855,10 @@ QString Stringify::JA(ArrayObject *a)
if (partial.isEmpty()) {
result = QStringLiteral("[]");
} else if (gap.isEmpty()) {
- result = QStringLiteral("[") + partial.join(QLatin1Char(',')) + QStringLiteral("]");
+ result = QLatin1Char('[') + partial.join(QLatin1Char(',')) + QLatin1Char(']');
} else {
- QString separator = QStringLiteral(",\n") + indent;
- result = QStringLiteral("[\n") + indent + partial.join(separator) + QStringLiteral("\n") + stepback + QStringLiteral("]");
+ QString separator = QLatin1String(",\n") + indent;
+ result = QLatin1String("[\n") + indent + partial.join(separator) + QLatin1Char('\n') + stepback + QLatin1Char(']');
}
indent = stepback;
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 46e47307ef..42e561bc7c 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -451,7 +451,8 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
l->getter = getterFallback;
@@ -473,7 +474,8 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
l->getter = getterFallback;
@@ -498,7 +500,8 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
}
@@ -542,7 +545,8 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engin
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
l->getter = getterGeneric;
@@ -562,7 +566,8 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
l->getter = getterGeneric;
@@ -665,7 +670,8 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine)
ScopedCallData callData(scope, 0);
callData->thisObject = Primitive::undefinedValue();
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -683,7 +689,8 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine)
ScopedCallData callData(scope, 0);
callData->thisObject = Primitive::undefinedValue();
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -704,7 +711,8 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine)
ScopedCallData callData(scope, 0);
callData->thisObject = Primitive::undefinedValue();
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
}
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index cb17583b98..9fe8224736 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -80,6 +80,7 @@ Heap::MathObject::MathObject()
m->defineDefaultProperty(QStringLiteral("pow"), QV4::MathObject::method_pow, 2);
m->defineDefaultProperty(QStringLiteral("random"), QV4::MathObject::method_random, 0);
m->defineDefaultProperty(QStringLiteral("round"), QV4::MathObject::method_round, 1);
+ m->defineDefaultProperty(QStringLiteral("sign"), QV4::MathObject::method_sign, 1);
m->defineDefaultProperty(QStringLiteral("sin"), QV4::MathObject::method_sin, 1);
m->defineDefaultProperty(QStringLiteral("sqrt"), QV4::MathObject::method_sqrt, 1);
m->defineDefaultProperty(QStringLiteral("tan"), QV4::MathObject::method_tan, 1);
@@ -292,6 +293,19 @@ ReturnedValue MathObject::method_round(CallContext *context)
return Encode(v);
}
+ReturnedValue MathObject::method_sign(CallContext *context)
+{
+ double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+
+ if (std::isnan(v))
+ return Encode(qt_qnan());
+
+ if (qIsNull(v))
+ return v;
+
+ return Encode(std::signbit(v) ? -1 : 1);
+}
+
ReturnedValue MathObject::method_sin(CallContext *context)
{
double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index 2b842a312f..01e778d9ec 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -84,6 +84,7 @@ struct MathObject: Object
static ReturnedValue method_pow(CallContext *context);
static ReturnedValue method_random(CallContext *context);
static ReturnedValue method_round(CallContext *context);
+ static ReturnedValue method_sign(CallContext *context);
static ReturnedValue method_sin(CallContext *context);
static ReturnedValue method_sqrt(CallContext *context);
static ReturnedValue method_tan(CallContext *context);
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index ab3e03b183..d27eef1d79 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -45,6 +45,7 @@
#include <QtCore/qmath.h>
#include <QtCore/QDebug>
#include <cassert>
+#include <limits>
using namespace QV4;
@@ -75,17 +76,16 @@ Heap::NumberCtor::NumberCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue NumberCtor::construct(const Managed *m, CallData *callData)
+void NumberCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(m->cast<NumberCtor>()->engine());
double dbl = callData->argc ? callData->args[0].toNumber() : 0.;
- return Encode(scope.engine->newNumberObject(dbl));
+ scope.result = Encode(scope.engine->newNumberObject(dbl));
}
-ReturnedValue NumberCtor::call(const Managed *, CallData *callData)
+void NumberCtor::call(const Managed *, Scope &scope, CallData *callData)
{
double dbl = callData->argc ? callData->args[0].toNumber() : 0.;
- return Encode(dbl);
+ scope.result = Encode(dbl);
}
void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -99,12 +99,16 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
ctor->defineReadonlyProperty(QStringLiteral("NEGATIVE_INFINITY"), Primitive::fromDouble(-qInf()));
ctor->defineReadonlyProperty(QStringLiteral("POSITIVE_INFINITY"), Primitive::fromDouble(qInf()));
ctor->defineReadonlyProperty(QStringLiteral("MAX_VALUE"), Primitive::fromDouble(1.7976931348623158e+308));
+ ctor->defineReadonlyProperty(QStringLiteral("EPSILON"), Primitive::fromDouble(std::numeric_limits<double>::epsilon()));
QT_WARNING_PUSH
QT_WARNING_DISABLE_INTEL(239)
ctor->defineReadonlyProperty(QStringLiteral("MIN_VALUE"), Primitive::fromDouble(5e-324));
QT_WARNING_POP
+ ctor->defineDefaultProperty(QStringLiteral("isFinite"), method_isFinite, 1);
+ ctor->defineDefaultProperty(QStringLiteral("isNaN"), method_isNaN, 1);
+
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString);
defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString);
@@ -134,6 +138,24 @@ inline double thisNumber(ExecutionContext *ctx)
return n->value();
}
+ReturnedValue NumberPrototype::method_isFinite(CallContext *ctx)
+{
+ if (!ctx->argc())
+ return Encode(false);
+
+ double v = ctx->args()[0].toNumber();
+ return Encode(!std::isnan(v) && !qt_is_inf(v));
+}
+
+ReturnedValue NumberPrototype::method_isNaN(CallContext *ctx)
+{
+ if (!ctx->argc())
+ return Encode(false);
+
+ double v = ctx->args()[0].toNumber();
+ return Encode(std::isnan(v));
+}
+
ReturnedValue NumberPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index ca6f686304..2416165c78 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -79,14 +79,16 @@ struct NumberCtor: FunctionObject
{
V4_OBJECT2(NumberCtor, FunctionObject)
- static ReturnedValue construct(const Managed *that, CallData *callData);
- static ReturnedValue call(const Managed *, CallData *callData);
+ static void construct(const Managed *that, Scope &scope, CallData *callData);
+ static void call(const Managed *, Scope &scope, CallData *callData);
};
struct NumberPrototype: NumberObject
{
void init(ExecutionEngine *engine, Object *ctor);
+ static ReturnedValue method_isFinite(CallContext *ctx);
+ static ReturnedValue method_isNaN(CallContext *ctx);
static ReturnedValue method_toString(CallContext *ctx);
static ReturnedValue method_toLocaleString(CallContext *ctx);
static ReturnedValue method_valueOf(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 0727f35edd..aeb185049f 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -109,7 +109,8 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property
Scope scope(f->engine());
ScopedCallData callData(scope);
callData->thisObject = thisObject;
- return f->call(callData);
+ f->call(scope, callData);
+ return scope.result.asReturnedValue();
}
void Object::putValue(uint memberIndex, const Value &value)
@@ -128,7 +129,7 @@ void Object::putValue(uint memberIndex, const Value &value)
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
- setter->call(callData);
+ setter->call(scope, callData);
return;
}
goto reject;
@@ -389,14 +390,14 @@ bool Object::hasOwnProperty(uint index) const
return false;
}
-ReturnedValue Object::construct(const Managed *m, CallData *)
+void Object::construct(const Managed *m, Scope &scope, CallData *)
{
- return static_cast<const Object *>(m)->engine()->throwTypeError();
+ scope.result = static_cast<const Object *>(m)->engine()->throwTypeError();
}
-ReturnedValue Object::call(const Managed *m, CallData *)
+void Object::call(const Managed *m, Scope &scope, CallData *)
{
- return static_cast<const Object *>(m)->engine()->throwTypeError();
+ scope.result = static_cast<const Object *>(m)->engine()->throwTypeError();
}
ReturnedValue Object::get(const Managed *m, String *name, bool *hasProperty)
@@ -744,7 +745,7 @@ void Object::internalPut(String *name, const Value &value)
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
- setter->call(callData);
+ setter->call(scope, callData);
return;
}
@@ -753,9 +754,8 @@ void Object::internalPut(String *name, const Value &value)
reject:
if (engine()->current->strictMode) {
- QString message = QStringLiteral("Cannot assign to read-only property \"");
- message += name->toQString();
- message += QLatin1Char('\"');
+ QString message = QLatin1String("Cannot assign to read-only property \"") +
+ name->toQString() + QLatin1Char('\"');
engine()->throwTypeError(message);
}
}
@@ -815,7 +815,7 @@ void Object::internalPutIndexed(uint index, const Value &value)
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
- setter->call(callData);
+ setter->call(scope, callData);
return;
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index e4431a9fc9..b68dbc27b7 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -56,6 +56,7 @@
#include "qv4engine_p.h"
#include "qv4scopedvalue_p.h"
#include "qv4value_p.h"
+#include "qv4internalclass_p.h"
QT_BEGIN_NAMESPACE
@@ -112,8 +113,8 @@ struct Object : Base {
struct ObjectVTable
{
VTable vTable;
- ReturnedValue (*call)(const Managed *, CallData *data);
- ReturnedValue (*construct)(const Managed *, CallData *data);
+ void (*call)(const Managed *, Scope &scope, CallData *data);
+ void (*construct)(const Managed *, Scope &scope, CallData *data);
ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty);
ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty);
void (*put)(Managed *, String *name, const Value &value);
@@ -324,14 +325,14 @@ public:
{ vtable()->advanceIterator(this, it, name, index, p, attributes); }
uint getLength() const { return vtable()->getLength(this); }
- inline ReturnedValue construct(CallData *d) const
- { return vtable()->construct(this, d); }
- inline ReturnedValue call(CallData *d) const
- { return vtable()->call(this, d); }
+ inline void construct(Scope &scope, CallData *d) const
+ { return vtable()->construct(this, scope, d); }
+ inline void call(Scope &scope, CallData *d) const
+ { vtable()->call(this, scope, d); }
protected:
static void markObjects(Heap::Base *that, ExecutionEngine *e);
- static ReturnedValue construct(const Managed *m, CallData *);
- static ReturnedValue call(const Managed *m, CallData *);
+ static void construct(const Managed *m, Scope &scope, CallData *);
+ static void call(const Managed *m, Scope &scope, CallData *);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
static void put(Managed *m, String *name, const Value &value);
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 015294e48a..cfd76166f2 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -59,28 +59,30 @@ Heap::ObjectCtor::ObjectCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue ObjectCtor::construct(const Managed *that, CallData *callData)
+void ObjectCtor::construct(const Managed *that, Scope &scope, CallData *callData)
{
const ObjectCtor *ctor = static_cast<const ObjectCtor *>(that);
ExecutionEngine *v4 = ctor->engine();
- Scope scope(v4);
if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) {
ScopedObject obj(scope, v4->newObject());
ScopedObject proto(scope, ctor->get(v4->id_prototype()));
if (!!proto)
obj->setPrototype(proto);
- return obj.asReturnedValue();
+ scope.result = obj.asReturnedValue();
+ } else {
+ scope.result = RuntimeHelpers::toObject(scope.engine, callData->args[0]);
}
- return RuntimeHelpers::toObject(scope.engine, callData->args[0]);
}
-ReturnedValue ObjectCtor::call(const Managed *m, CallData *callData)
+void ObjectCtor::call(const Managed *m, Scope &scope, CallData *callData)
{
const ObjectCtor *ctor = static_cast<const ObjectCtor *>(m);
ExecutionEngine *v4 = ctor->engine();
- if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull())
- return v4->newObject()->asReturnedValue();
- return RuntimeHelpers::toObject(v4, callData->args[0]);
+ if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) {
+ scope.result = v4->newObject()->asReturnedValue();
+ } else {
+ scope.result = RuntimeHelpers::toObject(v4, callData->args[0]);
+ }
}
void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
@@ -413,7 +415,8 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx)
return ctx->engine()->throwTypeError();
ScopedCallData callData(scope);
callData->thisObject = o;
- return f->call(callData);
+ f->call(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx)
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index ac1964103e..47a37b196f 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -70,8 +70,8 @@ struct ObjectCtor: FunctionObject
{
V4_OBJECT2(ObjectCtor, FunctionObject)
- static ReturnedValue construct(const Managed *that, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *that, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct ObjectPrototype: Object
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index 5b1926468a..a0ade2068f 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -118,7 +118,7 @@ public:
Managed *asManaged() const {
if (!val)
return 0;
- return val->as<Managed>();
+ return val->managed();
}
template<typename T>
T *as() const {
@@ -167,7 +167,7 @@ public:
Managed *asManaged() const {
if (!val)
return 0;
- return val->as<Managed>();
+ return val->managed();
}
template <typename T>
T *as() const {
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index a59190b846..349ec48e06 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -48,13 +48,10 @@ namespace Profiling {
FunctionLocation FunctionCall::resolveLocation() const
{
- FunctionLocation location = {
- m_function->name()->toQString(),
- m_function->compilationUnit->fileName(),
- m_function->compiledFunction->location.line,
- m_function->compiledFunction->location.column
- };
- return location;
+ return FunctionLocation(m_function->name()->toQString(),
+ m_function->compilationUnit->fileName(),
+ m_function->compiledFunction->location.line,
+ m_function->compiledFunction->location.column);
}
FunctionCallProperties FunctionCall::properties() const
@@ -81,7 +78,8 @@ Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(
void Profiler::stopProfiling()
{
featuresEnabled = 0;
- reportData();
+ reportData(true);
+ m_sentLocations.clear();
}
bool operator<(const FunctionCall &call1, const FunctionCall &call2)
@@ -91,16 +89,24 @@ bool operator<(const FunctionCall &call1, const FunctionCall &call2)
(call1.m_end == call2.m_end && call1.m_function < call2.m_function)));
}
-void Profiler::reportData()
+void Profiler::reportData(bool trackLocations)
{
std::sort(m_data.begin(), m_data.end());
QVector<FunctionCallProperties> properties;
- QHash<qint64, FunctionLocation> locations;
+ FunctionLocationHash locations;
properties.reserve(m_data.size());
foreach (const FunctionCall &call, m_data) {
properties.append(call.properties());
- locations[properties.constLast().id] = call.resolveLocation();
+ Function *function = call.function();
+ SentMarker &marker = m_sentLocations[reinterpret_cast<quintptr>(function)];
+ if (!trackLocations || !marker.isValid()) {
+ FunctionLocation &location = locations[properties.constLast().id];
+ if (!location.isValid())
+ location = call.resolveLocation();
+ if (trackLocations)
+ marker.setFunction(function);
+ }
}
emit dataReady(locations, properties, m_memory_data);
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index 0b4193204f..e06cb64a61 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -57,6 +57,40 @@
#include <QElapsedTimer>
+#ifdef QT_NO_QML_DEBUGGER
+
+#define Q_V4_PROFILE_ALLOC(engine, size, type) (!engine)
+#define Q_V4_PROFILE_DEALLOC(engine, size, type) (!engine)
+#define Q_V4_PROFILE(engine, function) (function->code(engine, function->codeData))
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace Profiling {
+struct Profiler {};
+}
+}
+
+QT_END_NAMESPACE
+
+#else
+
+#define Q_V4_PROFILE_ALLOC(engine, size, type)\
+ (engine->profiler() &&\
+ (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
+ engine->profiler()->trackAlloc(size, type) : false)
+
+#define Q_V4_PROFILE_DEALLOC(engine, size, type) \
+ (engine->profiler() &&\
+ (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
+ engine->profiler()->trackDealloc(size, type) : false)
+
+#define Q_V4_PROFILE(engine, function)\
+ (engine->profiler() &&\
+ (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureFunctionCall)) ?\
+ Profiling::FunctionCallProfiler::profileCall(engine->profiler(), engine, function) :\
+ function->code(engine, function->codeData))
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -81,13 +115,23 @@ struct FunctionCallProperties {
};
struct FunctionLocation {
+ FunctionLocation(const QString &name = QString(), const QString &file = QString(),
+ int line = -1, int column = -1) :
+ name(name), file(file), line(line), column(column)
+ {}
+
+ bool isValid()
+ {
+ return !name.isEmpty();
+ }
+
QString name;
QString file;
int line;
int column;
};
-typedef QHash<qint64, QV4::Profiling::FunctionLocation> FunctionLocationHash;
+typedef QHash<quintptr, QV4::Profiling::FunctionLocation> FunctionLocationHash;
struct MemoryAllocationProperties {
qint64 timestamp;
@@ -124,6 +168,11 @@ public:
return *this;
}
+ Function *function() const
+ {
+ return m_function;
+ }
+
FunctionLocation resolveLocation() const;
FunctionCallProperties properties() const;
@@ -135,48 +184,70 @@ private:
qint64 m_end;
};
-#define Q_V4_PROFILE_ALLOC(engine, size, type)\
- (engine->profiler &&\
- (engine->profiler->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
- engine->profiler->trackAlloc(size, type) : size)
-
-#define Q_V4_PROFILE_DEALLOC(engine, pointer, size, type) \
- (engine->profiler &&\
- (engine->profiler->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
- engine->profiler->trackDealloc(pointer, size, type) : pointer)
-
-#define Q_V4_PROFILE(engine, function)\
- (engine->profiler &&\
- (engine->profiler->featuresEnabled & (1 << Profiling::FeatureFunctionCall)) ?\
- Profiling::FunctionCallProfiler::profileCall(engine->profiler, engine, function) :\
- function->code(engine, function->codeData))
-
class Q_QML_EXPORT Profiler : public QObject {
Q_OBJECT
- Q_DISABLE_COPY(Profiler)
public:
+ struct SentMarker {
+ SentMarker() : m_function(nullptr) {}
+
+ SentMarker(const SentMarker &other) : m_function(other.m_function)
+ {
+ if (m_function)
+ m_function->compilationUnit->addref();
+ }
+
+ ~SentMarker()
+ {
+ if (m_function)
+ m_function->compilationUnit->release();
+ }
+
+ SentMarker &operator=(const SentMarker &other)
+ {
+ if (&other != this) {
+ if (m_function)
+ m_function->compilationUnit->release();
+ m_function = other.m_function;
+ m_function->compilationUnit->addref();
+ }
+ return *this;
+ }
+
+ void setFunction(Function *function)
+ {
+ Q_ASSERT(m_function == nullptr);
+ m_function = function;
+ m_function->compilationUnit->addref();
+ }
+
+ bool isValid() const
+ { return m_function != nullptr; }
+
+ private:
+ Function *m_function;
+ };
+
Profiler(QV4::ExecutionEngine *engine);
- size_t trackAlloc(size_t size, MemoryType type)
+ bool trackAlloc(size_t size, MemoryType type)
{
MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type};
m_memory_data.append(allocation);
- return size;
+ return true;
}
- void *trackDealloc(void *pointer, size_t size, MemoryType type)
+ bool trackDealloc(size_t size, MemoryType type)
{
MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type};
m_memory_data.append(allocation);
- return pointer;
+ return true;
}
quint64 featuresEnabled;
-public slots:
void stopProfiling();
void startProfiling(quint64 features);
- void reportData();
+ void reportData(bool trackLocations);
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
@@ -189,6 +260,7 @@ private:
QElapsedTimer m_timer;
QVector<FunctionCall> m_data;
QVector<MemoryAllocationProperties> m_memory_data;
+ QHash<quintptr, SentMarker> m_sentLocations;
friend class FunctionCallProfiler;
};
@@ -227,10 +299,13 @@ Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QV4::Profiling::Profiler::SentMarker, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash)
Q_DECLARE_METATYPE(QVector<QV4::Profiling::FunctionCallProperties>)
Q_DECLARE_METATYPE(QVector<QV4::Profiling::MemoryAllocationProperties>)
+#endif // QT_NO_QML_DEBUGGER
+
#endif // QV4PROFILING_H
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 462c4f3171..20179643fd 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -54,6 +54,7 @@
#include <private/qqmlbuiltinfunctions_p.h>
#include <private/qv8engine_p.h>
+#include <private/qv4arraybuffer_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4runtime_p.h>
#include <private/qv4variantobject_p.h>
@@ -74,6 +75,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qmetaobject.h>
QT_BEGIN_NAMESPACE
@@ -83,7 +85,7 @@ QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
using namespace QV4;
-static QPair<QObject *, int> extractQtMethod(QV4::FunctionObject *function)
+QPair<QObject *, int> QObjectMethod::extractQtMethod(const QV4::FunctionObject *function)
{
QV4::ExecutionEngine *v4 = function->engine();
if (v4) {
@@ -103,7 +105,7 @@ static QPair<QObject *, int> extractQtSignal(const Value &value)
QV4::Scope scope(v4);
QV4::ScopedFunctionObject function(scope, value);
if (function)
- return extractQtMethod(function);
+ return QObjectMethod::extractQtMethod(function);
QV4::Scoped<QV4::QmlSignalHandler> handler(scope, value);
if (handler)
@@ -360,7 +362,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje
Scope scope(engine);
QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(engine, object, *property, nptr));
- if (captureRequired) {
+ if (captureRequired && !property->isConstant()) {
if (property->accessors->notifier) {
if (n && ep->propertyCapture)
ep->propertyCapture->captureProperty(n);
@@ -463,7 +465,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
bindingFunction->initBindingLocation();
- newBinding = new QQmlBinding(value, object, callingQmlContext);
+ newBinding = QQmlBinding::create(property, value, object, callingQmlContext);
newBinding->setTarget(object, *property);
}
}
@@ -795,8 +797,8 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
if (!v4)
break;
- QVarLengthArray<int, 9> dummy;
- int *argsTypes = QQmlMetaObject(r).methodParameterTypes(This->signalIndex, dummy, 0);
+ QQmlMetaObject::ArgTypeStorage storage;
+ int *argsTypes = QQmlMetaObject(r).methodParameterTypes(This->signalIndex, &storage, 0);
int argCount = argsTypes ? argsTypes[0]:0;
@@ -814,7 +816,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
}
}
- f->call(callData);
+ f->call(scope, callData);
if (scope.hasException()) {
QQmlError error = v4->catchExceptionAsQmlError();
if (error.description().isEmpty()) {
@@ -859,7 +861,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
(connection->thisObject.isUndefined() || RuntimeHelpers::strictEqual(*connection->thisObject.valueRef(), thisObject))) {
QV4::ScopedFunctionObject f(scope, connection->function.value());
- QPair<QObject *, int> connectedFunctionData = extractQtMethod(f);
+ QPair<QObject *, int> connectedFunctionData = QObjectMethod::extractQtMethod(f);
if (connectedFunctionData.first == receiverToDisconnect &&
connectedFunctionData.second == slotIndexToDisconnect) {
*ret = true;
@@ -974,7 +976,7 @@ ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx)
if (!functionThisValue->isUndefined() && !functionThisValue->isObject())
V4THROW_ERROR("Function.prototype.disconnect: target this is not an object");
- QPair<QObject *, int> functionData = extractQtMethod(functionValue);
+ QPair<QObject *, int> functionData = QObjectMethod::extractQtMethod(functionValue);
void *a[] = {
ctx->d()->engine,
@@ -1098,6 +1100,7 @@ private:
// Pointers to allocData
union {
QString *qstringPtr;
+ QByteArray *qbyteArrayPtr;
QVariant *qvariantPtr;
QList<QObject *> *qlistPtr;
QJSValue *qjsValuePtr;
@@ -1112,7 +1115,8 @@ private:
}
static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index, int returnType, int argCount,
- int *argTypes, QV4::ExecutionEngine *engine, QV4::CallData *callArgs)
+ int *argTypes, QV4::ExecutionEngine *engine, QV4::CallData *callArgs,
+ QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
{
if (argCount > 0) {
// Convert all arguments.
@@ -1124,7 +1128,7 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index
for (int ii = 0; ii < args.count(); ++ii)
argData[ii] = args[ii].dataPtr();
- object.metacall(QMetaObject::InvokeMetaMethod, index, argData.data());
+ object.metacall(callType, index, argData.data());
return args[0].toValue(engine);
@@ -1135,14 +1139,14 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index
void *args[] = { arg.dataPtr() };
- object.metacall(QMetaObject::InvokeMetaMethod, index, args);
+ object.metacall(callType, index, args);
return arg.toValue(engine);
} else {
void *args[] = { 0 };
- object.metacall(QMetaObject::InvokeMetaMethod, index, args);
+ object.metacall(callType, index, args);
return Encode::undefined();
}
@@ -1219,6 +1223,13 @@ static int MatchScore(const QV4::Value &actual, int conversionType)
default:
return 10;
}
+ } else if (actual.as<ArrayBuffer>()) {
+ switch (conversionType) {
+ case QMetaType::QByteArray:
+ return 0;
+ default:
+ return 10;
+ }
} else if (actual.as<ArrayObject>()) {
switch (conversionType) {
case QMetaType::QJsonArray:
@@ -1345,7 +1356,8 @@ static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object,
}
static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
- QV4::ExecutionEngine *engine, QV4::CallData *callArgs)
+ QV4::ExecutionEngine *engine, QV4::CallData *callArgs,
+ QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
{
QByteArray unknownTypeError;
@@ -1360,9 +1372,13 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ
if (data.hasArguments()) {
int *args = 0;
- QVarLengthArray<int, 9> dummy;
+ QQmlMetaObject::ArgTypeStorage storage;
- args = object.methodParameterTypes(data.coreIndex, dummy, &unknownTypeError);
+ if (data.isConstructor())
+ args = static_cast<const QQmlStaticMetaObject&>(object).constructorParameterTypes(
+ data.coreIndex, &storage, &unknownTypeError);
+ else
+ args = object.methodParameterTypes(data.coreIndex, &storage, &unknownTypeError);
if (!args) {
QString typeName = QString::fromLatin1(unknownTypeError);
@@ -1375,11 +1391,11 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ
return engine->throwError(error);
}
- return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs);
+ return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs, callType);
} else {
- return CallMethod(object, data.coreIndex, returnType, 0, 0, engine, callArgs);
+ return CallMethod(object, data.coreIndex, returnType, 0, 0, engine, callArgs, callType);
}
}
@@ -1398,7 +1414,8 @@ Resolve the overloaded method to call. The algorithm works conceptually like th
score is constructed by adding the matchScore() result for each of the parameters.
*/
static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
- QV4::ExecutionEngine *engine, QV4::CallData *callArgs, const QQmlPropertyCache *propertyCache)
+ QV4::ExecutionEngine *engine, QV4::CallData *callArgs, const QQmlPropertyCache *propertyCache,
+ QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
{
int argumentCount = callArgs->argc;
@@ -1413,11 +1430,11 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const
QV4::ScopedValue v(scope);
do {
- QVarLengthArray<int, 9> dummy;
+ QQmlMetaObject::ArgTypeStorage storage;
int methodArgumentCount = 0;
int *methodArgTypes = 0;
if (attempt->hasArguments()) {
- int *args = object.methodParameterTypes(attempt->coreIndex, dummy, 0);
+ int *args = object.methodParameterTypes(attempt->coreIndex, &storage, 0);
if (!args) // Must be an unknown argument
continue;
@@ -1448,7 +1465,7 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const
} while ((attempt = RelatedMethod(object, attempt, dummy, propertyCache)) != 0);
if (best.isValid()) {
- return CallPrecise(object, best, engine, callArgs);
+ return CallPrecise(object, best, engine, callArgs, callType);
} else {
QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
const QQmlPropertyData *candidate = &data;
@@ -1477,6 +1494,8 @@ void CallArgument::cleanup()
{
if (type == QMetaType::QString) {
qstringPtr->~QString();
+ } else if (type == QMetaType::QByteArray) {
+ qbyteArrayPtr->~QByteArray();
} else if (type == -1 || type == QMetaType::QVariant) {
qvariantPtr->~QVariant();
} else if (type == qMetaTypeId<QJSValue>()) {
@@ -1676,6 +1695,8 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine)
return QV4::Encode(floatValue);
} else if (type == QMetaType::QString) {
return QV4::Encode(engine->newString(*qstringPtr));
+ } else if (type == QMetaType::QByteArray) {
+ return QV4::Encode(engine->newArrayBuffer(*qbyteArrayPtr));
} else if (type == QMetaType::QObjectStar) {
QObject *object = qobjectPtr;
if (object)
@@ -1730,7 +1751,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in
ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index)
{
Scope valueScope(scope);
- Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->allocObject<QObjectMethod>(scope));
+ Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope));
method->d()->propertyCache = valueType->d()->propertyCache;
method->d()->index = index;
method->d()->valueTypeWrapper = valueType->d();
@@ -1754,17 +1775,13 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) co
QString result;
if (const QMetaObject *metaObject = d()->metaObject()) {
- result += QString::fromUtf8(metaObject->className());
- result += QLatin1String("(0x");
- result += QString::number((quintptr)d()->object.data(),16);
+ result += QString::fromUtf8(metaObject->className()) +
+ QLatin1String("(0x") + QString::number((quintptr)d()->object.data(),16);
if (d()->object) {
QString objectName = d()->object->objectName();
- if (!objectName.isEmpty()) {
- result += QLatin1String(", \"");
- result += objectName;
- result += QLatin1Char('\"');
- }
+ if (!objectName.isEmpty())
+ result += QLatin1String(", \"") + objectName + QLatin1Char('\"');
}
result += QLatin1Char(')');
@@ -1794,25 +1811,32 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con
return Encode::undefined();
}
-ReturnedValue QObjectMethod::call(const Managed *m, CallData *callData)
+void QObjectMethod::call(const Managed *m, Scope &scope, CallData *callData)
{
const QObjectMethod *This = static_cast<const QObjectMethod*>(m);
- return This->callInternal(callData);
+ This->callInternal(callData, scope);
}
-ReturnedValue QObjectMethod::callInternal(CallData *callData) const
+void QObjectMethod::callInternal(CallData *callData, Scope &scope) const
{
ExecutionEngine *v4 = engine();
ExecutionContext *context = v4->currentContext;
- if (d()->index == DestroyMethod)
- return method_destroy(context, callData->args, callData->argc);
- else if (d()->index == ToStringMethod)
- return method_toString(context);
+ if (d()->index == DestroyMethod) {
+ scope.result = method_destroy(context, callData->args, callData->argc);
+ return;
+ }
+
+ else if (d()->index == ToStringMethod) {
+ scope.result = method_toString(context);
+ return;
+ }
QQmlObjectOrGadget object(d()->object.data());
if (!d()->object) {
- if (!d()->valueTypeWrapper)
- return Encode::undefined();
+ if (!d()->valueTypeWrapper) {
+ scope.result = Encode::undefined();
+ return;
+ }
object = QQmlObjectOrGadget(d()->propertyCache.data(), d()->valueTypeWrapper->gadgetPtr);
}
@@ -1821,16 +1845,20 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const
if (d()->propertyCache) {
QQmlPropertyData *data = d()->propertyCache->method(d()->index);
- if (!data)
- return QV4::Encode::undefined();
+ if (!data) {
+ scope.result = QV4::Encode::undefined();
+ return;
+ }
method = *data;
} else {
const QMetaObject *mo = d()->object->metaObject();
const QMetaMethod moMethod = mo->method(d()->index);
method.load(moMethod);
- if (method.coreIndex == -1)
- return QV4::Encode::undefined();
+ if (method.coreIndex == -1) {
+ scope.result = QV4::Encode::undefined();
+ return;
+ }
// Look for overloaded methods
QByteArray methodName = moMethod.name();
@@ -1846,21 +1874,20 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const
}
if (method.isV4Function()) {
- Scope scope(v4);
- QV4::ScopedValue rv(scope, QV4::Primitive::undefinedValue());
- QQmlV4Function func(callData, rv, v4);
+ scope.result = QV4::Encode::undefined();
+ QQmlV4Function func(callData, &scope.result, v4);
QQmlV4Function *funcptr = &func;
void *args[] = { 0, &funcptr };
object.metacall(QMetaObject::InvokeMetaMethod, method.coreIndex, args);
- return rv->asReturnedValue();
+ return;
}
if (!method.isOverload()) {
- return CallPrecise(object, method, v4, callData);
+ scope.result = CallPrecise(object, method, v4, callData);
} else {
- return CallOverloaded(object, method, v4, callData, d()->propertyCache);
+ scope.result = CallOverloaded(object, method, v4, callData, d()->propertyCache);
}
}
@@ -1875,6 +1902,169 @@ void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e)
DEFINE_OBJECT_VTABLE(QObjectMethod);
+
+Heap::QMetaObjectWrapper::QMetaObjectWrapper(const QMetaObject *metaObject)
+ : metaObject(metaObject) {
+
+}
+
+void Heap::QMetaObjectWrapper::ensureConstructorsCache() {
+
+ const int count = metaObject->constructorCount();
+ if (constructors.size() != count) {
+ constructors.clear();
+ constructors.reserve(count);
+
+ for (int i = 0; i < count; ++i) {
+ QMetaMethod method = metaObject->constructor(i);
+ QQmlPropertyData d;
+ d.load(method);
+ d.coreIndex = i;
+ constructors << d;
+ }
+ }
+}
+
+
+ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObject* metaObject) {
+
+ QV4::Scope scope(engine);
+ Scoped<QMetaObjectWrapper> mo(scope, engine->memoryManager->allocObject<QV4::QMetaObjectWrapper>(metaObject)->asReturnedValue());
+ mo->init(engine);
+ return mo->asReturnedValue();
+}
+
+void QMetaObjectWrapper::init(ExecutionEngine *) {
+ const QMetaObject & mo = *d()->metaObject;
+
+ for (int i = 0; i < mo.enumeratorCount(); i++) {
+ QMetaEnum Enum = mo.enumerator(i);
+ for (int k = 0; k < Enum.keyCount(); k++) {
+ const char* key = Enum.key(k);
+ const int value = Enum.value(k);
+ defineReadonlyProperty(QLatin1String(key), Primitive::fromInt32(value));
+ }
+ }
+}
+
+void QMetaObjectWrapper::construct(const Managed *m, Scope &scope, CallData *callData)
+{
+ const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(m);
+ scope.result = This->constructInternal(callData);
+}
+
+ReturnedValue QMetaObjectWrapper::constructInternal(CallData * callData) const {
+
+ d()->ensureConstructorsCache();
+
+ ExecutionEngine *v4 = engine();
+ const QMetaObject* mo = d()->metaObject;
+ if (d()->constructors.isEmpty()) {
+ return v4->throwTypeError(QStringLiteral("%1 has no invokable constructor")
+ .arg(QLatin1String(mo->className())));
+ }
+
+ Scope scope(v4);
+ Scoped<QObjectWrapper> object(scope);
+
+ if (d()->constructors.size() == 1) {
+ object = callConstructor(d()->constructors.first(), v4, callData);
+ }
+ else {
+ object = callOverloadedConstructor(v4, callData);
+ }
+ Scoped<QMetaObjectWrapper> metaObject(scope, this);
+ object->defineDefaultProperty(v4->id_constructor(), metaObject);
+ object->setPrototype(const_cast<QMetaObjectWrapper*>(this));
+ return object.asReturnedValue();
+
+}
+
+ReturnedValue QMetaObjectWrapper::callConstructor(const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const {
+
+ const QMetaObject* mo = d()->metaObject;
+ const QQmlStaticMetaObject object(mo);
+ return CallPrecise(object, data, engine, callArgs, QMetaObject::InvokeMetaMethod);
+}
+
+
+ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const {
+ const int numberOfConstructors = d()->constructors.size();
+ const int argumentCount = callArgs->argc;
+ const QQmlStaticMetaObject object(d()->metaObject);
+
+ QQmlPropertyData best;
+ int bestParameterScore = INT_MAX;
+ int bestMatchScore = INT_MAX;
+
+ QV4::Scope scope(engine);
+ QV4::ScopedValue v(scope);
+
+ for (int i = 0; i < numberOfConstructors; i++) {
+ const QQmlPropertyData & attempt = d()->constructors.at(i);
+ int methodArgumentCount = 0;
+ int *methodArgTypes = 0;
+ if (attempt.hasArguments()) {
+ QQmlMetaObject::ArgTypeStorage storage;
+ int *args = object.constructorParameterTypes(attempt.coreIndex, &storage, 0);
+ if (!args) // Must be an unknown argument
+ continue;
+
+ methodArgumentCount = args[0];
+ methodArgTypes = args + 1;
+ }
+
+ if (methodArgumentCount > argumentCount)
+ continue; // We don't have sufficient arguments to call this method
+
+ int methodParameterScore = argumentCount - methodArgumentCount;
+ if (methodParameterScore > bestParameterScore)
+ continue; // We already have a better option
+
+ int methodMatchScore = 0;
+ for (int ii = 0; ii < methodArgumentCount; ++ii)
+ methodMatchScore += MatchScore((v = callArgs->args[ii]), methodArgTypes[ii]);
+
+ if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
+ best = attempt;
+ bestParameterScore = methodParameterScore;
+ bestMatchScore = methodMatchScore;
+ }
+
+ if (bestParameterScore == 0 && bestMatchScore == 0)
+ break; // We can't get better than that
+ };
+
+ if (best.isValid()) {
+ return CallPrecise(object, best, engine, callArgs, QMetaObject::CreateInstance);
+ } else {
+ QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
+ for (int i = 0; i < numberOfConstructors; i++) {
+ const QQmlPropertyData & candidate = d()->constructors.at(i);
+ error += QLatin1String("\n ") +
+ QString::fromUtf8(d()->metaObject->constructor(candidate.coreIndex)
+ .methodSignature());
+ }
+
+ return engine->throwError(error);
+ }
+}
+
+bool QMetaObjectWrapper::isEqualTo(Managed *a, Managed *b)
+{
+ Q_ASSERT(a->as<QMetaObjectWrapper>());
+ QMetaObjectWrapper *aMetaObject = a->as<QMetaObjectWrapper>();
+ QMetaObjectWrapper *bMetaObject = b->as<QMetaObjectWrapper>();
+ if (!bMetaObject)
+ return true;
+ return aMetaObject->metaObject() == bMetaObject->metaObject();
+}
+
+DEFINE_OBJECT_VTABLE(QMetaObjectWrapper);
+
+
+
+
Heap::QmlSignalHandler::QmlSignalHandler(QObject *object, int signalIndex)
: object(object)
, signalIndex(signalIndex)
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index f101f352f1..8ab5c96c3a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -93,6 +93,14 @@ struct QObjectMethod : FunctionObject {
const QMetaObject *metaObject();
};
+struct QMetaObjectWrapper : FunctionObject {
+ QMetaObjectWrapper(const QMetaObject* metaObject);
+ const QMetaObject* metaObject;
+ QVector<QQmlPropertyData> constructors;
+
+ void ensureConstructorsCache();
+};
+
struct QmlSignalHandler : Object {
QmlSignalHandler(QObject *object, int signalIndex);
QPointer<QObject> object;
@@ -184,11 +192,33 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx) const;
QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const;
- static ReturnedValue call(const Managed *, CallData *callData);
+ static void call(const Managed *, Scope &scope, CallData *callData);
- ReturnedValue callInternal(CallData *callData) const;
+ void callInternal(CallData *callData, Scope &scope) const;
static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
+
+ static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
+};
+
+
+struct Q_QML_EXPORT QMetaObjectWrapper : public QV4::FunctionObject
+{
+ V4_OBJECT2(QMetaObjectWrapper, QV4::FunctionObject)
+ V4_NEEDS_DESTROY
+
+ static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static bool isEqualTo(Managed *a, Managed *b);
+
+ const QMetaObject *metaObject() const { return d()->metaObject; }
+
+private:
+ void init(ExecutionEngine *engine);
+ ReturnedValue constructInternal(CallData *callData) const;
+ ReturnedValue callConstructor(const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
+ ReturnedValue callOverloadedConstructor(QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
+
};
struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 71e2bd1a06..ab00859b3b 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -185,8 +185,7 @@ QRegExp RegExpObject::toQRegExp() const
QString RegExpObject::toString() const
{
- QString result = QLatin1Char('/') + source();
- result += QLatin1Char('/');
+ QString result = QLatin1Char('/') + source() + QLatin1Char('/');
if (global())
result += QLatin1Char('g');
if (value()->ignoreCase)
@@ -232,34 +231,39 @@ void Heap::RegExpCtor::clearLastMatch()
lastMatchEnd = 0;
}
-ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData)
+void RegExpCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const Object *>(m)->engine());
-
ScopedValue r(scope, callData->argument(0));
ScopedValue f(scope, callData->argument(1));
Scoped<RegExpObject> re(scope, r);
if (re) {
- if (!f->isUndefined())
- return scope.engine->throwTypeError();
+ if (!f->isUndefined()) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
Scoped<RegExp> regexp(scope, re->value());
- return Encode(scope.engine->newRegExpObject(regexp, re->global()));
+ scope.result = Encode(scope.engine->newRegExpObject(regexp, re->global()));
+ return;
}
QString pattern;
if (!r->isUndefined())
pattern = r->toQString();
- if (scope.hasException())
- return Encode::undefined();
+ if (scope.hasException()) {
+ scope.result = Encode::undefined();
+ return;
+ }
bool global = false;
bool ignoreCase = false;
bool multiLine = false;
if (!f->isUndefined()) {
f = RuntimeHelpers::toString(scope.engine, f);
- if (scope.hasException())
- return Encode::undefined();
+ if (scope.hasException()) {
+ scope.result = Encode::undefined();
+ return;
+ }
QString str = f->stringValue()->toQString();
for (int i = 0; i < str.length(); ++i) {
if (str.at(i) == QLatin1Char('g') && !global) {
@@ -269,26 +273,31 @@ ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData)
} else if (str.at(i) == QLatin1Char('m') && !multiLine) {
multiLine = true;
} else {
- return scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor"));
+ scope.result = scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor"));
+ return;
}
}
}
Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, ignoreCase, multiLine));
- if (!regexp->isValid())
- return scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression"));
+ if (!regexp->isValid()) {
+ scope.result = scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression"));
+ return;
+ }
- return Encode(scope.engine->newRegExpObject(regexp, global));
+ scope.result = Encode(scope.engine->newRegExpObject(regexp, global));
}
-ReturnedValue RegExpCtor::call(const Managed *that, CallData *callData)
+void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
if (callData->argc > 0 && callData->args[0].as<RegExpObject>()) {
- if (callData->argc == 1 || callData->args[1].isUndefined())
- return callData->args[0].asReturnedValue();
+ if (callData->argc == 1 || callData->args[1].isUndefined()) {
+ scope.result = callData->args[0];
+ return;
+ }
}
- return construct(that, callData);
+ construct(that, scope, callData);
}
void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e)
@@ -420,7 +429,8 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx)
ScopedCallData callData(scope, ctx->argc());
memcpy(callData->args, ctx->args(), ctx->argc()*sizeof(Value));
- Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(callData));
+ ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(scope, callData);
+ Scoped<RegExpObject> re(scope, scope.result.asReturnedValue());
r->d()->value = re->value();
r->d()->global = re->global();
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 4bd91bbedd..655e120c16 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -140,8 +140,8 @@ struct RegExpCtor: FunctionObject
int lastMatchStart() { return d()->lastMatchStart; }
int lastMatchEnd() { return d()->lastMatchEnd; }
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 0e10f7699e..a69874cacb 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -252,11 +252,11 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
result->append(QLatin1Char('+'));
result->append(QString::number(decpt - 1));
} else if (decpt <= 0) {
- result->prepend(QString::fromLatin1("0.%1").arg(QString().fill(zero, -decpt)));
+ result->prepend(QLatin1String("0.") + QString(-decpt, zero));
} else if (decpt < result->length()) {
result->insert(decpt, dot);
} else {
- result->append(QString().fill(zero, decpt - result->length()));
+ result->append(QString(decpt - result->length(), zero));
}
if (sign)
@@ -298,14 +298,14 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
result->prepend(QLatin1Char('-'));
}
-ReturnedValue Runtime::closure(ExecutionEngine *engine, int functionId)
+ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId)
{
QV4::Function *clos = engine->current->compilationUnit->runtimeFunctions[functionId];
Q_ASSERT(clos);
return FunctionObject::createScriptFunction(engine->currentContext, clos)->asReturnedValue();
}
-ReturnedValue Runtime::deleteElement(ExecutionEngine *engine, const Value &base, const Value &index)
+ReturnedValue Runtime::method_deleteElement(ExecutionEngine *engine, const Value &base, const Value &index)
{
Scope scope(engine);
ScopedObject o(scope, base);
@@ -317,17 +317,17 @@ ReturnedValue Runtime::deleteElement(ExecutionEngine *engine, const Value &base,
}
ScopedString name(scope, index.toString(engine));
- return Runtime::deleteMemberString(engine, base, name);
+ return method_deleteMemberString(engine, base, name);
}
-ReturnedValue Runtime::deleteMember(ExecutionEngine *engine, const Value &base, int nameIndex)
+ReturnedValue Runtime::method_deleteMember(ExecutionEngine *engine, const Value &base, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- return deleteMemberString(engine, base, name);
+ return method_deleteMemberString(engine, base, name);
}
-ReturnedValue Runtime::deleteMemberString(ExecutionEngine *engine, const Value &base, String *name)
+ReturnedValue Runtime::method_deleteMemberString(ExecutionEngine *engine, const Value &base, String *name)
{
Scope scope(engine);
ScopedObject obj(scope, base.toObject(engine));
@@ -336,14 +336,14 @@ ReturnedValue Runtime::deleteMemberString(ExecutionEngine *engine, const Value &
return Encode(obj->deleteProperty(name));
}
-ReturnedValue Runtime::deleteName(ExecutionEngine *engine, int nameIndex)
+ReturnedValue Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
return Encode(engine->currentContext->deleteProperty(name));
}
-QV4::ReturnedValue Runtime::instanceof(ExecutionEngine *engine, const Value &left, const Value &right)
+QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &left, const Value &right)
{
Scope scope(engine);
ScopedFunctionObject f(scope, right.as<FunctionObject>());
@@ -373,7 +373,7 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionEngine *engine, const Value &lef
return Encode(false);
}
-QV4::ReturnedValue Runtime::in(ExecutionEngine *engine, const Value &left, const Value &right)
+QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)
{
if (!right.isObject())
return engine->throwTypeError();
@@ -387,7 +387,7 @@ QV4::ReturnedValue Runtime::in(ExecutionEngine *engine, const Value &left, const
double RuntimeHelpers::stringToNumber(const QString &string)
{
- QString s = string.trimmed();
+ const QStringRef s = QStringRef(&string).trimmed();
if (s.startsWith(QLatin1String("0x")) || s.startsWith(QLatin1String("0X")))
return s.toLong(0, 16);
bool ok;
@@ -438,9 +438,9 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH
ScopedValue conv(scope, object->get(meth1));
if (FunctionObject *o = conv->as<FunctionObject>()) {
- ScopedValue r(scope, o->call(callData));
- if (r->isPrimitive())
- return r->asReturnedValue();
+ o->call(scope, callData);
+ if (scope.result.isPrimitive())
+ return scope.result.asReturnedValue();
}
if (engine->hasException)
@@ -448,9 +448,9 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH
conv = object->get(meth2);
if (FunctionObject *o = conv->as<FunctionObject>()) {
- ScopedValue r(scope, o->call(callData));
- if (r->isPrimitive())
- return r->asReturnedValue();
+ o->call(scope, callData);
+ if (scope.result.isPrimitive())
+ return scope.result.asReturnedValue();
}
return engine->throwTypeError();
@@ -562,7 +562,7 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu
return Encode(x + y);
}
-QV4::ReturnedValue Runtime::addString(ExecutionEngine *engine, const Value &left, const Value &right)
+QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Value &left, const Value &right)
{
Q_ASSERT(left.isString() || right.isString());
@@ -593,7 +593,7 @@ QV4::ReturnedValue Runtime::addString(ExecutionEngine *engine, const Value &left
return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d()))->asReturnedValue();
}
-void Runtime::setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)
+void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
@@ -603,7 +603,7 @@ void Runtime::setProperty(ExecutionEngine *engine, const Value &object, int name
o->put(name, value);
}
-ReturnedValue Runtime::getElement(ExecutionEngine *engine, const Value &object, const Value &index)
+ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &object, const Value &index)
{
Scope scope(engine);
uint idx = index.asArrayIndex();
@@ -646,7 +646,7 @@ ReturnedValue Runtime::getElement(ExecutionEngine *engine, const Value &object,
return o->get(name);
}
-void Runtime::setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
+void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
Scope scope(engine);
ScopedObject o(scope, object.toObject(engine));
@@ -670,7 +670,7 @@ void Runtime::setElement(ExecutionEngine *engine, const Value &object, const Val
o->put(name, value);
}
-ReturnedValue Runtime::foreachIterator(ExecutionEngine *engine, const Value &in)
+ReturnedValue Runtime::method_foreachIterator(ExecutionEngine *engine, const Value &in)
{
Scope scope(engine);
ScopedObject o(scope, (Object *)0);
@@ -679,7 +679,7 @@ ReturnedValue Runtime::foreachIterator(ExecutionEngine *engine, const Value &in)
return engine->newForEachIteratorObject(o)->asReturnedValue();
}
-ReturnedValue Runtime::foreachNextPropertyName(const Value &foreach_iterator)
+ReturnedValue Runtime::method_foreachNextPropertyName(const Value &foreach_iterator)
{
Q_ASSERT(foreach_iterator.isObject());
@@ -690,14 +690,14 @@ ReturnedValue Runtime::foreachNextPropertyName(const Value &foreach_iterator)
}
-void Runtime::setActivationProperty(ExecutionEngine *engine, int nameIndex, const Value &value)
+void Runtime::method_setActivationProperty(ExecutionEngine *engine, int nameIndex, const Value &value)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
engine->currentContext->setProperty(name, value);
}
-ReturnedValue Runtime::getProperty(ExecutionEngine *engine, const Value &object, int nameIndex)
+ReturnedValue Runtime::method_getProperty(ExecutionEngine *engine, const Value &object, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
@@ -717,7 +717,7 @@ ReturnedValue Runtime::getProperty(ExecutionEngine *engine, const Value &object,
return o->get(name);
}
-ReturnedValue Runtime::getActivationProperty(ExecutionEngine *engine, int nameIndex)
+ReturnedValue Runtime::method_getActivationProperty(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
@@ -743,9 +743,9 @@ uint RuntimeHelpers::equalHelper(const Value &x, const Value &y)
double dx = RuntimeHelpers::toNumber(x);
return dx == y.asDouble();
} else if (x.isBoolean()) {
- return Runtime::compareEqual(Primitive::fromDouble((double) x.booleanValue()), y);
+ return Runtime::method_compareEqual(Primitive::fromDouble((double) x.booleanValue()), y);
} else if (y.isBoolean()) {
- return Runtime::compareEqual(x, Primitive::fromDouble((double) y.booleanValue()));
+ return Runtime::method_compareEqual(x, Primitive::fromDouble((double) y.booleanValue()));
} else {
#ifdef V4_BOOTSTRAP
Q_UNIMPLEMENTED();
@@ -753,11 +753,11 @@ uint RuntimeHelpers::equalHelper(const Value &x, const Value &y)
if ((x.isNumber() || x.isString()) && y.isObject()) {
Scope scope(y.objectValue()->engine());
ScopedValue py(scope, RuntimeHelpers::toPrimitive(y, PREFERREDTYPE_HINT));
- return Runtime::compareEqual(x, py);
+ return Runtime::method_compareEqual(x, py);
} else if (x.isObject() && (y.isNumber() || y.isString())) {
Scope scope(x.objectValue()->engine());
ScopedValue px(scope, RuntimeHelpers::toPrimitive(x, PREFERREDTYPE_HINT));
- return Runtime::compareEqual(px, y);
+ return Runtime::method_compareEqual(px, y);
}
#endif
}
@@ -780,7 +780,7 @@ Bool RuntimeHelpers::strictEqual(const Value &x, const Value &y)
return false;
}
-QV4::Bool Runtime::compareGreaterThan(const Value &l, const Value &r)
+QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r)
{
TRACE2(l, r);
if (l.isInteger() && r.isInteger())
@@ -804,7 +804,7 @@ QV4::Bool Runtime::compareGreaterThan(const Value &l, const Value &r)
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT));
QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT));
- return Runtime::compareGreaterThan(pl, pr);
+ return Runtime::method_compareGreaterThan(pl, pr);
#endif
}
@@ -813,7 +813,7 @@ QV4::Bool Runtime::compareGreaterThan(const Value &l, const Value &r)
return dl > dr;
}
-QV4::Bool Runtime::compareLessThan(const Value &l, const Value &r)
+QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r)
{
TRACE2(l, r);
if (l.isInteger() && r.isInteger())
@@ -837,7 +837,7 @@ QV4::Bool Runtime::compareLessThan(const Value &l, const Value &r)
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT));
QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT));
- return Runtime::compareLessThan(pl, pr);
+ return Runtime::method_compareLessThan(pl, pr);
#endif
}
@@ -846,7 +846,7 @@ QV4::Bool Runtime::compareLessThan(const Value &l, const Value &r)
return dl < dr;
}
-QV4::Bool Runtime::compareGreaterEqual(const Value &l, const Value &r)
+QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r)
{
TRACE2(l, r);
if (l.isInteger() && r.isInteger())
@@ -870,7 +870,7 @@ QV4::Bool Runtime::compareGreaterEqual(const Value &l, const Value &r)
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT));
QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT));
- return Runtime::compareGreaterEqual(pl, pr);
+ return Runtime::method_compareGreaterEqual(pl, pr);
#endif
}
@@ -879,7 +879,7 @@ QV4::Bool Runtime::compareGreaterEqual(const Value &l, const Value &r)
return dl >= dr;
}
-QV4::Bool Runtime::compareLessEqual(const Value &l, const Value &r)
+QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r)
{
TRACE2(l, r);
if (l.isInteger() && r.isInteger())
@@ -903,7 +903,7 @@ QV4::Bool Runtime::compareLessEqual(const Value &l, const Value &r)
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT));
QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT));
- return Runtime::compareLessEqual(pl, pr);
+ return Runtime::method_compareLessEqual(pl, pr);
#endif
}
@@ -913,26 +913,26 @@ QV4::Bool Runtime::compareLessEqual(const Value &l, const Value &r)
}
#ifndef V4_BOOTSTRAP
-Bool Runtime::compareInstanceof(ExecutionEngine *engine, const Value &left, const Value &right)
+Bool Runtime::method_compareInstanceof(ExecutionEngine *engine, const Value &left, const Value &right)
{
TRACE2(left, right);
Scope scope(engine);
- ScopedValue v(scope, Runtime::instanceof(engine, left, right));
+ ScopedValue v(scope, method_instanceof(engine, left, right));
return v->booleanValue();
}
-uint Runtime::compareIn(ExecutionEngine *engine, const Value &left, const Value &right)
+uint Runtime::method_compareIn(ExecutionEngine *engine, const Value &left, const Value &right)
{
TRACE2(left, right);
Scope scope(engine);
- ScopedValue v(scope, Runtime::in(engine, left, right));
+ ScopedValue v(scope, method_in(engine, left, right));
return v->booleanValue();
}
-ReturnedValue Runtime::callGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData)
+ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData)
{
Scope scope(engine);
Q_ASSERT(callData->thisObject.isUndefined());
@@ -943,14 +943,17 @@ ReturnedValue Runtime::callGlobalLookup(ExecutionEngine *engine, uint index, Cal
return engine->throwTypeError();
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]);
- if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval()))
- return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true);
+ if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) {
+ static_cast<EvalFunction *>(o.getPointer())->evalCall(scope, callData, true);
+ } else {
+ o->call(scope, callData);
+ }
- return o->call(callData);
+ return scope.result.asReturnedValue();
}
-ReturnedValue Runtime::callActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
+ReturnedValue Runtime::method_callActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
{
Q_ASSERT(callData->thisObject.isUndefined());
Scope scope(engine);
@@ -974,36 +977,41 @@ ReturnedValue Runtime::callActivationProperty(ExecutionEngine *engine, int nameI
}
if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) {
- return static_cast<EvalFunction *>(o)->evalCall(callData, true);
+ static_cast<EvalFunction *>(o)->evalCall(scope, callData, true);
+ } else {
+ o->call(scope, callData);
}
- return o->call(callData);
+ return scope.result.asReturnedValue();
}
-ReturnedValue Runtime::callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData)
+ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData)
{
Scope scope(engine);
- ScopedFunctionObject o(scope, getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex));
+ ScopedFunctionObject o(scope, method_getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex));
if (!o) {
QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex);
return engine->throwTypeError(error);
}
- return o->call(callData);
+
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
-ReturnedValue Runtime::callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData)
+ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData)
{
Scope scope(engine);
- ScopedFunctionObject o(scope, getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex));
+ ScopedFunctionObject o(scope, method_getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex));
if (!o) {
QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex);
return engine->throwTypeError(error);
}
- return o->call(callData);
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
-ReturnedValue Runtime::callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
+ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
@@ -1022,26 +1030,31 @@ ReturnedValue Runtime::callProperty(ExecutionEngine *engine, int nameIndex, Call
}
ScopedFunctionObject o(scope, baseObject->get(name));
- if (!o) {
+ if (o) {
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString(), callData->thisObject.toQStringNoThrow());
return engine->throwTypeError(error);
}
- return o->call(callData);
}
-ReturnedValue Runtime::callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData)
+ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData)
{
Lookup *l = engine->current->lookups + index;
Value v;
v = l->getter(l, engine, callData->thisObject);
- if (!v.isObject())
+ if (v.isObject()) {
+ Scope scope(engine);
+ v.objectValue()->call(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
return engine->throwTypeError();
-
- return v.objectValue()->call(callData);
+ }
}
-ReturnedValue Runtime::callElement(ExecutionEngine *engine, const Value &index, CallData *callData)
+ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value &index, CallData *callData)
{
Scope scope(engine);
ScopedObject baseObject(scope, callData->thisObject.toObject(engine));
@@ -1055,33 +1068,38 @@ ReturnedValue Runtime::callElement(ExecutionEngine *engine, const Value &index,
if (!o)
return engine->throwTypeError();
- return o->call(callData);
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
-ReturnedValue Runtime::callValue(ExecutionEngine *engine, const Value &func, CallData *callData)
+ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, CallData *callData)
{
if (!func.isObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
- return func.objectValue()->call(callData);
+ Scope scope(engine);
+ func.objectValue()->call(scope, callData);
+ return scope.result.asReturnedValue();
}
-ReturnedValue Runtime::constructGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData)
+ReturnedValue Runtime::method_constructGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData)
{
Scope scope(engine);
Q_ASSERT(callData->thisObject.isUndefined());
Lookup *l = engine->current->lookups + index;
ScopedObject f(scope, l->globalGetter(l, engine));
- if (!f)
+ if (f) {
+ f->construct(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
return engine->throwTypeError();
-
- return f->construct(callData);
+ }
}
-ReturnedValue Runtime::constructActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
+ReturnedValue Runtime::method_constructActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
@@ -1093,19 +1111,22 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionEngine *engine, int
if (!f)
return engine->throwTypeError();
- return f->construct(callData);
+ f->construct(scope, callData);
+ return scope.result.asReturnedValue();
}
-ReturnedValue Runtime::constructValue(ExecutionEngine *engine, const Value &func, CallData *callData)
+ReturnedValue Runtime::method_constructValue(ExecutionEngine *engine, const Value &func, CallData *callData)
{
const Object *f = func.as<Object>();
if (!f)
return engine->throwTypeError();
- return f->construct(callData);
+ Scope scope(engine);
+ f->construct(scope, callData);
+ return scope.result.asReturnedValue();
}
-ReturnedValue Runtime::constructProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
+ReturnedValue Runtime::method_constructProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
{
Scope scope(engine);
ScopedObject thisObject(scope, callData->thisObject.toObject(engine));
@@ -1114,31 +1135,38 @@ ReturnedValue Runtime::constructProperty(ExecutionEngine *engine, int nameIndex,
return Encode::undefined();
ScopedObject f(scope, thisObject->get(name));
- if (!f)
+ if (f) {
+ Scope scope(engine);
+ f->construct(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
return engine->throwTypeError();
-
- return f->construct(callData);
+ }
}
-ReturnedValue Runtime::constructPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData)
+ReturnedValue Runtime::method_constructPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData)
{
Lookup *l = engine->current->lookups + index;
Value v;
v = l->getter(l, engine, callData->thisObject);
- if (!v.isObject())
+ if (v.isObject()) {
+ Scope scope(engine);
+ ScopedValue result(scope);
+ v.objectValue()->construct(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
return engine->throwTypeError();
-
- return v.objectValue()->construct(callData);
+ }
}
-void Runtime::throwException(ExecutionEngine *engine, const Value &value)
+void Runtime::method_throwException(ExecutionEngine *engine, const Value &value)
{
if (!value.isEmpty())
engine->throwError(value);
}
-ReturnedValue Runtime::typeofValue(ExecutionEngine *engine, const Value &value)
+ReturnedValue Runtime::method_typeofValue(ExecutionEngine *engine, const Value &value)
{
Scope scope(engine);
ScopedString res(scope);
@@ -1167,39 +1195,37 @@ ReturnedValue Runtime::typeofValue(ExecutionEngine *engine, const Value &value)
return res.asReturnedValue();
}
-QV4::ReturnedValue Runtime::typeofName(ExecutionEngine *engine, int nameIndex)
+QV4::ReturnedValue Runtime::method_typeofName(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
ScopedValue prop(scope, engine->currentContext->getProperty(name));
// typeof doesn't throw. clear any possible exception
scope.engine->hasException = false;
- return Runtime::typeofValue(engine, prop);
+ return method_typeofValue(engine, prop);
}
#ifndef V4_BOOTSTRAP
-ReturnedValue Runtime::typeofScopeObjectProperty(ExecutionEngine *engine, const Value &context,
- int propertyIndex)
+ReturnedValue Runtime::method_typeofScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
{
Scope scope(engine);
- ScopedValue prop(scope, getQmlScopeObjectProperty(engine, context, propertyIndex));
+ ScopedValue prop(scope, method_getQmlScopeObjectProperty(engine, context, propertyIndex));
if (scope.engine->hasException)
return Encode::undefined();
- return Runtime::typeofValue(engine, prop);
+ return method_typeofValue(engine, prop);
}
-ReturnedValue Runtime::typeofContextObjectProperty(ExecutionEngine *engine, const Value &context,
- int propertyIndex)
+ReturnedValue Runtime::method_typeofContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
{
Scope scope(engine);
- ScopedValue prop(scope, getQmlContextObjectProperty(engine, context, propertyIndex));
+ ScopedValue prop(scope, method_getQmlContextObjectProperty(engine, context, propertyIndex));
if (scope.engine->hasException)
return Encode::undefined();
- return Runtime::typeofValue(engine, prop);
+ return method_typeofValue(engine, prop);
}
#endif // V4_BOOTSTRAP
-QV4::ReturnedValue Runtime::typeofMember(ExecutionEngine *engine, const Value &base, int nameIndex)
+QV4::ReturnedValue Runtime::method_typeofMember(ExecutionEngine *engine, const Value &base, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
@@ -1207,10 +1233,10 @@ QV4::ReturnedValue Runtime::typeofMember(ExecutionEngine *engine, const Value &b
if (scope.engine->hasException)
return Encode::undefined();
ScopedValue prop(scope, obj->get(name));
- return Runtime::typeofValue(engine, prop);
+ return method_typeofValue(engine, prop);
}
-QV4::ReturnedValue Runtime::typeofElement(ExecutionEngine *engine, const Value &base, const Value &index)
+QV4::ReturnedValue Runtime::method_typeofElement(ExecutionEngine *engine, const Value &base, const Value &index)
{
Scope scope(engine);
ScopedString name(scope, index.toString(engine));
@@ -1218,10 +1244,10 @@ QV4::ReturnedValue Runtime::typeofElement(ExecutionEngine *engine, const Value &
if (scope.engine->hasException)
return Encode::undefined();
ScopedValue prop(scope, obj->get(name));
- return Runtime::typeofValue(engine, prop);
+ return method_typeofValue(engine, prop);
}
-ReturnedValue Runtime::unwindException(ExecutionEngine *engine)
+ReturnedValue Runtime::method_unwindException(ExecutionEngine *engine)
{
if (!engine->hasException)
return Primitive::emptyValue().asReturnedValue();
@@ -1233,39 +1259,39 @@ ReturnedValue Runtime::unwindException(ExecutionEngine *engine)
*
* Instead the push/pop pair acts as a non local scope.
*/
-void Runtime::pushWithScope(const Value &o, ExecutionEngine *engine)
+void Runtime::method_pushWithScope(const Value &o, ExecutionEngine *engine)
{
engine->pushContext(engine->currentContext->newWithContext(o.toObject(engine)));
Q_ASSERT(engine->jsStackTop = engine->currentContext + 2);
}
-void Runtime::pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex)
+void Runtime::method_pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex)
{
ExecutionContext *c = engine->currentContext;
engine->pushContext(c->newCatchContext(c->d()->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0)));
Q_ASSERT(engine->jsStackTop = engine->currentContext + 2);
}
-void Runtime::popScope(ExecutionEngine *engine)
+void Runtime::method_popScope(ExecutionEngine *engine)
{
Q_ASSERT(engine->jsStackTop = engine->currentContext + 2);
engine->popContext();
engine->jsStackTop -= 2;
}
-void Runtime::declareVar(ExecutionEngine *engine, bool deletable, int nameIndex)
+void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
engine->currentContext->createMutableBinding(name, deletable);
}
-ReturnedValue Runtime::arrayLiteral(ExecutionEngine *engine, Value *values, uint length)
+ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *values, uint length)
{
return engine->newArrayObject(values, length)->asReturnedValue();
}
-ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)
+ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)
{
Scope scope(engine);
QV4::InternalClass *klass = engine->current->compilationUnit->runtimeClasses[classId];
@@ -1307,7 +1333,7 @@ ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value *
return o.asReturnedValue();
}
-QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionEngine *engine)
+QV4::ReturnedValue Runtime::method_setupArgumentsObject(ExecutionEngine *engine)
{
Q_ASSERT(engine->current->type == Heap::ExecutionContext::Type_CallContext);
QV4::CallContext *c = static_cast<QV4::CallContext *>(engine->currentContext);
@@ -1317,7 +1343,7 @@ QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionEngine *engine)
#endif // V4_BOOTSTRAP
-QV4::ReturnedValue Runtime::increment(const Value &value)
+QV4::ReturnedValue Runtime::method_increment(const Value &value)
{
TRACE1(value);
@@ -1329,7 +1355,7 @@ QV4::ReturnedValue Runtime::increment(const Value &value)
}
}
-QV4::ReturnedValue Runtime::decrement(const Value &value)
+QV4::ReturnedValue Runtime::method_decrement(const Value &value)
{
TRACE1(value);
@@ -1364,31 +1390,31 @@ QV4::ReturnedValue RuntimeHelpers::toObject(ExecutionEngine *engine, const Value
#endif // V4_BOOTSTRAP
-ReturnedValue Runtime::toDouble(const Value &value)
+ReturnedValue Runtime::method_toDouble(const Value &value)
{
TRACE1(value);
return Encode(value.toNumber());
}
-int Runtime::toInt(const Value &value)
+int Runtime::method_toInt(const Value &value)
{
TRACE1(value);
return value.toInt32();
}
-int Runtime::doubleToInt(const double &d)
+int Runtime::method_doubleToInt(const double &d)
{
TRACE0();
return Primitive::toInt32(d);
}
-unsigned Runtime::toUInt(const Value &value)
+unsigned Runtime::method_toUInt(const Value &value)
{
TRACE1(value);
return value.toUInt32();
}
-unsigned Runtime::doubleToUInt(const double &d)
+unsigned Runtime::method_doubleToUInt(const double &d)
{
TRACE0();
return Primitive::toUInt32(d);
@@ -1396,17 +1422,17 @@ unsigned Runtime::doubleToUInt(const double &d)
#ifndef V4_BOOTSTRAP
-ReturnedValue Runtime::getQmlContext(NoThrowEngine *engine)
+ReturnedValue Runtime::method_getQmlContext(NoThrowEngine *engine)
{
return engine->qmlContext()->asReturnedValue();
}
-ReturnedValue Runtime::regexpLiteral(ExecutionEngine *engine, int id)
+ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id)
{
return engine->current->compilationUnit->runtimeRegularExpressions[id].asReturnedValue();
}
-ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
+ReturnedValue Runtime::method_getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
{
Scope scope(engine);
QV4::Scoped<QObjectWrapper> wrapper(scope, object);
@@ -1417,7 +1443,7 @@ ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Valu
return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->object(), propertyIndex, captureRequired);
}
-QV4::ReturnedValue Runtime::getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex)
+QV4::ReturnedValue Runtime::method_getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex)
{
QObject *scopeObject = engine->qmlScopeObject();
QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject);
@@ -1427,19 +1453,19 @@ QV4::ReturnedValue Runtime::getQmlAttachedProperty(ExecutionEngine *engine, int
return QV4::QObjectWrapper::getProperty(engine, attachedObject, propertyIndex, /*captureRequired*/true);
}
-ReturnedValue Runtime::getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
+ReturnedValue Runtime::method_getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->scopeObject, propertyIndex, false);
}
-ReturnedValue Runtime::getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
+ReturnedValue Runtime::method_getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->context->contextObject, propertyIndex, false);
}
-ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
+ReturnedValue Runtime::method_getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
{
Scope scope(engine);
QV4::Scoped<QmlTypeWrapper> wrapper(scope, object);
@@ -1450,7 +1476,7 @@ ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionEngine *engine, c
return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->singletonObject(), propertyIndex, captureRequired);
}
-ReturnedValue Runtime::getQmlIdObject(ExecutionEngine *engine, const Value &c, uint index)
+ReturnedValue Runtime::method_getQmlIdObject(ExecutionEngine *engine, const Value &c, uint index)
{
Scope scope(engine);
const QmlContext &qmlContext = static_cast<const QmlContext &>(c);
@@ -1465,19 +1491,19 @@ ReturnedValue Runtime::getQmlIdObject(ExecutionEngine *engine, const Value &c, u
return QObjectWrapper::wrap(engine, context->idValues[index].data());
}
-void Runtime::setQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
+void Runtime::method_setQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
return QV4::QObjectWrapper::setProperty(engine, c.d()->qml->scopeObject, propertyIndex, value);
}
-void Runtime::setQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
+void Runtime::method_setQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
return QV4::QObjectWrapper::setProperty(engine, c.d()->qml->context->contextObject, propertyIndex, value);
}
-void Runtime::setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value)
+void Runtime::method_setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value)
{
Scope scope(engine);
QV4::Scoped<QObjectWrapper> wrapper(scope, object);
@@ -1488,7 +1514,7 @@ void Runtime::setQmlQObjectProperty(ExecutionEngine *engine, const Value &object
wrapper->setProperty(engine, propertyIndex, value);
}
-ReturnedValue Runtime::getQmlImportedScripts(NoThrowEngine *engine)
+ReturnedValue Runtime::method_getQmlImportedScripts(NoThrowEngine *engine)
{
QQmlContextData *context = engine->callingQmlContext();
if (!context)
@@ -1496,14 +1522,14 @@ ReturnedValue Runtime::getQmlImportedScripts(NoThrowEngine *engine)
return context->importedScripts.value();
}
-QV4::ReturnedValue Runtime::getQmlSingleton(QV4::NoThrowEngine *engine, int nameIndex)
+QV4::ReturnedValue Runtime::method_getQmlSingleton(QV4::NoThrowEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
return engine->qmlSingletonWrapper(name);
}
-void Runtime::convertThisToObject(ExecutionEngine *engine)
+void Runtime::method_convertThisToObject(ExecutionEngine *engine)
{
Value *t = &engine->current->callData->thisObject;
if (t->isObject())
@@ -1515,6 +1541,289 @@ void Runtime::convertThisToObject(ExecutionEngine *engine)
}
}
+ReturnedValue Runtime::method_uPlus(const Value &value)
+{
+ TRACE1(value);
+
+ if (value.isNumber())
+ return value.asReturnedValue();
+ if (value.integerCompatible())
+ return Encode(value.int_32());
+
+ double n = value.toNumberImpl();
+ return Encode(n);
+}
+
+ReturnedValue Runtime::method_uMinus(const Value &value)
+{
+ TRACE1(value);
+
+ // +0 != -0, so we need to convert to double when negating 0
+ if (value.isInteger() && value.integerValue())
+ return Encode(-value.integerValue());
+ else {
+ double n = RuntimeHelpers::toNumber(value);
+ return Encode(-n);
+ }
+}
+
+ReturnedValue Runtime::method_complement(const Value &value)
+{
+ TRACE1(value);
+
+ int n = value.toInt32();
+ return Encode((int)~n);
+}
+
+ReturnedValue Runtime::method_uNot(const Value &value)
+{
+ TRACE1(value);
+
+ bool b = value.toBoolean();
+ return Encode(!b);
+}
+
+// binary operators
+ReturnedValue Runtime::method_bitOr(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ int lval = left.toInt32();
+ int rval = right.toInt32();
+ return Encode(lval | rval);
+}
+
+ReturnedValue Runtime::method_bitXor(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ int lval = left.toInt32();
+ int rval = right.toInt32();
+ return Encode(lval ^ rval);
+}
+
+ReturnedValue Runtime::method_bitAnd(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ int lval = left.toInt32();
+ int rval = right.toInt32();
+ return Encode(lval & rval);
+}
+
+#ifndef V4_BOOTSTRAP
+ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ if (Q_LIKELY(left.isInteger() && right.isInteger()))
+ return add_int32(left.integerValue(), right.integerValue());
+ if (left.isNumber() && right.isNumber())
+ return Primitive::fromDouble(left.asDouble() + right.asDouble()).asReturnedValue();
+
+ return RuntimeHelpers::addHelper(engine, left, right);
+}
+#endif // V4_BOOTSTRAP
+
+ReturnedValue Runtime::method_sub(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ if (Q_LIKELY(left.isInteger() && right.isInteger()))
+ return sub_int32(left.integerValue(), right.integerValue());
+
+ double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
+ double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
+
+ return Primitive::fromDouble(lval - rval).asReturnedValue();
+}
+
+ReturnedValue Runtime::method_mul(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ if (Q_LIKELY(left.isInteger() && right.isInteger()))
+ return mul_int32(left.integerValue(), right.integerValue());
+
+ double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
+ double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
+
+ return Primitive::fromDouble(lval * rval).asReturnedValue();
+}
+
+ReturnedValue Runtime::method_div(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ if (Value::integerCompatible(left, right)) {
+ int lval = left.integerValue();
+ int rval = right.integerValue();
+ if (rval != 0 && (lval % rval == 0))
+ return Encode(int(lval / rval));
+ else
+ return Encode(double(lval) / rval);
+ }
+
+ double lval = left.toNumber();
+ double rval = right.toNumber();
+ return Primitive::fromDouble(lval / rval).asReturnedValue();
+}
+
+ReturnedValue Runtime::method_mod(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ if (Value::integerCompatible(left, right) && right.integerValue() != 0) {
+ int intRes = left.integerValue() % right.integerValue();
+ if (intRes != 0 || left.integerValue() >= 0)
+ return Encode(intRes);
+ }
+
+ double lval = RuntimeHelpers::toNumber(left);
+ double rval = RuntimeHelpers::toNumber(right);
+#ifdef fmod
+# undef fmod
+#endif
+ return Primitive::fromDouble(std::fmod(lval, rval)).asReturnedValue();
+}
+
+ReturnedValue Runtime::method_shl(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ int lval = left.toInt32();
+ int rval = right.toInt32() & 0x1f;
+ return Encode((int)(lval << rval));
+}
+
+ReturnedValue Runtime::method_shr(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ int lval = left.toInt32();
+ unsigned rval = right.toUInt32() & 0x1f;
+ return Encode((int)(lval >> rval));
+}
+
+ReturnedValue Runtime::method_ushr(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ unsigned lval = left.toUInt32();
+ unsigned rval = right.toUInt32() & 0x1f;
+ uint res = lval >> rval;
+
+ return Encode(res);
+}
+
+ReturnedValue Runtime::method_greaterThan(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = method_compareGreaterThan(left, right);
+ return Encode(r);
+}
+
+ReturnedValue Runtime::method_lessThan(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = method_compareLessThan(left, right);
+ return Encode(r);
+}
+
+ReturnedValue Runtime::method_greaterEqual(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = method_compareGreaterEqual(left, right);
+ return Encode(r);
+}
+
+ReturnedValue Runtime::method_lessEqual(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = method_compareLessEqual(left, right);
+ return Encode(r);
+}
+
+Bool Runtime::method_compareEqual(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ if (left.rawValue() == right.rawValue())
+ // NaN != NaN
+ return !left.isNaN();
+
+ if (left.type() == right.type()) {
+ if (!left.isManaged())
+ return false;
+ if (left.isString() == right.isString())
+ return left.cast<Managed>()->isEqualTo(right.cast<Managed>());
+ }
+
+ return RuntimeHelpers::equalHelper(left, right);
+}
+
+ReturnedValue Runtime::method_equal(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = method_compareEqual(left, right);
+ return Encode(r);
+}
+
+ReturnedValue Runtime::method_notEqual(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = !method_compareEqual(left, right);
+ return Encode(r);
+}
+
+ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = RuntimeHelpers::strictEqual(left, right);
+ return Encode(r);
+}
+
+ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = ! RuntimeHelpers::strictEqual(left, right);
+ return Encode(r);
+}
+
+Bool Runtime::method_compareNotEqual(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ return !Runtime::method_compareEqual(left, right);
+}
+
+Bool Runtime::method_compareStrictEqual(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ return RuntimeHelpers::strictEqual(left, right);
+}
+
+Bool Runtime::method_compareStrictNotEqual(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ return ! RuntimeHelpers::strictEqual(left, right);
+}
+
+Bool Runtime::method_toBoolean(const Value &value)
+{
+ return value.toBoolean();
+}
+
#endif // V4_BOOTSTRAP
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index b63777e164..88c09ec5f9 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -55,10 +55,9 @@
#include "qv4context_p.h"
#include "qv4engine_p.h"
#include "qv4math_p.h"
-
+#include "qv4runtimeapi_p.h"
#include <QtCore/qnumeric.h>
-
QT_BEGIN_NAMESPACE
class QQmlAccessors;
@@ -100,156 +99,6 @@ enum TypeHint {
STRING_HINT
};
-// This is a trick to tell the code generators that functions taking a NoThrowContext won't
-// throw exceptions and therefore don't need a check after the call.
-
-#ifndef V4_BOOTSTRAP
-struct NoThrowEngine : public ExecutionEngine
-{
-};
-#else
-struct NoThrowEngine;
-#endif
-
-struct Q_QML_PRIVATE_EXPORT Runtime {
- // call
- static ReturnedValue callGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData);
- static ReturnedValue callActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData);
- static ReturnedValue callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData);
- static ReturnedValue callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData);
- static ReturnedValue callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData);
- static ReturnedValue callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData);
- static ReturnedValue callElement(ExecutionEngine *engine, const Value &index, CallData *callData);
- static ReturnedValue callValue(ExecutionEngine *engine, const Value &func, CallData *callData);
-
- // construct
- static ReturnedValue constructGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData);
- static ReturnedValue constructActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData);
- static ReturnedValue constructProperty(ExecutionEngine *engine, int nameIndex, CallData *callData);
- static ReturnedValue constructPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData);
- static ReturnedValue constructValue(ExecutionEngine *engine, const Value &func, CallData *callData);
-
- // set & get
- static void setActivationProperty(ExecutionEngine *engine, int nameIndex, const Value &value);
- static void setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value);
- static void setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value);
- static ReturnedValue getProperty(ExecutionEngine *engine, const Value &object, int nameIndex);
- static ReturnedValue getActivationProperty(ExecutionEngine *engine, int nameIndex);
- static ReturnedValue getElement(ExecutionEngine *engine, const Value &object, const Value &index);
-
- // typeof
- static ReturnedValue typeofValue(ExecutionEngine *engine, const Value &val);
- static ReturnedValue typeofName(ExecutionEngine *engine, int nameIndex);
- static ReturnedValue typeofScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex);
- static ReturnedValue typeofContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex);
- static ReturnedValue typeofMember(ExecutionEngine *engine, const Value &base, int nameIndex);
- static ReturnedValue typeofElement(ExecutionEngine *engine, const Value &base, const Value &index);
-
- // delete
- static ReturnedValue deleteElement(ExecutionEngine *engine, const Value &base, const Value &index);
- static ReturnedValue deleteMember(ExecutionEngine *engine, const Value &base, int nameIndex);
- static ReturnedValue deleteMemberString(ExecutionEngine *engine, const Value &base, String *name);
- static ReturnedValue deleteName(ExecutionEngine *engine, int nameIndex);
-
- // exceptions & scopes
- static void throwException(ExecutionEngine *engine, const Value &value);
- static ReturnedValue unwindException(ExecutionEngine *engine);
- static void pushWithScope(const Value &o, ExecutionEngine *engine);
- static void pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex);
- static void popScope(ExecutionEngine *engine);
-
- // closures
- static ReturnedValue closure(ExecutionEngine *engine, int functionId);
-
- // function header
- static void declareVar(ExecutionEngine *engine, bool deletable, int nameIndex);
- static ReturnedValue setupArgumentsObject(ExecutionEngine *engine);
- static void convertThisToObject(ExecutionEngine *engine);
-
- // literals
- static ReturnedValue arrayLiteral(ExecutionEngine *engine, Value *values, uint length);
- static ReturnedValue objectLiteral(ExecutionEngine *engine, const Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags);
- static ReturnedValue regexpLiteral(ExecutionEngine *engine, int id);
-
- // foreach
- static ReturnedValue foreachIterator(ExecutionEngine *engine, const Value &in);
- static ReturnedValue foreachNextPropertyName(const Value &foreach_iterator);
-
- // unary operators
- typedef ReturnedValue (*UnaryOperation)(const Value &value);
- static ReturnedValue uPlus(const Value &value);
- static ReturnedValue uMinus(const Value &value);
- static ReturnedValue uNot(const Value &value);
- static ReturnedValue complement(const Value &value);
- static ReturnedValue increment(const Value &value);
- static ReturnedValue decrement(const Value &value);
-
- // binary operators
- typedef ReturnedValue (*BinaryOperation)(const Value &left, const Value &right);
- typedef ReturnedValue (*BinaryOperationContext)(ExecutionEngine *engine, const Value &left, const Value &right);
-
- static ReturnedValue instanceof(ExecutionEngine *engine, const Value &left, const Value &right);
- static ReturnedValue in(ExecutionEngine *engine, const Value &left, const Value &right);
- static ReturnedValue add(ExecutionEngine *engine, const Value &left, const Value &right);
- static ReturnedValue addString(ExecutionEngine *engine, const Value &left, const Value &right);
- static ReturnedValue bitOr(const Value &left, const Value &right);
- static ReturnedValue bitXor(const Value &left, const Value &right);
- static ReturnedValue bitAnd(const Value &left, const Value &right);
- static ReturnedValue sub(const Value &left, const Value &right);
- static ReturnedValue mul(const Value &left, const Value &right);
- static ReturnedValue div(const Value &left, const Value &right);
- static ReturnedValue mod(const Value &left, const Value &right);
- static ReturnedValue shl(const Value &left, const Value &right);
- static ReturnedValue shr(const Value &left, const Value &right);
- static ReturnedValue ushr(const Value &left, const Value &right);
- static ReturnedValue greaterThan(const Value &left, const Value &right);
- static ReturnedValue lessThan(const Value &left, const Value &right);
- static ReturnedValue greaterEqual(const Value &left, const Value &right);
- static ReturnedValue lessEqual(const Value &left, const Value &right);
- static ReturnedValue equal(const Value &left, const Value &right);
- static ReturnedValue notEqual(const Value &left, const Value &right);
- static ReturnedValue strictEqual(const Value &left, const Value &right);
- static ReturnedValue strictNotEqual(const Value &left, const Value &right);
-
- // comparisons
- typedef Bool (*CompareOperation)(const Value &left, const Value &right);
- static Bool compareGreaterThan(const Value &l, const Value &r);
- static Bool compareLessThan(const Value &l, const Value &r);
- static Bool compareGreaterEqual(const Value &l, const Value &r);
- static Bool compareLessEqual(const Value &l, const Value &r);
- static Bool compareEqual(const Value &left, const Value &right);
- static Bool compareNotEqual(const Value &left, const Value &right);
- static Bool compareStrictEqual(const Value &left, const Value &right);
- static Bool compareStrictNotEqual(const Value &left, const Value &right);
-
- typedef Bool (*CompareOperationContext)(ExecutionEngine *engine, const Value &left, const Value &right);
- static Bool compareInstanceof(ExecutionEngine *engine, const Value &left, const Value &right);
- static Bool compareIn(ExecutionEngine *engine, const Value &left, const Value &right);
-
- // conversions
- static Bool toBoolean(const Value &value);
- static ReturnedValue toDouble(const Value &value);
- static int toInt(const Value &value);
- static int doubleToInt(const double &d);
- static unsigned toUInt(const Value &value);
- static unsigned doubleToUInt(const double &d);
-
- // qml
- static ReturnedValue getQmlContext(NoThrowEngine *engine);
- static ReturnedValue getQmlImportedScripts(NoThrowEngine *engine);
- static ReturnedValue getQmlSingleton(NoThrowEngine *engine, int nameIndex);
- static ReturnedValue getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex);
- static ReturnedValue getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex);
- static ReturnedValue getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex);
- static ReturnedValue getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired);
- static ReturnedValue getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired);
- static ReturnedValue getQmlIdObject(ExecutionEngine *engine, const Value &context, uint index);
-
- static void setQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value);
- static void setQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value);
- static void setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value);
-};
-
struct Q_QML_PRIVATE_EXPORT RuntimeHelpers {
static ReturnedValue objectDefaultValue(const Object *object, int typeHint);
static ReturnedValue toPrimitive(const Value &value, int typeHint);
@@ -287,287 +136,6 @@ inline double RuntimeHelpers::toNumber(const Value &value)
{
return value.toNumber();
}
-
-inline ReturnedValue Runtime::uPlus(const Value &value)
-{
- TRACE1(value);
-
- if (value.isNumber())
- return value.asReturnedValue();
- if (value.integerCompatible())
- return Encode(value.int_32());
-
- double n = value.toNumberImpl();
- return Encode(n);
-}
-
-inline ReturnedValue Runtime::uMinus(const Value &value)
-{
- TRACE1(value);
-
- // +0 != -0, so we need to convert to double when negating 0
- if (value.isInteger() && value.integerValue())
- return Encode(-value.integerValue());
- else {
- double n = RuntimeHelpers::toNumber(value);
- return Encode(-n);
- }
-}
-
-inline ReturnedValue Runtime::complement(const Value &value)
-{
- TRACE1(value);
-
- int n = value.toInt32();
- return Encode((int)~n);
-}
-
-inline ReturnedValue Runtime::uNot(const Value &value)
-{
- TRACE1(value);
-
- bool b = value.toBoolean();
- return Encode(!b);
-}
-
-// binary operators
-inline ReturnedValue Runtime::bitOr(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- int lval = left.toInt32();
- int rval = right.toInt32();
- return Encode(lval | rval);
-}
-
-inline ReturnedValue Runtime::bitXor(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- int lval = left.toInt32();
- int rval = right.toInt32();
- return Encode(lval ^ rval);
-}
-
-inline ReturnedValue Runtime::bitAnd(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- int lval = left.toInt32();
- int rval = right.toInt32();
- return Encode(lval & rval);
-}
-
-#ifndef V4_BOOTSTRAP
-inline ReturnedValue Runtime::add(ExecutionEngine *engine, const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- if (Q_LIKELY(left.isInteger() && right.isInteger()))
- return add_int32(left.integerValue(), right.integerValue());
- if (left.isNumber() && right.isNumber())
- return Primitive::fromDouble(left.asDouble() + right.asDouble()).asReturnedValue();
-
- return RuntimeHelpers::addHelper(engine, left, right);
-}
-#endif // V4_BOOTSTRAP
-
-inline ReturnedValue Runtime::sub(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- if (Q_LIKELY(left.isInteger() && right.isInteger()))
- return sub_int32(left.integerValue(), right.integerValue());
-
- double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
- double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
-
- return Primitive::fromDouble(lval - rval).asReturnedValue();
-}
-
-inline ReturnedValue Runtime::mul(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- if (Q_LIKELY(left.isInteger() && right.isInteger()))
- return mul_int32(left.integerValue(), right.integerValue());
-
- double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
- double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
-
- return Primitive::fromDouble(lval * rval).asReturnedValue();
-}
-
-inline ReturnedValue Runtime::div(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- if (Value::integerCompatible(left, right)) {
- int lval = left.integerValue();
- int rval = right.integerValue();
- if (rval != 0 && (lval % rval == 0))
- return Encode(int(lval / rval));
- else
- return Encode(double(lval) / rval);
- }
-
- double lval = left.toNumber();
- double rval = right.toNumber();
- return Primitive::fromDouble(lval / rval).asReturnedValue();
-}
-
-inline ReturnedValue Runtime::mod(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- if (Value::integerCompatible(left, right) && right.integerValue() != 0) {
- int intRes = left.integerValue() % right.integerValue();
- if (intRes != 0 || left.integerValue() >= 0)
- return Encode(intRes);
- }
-
- double lval = RuntimeHelpers::toNumber(left);
- double rval = RuntimeHelpers::toNumber(right);
- return Primitive::fromDouble(std::fmod(lval, rval)).asReturnedValue();
-}
-
-inline ReturnedValue Runtime::shl(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- int lval = left.toInt32();
- int rval = right.toInt32() & 0x1f;
- return Encode((int)(lval << rval));
-}
-
-inline ReturnedValue Runtime::shr(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- int lval = left.toInt32();
- unsigned rval = right.toUInt32() & 0x1f;
- return Encode((int)(lval >> rval));
-}
-
-inline ReturnedValue Runtime::ushr(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- unsigned lval = left.toUInt32();
- unsigned rval = right.toUInt32() & 0x1f;
- uint res = lval >> rval;
-
- return Encode(res);
-}
-
-inline ReturnedValue Runtime::greaterThan(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- bool r = Runtime::compareGreaterThan(left, right);
- return Encode(r);
-}
-
-inline ReturnedValue Runtime::lessThan(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- bool r = Runtime::compareLessThan(left, right);
- return Encode(r);
-}
-
-inline ReturnedValue Runtime::greaterEqual(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- bool r = Runtime::compareGreaterEqual(left, right);
- return Encode(r);
-}
-
-inline ReturnedValue Runtime::lessEqual(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- bool r = Runtime::compareLessEqual(left, right);
- return Encode(r);
-}
-
-inline Bool Runtime::compareEqual(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- if (left.rawValue() == right.rawValue())
- // NaN != NaN
- return !left.isNaN();
-
- if (left.type() == right.type()) {
- if (!left.isManaged())
- return false;
- if (left.isString() == right.isString())
- return left.cast<Managed>()->isEqualTo(right.cast<Managed>());
- }
-
- return RuntimeHelpers::equalHelper(left, right);
-}
-
-inline ReturnedValue Runtime::equal(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- bool r = Runtime::compareEqual(left, right);
- return Encode(r);
-}
-
-inline ReturnedValue Runtime::notEqual(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- bool r = !Runtime::compareEqual(left, right);
- return Encode(r);
-}
-
-inline ReturnedValue Runtime::strictEqual(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- bool r = RuntimeHelpers::strictEqual(left, right);
- return Encode(r);
-}
-
-inline ReturnedValue Runtime::strictNotEqual(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- bool r = ! RuntimeHelpers::strictEqual(left, right);
- return Encode(r);
-}
-
-inline Bool Runtime::compareNotEqual(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- return !Runtime::compareEqual(left, right);
-}
-
-inline Bool Runtime::compareStrictEqual(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- return RuntimeHelpers::strictEqual(left, right);
-}
-
-inline Bool Runtime::compareStrictNotEqual(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- return ! RuntimeHelpers::strictEqual(left, right);
-}
-
-inline Bool Runtime::toBoolean(const Value &value)
-{
- return value.toBoolean();
-}
-
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
new file mode 100644
index 0000000000..cbc7a2ddc1
--- /dev/null
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4RUNTIMEAPI_P_H
+#define QV4RUNTIMEAPI_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct NoThrowEngine;
+
+#define RUNTIME_METHOD(returnvalue, name, args) \
+ typedef returnvalue (*Method_##name)args; \
+ static returnvalue method_##name args; \
+ const Method_##name name
+
+#define INIT_RUNTIME_METHOD(name) \
+ name(method_##name)
+
+struct Q_QML_PRIVATE_EXPORT Runtime {
+ Runtime()
+ : INIT_RUNTIME_METHOD(callGlobalLookup)
+ , INIT_RUNTIME_METHOD(callActivationProperty)
+ , INIT_RUNTIME_METHOD(callQmlScopeObjectProperty)
+ , INIT_RUNTIME_METHOD(callQmlContextObjectProperty)
+ , INIT_RUNTIME_METHOD(callProperty)
+ , INIT_RUNTIME_METHOD(callPropertyLookup)
+ , INIT_RUNTIME_METHOD(callElement)
+ , INIT_RUNTIME_METHOD(callValue)
+ , INIT_RUNTIME_METHOD(constructGlobalLookup)
+ , INIT_RUNTIME_METHOD(constructActivationProperty)
+ , INIT_RUNTIME_METHOD(constructProperty)
+ , INIT_RUNTIME_METHOD(constructPropertyLookup)
+ , INIT_RUNTIME_METHOD(constructValue)
+ , INIT_RUNTIME_METHOD(setActivationProperty)
+ , INIT_RUNTIME_METHOD(setProperty)
+ , INIT_RUNTIME_METHOD(setElement)
+ , INIT_RUNTIME_METHOD(getProperty)
+ , INIT_RUNTIME_METHOD(getActivationProperty)
+ , INIT_RUNTIME_METHOD(getElement)
+ , INIT_RUNTIME_METHOD(typeofValue)
+ , INIT_RUNTIME_METHOD(typeofName)
+ , INIT_RUNTIME_METHOD(typeofScopeObjectProperty)
+ , INIT_RUNTIME_METHOD(typeofContextObjectProperty)
+ , INIT_RUNTIME_METHOD(typeofMember)
+ , INIT_RUNTIME_METHOD(typeofElement)
+ , INIT_RUNTIME_METHOD(deleteElement)
+ , INIT_RUNTIME_METHOD(deleteMember)
+ , INIT_RUNTIME_METHOD(deleteMemberString)
+ , INIT_RUNTIME_METHOD(deleteName)
+ , INIT_RUNTIME_METHOD(throwException)
+ , INIT_RUNTIME_METHOD(unwindException)
+ , INIT_RUNTIME_METHOD(pushWithScope)
+ , INIT_RUNTIME_METHOD(pushCatchScope)
+ , INIT_RUNTIME_METHOD(popScope)
+ , INIT_RUNTIME_METHOD(closure)
+ , INIT_RUNTIME_METHOD(declareVar)
+ , INIT_RUNTIME_METHOD(setupArgumentsObject)
+ , INIT_RUNTIME_METHOD(convertThisToObject)
+ , INIT_RUNTIME_METHOD(arrayLiteral)
+ , INIT_RUNTIME_METHOD(objectLiteral)
+ , INIT_RUNTIME_METHOD(regexpLiteral)
+ , INIT_RUNTIME_METHOD(foreachIterator)
+ , INIT_RUNTIME_METHOD(foreachNextPropertyName)
+ , INIT_RUNTIME_METHOD(uPlus)
+ , INIT_RUNTIME_METHOD(uMinus)
+ , INIT_RUNTIME_METHOD(uNot)
+ , INIT_RUNTIME_METHOD(complement)
+ , INIT_RUNTIME_METHOD(increment)
+ , INIT_RUNTIME_METHOD(decrement)
+ , INIT_RUNTIME_METHOD(instanceof)
+ , INIT_RUNTIME_METHOD(in)
+ , INIT_RUNTIME_METHOD(add)
+ , INIT_RUNTIME_METHOD(addString)
+ , INIT_RUNTIME_METHOD(bitOr)
+ , INIT_RUNTIME_METHOD(bitXor)
+ , INIT_RUNTIME_METHOD(bitAnd)
+ , INIT_RUNTIME_METHOD(sub)
+ , INIT_RUNTIME_METHOD(mul)
+ , INIT_RUNTIME_METHOD(div)
+ , INIT_RUNTIME_METHOD(mod)
+ , INIT_RUNTIME_METHOD(shl)
+ , INIT_RUNTIME_METHOD(shr)
+ , INIT_RUNTIME_METHOD(ushr)
+ , INIT_RUNTIME_METHOD(greaterThan)
+ , INIT_RUNTIME_METHOD(lessThan)
+ , INIT_RUNTIME_METHOD(greaterEqual)
+ , INIT_RUNTIME_METHOD(lessEqual)
+ , INIT_RUNTIME_METHOD(equal)
+ , INIT_RUNTIME_METHOD(notEqual)
+ , INIT_RUNTIME_METHOD(strictEqual)
+ , INIT_RUNTIME_METHOD(strictNotEqual)
+ , INIT_RUNTIME_METHOD(compareGreaterThan)
+ , INIT_RUNTIME_METHOD(compareLessThan)
+ , INIT_RUNTIME_METHOD(compareGreaterEqual)
+ , INIT_RUNTIME_METHOD(compareLessEqual)
+ , INIT_RUNTIME_METHOD(compareEqual)
+ , INIT_RUNTIME_METHOD(compareNotEqual)
+ , INIT_RUNTIME_METHOD(compareStrictEqual)
+ , INIT_RUNTIME_METHOD(compareStrictNotEqual)
+ , INIT_RUNTIME_METHOD(compareInstanceof)
+ , INIT_RUNTIME_METHOD(compareIn)
+ , INIT_RUNTIME_METHOD(toBoolean)
+ , INIT_RUNTIME_METHOD(toDouble)
+ , INIT_RUNTIME_METHOD(toInt)
+ , INIT_RUNTIME_METHOD(doubleToInt)
+ , INIT_RUNTIME_METHOD(toUInt)
+ , INIT_RUNTIME_METHOD(doubleToUInt)
+ , INIT_RUNTIME_METHOD(getQmlContext)
+ , INIT_RUNTIME_METHOD(getQmlImportedScripts)
+ , INIT_RUNTIME_METHOD(getQmlSingleton)
+ , INIT_RUNTIME_METHOD(getQmlAttachedProperty)
+ , INIT_RUNTIME_METHOD(getQmlScopeObjectProperty)
+ , INIT_RUNTIME_METHOD(getQmlContextObjectProperty)
+ , INIT_RUNTIME_METHOD(getQmlQObjectProperty)
+ , INIT_RUNTIME_METHOD(getQmlSingletonQObjectProperty)
+ , INIT_RUNTIME_METHOD(getQmlIdObject)
+ , INIT_RUNTIME_METHOD(setQmlScopeObjectProperty)
+ , INIT_RUNTIME_METHOD(setQmlContextObjectProperty)
+ , INIT_RUNTIME_METHOD(setQmlQObjectProperty)
+ { }
+
+ // call
+ RUNTIME_METHOD(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, callActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, callQmlScopeObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, callQmlContextObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, callProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, callElement, (ExecutionEngine *engine, const Value &index, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, CallData *callData));
+
+ // construct
+ RUNTIME_METHOD(ReturnedValue, constructGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, constructActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, constructProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, constructPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData));
+ RUNTIME_METHOD(ReturnedValue, constructValue, (ExecutionEngine *engine, const Value &func, CallData *callData));
+
+ // set & get
+ RUNTIME_METHOD(void, setActivationProperty, (ExecutionEngine *engine, int nameIndex, const Value &value));
+ RUNTIME_METHOD(void, setProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value));
+ RUNTIME_METHOD(void, setElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value));
+ RUNTIME_METHOD(ReturnedValue, getProperty, (ExecutionEngine *engine, const Value &object, int nameIndex));
+ RUNTIME_METHOD(ReturnedValue, getActivationProperty, (ExecutionEngine *engine, int nameIndex));
+ RUNTIME_METHOD(ReturnedValue, getElement, (ExecutionEngine *engine, const Value &object, const Value &index));
+
+ // typeof
+ RUNTIME_METHOD(ReturnedValue, typeofValue, (ExecutionEngine *engine, const Value &val));
+ RUNTIME_METHOD(ReturnedValue, typeofName, (ExecutionEngine *engine, int nameIndex));
+ RUNTIME_METHOD(ReturnedValue, typeofScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex));
+ RUNTIME_METHOD(ReturnedValue, typeofContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex));
+ RUNTIME_METHOD(ReturnedValue, typeofMember, (ExecutionEngine *engine, const Value &base, int nameIndex));
+ RUNTIME_METHOD(ReturnedValue, typeofElement, (ExecutionEngine *engine, const Value &base, const Value &index));
+
+ // delete
+ RUNTIME_METHOD(ReturnedValue, deleteElement, (ExecutionEngine *engine, const Value &base, const Value &index));
+ RUNTIME_METHOD(ReturnedValue, deleteMember, (ExecutionEngine *engine, const Value &base, int nameIndex));
+ RUNTIME_METHOD(ReturnedValue, deleteMemberString, (ExecutionEngine *engine, const Value &base, String *name));
+ RUNTIME_METHOD(ReturnedValue, deleteName, (ExecutionEngine *engine, int nameIndex));
+
+ // exceptions & scopes
+ RUNTIME_METHOD(void, throwException, (ExecutionEngine *engine, const Value &value));
+ RUNTIME_METHOD(ReturnedValue, unwindException, (ExecutionEngine *engine));
+ RUNTIME_METHOD(void, pushWithScope, (const Value &o, ExecutionEngine *engine));
+ RUNTIME_METHOD(void, pushCatchScope, (NoThrowEngine *engine, int exceptionVarNameIndex));
+ RUNTIME_METHOD(void, popScope, (ExecutionEngine *engine));
+
+ // closures
+ RUNTIME_METHOD(ReturnedValue, closure, (ExecutionEngine *engine, int functionId));
+
+ // function header
+ RUNTIME_METHOD(void, declareVar, (ExecutionEngine *engine, bool deletable, int nameIndex));
+ RUNTIME_METHOD(ReturnedValue, setupArgumentsObject, (ExecutionEngine *engine));
+ RUNTIME_METHOD(void, convertThisToObject, (ExecutionEngine *engine));
+
+ // literals
+ RUNTIME_METHOD(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length));
+ RUNTIME_METHOD(ReturnedValue, objectLiteral, (ExecutionEngine *engine, const Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags));
+ RUNTIME_METHOD(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id));
+
+ // foreach
+ RUNTIME_METHOD(ReturnedValue, foreachIterator, (ExecutionEngine *engine, const Value &in));
+ RUNTIME_METHOD(ReturnedValue, foreachNextPropertyName, (const Value &foreach_iterator));
+
+ // unary operators
+ typedef ReturnedValue (*UnaryOperation)(const Value &value);
+ RUNTIME_METHOD(ReturnedValue, uPlus, (const Value &value));
+ RUNTIME_METHOD(ReturnedValue, uMinus, (const Value &value));
+ RUNTIME_METHOD(ReturnedValue, uNot, (const Value &value));
+ RUNTIME_METHOD(ReturnedValue, complement, (const Value &value));
+ RUNTIME_METHOD(ReturnedValue, increment, (const Value &value));
+ RUNTIME_METHOD(ReturnedValue, decrement, (const Value &value));
+
+ // binary operators
+ typedef ReturnedValue (*BinaryOperation)(const Value &left, const Value &right);
+ typedef ReturnedValue (*BinaryOperationContext)(ExecutionEngine *engine, const Value &left, const Value &right);
+
+ RUNTIME_METHOD(ReturnedValue, instanceof, (ExecutionEngine *engine, const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, in, (ExecutionEngine *engine, const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, add, (ExecutionEngine *engine, const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, addString, (ExecutionEngine *engine, const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, bitOr, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, bitXor, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, bitAnd, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, sub, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, mul, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, div, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, mod, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, shl, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, shr, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, ushr, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, greaterThan, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, lessThan, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, greaterEqual, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, lessEqual, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, equal, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, notEqual, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, strictEqual, (const Value &left, const Value &right));
+ RUNTIME_METHOD(ReturnedValue, strictNotEqual, (const Value &left, const Value &right));
+
+ // comparisons
+ RUNTIME_METHOD(Bool, compareGreaterThan, (const Value &l, const Value &r));
+ RUNTIME_METHOD(Bool, compareLessThan, (const Value &l, const Value &r));
+ RUNTIME_METHOD(Bool, compareGreaterEqual, (const Value &l, const Value &r));
+ RUNTIME_METHOD(Bool, compareLessEqual, (const Value &l, const Value &r));
+ RUNTIME_METHOD(Bool, compareEqual, (const Value &left, const Value &right));
+ RUNTIME_METHOD(Bool, compareNotEqual, (const Value &left, const Value &right));
+ RUNTIME_METHOD(Bool, compareStrictEqual, (const Value &left, const Value &right));
+ RUNTIME_METHOD(Bool, compareStrictNotEqual, (const Value &left, const Value &right));
+
+ RUNTIME_METHOD(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right));
+ RUNTIME_METHOD(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right));
+
+ // conversions
+ RUNTIME_METHOD(Bool, toBoolean, (const Value &value));
+ RUNTIME_METHOD(ReturnedValue, toDouble, (const Value &value));
+ RUNTIME_METHOD(int, toInt, (const Value &value));
+ RUNTIME_METHOD(int, doubleToInt, (const double &d));
+ RUNTIME_METHOD(unsigned, toUInt, (const Value &value));
+ RUNTIME_METHOD(unsigned, doubleToUInt, (const double &d));
+
+ // qml
+ RUNTIME_METHOD(ReturnedValue, getQmlContext, (NoThrowEngine *engine));
+ RUNTIME_METHOD(ReturnedValue, getQmlImportedScripts, (NoThrowEngine *engine));
+ RUNTIME_METHOD(ReturnedValue, getQmlSingleton, (NoThrowEngine *engine, int nameIndex));
+ RUNTIME_METHOD(ReturnedValue, getQmlAttachedProperty, (ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex));
+ RUNTIME_METHOD(ReturnedValue, getQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex));
+ RUNTIME_METHOD(ReturnedValue, getQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex));
+ RUNTIME_METHOD(ReturnedValue, getQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired));
+ RUNTIME_METHOD(ReturnedValue, getQmlSingletonQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired));
+ RUNTIME_METHOD(ReturnedValue, getQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index));
+
+ RUNTIME_METHOD(void, setQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value));
+ RUNTIME_METHOD(void, setQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value));
+ RUNTIME_METHOD(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value));
+};
+
+#undef RUNTIME_METHOD
+#undef INIT_RUNTIME_METHOD
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4RUNTIMEAPI_P_H
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index a6f7f8e0e7..44d171e087 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -71,14 +71,18 @@ struct ScopedValue;
struct Scope {
inline Scope(ExecutionContext *ctx)
: engine(ctx->d()->engine)
+ , mark(engine->jsStackTop)
+ , result(*engine->jsAlloca(1))
{
- mark = engine->jsStackTop;
+ result = Encode::undefined();
}
explicit Scope(ExecutionEngine *e)
: engine(e)
+ , mark(engine->jsStackTop)
+ , result(*engine->jsAlloca(1))
{
- mark = engine->jsStackTop;
+ result = Encode::undefined();
}
~Scope() {
@@ -93,7 +97,7 @@ struct Scope {
engine->jsStackTop = mark;
}
- Value *alloc(int nValues) {
+ Value *alloc(int nValues) const {
return engine->jsAlloca(nValues);
}
@@ -103,6 +107,7 @@ struct Scope {
ExecutionEngine *engine;
Value *mark;
+ Value &result;
private:
Q_DISABLE_COPY(Scope)
@@ -190,59 +195,59 @@ struct Scoped
Scoped(const Scope &scope)
{
- ptr = scope.engine->jsStackTop++;
- ptr->setM(0);
+ ptr = scope.engine->jsAlloca(1);
}
Scoped(const Scope &scope, const Value &v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(v.as<T>());
}
Scoped(const Scope &scope, Heap::Base *o)
{
Value v;
v = o;
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(v.as<T>());
}
Scoped(const Scope &scope, const ScopedValue &v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(v.ptr->as<T>());
}
Scoped(const Scope &scope, const Value &v, ConvertType)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
ptr->setRawValue(value_convert<T>(scope.engine, v));
}
Scoped(const Scope &scope, const Value *v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(v ? v->as<T>() : 0);
}
Scoped(const Scope &scope, T *t)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(t);
}
Scoped(const Scope &scope, typename T::Data *t)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
*ptr = t;
}
Scoped(const Scope &scope, const ReturnedValue &v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(QV4::Value::fromReturnedValue(v).as<T>());
}
+
Scoped(const Scope &scope, const ReturnedValue &v, ConvertType)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v)));
}
@@ -289,6 +294,10 @@ struct Scoped
return ptr->cast<T>();
}
+ const T *operator->() const {
+ return ptr->cast<T>();
+ }
+
bool operator!() const {
return !ptr->m();
}
@@ -311,7 +320,7 @@ struct Scoped
};
struct ScopedCallData {
- ScopedCallData(Scope &scope, int argc = 0)
+ ScopedCallData(const Scope &scope, int argc = 0)
{
int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value);
ptr = reinterpret_cast<CallData *>(scope.alloc(size));
@@ -362,19 +371,19 @@ struct ScopedProperty
struct ExecutionContextSaver
{
- ExecutionEngine *engine;
+ Scope scope; // this makes sure that a reference to context on the JS stack goes out of scope as soon as the context is not used anymore.
ExecutionContext *savedContext;
- ExecutionContextSaver(Scope &scope)
- : engine(scope.engine)
+ ExecutionContextSaver(const Scope &scope)
+ : scope(scope.engine)
{
- savedContext = engine->currentContext;
+ savedContext = scope.engine->currentContext;
}
~ExecutionContextSaver()
{
- Q_ASSERT(engine->jsStackTop > engine->currentContext);
- engine->currentContext = savedContext;
- engine->current = savedContext->d();
+ Q_ASSERT(scope.engine->jsStackTop > scope.engine->currentContext);
+ scope.engine->currentContext = savedContext;
+ scope.engine->current = savedContext->d();
}
};
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 4b847600b4..a2e379ec1a 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -64,34 +64,16 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Heap {
-struct CompilationUnitHolder : Object {
- inline CompilationUnitHolder(CompiledData::CompilationUnit *unit);
-
- QQmlRefPointer<CompiledData::CompilationUnit> unit;
-};
-
struct QmlBindingWrapper : FunctionObject {
QmlBindingWrapper(QV4::QmlContext *scope, Function *f);
};
}
-struct CompilationUnitHolder : public Object
-{
- V4_OBJECT2(CompilationUnitHolder, Object)
- V4_NEEDS_DESTROY
-};
-
-inline
-Heap::CompilationUnitHolder::CompilationUnitHolder(CompiledData::CompilationUnit *unit)
- : unit(unit)
-{
-}
-
struct QmlBindingWrapper : FunctionObject {
V4_OBJECT2(QmlBindingWrapper, FunctionObject)
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
}
@@ -101,7 +83,6 @@ QT_END_NAMESPACE
using namespace QV4;
DEFINE_OBJECT_VTABLE(QmlBindingWrapper);
-DEFINE_OBJECT_VTABLE(CompilationUnitHolder);
Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::QmlContext *scope, Function *f)
: Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false)
@@ -113,32 +94,33 @@ Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::QmlContext *scope, Function *f)
function->compilationUnit->addref();
}
-ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData)
+void QmlBindingWrapper::call(const Managed *that, Scope &scope, CallData *callData)
{
const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that);
ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
QV4::Function *f = This->function();
- if (!f)
- return QV4::Encode::undefined();
+ if (!f) {
+ scope.result = QV4::Encode::undefined();
+ return;
+ }
Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(This, callData));
v4->pushContext(ctx);
- ScopedValue result(scope, Q_V4_PROFILE(v4, f));
-
- return result->asReturnedValue();
+ scope.result = Q_V4_PROFILE(v4, f);
}
Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit)
: line(0), column(0), scope(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
- , vmFunction(0), parseAsBinding(true)
+ , compilationUnit(compilationUnit), vmFunction(0), parseAsBinding(true)
{
if (qml)
qmlContext.set(v4, *qml);
@@ -146,11 +128,6 @@ Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUn
parsed = true;
vmFunction = compilationUnit ? compilationUnit->linkToEngine(v4) : 0;
- if (vmFunction) {
- Scope valueScope(v4);
- ScopedObject holder(valueScope, v4->memoryManager->allocObject<CompilationUnitHolder>(compilationUnit));
- compilationUnitHolder.set(v4, holder);
- }
}
Script::~Script()
@@ -171,7 +148,7 @@ void Script::parse()
MemoryManager::GCBlocker gcBlocker(v4->memoryManager);
- IR::Module module(v4->debugger != 0);
+ IR::Module module(v4->debugger() != 0);
QQmlJS::Engine ee, *engine = &ee;
Lexer lexer(engine);
@@ -217,10 +194,8 @@ void Script::parse()
QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
if (inheritContext)
isel->setUseFastLookups(false);
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile();
+ compilationUnit = isel->compile();
vmFunction = compilationUnit->linkToEngine(v4);
- ScopedObject holder(valueScope, v4->memoryManager->allocObject<CompilationUnitHolder>(compilationUnit));
- compilationUnitHolder.set(v4, holder);
}
if (!vmFunction) {
@@ -255,7 +230,8 @@ ReturnedValue Script::run()
ScopedFunctionObject f(valueScope, engine->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction));
ScopedCallData callData(valueScope);
callData->thisObject = Primitive::undefinedValue();
- return f->call(callData);
+ f->call(valueScope, callData);
+ return valueScope.result.asReturnedValue();
}
}
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index d7b82218e7..e81bc3049c 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -74,7 +74,7 @@ struct ContextStateSaver {
CompiledData::CompilationUnit *compilationUnit;
int lineNumber;
- ContextStateSaver(Scope &scope, ExecutionContext *context)
+ ContextStateSaver(const Scope &scope, ExecutionContext *context)
: savedContext(scope.alloc(1))
, strictMode(context->d()->strictMode)
, lookups(context->d()->lookups)
@@ -83,7 +83,7 @@ struct ContextStateSaver {
{
savedContext->setM(context->d());
}
- ContextStateSaver(Scope &scope, Heap::ExecutionContext *context)
+ ContextStateSaver(const Scope &scope, Heap::ExecutionContext *context)
: savedContext(scope.alloc(1))
, strictMode(context->strictMode)
, lookups(context->lookups)
@@ -126,7 +126,7 @@ struct Q_QML_EXPORT Script {
bool inheritContext;
bool parsed;
QV4::PersistentValue qmlContext;
- QV4::PersistentValue compilationUnitHolder;
+ QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit;
Function *vmFunction;
bool parseAsBinding;
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index fa2409a85c..b15ac7eb5e 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -411,8 +411,8 @@ public:
callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs);
callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs);
callData->thisObject = this->m_ctx->d()->engine->globalObject;
- QV4::ScopedValue result(scope, compare->call(callData));
- return result->toNumber() < 0;
+ compare->call(scope, callData);
+ return scope.result.toNumber() < 0;
}
private:
@@ -531,7 +531,7 @@ public:
Q_ASSERT(d()->object);
Q_ASSERT(d()->isReference);
int status = -1;
- QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding;
+ QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding;
void *a[] = { &d()->container, 0, &status, &flags };
QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a);
}
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index abef885249..3901514326 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -49,57 +49,8 @@
using namespace QV4;
-static uint toArrayIndex(const QChar *ch, const QChar *end)
-{
- uint i = ch->unicode() - '0';
- if (i > 9)
- return UINT_MAX;
- ++ch;
- // reject "01", "001", ...
- if (i == 0 && ch != end)
- return UINT_MAX;
-
- while (ch < end) {
- uint x = ch->unicode() - '0';
- if (x > 9)
- return UINT_MAX;
- uint n = i*10 + x;
- if (n < i)
- // overflow
- return UINT_MAX;
- i = n;
- ++ch;
- }
- return i;
-}
-
#ifndef V4_BOOTSTRAP
-static uint toArrayIndex(const char *ch, const char *end)
-{
- uint i = *ch - '0';
- if (i > 9)
- return UINT_MAX;
- ++ch;
- // reject "01", "001", ...
- if (i == 0 && ch != end)
- return UINT_MAX;
-
- while (ch < end) {
- uint x = *ch - '0';
- if (x > 9)
- return UINT_MAX;
- uint n = i*10 + x;
- if (n < i)
- // overflow
- return UINT_MAX;
- i = n;
- ++ch;
- }
- return i;
-}
-
-
DEFINE_MANAGED_VTABLE(String);
void String::markObjects(Heap::Base *that, ExecutionEngine *e)
@@ -198,31 +149,6 @@ void Heap::String::simplifyString() const
mm->growUnmanagedHeapSizeUsage(size_t(text->size) * sizeof(QChar));
}
-void Heap::String::createHashValue() const
-{
- if (largestSubLength)
- simplifyString();
- Q_ASSERT(!largestSubLength);
- const QChar *ch = reinterpret_cast<const QChar *>(text->data());
- const QChar *end = ch + text->size;
-
- // array indices get their number as hash value
- stringHash = ::toArrayIndex(ch, end);
- if (stringHash != UINT_MAX) {
- subtype = Heap::String::StringType_ArrayIndex;
- return;
- }
-
- uint h = 0xffffffff;
- while (ch < end) {
- h = 31 * h + ch->unicode();
- ++ch;
- }
-
- stringHash = h;
- subtype = Heap::String::StringType_Regular;
-}
-
void Heap::String::append(const String *data, QChar *ch)
{
std::vector<const String *> worklist;
@@ -243,45 +169,14 @@ void Heap::String::append(const String *data, QChar *ch)
}
}
-
-
-
-uint String::createHashValue(const QChar *ch, int length)
-{
- const QChar *end = ch + length;
-
- // array indices get their number as hash value
- uint stringHash = ::toArrayIndex(ch, end);
- if (stringHash != UINT_MAX)
- return stringHash;
-
- uint h = 0xffffffff;
- while (ch < end) {
- h = 31 * h + ch->unicode();
- ++ch;
- }
-
- return h;
-}
-
-uint String::createHashValue(const char *ch, int length)
+void Heap::String::createHashValue() const
{
- const char *end = ch + length;
-
- // array indices get their number as hash value
- uint stringHash = ::toArrayIndex(ch, end);
- if (stringHash != UINT_MAX)
- return stringHash;
-
- uint h = 0xffffffff;
- while (ch < end) {
- if ((uchar)(*ch) >= 0x80)
- return UINT_MAX;
- h = 31 * h + *ch;
- ++ch;
- }
-
- return h;
+ if (largestSubLength)
+ simplifyString();
+ Q_ASSERT(!largestSubLength);
+ const QChar *ch = reinterpret_cast<const QChar *>(text->data());
+ const QChar *end = ch + text->size;
+ stringHash = QV4::String::calculateHashValue(ch, end, &subtype);
}
uint String::getLength(const Managed *m)
@@ -293,6 +188,6 @@ uint String::getLength(const Managed *m)
uint String::toArrayIndex(const QString &str)
{
- return ::toArrayIndex(str.constData(), str.constData() + str.length());
+ return QV4::String::toArrayIndex(str.constData(), str.constData() + str.length());
}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 3196f49896..ff42ab6471 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -52,6 +52,7 @@
#include <QtCore/qstring.h>
#include "qv4managed_p.h"
+#include <QtCore/private/qnumeric_p.h>
QT_BEGIN_NAMESPACE
@@ -62,7 +63,6 @@ struct Identifier;
namespace Heap {
-#ifndef V4_BOOTSTRAP
struct Q_QML_PRIVATE_EXPORT String : Base {
enum StringType {
StringType_Unknown,
@@ -70,6 +70,7 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
StringType_ArrayIndex
};
+#ifndef V4_BOOTSTRAP
String(MemoryManager *mm, const QString &text);
String(MemoryManager *mm, String *l, String *n);
~String() {
@@ -130,8 +131,8 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
MemoryManager *mm;
private:
static void append(const String *data, QChar *ch);
-};
#endif
+};
}
@@ -183,8 +184,17 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
void makeIdentifierImpl(ExecutionEngine *e) const;
- static uint createHashValue(const QChar *ch, int length);
- static uint createHashValue(const char *ch, int length);
+ static uint createHashValue(const QChar *ch, int length, uint *subtype)
+ {
+ const QChar *end = ch + length;
+ return calculateHashValue(ch, end, subtype);
+ }
+
+ static uint createHashValue(const char *ch, int length, uint *subtype)
+ {
+ const char *end = ch + length;
+ return calculateHashValue(ch, end, subtype);
+ }
bool startsWithUpper() const {
const String::Data *l = d();
@@ -203,6 +213,54 @@ protected:
public:
static uint toArrayIndex(const QString &str);
+
+private:
+ static inline uint toUInt(const QChar *ch) { return ch->unicode(); }
+ static inline uint toUInt(const char *ch) { return *ch; }
+
+ template <typename T>
+ static inline uint toArrayIndex(const T *ch, const T *end)
+ {
+ uint i = toUInt(ch) - '0';
+ if (i > 9)
+ return UINT_MAX;
+ ++ch;
+ // reject "01", "001", ...
+ if (i == 0 && ch != end)
+ return UINT_MAX;
+
+ while (ch < end) {
+ uint x = toUInt(ch) - '0';
+ if (x > 9)
+ return UINT_MAX;
+ if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x
+ return UINT_MAX;
+ ++ch;
+ }
+ return i;
+ }
+
+public:
+ template <typename T>
+ static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
+ {
+ // array indices get their number as hash value
+ uint h = toArrayIndex(ch, end);
+ if (h != UINT_MAX) {
+ if (subtype)
+ *subtype = Heap::String::StringType_ArrayIndex;
+ return h;
+ }
+
+ while (ch < end) {
+ h = 31 * h + toUInt(ch);
+ ++ch;
+ }
+
+ if (subtype)
+ *subtype = Heap::String::StringType_Regular;
+ return h;
+ }
};
template<>
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index b874766655..1989f747e9 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -157,28 +157,24 @@ Heap::StringCtor::StringCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue StringCtor::construct(const Managed *m, CallData *callData)
+void StringCtor::construct(const Managed *m, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const Object *>(m)->engine();
- Scope scope(v4);
ScopedString value(scope);
if (callData->argc)
value = callData->args[0].toString(v4);
else
value = v4->newString();
- return Encode(v4->newStringObject(value));
+ scope.result = Encode(v4->newStringObject(value));
}
-ReturnedValue StringCtor::call(const Managed *m, CallData *callData)
+void StringCtor::call(const Managed *, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const Object *>(m)->engine();
- Scope scope(v4);
- ScopedValue value(scope);
+ ExecutionEngine *v4 = scope.engine;
if (callData->argc)
- value = callData->args[0].toString(v4);
+ scope.result = callData->args[0].toString(v4);
else
- value = v4->newString();
- return value->asReturnedValue();
+ scope.result = v4->newString();
}
void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -196,7 +192,9 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("charAt"), method_charAt, 1);
defineDefaultProperty(QStringLiteral("charCodeAt"), method_charCodeAt, 1);
defineDefaultProperty(QStringLiteral("concat"), method_concat, 1);
+ defineDefaultProperty(QStringLiteral("endsWith"), method_endsWith, 1);
defineDefaultProperty(QStringLiteral("indexOf"), method_indexOf, 1);
+ defineDefaultProperty(QStringLiteral("includes"), method_includes, 1);
defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare, 1);
defineDefaultProperty(QStringLiteral("match"), method_match, 1);
@@ -204,6 +202,7 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("search"), method_search, 1);
defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
defineDefaultProperty(QStringLiteral("split"), method_split, 2);
+ defineDefaultProperty(QStringLiteral("startsWith"), method_startsWith, 1);
defineDefaultProperty(QStringLiteral("substr"), method_substr, 2);
defineDefaultProperty(QStringLiteral("substring"), method_substring, 2);
defineDefaultProperty(QStringLiteral("toLowerCase"), method_toLowerCase);
@@ -293,6 +292,30 @@ ReturnedValue StringPrototype::method_concat(CallContext *context)
return context->d()->engine->newString(value)->asReturnedValue();
}
+ReturnedValue StringPrototype::method_endsWith(CallContext *context)
+{
+ QString value = getThisString(context);
+ if (context->d()->engine->hasException)
+ return Encode::undefined();
+
+ QString searchString;
+ if (context->argc()) {
+ if (context->args()[0].as<RegExpObject>())
+ return context->engine()->throwTypeError();
+ searchString = context->args()[0].toQString();
+ }
+
+ int pos = value.length();
+ if (context->argc() > 1)
+ pos = (int) context->args()[1].toInteger();
+
+ if (pos == value.length())
+ return Encode(value.endsWith(searchString));
+
+ QStringRef stringToSearch = value.leftRef(pos);
+ return Encode(stringToSearch.endsWith(searchString));
+}
+
ReturnedValue StringPrototype::method_indexOf(CallContext *context)
{
QString value = getThisString(context);
@@ -314,6 +337,35 @@ ReturnedValue StringPrototype::method_indexOf(CallContext *context)
return Encode(index);
}
+ReturnedValue StringPrototype::method_includes(CallContext *context)
+{
+ QString value = getThisString(context);
+ if (context->d()->engine->hasException)
+ return Encode::undefined();
+
+ QString searchString;
+ if (context->argc()) {
+ if (context->args()[0].as<RegExpObject>())
+ return context->engine()->throwTypeError();
+ searchString = context->args()[0].toQString();
+ }
+
+ int pos = 0;
+ if (context->argc() > 1) {
+ Scope scope(context);
+ ScopedValue posArg(scope, context->argument(1));
+ pos = (int) posArg->toInteger();
+ if (!posArg->isInteger() && posArg->isNumber() && qIsInf(posArg->toNumber()))
+ pos = value.length();
+ }
+
+ if (pos == 0)
+ return Encode(value.contains(searchString));
+
+ QStringRef stringToSearch = value.midRef(pos);
+ return Encode(stringToSearch.contains(searchString));
+}
+
ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context)
{
Scope scope(context);
@@ -367,7 +419,8 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
if (!rx) {
ScopedCallData callData(scope, 1);
callData->args[0] = regexp;
- rx = context->d()->engine->regExpCtor()->construct(callData);
+ context->d()->engine->regExpCtor()->construct(scope, callData);
+ rx = scope.result.asReturnedValue();
}
if (!rx)
@@ -383,8 +436,10 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
ScopedCallData callData(scope, 1);
callData->thisObject = rx;
callData->args[0] = s;
- if (!global)
- return exec->call(callData);
+ if (!global) {
+ exec->call(scope, callData);
+ return scope.result.asReturnedValue();
+ }
ScopedString lastIndex(scope, context->d()->engine->newString(QStringLiteral("lastIndex")));
rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0)));
@@ -392,14 +447,13 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
double previousLastIndex = 0;
uint n = 0;
- ScopedValue result(scope);
ScopedValue matchStr(scope);
ScopedValue index(scope);
while (1) {
- result = exec->call(callData);
- if (result->isNull())
+ exec->call(scope, callData);
+ if (scope.result.isNull())
break;
- assert(result->isObject());
+ assert(scope.result.isObject());
index = rx->get(lastIndex, 0);
double thisIndex = index->toInteger();
if (previousLastIndex == thisIndex) {
@@ -408,7 +462,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
} else {
previousLastIndex = thisIndex;
}
- matchStr = result->objectValue()->getIndexed(0);
+ matchStr = scope.result.objectValue()->getIndexed(0);
a->arraySet(n, matchStr);
++n;
}
@@ -524,7 +578,6 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
}
QString result;
- ScopedValue replacement(scope);
ScopedValue replaceValue(scope, ctx->argument(1));
ScopedFunctionObject searchCallback(scope, replaceValue);
if (!!searchCallback) {
@@ -549,9 +602,9 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
callData->args[numCaptures] = Primitive::fromUInt32(matchStart);
callData->args[numCaptures + 1] = ctx->d()->engine->newString(string);
- replacement = searchCallback->call(callData);
+ searchCallback->call(scope, callData);
result += string.midRef(lastEnd, matchStart - lastEnd);
- result += replacement->toQString();
+ result += scope.result.toQString();
lastEnd = matchEnd;
}
result += string.midRef(lastEnd);
@@ -584,17 +637,17 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx)
{
Scope scope(ctx);
QString string = getThisString(ctx);
- ScopedValue regExpValue(scope, ctx->argument(0));
+ scope.result = ctx->argument(0);
if (scope.engine->hasException)
return Encode::undefined();
- Scoped<RegExpObject> regExp(scope, regExpValue->as<RegExpObject>());
+ Scoped<RegExpObject> regExp(scope, scope.result.as<RegExpObject>());
if (!regExp) {
ScopedCallData callData(scope, 1);
- callData->args[0] = regExpValue;
- regExpValue = ctx->d()->engine->regExpCtor()->construct(callData);
+ callData->args[0] = scope.result;
+ ctx->d()->engine->regExpCtor()->construct(scope, callData);
if (scope.engine->hasException)
return Encode::undefined();
- regExp = regExpValue->as<RegExpObject>();
+ regExp = scope.result.as<RegExpObject>();
Q_ASSERT(regExp);
}
Scoped<RegExp> re(scope, regExp->value());
@@ -716,6 +769,30 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
return array.asReturnedValue();
}
+ReturnedValue StringPrototype::method_startsWith(CallContext *context)
+{
+ QString value = getThisString(context);
+ if (context->d()->engine->hasException)
+ return Encode::undefined();
+
+ QString searchString;
+ if (context->argc()) {
+ if (context->args()[0].as<RegExpObject>())
+ return context->engine()->throwTypeError();
+ searchString = context->args()[0].toQString();
+ }
+
+ int pos = 0;
+ if (context->argc() > 1)
+ pos = (int) context->args()[1].toInteger();
+
+ if (pos == 0)
+ return Encode(value.startsWith(searchString));
+
+ QStringRef stringToSearch = value.midRef(pos);
+ return Encode(stringToSearch.startsWith(searchString));
+}
+
ReturnedValue StringPrototype::method_substr(CallContext *context)
{
const QString value = getThisString(context);
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 3930a011e6..54425b0909 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -103,8 +103,8 @@ struct StringCtor: FunctionObject
{
V4_OBJECT2(StringCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *, Scope &scope, CallData *callData);
};
struct StringPrototype: StringObject
@@ -115,7 +115,9 @@ struct StringPrototype: StringObject
static ReturnedValue method_charAt(CallContext *context);
static ReturnedValue method_charCodeAt(CallContext *context);
static ReturnedValue method_concat(CallContext *context);
+ static ReturnedValue method_endsWith(CallContext *ctx);
static ReturnedValue method_indexOf(CallContext *context);
+ static ReturnedValue method_includes(CallContext *context);
static ReturnedValue method_lastIndexOf(CallContext *context);
static ReturnedValue method_localeCompare(CallContext *context);
static ReturnedValue method_match(CallContext *context);
@@ -123,6 +125,7 @@ struct StringPrototype: StringObject
static ReturnedValue method_search(CallContext *ctx);
static ReturnedValue method_slice(CallContext *ctx);
static ReturnedValue method_split(CallContext *ctx);
+ static ReturnedValue method_startsWith(CallContext *ctx);
static ReturnedValue method_substr(CallContext *context);
static ReturnedValue method_substring(CallContext *context);
static ReturnedValue method_toLowerCase(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index c86f252353..ae5ebcad1b 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -208,30 +208,34 @@ Heap::TypedArrayCtor::TypedArrayCtor(QV4::ExecutionContext *scope, TypedArray::T
{
}
-ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
+void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const Object *>(m)->engine());
Scoped<TypedArrayCtor> that(scope, static_cast<const TypedArrayCtor *>(m));
if (!callData->argc || !callData->args[0].isObject()) {
// ECMA 6 22.2.1.1
double l = callData->argc ? callData->args[0].toNumber() : 0;
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
uint len = (uint)l;
if (l != len)
scope.engine->throwRangeError(QStringLiteral("Non integer length for typed array."));
uint byteLength = len * operations[that->d()->type].bytesPerElement;
Scoped<ArrayBuffer> buffer(scope, scope.engine->newArrayBuffer(byteLength));
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
array->d()->buffer = buffer->d();
array->d()->byteLength = byteLength;
array->d()->byteOffset = 0;
- return array.asReturnedValue();
+ scope.result = array.asReturnedValue();
+ return;
}
Scoped<TypedArray> typedArray(scope, callData->argument(0));
if (!!typedArray) {
@@ -243,8 +247,10 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
uint destByteLength = byteLength*destElementSize/srcElementSize;
Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(destByteLength));
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
array->d()->buffer = newBuffer->d();
@@ -269,7 +275,8 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
}
}
- return array.asReturnedValue();
+ scope.result = array.asReturnedValue();
+ return;
}
Scoped<ArrayBuffer> buffer(scope, callData->argument(0));
if (!!buffer) {
@@ -278,21 +285,29 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
double dbyteOffset = callData->argc > 1 ? callData->args[1].toInteger() : 0;
uint byteOffset = (uint)dbyteOffset;
uint elementSize = operations[that->d()->type].bytesPerElement;
- if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength())
- return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset"));
+ if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength()) {
+ scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset"));
+ return;
+ }
uint byteLength;
if (callData->argc < 3 || callData->args[2].isUndefined()) {
byteLength = buffer->byteLength() - byteOffset;
- if (buffer->byteLength() < byteOffset || byteLength % elementSize)
- return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
+ if (buffer->byteLength() < byteOffset || byteLength % elementSize) {
+ scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
+ return;
+ }
} else {
double l = qBound(0., callData->args[2].toInteger(), (double)UINT_MAX);
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
l *= elementSize;
- if (buffer->byteLength() - byteOffset < l)
- return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
+ if (buffer->byteLength() - byteOffset < l) {
+ scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
+ return;
+ }
byteLength = (uint)l;
}
@@ -300,20 +315,25 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
array->d()->buffer = buffer->d();
array->d()->byteLength = byteLength;
array->d()->byteOffset = byteOffset;
- return array.asReturnedValue();
+ scope.result = array.asReturnedValue();
+ return;
}
// ECMA 6 22.2.1.3
ScopedObject o(scope, callData->argument(0));
uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length()))->toInteger(), (double)UINT_MAX);
- if (scope.engine->hasException)
- return scope.engine->throwTypeError();
+ if (scope.engine->hasException) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
uint elementSize = operations[that->d()->type].bytesPerElement;
Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(l * elementSize));
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
array->d()->buffer = newBuffer->d();
@@ -326,19 +346,21 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
while (idx < l) {
val = o->getIndexed(idx);
array->d()->type->write(scope.engine, b, 0, val);
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
++idx;
b += elementSize;
}
- return array.asReturnedValue();
+ scope.result = array.asReturnedValue();
}
-ReturnedValue TypedArrayCtor::call(const Managed *that, CallData *callData)
+void TypedArrayCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
Heap::TypedArray::TypedArray(Type t)
@@ -582,5 +604,6 @@ ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx)
callData->args[0] = buffer;
callData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement);
callData->args[2] = Encode(newLen);
- return constructor->construct(callData);
+ constructor->construct(scope, callData);
+ return scope.result.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 757273e4ed..d96027b96a 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -140,8 +140,8 @@ struct TypedArrayCtor: FunctionObject
{
V4_OBJECT2(TypedArrayCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index b2d64213f5..dae4d11767 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -322,16 +322,22 @@ public:
}
Q_ALWAYS_INLINE String *stringValue() const {
+ if (!isString())
+ return nullptr;
return m() ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0;
}
Q_ALWAYS_INLINE Object *objectValue() const {
+ if (!isObject())
+ return nullptr;
return m() ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0;
}
Q_ALWAYS_INLINE Managed *managed() const {
+ if (!isManaged())
+ return nullptr;
return m() ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0;
}
Q_ALWAYS_INLINE Heap::Base *heapObject() const {
- return m();
+ return isManaged() ? m() : nullptr;
}
static inline Value fromHeapObject(Heap::Base *m)
@@ -381,7 +387,10 @@ public:
}
template <typename T>
T *as() {
- return const_cast<T *>(const_cast<const Value *>(this)->as<T>());
+ if (isManaged())
+ return const_cast<T *>(const_cast<const Value *>(this)->as<T>());
+ else
+ return nullptr;
}
template<typename T> inline T *cast() {
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index ecbc243baa..b6dc7716ba 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -142,6 +142,7 @@ Q_QML_EXPORT int qt_v4DebuggerHook(const char *json);
} // extern "C"
+#ifndef QT_NO_QML_DEBUGGER
static int qt_v4BreakpointCount = 0;
static bool qt_v4IsDebugging = true;
static bool qt_v4IsStepping = false;
@@ -203,7 +204,7 @@ int qt_v4DebuggerHook(const char *json)
QJsonDocument doc = QJsonDocument::fromJson(json);
QJsonObject ob = doc.object();
- QByteArray command = ob.value(QStringLiteral("command")).toString().toUtf8();
+ QByteArray command = ob.value(QLatin1String("command")).toString().toUtf8();
if (command == "protocolVersion") {
return ProtocolVersion; // Version number.
@@ -217,17 +218,17 @@ int qt_v4DebuggerHook(const char *json)
if (command == "insertBreakpoint") {
Breakpoint bp;
bp.bpNumber = ++qt_v4BreakpointCount;
- bp.lineNumber = ob.value(QStringLiteral("lineNumber")).toString().toInt();
- bp.engineName = ob.value(QStringLiteral("engineName")).toString();
- bp.fullName = ob.value(QStringLiteral("fullName")).toString();
- bp.condition = ob.value(QStringLiteral("condition")).toString();
+ bp.lineNumber = ob.value(QLatin1String("lineNumber")).toString().toInt();
+ bp.engineName = ob.value(QLatin1String("engineName")).toString();
+ bp.fullName = ob.value(QLatin1String("fullName")).toString();
+ bp.condition = ob.value(QLatin1String("condition")).toString();
qt_v4Breakpoints.append(bp);
return bp.bpNumber;
}
if (command == "removeBreakpoint") {
- int lineNumber = ob.value(QStringLiteral("lineNumber")).toString().toInt();
- QString fullName = ob.value(QStringLiteral("fullName")).toString();
+ int lineNumber = ob.value(QLatin1String("lineNumber")).toString().toInt();
+ QString fullName = ob.value(QLatin1String("fullName")).toString();
if (qt_v4Breakpoints.last().matches(fullName, lineNumber)) {
qt_v4Breakpoints.removeLast();
return Success;
@@ -285,6 +286,7 @@ static void qt_v4CheckForBreak(QV4::ExecutionContext *context, QV4::Value **scop
}
}
+#endif // QT_NO_QML_DEBUGGER
// End of debugger interface
using namespace QV4;
@@ -451,12 +453,12 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(LoadRegExp)
MOTH_BEGIN_INSTR(LoadClosure)
- STOREVALUE(instr.result, Runtime::closure(engine, instr.value));
+ STOREVALUE(instr.result, engine->runtime.closure(engine, instr.value));
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData());
- STOREVALUE(instr.result, Runtime::getActivationProperty(engine, instr.name));
+ STOREVALUE(instr.result, engine->runtime.getActivationProperty(engine, instr.name));
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(GetGlobalLookup)
@@ -466,12 +468,12 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(StoreName)
TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData());
- Runtime::setActivationProperty(engine, instr.name, VALUE(instr.source));
+ engine->runtime.setActivationProperty(engine, instr.name, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreName)
MOTH_BEGIN_INSTR(LoadElement)
- STOREVALUE(instr.result, Runtime::getElement(engine, VALUE(instr.base), VALUE(instr.index)));
+ STOREVALUE(instr.result, engine->runtime.getElement(engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(LoadElementLookup)
@@ -480,7 +482,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(LoadElementLookup)
MOTH_BEGIN_INSTR(StoreElement)
- Runtime::setElement(engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
+ engine->runtime.setElement(engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElement)
@@ -491,7 +493,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(StoreElementLookup)
MOTH_BEGIN_INSTR(LoadProperty)
- STOREVALUE(instr.result, Runtime::getProperty(engine, VALUE(instr.base), instr.name));
+ STOREVALUE(instr.result, engine->runtime.getProperty(engine, VALUE(instr.base), instr.name));
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
@@ -500,7 +502,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
- Runtime::setProperty(engine, VALUE(instr.base), instr.name, VALUE(instr.source));
+ engine->runtime.setProperty(engine, VALUE(instr.base), instr.name, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreProperty)
@@ -511,42 +513,42 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(SetLookup)
MOTH_BEGIN_INSTR(StoreQObjectProperty)
- Runtime::setQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
+ engine->runtime.setQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreQObjectProperty)
MOTH_BEGIN_INSTR(LoadQObjectProperty)
- STOREVALUE(instr.result, Runtime::getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
+ STOREVALUE(instr.result, engine->runtime.getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadQObjectProperty)
MOTH_BEGIN_INSTR(StoreScopeObjectProperty)
- Runtime::setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
+ engine->runtime.setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreScopeObjectProperty)
MOTH_BEGIN_INSTR(LoadScopeObjectProperty)
- STOREVALUE(instr.result, Runtime::getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex));
+ STOREVALUE(instr.result, engine->runtime.getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex));
MOTH_END_INSTR(LoadScopeObjectProperty)
MOTH_BEGIN_INSTR(StoreContextObjectProperty)
- Runtime::setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
+ engine->runtime.setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreContextObjectProperty)
MOTH_BEGIN_INSTR(LoadContextObjectProperty)
- STOREVALUE(instr.result, Runtime::getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex));
+ STOREVALUE(instr.result, engine->runtime.getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex));
MOTH_END_INSTR(LoadContextObjectProperty)
MOTH_BEGIN_INSTR(LoadIdObject)
- STOREVALUE(instr.result, Runtime::getQmlIdObject(engine, VALUE(instr.base), instr.index));
+ STOREVALUE(instr.result, engine->runtime.getQmlIdObject(engine, VALUE(instr.base), instr.index));
MOTH_END_INSTR(LoadIdObject)
MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty)
- STOREVALUE(instr.result, Runtime::getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex));
+ STOREVALUE(instr.result, engine->runtime.getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex));
MOTH_END_INSTR(LoadAttachedQObjectProperty)
MOTH_BEGIN_INSTR(LoadSingletonQObjectProperty)
- STOREVALUE(instr.result, Runtime::getQmlSingletonQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
+ STOREVALUE(instr.result, engine->runtime.getQmlSingletonQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadSingletonQObjectProperty)
MOTH_BEGIN_INSTR(Push)
@@ -572,7 +574,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::callValue(engine, VALUE(instr.dest), callData));
+ STOREVALUE(instr.result, engine->runtime.callValue(engine, VALUE(instr.dest), callData));
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallProperty)
@@ -582,7 +584,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::callProperty(engine, instr.name, callData));
+ STOREVALUE(instr.result, engine->runtime.callProperty(engine, instr.name, callData));
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
@@ -591,7 +593,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::callPropertyLookup(engine, instr.lookupIndex, callData));
+ STOREVALUE(instr.result, engine->runtime.callPropertyLookup(engine, instr.lookupIndex, callData));
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallScopeObjectProperty)
@@ -601,7 +603,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::callQmlScopeObjectProperty(engine, instr.index, callData));
+ STOREVALUE(instr.result, engine->runtime.callQmlScopeObjectProperty(engine, instr.index, callData));
MOTH_END_INSTR(CallScopeObjectProperty)
MOTH_BEGIN_INSTR(CallContextObjectProperty)
@@ -611,7 +613,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::callQmlContextObjectProperty(engine, instr.index, callData));
+ STOREVALUE(instr.result, engine->runtime.callQmlContextObjectProperty(engine, instr.index, callData));
MOTH_END_INSTR(CallContextObjectProperty)
MOTH_BEGIN_INSTR(CallElement)
@@ -620,7 +622,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::callElement(engine, VALUE(instr.index), callData));
+ STOREVALUE(instr.result, engine->runtime.callElement(engine, VALUE(instr.index), callData));
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallActivationProperty)
@@ -629,7 +631,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::callActivationProperty(engine, instr.name, callData));
+ STOREVALUE(instr.result, engine->runtime.callActivationProperty(engine, instr.name, callData));
MOTH_END_INSTR(CallActivationProperty)
MOTH_BEGIN_INSTR(CallGlobalLookup)
@@ -638,7 +640,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::callGlobalLookup(engine, instr.index, callData));
+ STOREVALUE(instr.result, Runtime::method_callGlobalLookup(engine, instr.index, callData));
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(SetExceptionHandler)
@@ -646,95 +648,95 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(SetExceptionHandler)
MOTH_BEGIN_INSTR(CallBuiltinThrow)
- Runtime::throwException(engine, VALUE(instr.arg));
+ engine->runtime.throwException(engine, VALUE(instr.arg));
CHECK_EXCEPTION;
MOTH_END_INSTR(CallBuiltinThrow)
MOTH_BEGIN_INSTR(CallBuiltinUnwindException)
- STOREVALUE(instr.result, Runtime::unwindException(engine));
+ STOREVALUE(instr.result, engine->runtime.unwindException(engine));
MOTH_END_INSTR(CallBuiltinUnwindException)
MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope)
- Runtime::pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
+ engine->runtime.pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
context = engine->currentContext;
MOTH_END_INSTR(CallBuiltinPushCatchScope)
MOTH_BEGIN_INSTR(CallBuiltinPushScope)
- Runtime::pushWithScope(VALUE(instr.arg), engine);
+ engine->runtime.pushWithScope(VALUE(instr.arg), engine);
context = engine->currentContext;
CHECK_EXCEPTION;
MOTH_END_INSTR(CallBuiltinPushScope)
MOTH_BEGIN_INSTR(CallBuiltinPopScope)
- Runtime::popScope(engine);
+ engine->runtime.popScope(engine);
context = engine->currentContext;
MOTH_END_INSTR(CallBuiltinPopScope)
MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject)
- STOREVALUE(instr.result, Runtime::foreachIterator(engine, VALUE(instr.arg)));
+ STOREVALUE(instr.result, engine->runtime.foreachIterator(engine, VALUE(instr.arg)));
MOTH_END_INSTR(CallBuiltinForeachIteratorObject)
MOTH_BEGIN_INSTR(CallBuiltinForeachNextPropertyName)
- STOREVALUE(instr.result, Runtime::foreachNextPropertyName(VALUE(instr.arg)));
+ STOREVALUE(instr.result, engine->runtime.foreachNextPropertyName(VALUE(instr.arg)));
MOTH_END_INSTR(CallBuiltinForeachNextPropertyName)
MOTH_BEGIN_INSTR(CallBuiltinDeleteMember)
- STOREVALUE(instr.result, Runtime::deleteMember(engine, VALUE(instr.base), instr.member));
+ STOREVALUE(instr.result, engine->runtime.deleteMember(engine, VALUE(instr.base), instr.member));
MOTH_END_INSTR(CallBuiltinDeleteMember)
MOTH_BEGIN_INSTR(CallBuiltinDeleteSubscript)
- STOREVALUE(instr.result, Runtime::deleteElement(engine, VALUE(instr.base), VALUE(instr.index)));
+ STOREVALUE(instr.result, engine->runtime.deleteElement(engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(CallBuiltinDeleteSubscript)
MOTH_BEGIN_INSTR(CallBuiltinDeleteName)
- STOREVALUE(instr.result, Runtime::deleteName(engine, instr.name));
+ STOREVALUE(instr.result, engine->runtime.deleteName(engine, instr.name));
MOTH_END_INSTR(CallBuiltinDeleteName)
MOTH_BEGIN_INSTR(CallBuiltinTypeofScopeObjectProperty)
- STOREVALUE(instr.result, Runtime::typeofScopeObjectProperty(engine, VALUE(instr.base), instr.index));
+ STOREVALUE(instr.result, engine->runtime.typeofScopeObjectProperty(engine, VALUE(instr.base), instr.index));
MOTH_END_INSTR(CallBuiltinTypeofMember)
MOTH_BEGIN_INSTR(CallBuiltinTypeofContextObjectProperty)
- STOREVALUE(instr.result, Runtime::typeofContextObjectProperty(engine, VALUE(instr.base), instr.index));
+ STOREVALUE(instr.result, engine->runtime.typeofContextObjectProperty(engine, VALUE(instr.base), instr.index));
MOTH_END_INSTR(CallBuiltinTypeofMember)
MOTH_BEGIN_INSTR(CallBuiltinTypeofMember)
- STOREVALUE(instr.result, Runtime::typeofMember(engine, VALUE(instr.base), instr.member));
+ STOREVALUE(instr.result, engine->runtime.typeofMember(engine, VALUE(instr.base), instr.member));
MOTH_END_INSTR(CallBuiltinTypeofMember)
MOTH_BEGIN_INSTR(CallBuiltinTypeofSubscript)
- STOREVALUE(instr.result, Runtime::typeofElement(engine, VALUE(instr.base), VALUE(instr.index)));
+ STOREVALUE(instr.result, engine->runtime.typeofElement(engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(CallBuiltinTypeofSubscript)
MOTH_BEGIN_INSTR(CallBuiltinTypeofName)
- STOREVALUE(instr.result, Runtime::typeofName(engine, instr.name));
+ STOREVALUE(instr.result, engine->runtime.typeofName(engine, instr.name));
MOTH_END_INSTR(CallBuiltinTypeofName)
MOTH_BEGIN_INSTR(CallBuiltinTypeofValue)
- STOREVALUE(instr.result, Runtime::typeofValue(engine, VALUE(instr.value)));
+ STOREVALUE(instr.result, engine->runtime.typeofValue(engine, VALUE(instr.value)));
MOTH_END_INSTR(CallBuiltinTypeofValue)
MOTH_BEGIN_INSTR(CallBuiltinDeclareVar)
- Runtime::declareVar(engine, instr.isDeletable, instr.varName);
+ engine->runtime.declareVar(engine, instr.isDeletable, instr.varName);
MOTH_END_INSTR(CallBuiltinDeclareVar)
MOTH_BEGIN_INSTR(CallBuiltinDefineArray)
Q_ASSERT(instr.args + instr.argc <= stackSize);
QV4::Value *args = stack + instr.args;
- STOREVALUE(instr.result, Runtime::arrayLiteral(engine, args, instr.argc));
+ STOREVALUE(instr.result, engine->runtime.arrayLiteral(engine, args, instr.argc));
MOTH_END_INSTR(CallBuiltinDefineArray)
MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral)
QV4::Value *args = stack + instr.args;
- STOREVALUE(instr.result, Runtime::objectLiteral(engine, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCountAndFlags));
+ STOREVALUE(instr.result, engine->runtime.objectLiteral(engine, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCountAndFlags));
MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject)
- STOREVALUE(instr.result, Runtime::setupArgumentsObject(engine));
+ STOREVALUE(instr.result, engine->runtime.setupArgumentsObject(engine));
MOTH_END_INSTR(CallBuiltinSetupArgumentsObject)
MOTH_BEGIN_INSTR(CallBuiltinConvertThisToObject)
- Runtime::convertThisToObject(engine);
+ engine->runtime.convertThisToObject(engine);
CHECK_EXCEPTION;
MOTH_END_INSTR(CallBuiltinConvertThisToObject)
@@ -744,7 +746,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::constructValue(engine, VALUE(instr.func), callData));
+ STOREVALUE(instr.result, engine->runtime.constructValue(engine, VALUE(instr.func), callData));
MOTH_END_INSTR(CreateValue)
MOTH_BEGIN_INSTR(CreateProperty)
@@ -753,7 +755,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::constructProperty(engine, instr.name, callData));
+ STOREVALUE(instr.result, engine->runtime.constructProperty(engine, instr.name, callData));
MOTH_END_INSTR(CreateProperty)
MOTH_BEGIN_INSTR(ConstructPropertyLookup)
@@ -762,7 +764,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::constructPropertyLookup(engine, instr.index, callData));
+ STOREVALUE(instr.result, engine->runtime.constructPropertyLookup(engine, instr.index, callData));
MOTH_END_INSTR(ConstructPropertyLookup)
MOTH_BEGIN_INSTR(CreateActivationProperty)
@@ -771,7 +773,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::constructActivationProperty(engine, instr.name, callData));
+ STOREVALUE(instr.result, engine->runtime.constructActivationProperty(engine, instr.name, callData));
MOTH_END_INSTR(CreateActivationProperty)
MOTH_BEGIN_INSTR(ConstructGlobalLookup)
@@ -780,7 +782,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::constructGlobalLookup(engine, instr.index, callData));
+ STOREVALUE(instr.result, engine->runtime.constructGlobalLookup(engine, instr.index, callData));
MOTH_END_INSTR(ConstructGlobalLookup)
MOTH_BEGIN_INSTR(Jump)
@@ -802,7 +804,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(JumpNe)
MOTH_BEGIN_INSTR(UNot)
- STOREVALUE(instr.result, Runtime::uNot(VALUE(instr.source)));
+ STOREVALUE(instr.result, engine->runtime.uNot(VALUE(instr.source)));
MOTH_END_INSTR(UNot)
MOTH_BEGIN_INSTR(UNotBool)
@@ -811,15 +813,15 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(UNotBool)
MOTH_BEGIN_INSTR(UPlus)
- STOREVALUE(instr.result, Runtime::uPlus(VALUE(instr.source)));
+ STOREVALUE(instr.result, engine->runtime.uPlus(VALUE(instr.source)));
MOTH_END_INSTR(UPlus)
MOTH_BEGIN_INSTR(UMinus)
- STOREVALUE(instr.result, Runtime::uMinus(VALUE(instr.source)));
+ STOREVALUE(instr.result, engine->runtime.uMinus(VALUE(instr.source)));
MOTH_END_INSTR(UMinus)
MOTH_BEGIN_INSTR(UCompl)
- STOREVALUE(instr.result, Runtime::complement(VALUE(instr.source)));
+ STOREVALUE(instr.result, engine->runtime.complement(VALUE(instr.source)));
MOTH_END_INSTR(UCompl)
MOTH_BEGIN_INSTR(UComplInt)
@@ -827,31 +829,32 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(UComplInt)
MOTH_BEGIN_INSTR(Increment)
- STOREVALUE(instr.result, Runtime::increment(VALUE(instr.source)));
+ STOREVALUE(instr.result, engine->runtime.increment(VALUE(instr.source)));
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
- STOREVALUE(instr.result, Runtime::decrement(VALUE(instr.source)));
+ STOREVALUE(instr.result, engine->runtime.decrement(VALUE(instr.source)));
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Binop)
- STOREVALUE(instr.result, instr.alu(VALUE(instr.lhs), VALUE(instr.rhs)));
+ QV4::Runtime::BinaryOperation op = *reinterpret_cast<QV4::Runtime::BinaryOperation *>(reinterpret_cast<char *>(&engine->runtime) + instr.alu);
+ STOREVALUE(instr.result, op(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(Binop)
MOTH_BEGIN_INSTR(Add)
- STOREVALUE(instr.result, Runtime::add(engine, VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, engine->runtime.add(engine, VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(BitAnd)
- STOREVALUE(instr.result, Runtime::bitAnd(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, engine->runtime.bitAnd(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(BitAnd)
MOTH_BEGIN_INSTR(BitOr)
- STOREVALUE(instr.result, Runtime::bitOr(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, engine->runtime.bitOr(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(BitOr)
MOTH_BEGIN_INSTR(BitXor)
- STOREVALUE(instr.result, Runtime::bitXor(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, engine->runtime.bitXor(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(BitXor)
MOTH_BEGIN_INSTR(Shr)
@@ -886,15 +889,16 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(ShlConst)
MOTH_BEGIN_INSTR(Mul)
- STOREVALUE(instr.result, Runtime::mul(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, engine->runtime.mul(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(Mul)
MOTH_BEGIN_INSTR(Sub)
- STOREVALUE(instr.result, Runtime::sub(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, engine->runtime.sub(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(Sub)
MOTH_BEGIN_INSTR(BinopContext)
- STOREVALUE(instr.result, instr.alu(engine, VALUE(instr.lhs), VALUE(instr.rhs)));
+ QV4::Runtime::BinaryOperationContext op = *reinterpret_cast<QV4::Runtime::BinaryOperationContext *>(reinterpret_cast<char *>(&engine->runtime) + instr.alu);
+ STOREVALUE(instr.result, op(engine, VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(BinopContext)
MOTH_BEGIN_INSTR(Ret)
@@ -902,9 +906,10 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
return VALUE(instr.result).asReturnedValue();
MOTH_END_INSTR(Ret)
+#ifndef QT_NO_QML_DEBUGGER
MOTH_BEGIN_INSTR(Debug)
engine->current->lineNumber = instr.lineNumber;
- QV4::Debugging::Debugger *debugger = context->engine()->debugger;
+ QV4::Debugging::Debugger *debugger = context->engine()->debugger();
if (debugger && debugger->pauseAtNextOpportunity())
debugger->maybeBreakAtInstruction();
if (qt_v4IsDebugging)
@@ -916,21 +921,22 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
if (qt_v4IsDebugging)
qt_v4CheckForBreak(context, scopes, scopeDepth);
MOTH_END_INSTR(Line)
+#endif // QT_NO_QML_DEBUGGER
MOTH_BEGIN_INSTR(LoadThis)
VALUE(instr.result) = context->thisObject();
MOTH_END_INSTR(LoadThis)
MOTH_BEGIN_INSTR(LoadQmlContext)
- VALUE(instr.result) = Runtime::getQmlContext(static_cast<QV4::NoThrowEngine*>(engine));
+ VALUE(instr.result) = engine->runtime.getQmlContext(static_cast<QV4::NoThrowEngine*>(engine));
MOTH_END_INSTR(LoadQmlContext)
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
- VALUE(instr.result) = Runtime::getQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
+ VALUE(instr.result) = engine->runtime.getQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
MOTH_END_INSTR(LoadQmlImportedScripts)
MOTH_BEGIN_INSTR(LoadQmlSingleton)
- VALUE(instr.result) = Runtime::getQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
+ VALUE(instr.result) = engine->runtime.getQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
MOTH_END_INSTR(LoadQmlSingleton)
#ifdef MOTH_THREADED_INTERPRETER
@@ -968,7 +974,7 @@ void **VME::instructionJumpTable()
QV4::ReturnedValue VME::exec(ExecutionEngine *engine, const uchar *code)
{
VME vme;
- QV4::Debugging::Debugger *debugger = engine->debugger;
+ QV4::Debugging::Debugger *debugger = engine->debugger();
if (debugger)
debugger->enteringFunction();
QV4::ReturnedValue retVal = vme.run(engine, code);
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index fe94a11082..a6d7c3b1ed 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -60,6 +60,10 @@
#include <valgrind/memcheck.h>
#endif
+#ifdef V4_USE_HEAPTRACK
+#include <heaptrack_api.h>
+#endif
+
#if OS(QNX)
#include <sys/storage.h> // __tls()
#endif
@@ -68,7 +72,7 @@
#include <pthread_np.h>
#endif
-#define MIN_UNMANAGED_HEAPSIZE_GC_LIMIT (std::size_t)128*1024
+#define MIN_UNMANAGED_HEAPSIZE_GC_LIMIT std::size_t(128 * 1024)
using namespace WTF;
@@ -79,9 +83,9 @@ static uint maxShiftValue()
static uint result = 0;
if (!result) {
result = 6;
- if (Q_UNLIKELY(qEnvironmentVariableIsSet("QV4_MM_MAXBLOCK_SHIFT"))) {
+ if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAXBLOCK_SHIFT))) {
bool ok;
- const uint overrideValue = qgetenv("QV4_MM_MAXBLOCK_SHIFT").toUInt(&ok);
+ const uint overrideValue = qgetenv(QV4_MM_MAXBLOCK_SHIFT).toUInt(&ok);
if (ok && overrideValue <= 11 && overrideValue > 0)
result = overrideValue;
}
@@ -94,9 +98,9 @@ static std::size_t maxChunkSizeValue()
static std::size_t result = 0;
if (!result) {
result = 32 * 1024;
- if (Q_UNLIKELY(qEnvironmentVariableIsSet("QV4_MM_MAX_CHUNK_SIZE"))) {
+ if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAX_CHUNK_SIZE))) {
bool ok;
- const std::size_t overrideValue = qgetenv("QV4_MM_MAX_CHUNK_SIZE").toUInt(&ok);
+ const std::size_t overrideValue = qgetenv(QV4_MM_MAX_CHUNK_SIZE).toUInt(&ok);
if (ok)
result = overrideValue;
}
@@ -108,29 +112,20 @@ using namespace QV4;
struct MemoryManager::Data
{
+ const size_t pageSize;
+
struct ChunkHeader {
Heap::Base freeItems;
ChunkHeader *nextNonFull;
char *itemStart;
char *itemEnd;
- int itemSize;
+ unsigned itemSize;
};
- bool gcBlocked;
- bool aggressiveGC;
- bool gcStats;
ExecutionEngine *engine;
- enum { MaxItemSize = 512 };
- ChunkHeader *nonFullChunks[MaxItemSize/16];
- uint nChunks[MaxItemSize/16];
- uint availableItems[MaxItemSize/16];
- uint allocCount[MaxItemSize/16];
- int totalItems;
- int totalAlloc;
- uint maxShift;
std::size_t maxChunkSize;
- QVector<PageAllocation> heapChunks;
+ std::vector<PageAllocation> heapChunks;
std::size_t unmanagedHeapSize; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
std::size_t unmanagedHeapSizeGCLimit;
@@ -147,24 +142,39 @@ struct MemoryManager::Data
LargeItem *largeItems;
std::size_t totalLargeItemsAllocated;
+ enum { MaxItemSize = 512 };
+ ChunkHeader *nonFullChunks[MaxItemSize/16];
+ uint nChunks[MaxItemSize/16];
+ uint availableItems[MaxItemSize/16];
+ uint allocCount[MaxItemSize/16];
+ int totalItems;
+ int totalAlloc;
+ uint maxShift;
+
+ bool gcBlocked;
+ bool aggressiveGC;
+ bool gcStats;
+ bool unused; // suppress padding warning
+
// statistics:
#ifdef DETAILED_MM_STATS
QVector<unsigned> allocSizeCounters;
#endif // DETAILED_MM_STATS
Data()
- : gcBlocked(false)
- , aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
- , gcStats(!qEnvironmentVariableIsEmpty("QV4_MM_STATS"))
+ : pageSize(WTF::pageSize())
, engine(0)
- , totalItems(0)
- , totalAlloc(0)
- , maxShift(maxShiftValue())
, maxChunkSize(maxChunkSizeValue())
, unmanagedHeapSize(0)
, unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
, largeItems(0)
, totalLargeItemsAllocated(0)
+ , totalItems(0)
+ , totalAlloc(0)
+ , maxShift(maxShiftValue())
+ , gcBlocked(false)
+ , aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
+ , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS))
{
memset(nonFullChunks, 0, sizeof(nonFullChunks));
memset(nChunks, 0, sizeof(nChunks));
@@ -174,8 +184,8 @@ struct MemoryManager::Data
~Data()
{
- for (QVector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
- Q_V4_PROFILE_DEALLOC(engine, 0, i->size(), Profiling::HeapPage);
+ for (std::vector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
+ Q_V4_PROFILE_DEALLOC(engine, i->size(), Profiling::HeapPage);
i->deallocate();
}
}
@@ -198,7 +208,7 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec
// qDebug("chunk @ %p, in use: %s, mark bit: %s",
// item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false"));
- Q_ASSERT((qintptr) item % 16 == 0);
+ Q_ASSERT(qintptr(item) % 16 == 0);
if (m->isMarked()) {
Q_ASSERT(m->inUse());
@@ -226,7 +236,10 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec
VALGRIND_DISABLE_ERROR_REPORTING;
VALGRIND_MEMPOOL_FREE(engine->memoryManager, m);
#endif
- Q_V4_PROFILE_DEALLOC(engine, m, header->itemSize, Profiling::SmallItem);
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_free(m);
+#endif
+ Q_V4_PROFILE_DEALLOC(engine, header->itemSize, Profiling::SmallItem);
++(*itemsInUse);
}
// Relink all free blocks to rewrite references to any released chunk.
@@ -289,10 +302,11 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
runGC();
// we use malloc for this
- MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(
- malloc(Q_V4_PROFILE_ALLOC(engine, size + sizeof(MemoryManager::Data::LargeItem),
- Profiling::LargeItem)));
- memset(item, 0, size + sizeof(MemoryManager::Data::LargeItem));
+ const size_t totalSize = size + sizeof(MemoryManager::Data::LargeItem);
+ Q_V4_PROFILE_ALLOC(engine, totalSize, Profiling::LargeItem);
+ MemoryManager::Data::LargeItem *item =
+ static_cast<MemoryManager::Data::LargeItem *>(malloc(totalSize));
+ memset(item, 0, totalSize);
item->next = m_d->largeItems;
item->size = size;
m_d->largeItems = item;
@@ -324,14 +338,14 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
if (shift > m_d->maxShift)
shift = m_d->maxShift;
std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift);
- allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize);
- PageAllocation allocation = PageAllocation::allocate(
- Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage),
- OSAllocator::JSGCHeapPages);
- m_d->heapChunks.append(allocation);
+ allocSize = roundUpToMultipleOf(m_d->pageSize, allocSize);
+ Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage);
+ PageAllocation allocation = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages);
+ m_d->heapChunks.push_back(allocation);
header = reinterpret_cast<Data::ChunkHeader *>(allocation.base());
- header->itemSize = int(size);
+ Q_ASSERT(size <= UINT_MAX);
+ header->itemSize = unsigned(size);
header->itemStart = reinterpret_cast<char *>(allocation.base()) + roundUpToMultipleOf(16, sizeof(Data::ChunkHeader));
header->itemEnd = reinterpret_cast<char *>(allocation.base()) + allocation.size() - header->itemSize;
@@ -347,19 +361,26 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
}
last->setNextFree(0);
m = header->freeItems.nextFree();
- const size_t increase = (header->itemEnd - header->itemStart) / header->itemSize;
+ Q_ASSERT(header->itemEnd >= header->itemStart);
+ const size_t increase = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
m_d->availableItems[pos] += uint(increase);
m_d->totalItems += int(increase);
#ifdef V4_USE_VALGRIND
VALGRIND_MAKE_MEM_NOACCESS(allocation.base(), allocSize);
VALGRIND_MEMPOOL_ALLOC(this, header, sizeof(Data::ChunkHeader));
#endif
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_alloc(header, sizeof(Data::ChunkHeader));
+#endif
}
found:
#ifdef V4_USE_VALGRIND
VALGRIND_MEMPOOL_ALLOC(this, m, size);
#endif
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_alloc(m, size);
+#endif
Q_V4_PROFILE_ALLOC(engine, size, Profiling::SmallItem);
++m_d->allocCount[pos];
@@ -374,6 +395,7 @@ static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
{
while (engine->jsStackTop > markBase) {
Heap::Base *h = engine->popForGC();
+ Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen.
Q_ASSERT (h->vtable()->markObjects);
h->vtable()->markObjects(h, engine);
}
@@ -430,7 +452,7 @@ void MemoryManager::sweep(bool lastSweep)
for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
if (!(*it).isManaged())
continue;
- Managed *m = (*it).as<Managed>();
+ Managed *m = (*it).managed();
if (m->markBit())
continue;
// we need to call detroyObject on qobjectwrappers now, so that they can emit the destroyed
@@ -465,29 +487,33 @@ void MemoryManager::sweep(bool lastSweep)
}
}
- bool *chunkIsEmpty = (bool *)alloca(m_d->heapChunks.size() * sizeof(bool));
+ bool *chunkIsEmpty = static_cast<bool *>(alloca(m_d->heapChunks.size() * sizeof(bool)));
uint itemsInUse[MemoryManager::Data::MaxItemSize/16];
memset(itemsInUse, 0, sizeof(itemsInUse));
memset(m_d->nonFullChunks, 0, sizeof(m_d->nonFullChunks));
- for (int i = 0; i < m_d->heapChunks.size(); ++i) {
+ for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base());
chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine, &m_d->unmanagedHeapSize);
}
- QVector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
- for (int i = 0; i < m_d->heapChunks.size(); ++i) {
+ std::vector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
+ for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
Q_ASSERT(chunkIter != m_d->heapChunks.end());
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base());
const size_t pos = header->itemSize >> 4;
- const size_t decrease = (header->itemEnd - header->itemStart) / header->itemSize;
+ Q_ASSERT(header->itemEnd >= header->itemStart);
+ const size_t decrease = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
// Release that chunk if it could have been spared since the last GC run without any difference.
if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) {
- Q_V4_PROFILE_DEALLOC(engine, 0, chunkIter->size(), Profiling::HeapPage);
+ Q_V4_PROFILE_DEALLOC(engine, chunkIter->size(), Profiling::HeapPage);
#ifdef V4_USE_VALGRIND
VALGRIND_MEMPOOL_FREE(this, header);
#endif
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_free(header);
+#endif
--m_d->nChunks[pos];
m_d->availableItems[pos] -= uint(decrease);
m_d->totalItems -= int(decrease);
@@ -516,8 +542,8 @@ void MemoryManager::sweep(bool lastSweep)
m->vtable()->destroy(m);
*last = i->next;
- free(Q_V4_PROFILE_DEALLOC(engine, i, i->size + sizeof(Data::LargeItem),
- Profiling::LargeItem));
+ Q_V4_PROFILE_DEALLOC(engine, i->size + sizeof(Data::LargeItem), Profiling::LargeItem);
+ free(i);
i = *last;
}
@@ -561,7 +587,7 @@ void MemoryManager::runGC()
t.restart();
const size_t usedBefore = getUsedMem();
const size_t largeItemsBefore = getLargeItemsMem();
- int chunksBefore = m_d->heapChunks.size();
+ size_t chunksBefore = m_d->heapChunks.size();
sweep();
const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem();
@@ -589,11 +615,11 @@ void MemoryManager::runGC()
size_t MemoryManager::getUsedMem() const
{
size_t usedMem = 0;
- for (QVector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) {
+ for (std::vector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) {
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base());
for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
- Q_ASSERT((qintptr) item % 16 == 0);
+ Q_ASSERT(qintptr(item) % 16 == 0);
if (m->inUse())
usedMem += header->itemSize;
}
@@ -604,7 +630,7 @@ size_t MemoryManager::getUsedMem() const
size_t MemoryManager::getAllocatedMem() const
{
size_t total = 0;
- for (int i = 0; i < m_d->heapChunks.size(); ++i)
+ for (size_t i = 0; i < m_d->heapChunks.size(); ++i)
total += m_d->heapChunks.at(i).size();
return total;
}
@@ -667,7 +693,7 @@ void MemoryManager::collectFromJSStack() const
Value *v = engine->jsStackBase;
Value *top = engine->jsStackTop;
while (v < top) {
- Managed *m = v->as<Managed>();
+ Managed *m = v->managed();
if (m && m->inUse())
// Skip pointers to already freed objects, they are bogus as well
m->mark(engine);
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index e169675f7d..026cbd8c6b 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -59,6 +59,10 @@
//#define DETAILED_MM_STATS
+#define QV4_MM_MAXBLOCK_SHIFT "QV4_MM_MAXBLOCK_SHIFT"
+#define QV4_MM_MAX_CHUNK_SIZE "QV4_MM_MAX_CHUNK_SIZE"
+#define QV4_MM_STATS "QV4_MM_STATS"
+
QT_BEGIN_NAMESPACE
namespace QV4 {
diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp
index 07064a4889..7a6d9c3826 100644
--- a/src/qml/parser/qqmljsengine_p.cpp
+++ b/src/qml/parser/qqmljsengine_p.cpp
@@ -114,7 +114,7 @@ double integerFromString(const char *buf, int size, int radix)
double integerFromString(const QString &str, int radix)
{
- QByteArray ba = str.trimmed().toLatin1();
+ QByteArray ba = QStringRef(&str).trimmed().toLatin1();
return integerFromString(ba.constData(), ba.size(), radix);
}
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index f4862a17a6..cc5023f12a 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -1,11 +1,17 @@
TARGET = QtQml
-QT = core-private network
+QT = core-private
+
+no_network {
+ DEFINES += QT_NO_NETWORK
+} else {
+ QT += network
+}
DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS
-win32:!wince*:!winrt:LIBS += -lshell32
+win32:!winrt:LIBS += -lshell32
solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
# Ensure this gcc optimization is switched off for mips platforms to avoid trouble with JIT.
@@ -16,7 +22,7 @@ exists("qqml_enable_gcov") {
LIBS_PRIVATE += -lgcov
}
-greaterThan(QT_GCC_MAJOR_VERSION, 5) {
+gcc:!intel_icc:greaterThan(QT_GCC_MAJOR_VERSION, 5) {
# Our code is bad. Temporary workaround.
QMAKE_CXXFLAGS += -fno-delete-null-pointer-checks
}
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
index a671cfa12d..addf1d9ff8 100644
--- a/src/qml/qml/ftw/ftw.pri
+++ b/src/qml/qml/ftw/ftw.pri
@@ -11,7 +11,6 @@ HEADERS += \
$$PWD/qdeletewatcher_p.h \
$$PWD/qrecyclepool_p.h \
$$PWD/qflagpointer_p.h \
- $$PWD/qpointervaluepair_p.h \
$$PWD/qlazilyallocated_p.h \
$$PWD/qqmlnullablevalue_p.h \
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 37c1003748..117670dbfc 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -39,30 +39,7 @@
#include "qhashedstring_p.h"
-inline quint32 stringHash(const QChar* data, int length)
-{
- return QV4::String::createHashValue(data, length);
-}
-inline quint32 stringHash(const char *data, int length)
-{
- return QV4::String::createHashValue(data, length);
-}
-
-void QHashedString::computeHash() const
-{
- m_hash = stringHash(constData(), length());
-}
-
-void QHashedStringRef::computeHash() const
-{
- m_hash = stringHash(m_data, m_length);
-}
-
-void QHashedCStringRef::computeHash() const
-{
- m_hash = stringHash(m_data, m_length);
-}
/*
A QHash has initially around pow(2, MinNumBits) buckets. For
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index 6ff3e4a11b..9ee50ec931 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
// #define QSTRINGHASH_LINK_DEBUG
class QHashedStringRef;
-class Q_AUTOTEST_EXPORT QHashedString : public QString
+class Q_QML_PRIVATE_EXPORT QHashedString : public QString
{
public:
inline QHashedString();
@@ -85,16 +85,20 @@ public:
static bool compare(const QChar *lhs, const QChar *rhs, int length);
static inline bool compare(const QChar *lhs, const char *rhs, int length);
static inline bool compare(const char *lhs, const char *rhs, int length);
+
+ static inline quint32 stringHash(const QChar* data, int length);
+ static inline quint32 stringHash(const char *data, int length);
+
private:
friend class QHashedStringRef;
friend class QStringHashNode;
- void computeHash() const;
+ inline void computeHash() const;
mutable quint32 m_hash;
};
class QHashedCStringRef;
-class Q_AUTOTEST_EXPORT QHashedStringRef
+class Q_QML_PRIVATE_EXPORT QHashedStringRef
{
public:
inline QHashedStringRef();
@@ -136,7 +140,7 @@ public:
private:
friend class QHashedString;
- void computeHash() const;
+ inline void computeHash() const;
const QChar *m_data;
int m_length;
@@ -163,7 +167,7 @@ public:
private:
friend class QHashedStringRef;
- void computeHash() const;
+ inline void computeHash() const;
const char *m_data;
int m_length;
@@ -1214,6 +1218,11 @@ bool QHashedStringRef::isLatin1() const
return true;
}
+void QHashedStringRef::computeHash() const
+{
+ m_hash = QHashedString::stringHash(m_data, m_length);
+}
+
bool QHashedStringRef::startsWithUpper() const
{
if (m_length < 1) return false;
@@ -1280,6 +1289,11 @@ void QHashedCStringRef::writeUtf16(quint16 *output) const
*output++ = *d++;
}
+void QHashedCStringRef::computeHash() const
+{
+ m_hash = QHashedString::stringHash(m_data, m_length);
+}
+
bool QHashedString::compare(const QChar *lhs, const char *rhs, int length)
{
Q_ASSERT(lhs && rhs);
@@ -1295,6 +1309,21 @@ bool QHashedString::compare(const char *lhs, const char *rhs, int length)
return 0 == ::memcmp(lhs, rhs, length);
}
+quint32 QHashedString::stringHash(const QChar *data, int length)
+{
+ return QV4::String::createHashValue(data, length, Q_NULLPTR);
+}
+
+quint32 QHashedString::stringHash(const char *data, int length)
+{
+ return QV4::String::createHashValue(data, length, Q_NULLPTR);
+}
+
+void QHashedString::computeHash() const
+{
+ m_hash = stringHash(constData(), length());
+}
+
QT_END_NAMESPACE
#endif // QHASHEDSTRING_P_H
diff --git a/src/qml/qml/ftw/qpointervaluepair_p.h b/src/qml/qml/ftw/qpointervaluepair_p.h
deleted file mode 100644
index 3d0644039f..0000000000
--- a/src/qml/qml/ftw/qpointervaluepair_p.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QPOINTERVALUEPAIR_P_H
-#define QPOINTERVALUEPAIR_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-#include <private/qflagpointer_p.h>
-
-QT_BEGIN_NAMESPACE
-
-// QPointerValuePair is intended to help reduce the memory consumption of a class.
-// In the common case, QPointerValuePair behaves like a pointer. In this mode, it
-// consumes the same memory as a regular pointer.
-// Additionally, QPointerValuePair can store an arbitrary value type in *addition*
-// to the pointer. In this case, it uses slightly more memory than the pointer and
-// value type combined.
-// Consequently, this class is most useful in cases where a pointer is always stored
-// and a value type is rarely stored.
-template<typename P, typename V>
-class QPointerValuePair {
-public:
- inline QPointerValuePair();
- inline QPointerValuePair(P *);
- inline ~QPointerValuePair();
-
- inline bool isNull() const;
-
- inline bool flag() const;
- inline void setFlag();
- inline void clearFlag();
- inline void setFlagValue(bool);
-
- inline QPointerValuePair<P, V> &operator=(P *);
-
- inline P *operator->() const;
- inline P *operator*() const;
-
- inline bool hasValue() const;
- inline V &value();
- inline const V *constValue() const;
-
-private:
- struct Value { P *pointer; V value; };
- QBiPointer<P, Value> d;
-};
-
-template<typename P, typename V>
-QPointerValuePair<P, V>::QPointerValuePair()
-{
-}
-
-template<typename P, typename V>
-QPointerValuePair<P, V>::QPointerValuePair(P *p)
-: d(p)
-{
-}
-
-template<typename P, typename V>
-QPointerValuePair<P, V>::~QPointerValuePair()
-{
- if (d.isT2()) delete d.asT2();
-}
-
-template<typename P, typename V>
-bool QPointerValuePair<P, V>::isNull() const
-{
- if (d.isT1()) return 0 == d.asT1();
- else return d.asT2()->pointer == 0;
-}
-
-template<typename P, typename V>
-bool QPointerValuePair<P, V>::flag() const
-{
- return d.flag();
-}
-
-template<typename P, typename V>
-void QPointerValuePair<P, V>::setFlag()
-{
- d.setFlag();
-}
-
-template<typename P, typename V>
-void QPointerValuePair<P, V>::clearFlag()
-{
- d.clearFlag();
-}
-
-template<typename P, typename V>
-void QPointerValuePair<P, V>::setFlagValue(bool v)
-{
- d.setFlagValue(v);
-}
-
-template<typename P, typename V>
-QPointerValuePair<P, V> &QPointerValuePair<P, V>::operator=(P *o)
-{
- if (d.isT1()) d = o;
- else d.asT2()->pointer = o;
- return *this;
-}
-
-template<typename P, typename V>
-P *QPointerValuePair<P, V>::operator->() const
-{
- if (d.isT1()) return d.asT1();
- else return d.asT2()->pointer;
-}
-
-template<typename P, typename V>
-P *QPointerValuePair<P, V>::operator*() const
-{
- if (d.isT1()) return d.asT1();
- else return d.asT2()->pointer;
-}
-
-template<typename P, typename V>
-bool QPointerValuePair<P, V>::hasValue() const
-{
- return d.isT2();
-}
-
-template<typename P, typename V>
-V &QPointerValuePair<P, V>::value()
-{
- if (d.isT1()) {
- P *p = d.asT1();
- Value *value = new Value;
- value->pointer = p;
- d = value;
- }
-
- return d.asT2()->value;
-}
-
-// Will return null if hasValue() == false
-template<typename P, typename V>
-const V *QPointerValuePair<P, V>::constValue() const
-{
- if (d.isT2()) return &d.asT2()->value;
- else return 0;
-}
-
-QT_END_NAMESPACE
-
-#endif // QPOINTERVALUEPAIR_P_H
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 4d84cc82ae..cc394b78cb 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -12,7 +12,6 @@ SOURCES += \
$$PWD/qqmlpropertyvalueinterceptor.cpp \
$$PWD/qqmlproxymetaobject.cpp \
$$PWD/qqmlvme.cpp \
- $$PWD/qqmlcompileddata.cpp \
$$PWD/qqmlboundsignal.cpp \
$$PWD/qqmlmetatype.cpp \
$$PWD/qqmlstringconverters.cpp \
@@ -39,7 +38,6 @@ SOURCES += \
$$PWD/qqmlvaluetypeproxybinding.cpp \
$$PWD/qqmlglobal.cpp \
$$PWD/qqmlfile.cpp \
- $$PWD/qqmlmemoryprofiler.cpp \
$$PWD/qqmlplatform.cpp \
$$PWD/qqmlbinding.cpp \
$$PWD/qqmlabstracturlinterceptor.cpp \
@@ -50,7 +48,8 @@ SOURCES += \
$$PWD/qqmltypewrapper.cpp \
$$PWD/qqmlfileselector.cpp \
$$PWD/qqmlobjectcreator.cpp \
- $$PWD/qqmldirparser.cpp
+ $$PWD/qqmldirparser.cpp \
+ $$PWD/qqmldelayedcallqueue.cpp
HEADERS += \
$$PWD/qqmlglobal_p.h \
@@ -70,7 +69,6 @@ HEADERS += \
$$PWD/qqmlparserstatus.h \
$$PWD/qqmlproxymetaobject_p.h \
$$PWD/qqmlvme_p.h \
- $$PWD/qqmlcompiler_p.h \
$$PWD/qqmlengine_p.h \
$$PWD/qqmlexpression_p.h \
$$PWD/qqmlprivate.h \
@@ -108,7 +106,6 @@ HEADERS += \
$$PWD/qqmlabstractbinding_p.h \
$$PWD/qqmlvaluetypeproxybinding_p.h \
$$PWD/qqmlfile.h \
- $$PWD/qqmlmemoryprofiler_p.h \
$$PWD/qqmlplatform_p.h \
$$PWD/qqmlbinding_p.h \
$$PWD/qqmlextensionplugin_p.h \
@@ -122,7 +119,8 @@ HEADERS += \
$$PWD/qqmlfileselector_p.h \
$$PWD/qqmlfileselector.h \
$$PWD/qqmlobjectcreator_p.h \
- $$PWD/qqmldirparser_p.h
+ $$PWD/qqmldirparser_p.h \
+ $$PWD/qqmldelayedcallqueue_p.h
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h
index 674178153a..0ccfae4610 100644
--- a/src/qml/qml/qqmlabstractbinding_p.h
+++ b/src/qml/qml/qqmlabstractbinding_p.h
@@ -55,7 +55,6 @@
#include <QtCore/qshareddata.h>
#include <private/qtqmlglobal_p.h>
#include <private/qqmlproperty_p.h>
-#include <private/qpointervaluepair_p.h>
QT_BEGIN_NAMESPACE
@@ -83,7 +82,7 @@ public:
// binding is not enabled or added to the object.
QObject *targetObject() const { return m_target.data(); }
- virtual void setEnabled(bool e, QQmlPropertyPrivate::WriteFlags f = QQmlPropertyPrivate::DontRemoveBinding) = 0;
+ virtual void setEnabled(bool e, QQmlPropertyData::WriteFlags f = QQmlPropertyData::DontRemoveBinding) = 0;
void addToObject();
void removeFromObject();
@@ -92,6 +91,8 @@ public:
inline QQmlAbstractBinding *nextBinding() const;
+ inline bool canUseAccessor() const
+ { return m_nextBinding.flag2(); }
struct RefCount {
RefCount() : refCount(0) {}
@@ -113,8 +114,15 @@ protected:
inline void setNextBinding(QQmlAbstractBinding *);
int m_targetIndex;
+
+ // Pointer is the target object to which the binding binds
+ // flag1 is the updating flag
+ // flag2 is the enabled flag
QFlagPointer<QObject> m_target;
+
// Pointer to the next binding in the linked list of bindings.
+ // flag1 is used for addedToObject
+ // flag2 indicates if an accessor is can be used (i.e. there is no interceptor on the target)
QFlagPointer<QQmlAbstractBinding> m_nextBinding;
};
diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h
index 55562a5307..e98663adfe 100644
--- a/src/qml/qml/qqmlaccessors_p.h
+++ b/src/qml/qml/qqmlaccessors_p.h
@@ -102,11 +102,15 @@ class QQmlNotifier;
} \
} while (false);
-#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable) \
+#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable, setter) \
static void clazz ## _ ## name ## Read(QObject *o, void *rv) \
{ \
clazz ## Private *d = clazz ## Private::get(static_cast<clazz *>(o)); \
*static_cast<cpptype *>(rv) = d->variable; \
+ } \
+ static void clazz ## _ ## name ## Write(QObject *o, void *rv) \
+ { \
+ static_cast<clazz *>(o)->setter(*static_cast<cpptype *>(rv)); \
}
#define QML_PROPERTY_NAME(name) #name, sizeof #name - 1
@@ -115,6 +119,7 @@ class QQmlAccessors
{
public:
void (*read)(QObject *object, void *output);
+ void (*write)(QObject *object, void *output);
void (*notifier)(QObject *object, QQmlNotifier **notifier);
};
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index 57cdd3f47f..8c342e0592 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -211,11 +211,8 @@ QQmlApplicationEngine::QQmlApplicationEngine(QObject *parent)
This is provided as a convenience, and is the same as using the empty constructor and calling load afterwards.
*/
QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent)
- : QQmlEngine(*(new QQmlApplicationEnginePrivate(this)), parent)
+ : QQmlApplicationEngine(parent)
{
- Q_D(QQmlApplicationEngine);
- d->init();
- QJSEnginePrivate::addToDebugServer(this);
load(url);
}
@@ -228,12 +225,8 @@ QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent)
This is provided as a convenience, and is the same as using the empty constructor and calling load afterwards.
*/
QQmlApplicationEngine::QQmlApplicationEngine(const QString &filePath, QObject *parent)
- : QQmlEngine(*(new QQmlApplicationEnginePrivate(this)), parent)
+ : QQmlApplicationEngine(QUrl::fromLocalFile(filePath), parent)
{
- Q_D(QQmlApplicationEngine);
- d->init();
- QJSEnginePrivate::addToDebugServer(this);
- load(QUrl::fromLocalFile(filePath));
}
/*!
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 1249e1b6c8..10d16a8a12 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -42,8 +42,8 @@
#include "qqml.h"
#include "qqmlcontext.h"
#include "qqmlinfo.h"
-#include "qqmlcompiler_p.h"
#include "qqmldata_p.h"
+#include "qqmlaccessors_p.h"
#include <private/qqmlprofiler_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qqmlscriptstring_p.h>
@@ -57,27 +57,28 @@
QT_BEGIN_NAMESPACE
-QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContext *ctxt)
{
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt));
- setScopeObject(obj);
+ QQmlBinding *b = newBinding(property);
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt));
+ b->setScopeObject(obj);
- createQmlBinding(context(), obj, str, QString(), 0);
+ b->createQmlBinding(b->context(), obj, str, QString(), 0);
+
+ return b;
}
-QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
{
+ QQmlBinding *b = newBinding(property);
+
if (ctxt && !ctxt->isValid())
- return;
+ return b;
const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
- return;
+ return b;
QString url;
QV4::Function *runtimeFunction = 0;
@@ -90,53 +91,61 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte
runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId);
}
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
- setScopeObject(obj ? obj : scriptPrivate->scope);
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
+ b->setScopeObject(obj ? obj : scriptPrivate->scope);
- QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(b->context()->engine)->v4engine();
if (runtimeFunction) {
- m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, scopeObject(), runtimeFunction));
+ b->m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, b->scopeObject(), runtimeFunction));
} else {
QString code = scriptPrivate->script;
- createQmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber);
+ b->createQmlBinding(b->context(), b->scopeObject(), code, url, scriptPrivate->lineNumber);
}
+
+ return b;
}
-QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContextData *ctxt)
{
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(ctxt);
- setScopeObject(obj);
+ QQmlBinding *b = newBinding(property);
+
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(ctxt);
+ b->setScopeObject(obj);
- createQmlBinding(ctxt, obj, str, QString(), 0);
+ b->createQmlBinding(ctxt, obj, str, QString(), 0);
+
+ return b;
}
-QQmlBinding::QQmlBinding(const QString &str, QObject *obj,
- QQmlContextData *ctxt,
- const QString &url, quint16 lineNumber, quint16 columnNumber)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj,
+ QQmlContextData *ctxt, const QString &url, quint16 lineNumber,
+ quint16 columnNumber)
{
+ QQmlBinding *b = newBinding(property);
+
Q_UNUSED(columnNumber);
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(ctxt);
- setScopeObject(obj);
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(ctxt);
+ b->setScopeObject(obj);
- createQmlBinding(ctxt, obj, str, url, lineNumber);
+ b->createQmlBinding(ctxt, obj, str, url, lineNumber);
+
+ return b;
}
-QQmlBinding::QQmlBinding(const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt)
{
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(ctxt);
- setScopeObject(obj);
+ QQmlBinding *b = newBinding(property);
+
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(ctxt);
+ b->setScopeObject(obj);
- m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr);
+ b->m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr);
+
+ return b;
}
QQmlBinding::~QQmlBinding()
@@ -148,7 +157,7 @@ void QQmlBinding::setNotifyOnValueChanged(bool v)
QQmlJavaScriptExpression::setNotifyOnValueChanged(v);
}
-void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
+void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
{
if (!enabledFlag() || !context() || !context()->isValid())
return;
@@ -157,44 +166,73 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
if (QQmlData::wasDeleted(targetObject()))
return;
+ // Check for a binding update loop
+ if (Q_UNLIKELY(updatingFlag())) {
+ QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0);
+ QQmlAbstractBinding::printBindingLoopError(p);
+ return;
+ }
+ setUpdatingFlag(true);
+
+ DeleteWatcher watcher(this);
+
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
QV4::Scope scope(ep->v4engine());
QV4::ScopedFunctionObject f(scope, m_function.value());
Q_ASSERT(f);
- if (updatingFlag()) {
- QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0);
- QQmlAbstractBinding::printBindingLoopError(p);
- return;
- }
+ if (canUseAccessor())
+ flags.setFlag(QQmlPropertyData::BypassInterceptor);
QQmlBindingProfiler prof(ep->profiler, this, f);
- setUpdatingFlag(true);
-
- QQmlJavaScriptExpression::DeleteWatcher watcher(this);
+ doUpdate(this, watcher, flags, scope, f);
- QQmlPropertyData pd = getPropertyData();
+ if (!watcher.wasDeleted())
+ setUpdatingFlag(false);
+}
- if (pd.propType == qMetaTypeId<QQmlBinding *>()) {
+// QQmlBindingBinding is for target properties which are of type "binding" (instead of, say, int or
+// double). The reason for being is that GenericBinding::fastWrite needs a compile-time constant
+// expression for the switch for the compiler to generate the optimal code, but
+// qMetaTypeId<QQmlBinding *>() needs to be used for the ID. So QQmlBinding::newBinding uses that
+// to instantiate this class.
+class QQmlBindingBinding: public QQmlBinding
+{
+protected:
+ void doUpdate(QQmlBinding *binding, const DeleteWatcher &,
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &,
+ const QV4::ScopedFunctionObject &) Q_DECL_OVERRIDE Q_DECL_FINAL
+ {
+ QQmlPropertyData pd = getPropertyData();
int idx = pd.coreIndex;
Q_ASSERT(idx != -1);
- QQmlBinding *t = this;
int status = -1;
- void *a[] = { &t, 0, &status, &flags };
+ void *a[] = { &binding, 0, &status, &flags };
QMetaObject::metacall(*m_target, QMetaObject::WriteProperty, idx, a);
+ }
+};
- } else {
+template<int StaticPropType>
+class GenericBinding: public QQmlBinding
+{
+protected:
+ void doUpdate(QQmlBinding *binding, const DeleteWatcher &watcher,
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &scope,
+ const QV4::ScopedFunctionObject &f) Q_DECL_OVERRIDE Q_DECL_FINAL
+ {
+ auto ep = QQmlEnginePrivate::get(scope.engine);
ep->referenceScarceResources();
bool isUndefined = false;
- QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
+ QV4::ScopedCallData callData(scope);
+ binding->QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope);
bool error = false;
if (!watcher.wasDeleted() && isAddedToObject() && !hasError())
- error = !write(pd, result, isUndefined, flags);
+ error = !write(scope.result, isUndefined, flags);
if (!watcher.wasDeleted()) {
@@ -214,59 +252,65 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
ep->dereferenceScarceResources();
}
- if (!watcher.wasDeleted())
- setUpdatingFlag(false);
-}
-
-// Returns true if successful, false if an error description was set on expression
-bool QQmlBinding::write(const QQmlPropertyData &core,
- const QV4::Value &result, bool isUndefined,
- QQmlPropertyPrivate::WriteFlags flags)
-{
- Q_ASSERT(m_target.data());
- Q_ASSERT(core.coreIndex != -1);
-
-#define QUICK_STORE(cpptype, conversion) \
- { \
- cpptype o = (conversion); \
- int status = -1; \
- void *argv[] = { &o, 0, &status, &flags }; \
- QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, core.coreIndex, argv); \
- return true; \
- } \
-
-
- if (Q_LIKELY(!isUndefined && !core.isValueTypeVirtual())) {
- switch (core.propType) {
- case QMetaType::Int:
- if (result.isInteger())
- QUICK_STORE(int, result.integerValue())
- else if (result.isNumber())
- QUICK_STORE(int, result.doubleValue())
- break;
- case QMetaType::Double:
- if (result.isNumber())
- QUICK_STORE(double, result.asDouble())
- break;
- case QMetaType::Float:
- if (result.isNumber())
- QUICK_STORE(float, result.asDouble())
- break;
- case QMetaType::QString:
- if (result.isString())
- QUICK_STORE(QString, result.toQStringNoThrow())
- break;
- default:
- if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
- if (vtw->d()->valueType->typeId == core.propType) {
- return vtw->write(m_target.data(), core.coreIndex);
+ // Returns true if successful, false if an error description was set on expression
+ Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags)
+ {
+ QQmlPropertyData pd = getPropertyData();
+ int propertyType = StaticPropType; // If the binding is specialized to a type, the if and switch below will be constant-folded.
+ if (propertyType == QMetaType::UnknownType)
+ propertyType = pd.propType;
+ Q_ASSERT(targetObject());
+
+ if (Q_LIKELY(!isUndefined && !pd.isValueTypeVirtual())) {
+ switch (propertyType) {
+ case QMetaType::Bool:
+ if (result.isBoolean())
+ return doStore<bool>(result.booleanValue(), pd, flags);
+ else
+ return doStore<bool>(result.toBoolean(), pd, flags);
+ case QMetaType::Int:
+ if (result.isInteger())
+ return doStore<int>(result.integerValue(), pd, flags);
+ else if (result.isNumber())
+ return doStore<int>(result.doubleValue(), pd, flags);
+ break;
+ case QMetaType::Double:
+ if (result.isNumber())
+ return doStore<double>(result.asDouble(), pd, flags);
+ break;
+ case QMetaType::Float:
+ if (result.isNumber())
+ return doStore<float>(result.asDouble(), pd, flags);
+ break;
+ case QMetaType::QString:
+ if (result.isString())
+ return doStore<QString>(result.toQStringNoThrow(), pd, flags);
+ break;
+ default:
+ if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
+ if (vtw->d()->valueType->typeId == pd.propType) {
+ return vtw->write(m_target.data(), pd.coreIndex);
+ }
}
+ break;
}
- break;
}
+
+ return slowWrite(pd, result, isUndefined, flags);
+ }
+
+ template <typename T>
+ Q_ALWAYS_INLINE bool doStore(T value, const QQmlPropertyData &pd, QQmlPropertyData::WriteFlags flags) const
+ {
+ void *o = &value;
+ return pd.writeProperty(targetObject(), o, flags);
}
-#undef QUICK_STORE
+};
+Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core, const QV4::Value &result,
+ bool isUndefined, QQmlPropertyData::WriteFlags flags)
+{
QQmlEngine *engine = context()->engine;
QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
@@ -378,11 +422,12 @@ QVariant QQmlBinding::evaluate()
bool isUndefined = false;
QV4::Scope scope(ep->v4engine());
- QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
+ QV4::ScopedCallData callData(scope);
+ QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope);
ep->dereferenceScarceResources();
- return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >());
+ return scope.engine->toVariant(scope.result, qMetaTypeId<QList<QObject*> >());
}
QString QQmlBinding::expressionIdentifier()
@@ -409,11 +454,18 @@ void QQmlBinding::refresh()
update();
}
-void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
+void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
{
setEnabledFlag(e);
setNotifyOnValueChanged(e);
+ m_nextBinding.setFlag2(); // Always use accessors, only not when:
+ if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
+ int coreIndex = getPropertyCoreIndex();
+ if (coreIndex == -1 || interceptorMetaObject->intercepts(coreIndex))
+ m_nextBinding.clearFlag2();
+ }
+
if (e)
update(flags);
}
@@ -509,4 +561,39 @@ QQmlPropertyData QQmlBinding::getPropertyData() const
return d;
}
+Q_ALWAYS_INLINE int QQmlBinding::getPropertyCoreIndex() const
+{
+ int coreIndex;
+ int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(m_targetIndex, &coreIndex);
+ if (valueTypeIndex != -1) {
+ return -1;
+ } else {
+ return coreIndex;
+ }
+}
+
+QQmlBinding *QQmlBinding::newBinding(const QQmlPropertyData *property)
+{
+ const int type = (property && property->isFullyResolved()) ? property->propType : QMetaType::UnknownType;
+
+ if (type == qMetaTypeId<QQmlBinding *>()) {
+ return new QQmlBindingBinding;
+ }
+
+ switch (type) {
+ case QMetaType::Bool:
+ return new GenericBinding<QMetaType::Bool>;
+ case QMetaType::Int:
+ return new GenericBinding<QMetaType::Int>;
+ case QMetaType::Double:
+ return new GenericBinding<QMetaType::Double>;
+ case QMetaType::Float:
+ return new GenericBinding<QMetaType::Float>;
+ case QMetaType::QString:
+ return new GenericBinding<QMetaType::QString>;
+ default:
+ return new GenericBinding<QMetaType::UnknownType>;
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 7814b9dee8..0c797d7df2 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -61,7 +61,6 @@
#include <QtCore/QObject>
#include <QtCore/QMetaProperty>
-#include <private/qpointervaluepair_p.h>
#include <private/qqmlabstractbinding_p.h>
#include <private/qqmljavascriptexpression_p.h>
@@ -73,12 +72,12 @@ class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression,
{
friend class QQmlAbstractBinding;
public:
- QQmlBinding(const QString &, QObject *, QQmlContext *);
- QQmlBinding(const QQmlScriptString &, QObject *, QQmlContext *);
- QQmlBinding(const QString &, QObject *, QQmlContextData *);
- QQmlBinding(const QString &, QObject *, QQmlContextData *,
- const QString &url, quint16 lineNumber, quint16 columnNumber);
- QQmlBinding(const QV4::Value &, QObject *, QQmlContextData *);
+ static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContext *);
+ static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *);
+ static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *);
+ static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *,
+ const QString &url, quint16 lineNumber, quint16 columnNumber);
+ static QQmlBinding *create(const QQmlPropertyData *, const QV4::Value &, QObject *, QQmlContextData *);
~QQmlBinding();
void setTarget(const QQmlProperty &);
@@ -86,13 +85,11 @@ public:
void setNotifyOnValueChanged(bool);
- // Inherited from QQmlJavaScriptExpression
- virtual void refresh();
+ void refresh() Q_DECL_OVERRIDE;
- // Inherited from QQmlAbstractBinding
- virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding);
- virtual QString expression() const;
- void update(QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding);
+ void setEnabled(bool, QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding) Q_DECL_OVERRIDE;
+ QString expression() const Q_DECL_OVERRIDE;
+ void update(QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding);
typedef int Identifier;
enum {
@@ -101,20 +98,28 @@ public:
QVariant evaluate();
- virtual QString expressionIdentifier();
- virtual void expressionChanged();
+ QString expressionIdentifier() Q_DECL_OVERRIDE;
+ void expressionChanged() Q_DECL_OVERRIDE;
+
+protected:
+ virtual void doUpdate(QQmlBinding *binding, const DeleteWatcher &watcher,
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &scope,
+ const QV4::ScopedFunctionObject &f) = 0;
+
+ QQmlPropertyData getPropertyData() const;
+ int getPropertyCoreIndex() const;
+ int getPropertyType() const;
+
+ bool slowWrite(const QQmlPropertyData &core, const QV4::Value &result, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags);
private:
inline bool updatingFlag() const;
inline void setUpdatingFlag(bool);
inline bool enabledFlag() const;
inline void setEnabledFlag(bool);
- QQmlPropertyData getPropertyData() const;
-
- bool write(const QQmlPropertyData &core,
- const QV4::Value &result, bool isUndefined,
- QQmlPropertyPrivate::WriteFlags flags);
+ static QQmlBinding *newBinding(const QQmlPropertyData *property);
};
bool QQmlBinding::updatingFlag() const
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index c6a7cde240..ef837183db 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -51,14 +51,12 @@
#include <private/qqmlprofiler_p.h>
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
-#include <private/qqmlcompiler_p.h>
#include "qqmlinfo.h"
#include <private/qjsvalue_p.h>
#include <private/qv4value_p.h>
#include <private/qv4qobjectwrapper_p.h>
-#include <QtCore/qstringbuilder.h>
#include <QtCore/qdebug.h>
@@ -83,9 +81,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
// Add some leading whitespace to account for the binding's column offset.
// It's 2 off because a, we start counting at 1 and b, the '(' below is not counted.
function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2);
- function += QStringLiteral("(function ");
- function += handlerName;
- function += QLatin1Char('(');
+ function += QLatin1String("(function ") + handlerName + QLatin1Char('(');
if (parameterString.isEmpty()) {
QString error;
@@ -101,10 +97,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
} else
function += parameterString;
- function += QStringLiteral(") { ");
- function += expression;
- function += QStringLiteral(" })");
-
+ function += QLatin1String(") { ") + expression + QLatin1String(" })");
m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line));
if (m_function.isNullOrUndefined())
@@ -213,10 +206,10 @@ void QQmlBoundSignalExpression::evaluate(void **a)
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QVarLengthArray<int, 9> dummy;
+ QQmlMetaObject::ArgTypeStorage storage;
//TODO: lookup via signal index rather than method index as an optimization
int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
- int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0);
+ int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, &storage, 0);
int argCount = argsTypes ? *argsTypes : 0;
QV4::ScopedCallData callData(scope, argCount);
@@ -244,7 +237,7 @@ void QQmlBoundSignalExpression::evaluate(void **a)
}
}
- QQmlJavaScriptExpression::evaluate(callData, 0);
+ QQmlJavaScriptExpression::evaluate(callData, 0, scope);
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
@@ -266,7 +259,7 @@ void QQmlBoundSignalExpression::evaluate(const QList<QVariant> &args)
callData->args[ii] = scope.engine->fromVariant(args[ii]);
}
- QQmlJavaScriptExpression::evaluate(callData, 0);
+ QQmlJavaScriptExpression::evaluate(callData, 0, scope);
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
deleted file mode 100644
index 28d599a593..0000000000
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlcompiler_p.h"
-#include "qqmlengine.h"
-#include "qqmlcomponent.h"
-#include "qqmlcomponent_p.h"
-#include "qqmlcontext.h"
-#include "qqmlcontext_p.h"
-#include "qqmlpropertymap.h"
-#ifdef QML_THREADED_VME_INTERPRETER
-#include "qqmlvme_p.h"
-#endif
-
-#include <QtCore/qdebug.h>
-
-#include <private/qobject_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine)
-: engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false),
- rootPropertyCache(0), totalBindingsCount(0), totalParserStatusCount(0)
-{
- Q_ASSERT(engine);
-}
-
-void QQmlCompiledData::destroy()
-{
- if (engine && hasEngine())
- QQmlEnginePrivate::deleteInEngineThread(engine, this);
- else
- delete this;
-}
-
-QQmlCompiledData::~QQmlCompiledData()
-{
- if (isRegisteredWithEngine)
- QQmlEnginePrivate::get(engine)->unregisterInternalCompositeType(this);
-
- clear();
-
- for (QHash<int, TypeReference*>::Iterator resolvedType = resolvedTypes.begin(), end = resolvedTypes.end();
- resolvedType != end; ++resolvedType) {
- if ((*resolvedType)->component)
- (*resolvedType)->component->release();
- if ((*resolvedType)->typePropertyCache)
- (*resolvedType)->typePropertyCache->release();
- }
- qDeleteAll(resolvedTypes);
- resolvedTypes.clear();
-
- for (int ii = 0; ii < propertyCaches.count(); ++ii)
- if (propertyCaches.at(ii))
- propertyCaches.at(ii)->release();
-
- for (int ii = 0; ii < scripts.count(); ++ii)
- scripts.at(ii)->release();
-
- if (importCache)
- importCache->release();
-
- if (rootPropertyCache)
- rootPropertyCache->release();
-}
-
-void QQmlCompiledData::clear()
-{
-}
-
-/*!
-Returns the property cache, if one alread exists. The cache is not referenced.
-*/
-QQmlPropertyCache *QQmlCompiledData::TypeReference::propertyCache() const
-{
- if (type)
- return typePropertyCache;
- else
- return component->rootPropertyCache;
-}
-
-/*!
-Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
-*/
-QQmlPropertyCache *QQmlCompiledData::TypeReference::createPropertyCache(QQmlEngine *engine)
-{
- if (typePropertyCache) {
- return typePropertyCache;
- } else if (type) {
- typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type->metaObject());
- typePropertyCache->addref();
- return typePropertyCache;
- } else {
- return component->rootPropertyCache;
- }
-}
-
-template <typename T>
-bool qtTypeInherits(const QMetaObject *mo) {
- while (mo) {
- if (mo == &T::staticMetaObject)
- return true;
- mo = mo->superClass();
- }
- return false;
-}
-
-void QQmlCompiledData::TypeReference::doDynamicTypeCheck()
-{
- const QMetaObject *mo = 0;
- if (typePropertyCache)
- mo = typePropertyCache->firstCppMetaObject();
- else if (type)
- mo = type->metaObject();
- else if (component)
- mo = component->rootPropertyCache->firstCppMetaObject();
- isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
-}
-
-void QQmlCompiledData::initialize(QQmlEngine *engine)
-{
- Q_ASSERT(!hasEngine());
- QQmlCleanup::addToEngine(engine);
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- if (compilationUnit && !compilationUnit->engine)
- compilationUnit->linkToEngine(v4);
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
deleted file mode 100644
index 1c43a85de3..0000000000
--- a/src/qml/qml/qqmlcompiler_p.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLCOMPILER_P_H
-#define QQMLCOMPILER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qqml.h"
-#include "qqmlerror.h"
-#include "qqmlengine_p.h"
-#include <private/qbitfield_p.h>
-#include "qqmlpropertycache_p.h"
-#include "qqmltypenamecache_p.h"
-#include "qqmltypeloader_p.h"
-#include "private/qv4identifier_p.h"
-#include <private/qqmljsastfwd_p.h>
-#include "qqmlcustomparser_p.h"
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qset.h>
-#include <QtCore/QCoreApplication>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace CompiledData {
-struct CompilationUnit;
-struct Unit;
-}
-}
-
-class QQmlEngine;
-class QQmlComponent;
-class QQmlContext;
-class QQmlContextData;
-
-// ### Merge with QV4::CompiledData::CompilationUnit
-class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup
-{
-public:
- QQmlCompiledData(QQmlEngine *engine);
- virtual ~QQmlCompiledData();
-
- QQmlEngine *engine;
-
- QString fileName() const { return compilationUnit->fileName(); }
- QUrl url() const { return compilationUnit->url(); }
- QQmlTypeNameCache *importCache;
-
- int metaTypeId;
- int listMetaTypeId;
- bool isRegisteredWithEngine;
-
- struct TypeReference
- {
- TypeReference()
- : type(0), typePropertyCache(0), component(0)
- , majorVersion(0)
- , minorVersion(0)
- , isFullyDynamicType(false)
- {}
-
- QQmlType *type;
- QQmlPropertyCache *typePropertyCache;
- QQmlCompiledData *component;
-
- int majorVersion;
- int minorVersion;
- // Types such as QQmlPropertyMap can add properties dynamically at run-time and
- // therefore cannot have a property cache installed when instantiated.
- bool isFullyDynamicType;
-
- QQmlPropertyCache *propertyCache() const;
- QQmlPropertyCache *createPropertyCache(QQmlEngine *);
-
- void doDynamicTypeCheck();
- };
- // map from name index
- QHash<int, TypeReference*> resolvedTypes;
-
- QQmlPropertyCache *rootPropertyCache;
- QVector<QByteArray> metaObjects;
- QVector<QQmlPropertyCache *> propertyCaches;
- QList<QQmlScriptData *> scripts;
-
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
- // index in first hash is component index, hash inside maps from object index in that scope to integer id
- QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
- QHash<int, int> objectIndexToIdForRoot;
- // hash key is object index, value is indicies of bindings covered by custom parser
- QHash<int, QBitArray> customParserBindings;
- QHash<int, QBitArray> deferredBindingsPerObject; // index is object index
- int totalBindingsCount; // Number of bindings used in this type
- int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
- int totalObjectCount; // Number of objects explicitly instantiated
-
- bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
- bool isCompositeType() const { return !metaObjects.at(compilationUnit->data->indexOfRootObject).isEmpty(); }
-
- bool isInitialized() const { return hasEngine(); }
- void initialize(QQmlEngine *);
-
-protected:
- virtual void destroy(); // From QQmlRefCount
- virtual void clear(); // From QQmlCleanup
-
-private:
- QQmlCompiledData(const QQmlCompiledData &other);
- QQmlCompiledData &operator=(const QQmlCompiledData &other);
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLCOMPILER_P_H
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index c64851cac5..9c7b4fe1c0 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -41,7 +41,6 @@
#include "qqmlcomponent_p.h"
#include "qqmlcomponentattached_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlcontext_p.h"
#include "qqmlengine_p.h"
#include "qqmlvme_p.h"
@@ -335,14 +334,11 @@ void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data)
{
url = data->finalUrl();
- QQmlCompiledData *c = data->compiledData();
+ compilationUnit = data->compilationUnit();
- if (!c) {
+ if (!compilationUnit) {
Q_ASSERT(data->isError());
state.errors = data->errors();
- } else {
- cc = c;
- cc->addref();
}
data->release();
@@ -356,10 +352,7 @@ void QQmlComponentPrivate::clear()
typeData = 0;
}
- if (cc) {
- cc->release();
- cc = 0;
- }
+ compilationUnit = nullptr;
}
/*!
@@ -393,8 +386,6 @@ QQmlComponent::~QQmlComponent()
d->typeData->unregisterCallback(d);
d->typeData->release();
}
- if (d->cc)
- d->cc->release();
}
/*!
@@ -422,7 +413,7 @@ QQmlComponent::Status QQmlComponent::status() const
return Loading;
else if (!d->state.errors.isEmpty())
return Error;
- else if (d->engine && d->cc)
+ else if (d->engine && d->compilationUnit)
return Ready;
else
return Null;
@@ -512,11 +503,8 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
\sa loadUrl()
*/
QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *parent)
-: QObject(*(new QQmlComponentPrivate), parent)
+ : QQmlComponent(engine, url, QQmlComponent::PreferSynchronous, parent)
{
- Q_D(QQmlComponent);
- d->engine = engine;
- d->loadUrl(url);
}
/*!
@@ -531,10 +519,9 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *paren
*/
QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMode mode,
QObject *parent)
-: QObject(*(new QQmlComponentPrivate), parent)
+ : QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- d->engine = engine;
d->loadUrl(url, mode);
}
@@ -546,11 +533,8 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMod
*/
QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
QObject *parent)
-: QObject(*(new QQmlComponentPrivate), parent)
+ : QQmlComponent(engine, fileName, QQmlComponent::PreferSynchronous, parent)
{
- Q_D(QQmlComponent);
- d->engine = engine;
- d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
}
/*!
@@ -562,25 +546,22 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
*/
QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
CompilationMode mode, QObject *parent)
-: QObject(*(new QQmlComponentPrivate), parent)
+ : QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- d->engine = engine;
d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)), mode);
}
/*!
\internal
*/
-QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start, QObject *parent)
- : QObject(*(new QQmlComponentPrivate), parent)
+QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::CompiledData::CompilationUnit *compilationUnit, int start, QObject *parent)
+ : QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- d->engine = engine;
- d->cc = cc;
- cc->addref();
+ d->compilationUnit = compilationUnit;
d->start = start;
- d->url = cc->url();
+ d->url = compilationUnit->url();
d->progress = 1.0;
}
@@ -873,7 +854,7 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
enginePriv->referenceScarceResources();
QObject *rv = 0;
- state.creator.reset(new QQmlObjectCreator(context, cc, creationContext));
+ state.creator.reset(new QQmlObjectCreator(context, compilationUnit, creationContext));
rv = state.creator->create(start);
if (!rv)
state.errors = state.creator->errors;
@@ -893,11 +874,13 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
depthIncreased = false;
}
- QQmlEngineDebugService *service = QQmlDebugConnector::service<QQmlEngineDebugService>();
- if (service && rv) {
- if (!context->isInternal)
- context->asQQmlContextPrivate()->instances.append(rv);
- service->objectCreated(engine, rv);
+ if (rv) {
+ if (QQmlEngineDebugService *service =
+ QQmlDebugConnector::service<QQmlEngineDebugService>()) {
+ if (!context->isInternal)
+ context->asQQmlContextPrivate()->instances.append(rv);
+ service->objectCreated(engine, rv);
+ }
}
return rv;
@@ -914,7 +897,7 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
Q_ASSERT(ddata->deferredData);
QQmlData::DeferredData *deferredData = ddata->deferredData;
QQmlContextData *creationContext = 0;
- state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compiledData, creationContext));
+ state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compilationUnit, creationContext));
if (!state->creator->populateDeferredProperties(object))
state->errors << state->creator->errors;
}
@@ -1058,9 +1041,9 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
- p->compiledData = d->cc;
- p->compiledData->addref();
- p->creator.reset(new QQmlObjectCreator(contextData, d->cc, d->creationContext, p.data()));
+ p->compilationUnit = d->compilationUnit;
+ p->enginePriv = enginePriv;
+ p->creator.reset(new QQmlObjectCreator(contextData, d->compilationUnit, d->creationContext, p.data()));
p->subComponentToCreate = d->start;
enginePriv->incubate(incubator, forContextData);
@@ -1193,7 +1176,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
*/
-static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v)
+void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v)
{
QV4::Scope scope(engine);
QV4::ScopedObject object(scope);
@@ -1282,7 +1265,7 @@ void QQmlComponent::createObject(QQmlV4Function *args)
if (!valuemap->isUndefined()) {
QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext());
- setInitialProperties(v4, qmlContext, object, valuemap);
+ QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap);
}
d->completeCreate();
@@ -1515,7 +1498,7 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o)
QV4::Scope scope(v4);
QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o));
QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext);
- setInitialProperties(v4, qmlCtxt, obj, d()->valuemap);
+ QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap);
}
}
@@ -1546,7 +1529,7 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
QV4::ScopedCallData callData(scope, 1);
callData->thisObject = this;
callData->args[0] = QV4::Primitive::fromUInt32(s);
- f->call(callData);
+ f->call(scope, callData);
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error);
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index aefbf20aff..ca60f01eb5 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -55,10 +55,15 @@ class QQmlEngine;
class QQmlComponent;
class QQmlIncubator;
class QQmlV4Function;
-class QQmlCompiledData;
class QQmlComponentPrivate;
class QQmlComponentAttached;
+namespace QV4 {
+namespace CompiledData {
+struct CompilationUnit;
+}
+}
+
class Q_QML_EXPORT QQmlComponent : public QObject
{
Q_OBJECT
@@ -122,7 +127,7 @@ protected:
Q_INVOKABLE void incubateObject(QQmlV4Function *);
private:
- QQmlComponent(QQmlEngine *, QQmlCompiledData *, int, QObject *parent);
+ QQmlComponent(QQmlEngine *, QV4::CompiledData::CompilationUnit *compilationUnit, int, QObject *parent);
Q_DISABLE_COPY(QQmlComponent)
friend class QQmlTypeData;
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 039b267433..3a84e724da 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -71,7 +71,6 @@ QT_BEGIN_NAMESPACE
class QQmlComponent;
class QQmlEngine;
-class QQmlCompiledData;
class QQmlComponentAttached;
class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback
@@ -80,13 +79,14 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public
public:
QQmlComponentPrivate()
- : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0), depthIncreased(false) {}
+ : typeData(0), progress(0.), start(-1), engine(0), creationContext(0), depthIncreased(false) {}
void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
QObject *beginCreate(QQmlContextData *);
void completeCreate();
void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate);
+ static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v);
QQmlTypeData *typeData;
virtual void typeDataReady(QQmlTypeData *);
@@ -98,7 +98,7 @@ public:
qreal progress;
int start;
- QQmlCompiledData *cc;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
struct ConstructionState {
ConstructionState()
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 65a337f4e5..6621f48e20 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -310,7 +310,7 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
}
}
- QV4::IdentifierHash<int> &properties = data->propertyNames();
+ QV4::IdentifierHash<int> &properties = data->detachedPropertyNames();
int idx = properties.value(name);
if (idx == -1) {
properties.add(name, data->idValueCount + d->propertyValues.count());
@@ -346,7 +346,7 @@ void QQmlContext::setContextProperty(const QString &name, QObject *value)
return;
}
- QV4::IdentifierHash<int> &properties = data->propertyNames();
+ QV4::IdentifierHash<int> &properties = data->detachedPropertyNames();
int idx = properties.value(name);
if (idx == -1) {
@@ -516,20 +516,15 @@ QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int ind
QQmlContextData::QQmlContextData()
-: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
- isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
- publicContext(0), activeVMEData(0),
- contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
- expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
- componentAttached(0)
+ : QQmlContextData(nullptr)
{
}
QQmlContextData::QQmlContextData(QQmlContext *ctxt)
: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
- publicContext(ctxt), activeVMEData(0),
- contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ publicContext(ctxt), activeVMEData(0), componentObjectIndex(-1),
+ contextObject(0), childContexts(0), nextChild(0), prevChild(0),
expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
componentAttached(0)
{
@@ -633,9 +628,6 @@ void QQmlContextData::destroy()
}
contextGuards = 0;
- if (imports)
- imports->release();
-
delete [] idValues;
if (isInternal)
@@ -765,15 +757,6 @@ void QQmlContextData::setIdProperty(int idx, QObject *obj)
idValues[idx].context = this;
}
-void QQmlContextData::setIdPropertyData(const QHash<int, int> &data)
-{
- Q_ASSERT(objectIndexToId.isEmpty());
- objectIndexToId = data;
- Q_ASSERT(propertyNameCache.isEmpty());
- idValueCount = data.count();
- idValues = new ContextGuard[idValueCount];
-}
-
QString QQmlContextData::findObjectId(const QObject *obj) const
{
const QV4::IdentifierHash<int> &properties = propertyNames();
@@ -809,21 +792,33 @@ QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
return QQmlContextPrivate::get(asQQmlContext());
}
-QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const
+void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex)
+{
+ typeCompilationUnit = unit;
+ componentObjectIndex = subComponentIndex == -1 ? typeCompilationUnit->data->indexOfRootObject : subComponentIndex;
+ Q_ASSERT(!idValues);
+ idValueCount = typeCompilationUnit->data->objectAt(componentObjectIndex)->nNamedObjectsInComponent;
+ idValues = new ContextGuard[idValueCount];
+}
+
+const QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const
{
if (propertyNameCache.isEmpty()) {
- propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine->handle()));
- for (QHash<int, int>::ConstIterator it = objectIndexToId.cbegin(), end = objectIndexToId.cend();
- it != end; ++it) {
- const QV4::CompiledData::Object *obj = typeCompilationUnit->data->objectAt(it.key());
- const QString name = typeCompilationUnit->data->stringAt(obj->idIndex);
- propertyNameCache.add(name, it.value());
- }
- objectIndexToId.clear();
+ if (typeCompilationUnit)
+ propertyNameCache = typeCompilationUnit->namedObjectsPerComponent(componentObjectIndex);
+ else
+ propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine));
}
return propertyNameCache;
}
+QV4::IdentifierHash<int> &QQmlContextData::detachedPropertyNames()
+{
+ propertyNames();
+ propertyNameCache.detach();
+ return propertyNameCache;
+}
+
QUrl QQmlContextData::url() const
{
if (typeCompilationUnit)
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index 48d596418d..62cd3d4877 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -151,9 +151,15 @@ public:
// Compilation unit for contexts that belong to a compiled type.
QQmlRefPointer<QV4::CompiledData::CompilationUnit> typeCompilationUnit;
- mutable QHash<int, int> objectIndexToId;
+ // object index in CompiledData::Unit to component that created this context
+ int componentObjectIndex;
+
+ void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex);
+
+ // flag indicates whether the context owns the cache (after mutation) or not.
mutable QV4::IdentifierHash<int> propertyNameCache;
- QV4::IdentifierHash<int> &propertyNames() const;
+ const QV4::IdentifierHash<int> &propertyNames() const;
+ QV4::IdentifierHash<int> &detachedPropertyNames();
// Context object
QObject *contextObject;
@@ -168,7 +174,7 @@ public:
QString urlString() const;
// List of imports that apply to this context
- QQmlTypeNameCache *imports;
+ QQmlRefPointer<QQmlTypeNameCache> imports;
// My children
QQmlContextData *childContexts;
@@ -201,7 +207,6 @@ public:
ContextGuard *idValues;
int idValueCount;
void setIdProperty(int, QObject *);
- void setIdPropertyData(const QHash<int, int> &);
// Linked contexts. this owns linkedContext.
QQmlContextData *linkedContext;
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 134002cf33..85c91a592a 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -39,7 +39,6 @@
#include "qqmlcustomparser_p.h"
-#include "qqmlcompiler_p.h"
#include <private/qqmltypecompiler_p.h>
#include <QtCore/qdebug.h>
@@ -101,11 +100,7 @@ void QQmlCustomParser::clearErrors()
*/
void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
{
- QQmlError error;
- error.setLine(location.line);
- error.setColumn(location.column);
- error.setDescription(description);
- exceptions << error;
+ exceptions << QQmlCompileError(location, description);
}
struct StaticQtMetaObject : public QObject
@@ -166,11 +161,13 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
*/
const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
{
+ if (!imports.isT1())
+ return nullptr;
QQmlType *qmltype = 0;
- if (!validator->imports().resolveType(name, &qmltype, 0, 0, 0))
- return 0;
+ if (!imports.asT1()->resolveType(name, &qmltype, 0, 0, 0))
+ return nullptr;
if (!qmltype)
- return 0;
+ return nullptr;
return qmltype->metaObject();
}
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index d8e25c55fd..5eb409990d 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -54,13 +54,13 @@
#include "qqmlmetatype_p.h"
#include "qqmlerror.h"
#include "qqmlbinding_p.h"
+#include <private/qqmltypecompiler_p.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qxmlstream.h>
QT_BEGIN_NAMESPACE
-class QQmlCompiledData;
class QQmlPropertyValidator;
class QQmlEnginePrivate;
@@ -82,9 +82,9 @@ public:
Flags flags() const { return m_flags; }
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
- virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) = 0;
+ virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
- QList<QQmlError> errors() const { return exceptions; }
+ QVector<QQmlCompileError> errors() const { return exceptions; }
protected:
void error(const QV4::CompiledData::Binding *binding, const QString& description)
@@ -98,7 +98,7 @@ protected:
const QMetaObject *resolveType(const QString&) const;
private:
- QList<QQmlError> exceptions;
+ QVector<QQmlCompileError> exceptions;
QQmlEnginePrivate *engine;
const QQmlPropertyValidator *validator;
Flags m_flags;
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index ad2456a68d..a9f2acdb06 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -63,7 +63,6 @@ QT_BEGIN_NAMESPACE
template <class Key, class T> class QHash;
class QQmlEngine;
class QQmlGuardImpl;
-class QQmlCompiledData;
class QQmlAbstractBinding;
class QQmlBoundSignal;
class QQmlContext;
@@ -72,6 +71,13 @@ class QQmlContextData;
class QQmlNotifier;
class QQmlDataExtended;
class QQmlNotifierEndpoint;
+
+namespace QV4 {
+namespace CompiledData {
+struct CompilationUnit;
+}
+}
+
// This class is structured in such a way, that simply zero'ing it is the
// default state for elemental object allocations. This is crucial in the
// workings of the QQmlInstruction::CreateSimpleObject instruction.
@@ -179,10 +185,10 @@ public:
struct DeferredData {
unsigned int deferredIdx;
- QQmlCompiledData *compiledData;//Not always the same as the other compiledData
+ QV4::CompiledData::CompilationUnit *compilationUnit;//Not always the same as the other compilation unit
QQmlContextData *context;//Could be either context or outerContext
};
- QQmlCompiledData *compiledData;
+ QV4::CompiledData::CompilationUnit *compilationUnit;
DeferredData *deferredData;
QV4::WeakValue jsWrapper;
@@ -223,7 +229,7 @@ public:
static inline void flushPendingBinding(QObject *, int coreIndex);
- static void ensurePropertyCache(QJSEngine *engine, QObject *object);
+ static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object);
private:
// For attachedProperties
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
new file mode 100644
index 0000000000..d10a8c7718
--- /dev/null
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -0,0 +1,215 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldelayedcallqueue_p.h"
+#include <private/qv8engine_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmljavascriptexpression_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qqmlcontextwrapper_p.h>
+
+#include <QQmlError>
+
+QT_BEGIN_NAMESPACE
+
+//
+// struct QQmlDelayedCallQueue::DelayedFunctionCall
+//
+
+void QQmlDelayedCallQueue::DelayedFunctionCall::execute(QV4::ExecutionEngine *engine) const
+{
+ if (!m_guarded ||
+ (!m_objectGuard.isNull() &&
+ !QQmlData::wasDeleted(m_objectGuard) &&
+ QQmlData::get(m_objectGuard) &&
+ !QQmlData::get(m_objectGuard)->isQueuedForDeletion)) {
+
+ QV4::Scope scope(engine);
+
+ QV4::ArrayObject *array = m_args.as<QV4::ArrayObject>();
+ const int argCount = array ? array->getLength() : 0;
+ QV4::ScopedCallData callData(scope, argCount);
+ callData->thisObject = QV4::Encode::undefined();
+
+ for (int i = 0; i < argCount; i++) {
+ callData->args[i] = array->getIndexed(i);
+ }
+
+ const QV4::FunctionObject *callback = m_function.as<QV4::FunctionObject>();
+ Q_ASSERT(callback);
+ callback->call(scope, callData);
+
+ if (scope.engine->hasException) {
+ QQmlError error = scope.engine->catchExceptionAsQmlError();
+ error.setDescription(error.description() + QLatin1String(" (exception occurred during delayed function evaluation)"));
+ QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error);
+ }
+ }
+}
+
+//
+// class QQmlDelayedCallQueue
+//
+
+QQmlDelayedCallQueue::QQmlDelayedCallQueue()
+ : QObject(0), m_engine(0), m_callbackOutstanding(false)
+{
+}
+
+QQmlDelayedCallQueue::~QQmlDelayedCallQueue()
+{
+}
+
+void QQmlDelayedCallQueue::init(QV4::ExecutionEngine* engine)
+{
+ m_engine = engine;
+
+ const QMetaObject &metaObject = QQmlDelayedCallQueue::staticMetaObject;
+ int methodIndex = metaObject.indexOfSlot("ticked()");
+ m_tickedMethod = metaObject.method(methodIndex);
+}
+
+QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::CallContext *ctx)
+{
+ const QV4::CallData *callData = ctx->d()->callData;
+
+ if (callData->argc == 0)
+ V4THROW_ERROR("Qt.callLater: no arguments given");
+
+ const QV4::FunctionObject *func = callData->args[0].as<QV4::FunctionObject>();
+
+ if (!func)
+ V4THROW_ERROR("Qt.callLater: first argument not a function or signal");
+
+ QPair<QObject *, int> functionData = QV4::QObjectMethod::extractQtMethod(func);
+
+ QVector<DelayedFunctionCall>::Iterator iter;
+ if (functionData.second != -1) {
+ // This is a QObject function wrapper
+ iter = m_delayedFunctionCalls.begin();
+ while (iter != m_delayedFunctionCalls.end()) {
+ DelayedFunctionCall& dfc = *iter;
+ QPair<QObject *, int> storedFunctionData = QV4::QObjectMethod::extractQtMethod(dfc.m_function.as<QV4::FunctionObject>());
+ if (storedFunctionData == functionData) {
+ break; // Already stored!
+ }
+ ++iter;
+ }
+ } else {
+ // This is a JavaScript function (dynamic slot on VMEMO)
+ iter = m_delayedFunctionCalls.begin();
+ while (iter != m_delayedFunctionCalls.end()) {
+ DelayedFunctionCall& dfc = *iter;
+ if (callData->argument(0) == dfc.m_function.value()) {
+ break; // Already stored!
+ }
+ ++iter;
+ }
+ }
+
+ const bool functionAlreadyStored = (iter != m_delayedFunctionCalls.end());
+ if (functionAlreadyStored) {
+ DelayedFunctionCall dfc = *iter;
+ m_delayedFunctionCalls.erase(iter);
+ m_delayedFunctionCalls.append(dfc);
+ } else {
+ m_delayedFunctionCalls.append(QV4::PersistentValue(m_engine, callData->argument(0)));
+ }
+
+ DelayedFunctionCall& dfc = m_delayedFunctionCalls.last();
+ if (dfc.m_objectGuard.isNull()) {
+ if (functionData.second != -1) {
+ // if it's a qobject function wrapper, guard against qobject deletion
+ dfc.m_objectGuard = QQmlGuard<QObject>(functionData.first);
+ dfc.m_guarded = true;
+ } else if (func->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) {
+ QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(func->scope());
+ Q_ASSERT(g->qml->scopeObject);
+ dfc.m_objectGuard = QQmlGuard<QObject>(g->qml->scopeObject);
+ dfc.m_guarded = true;
+ }
+ }
+ storeAnyArguments(dfc, callData, 1, m_engine);
+
+ if (!m_callbackOutstanding) {
+ m_tickedMethod.invoke(this, Qt::QueuedConnection);
+ m_callbackOutstanding = true;
+ }
+ return QV4::Encode::undefined();
+}
+
+void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4::CallData *callData, int offset, QV4::ExecutionEngine *engine)
+{
+ const int length = callData->argc - offset;
+ if (length == 0) {
+ dfc.m_args.clear();
+ return;
+ }
+ QV4::Scope scope(engine);
+ QV4::ScopedArrayObject array(scope, engine->newArrayObject(length));
+ int i = 0;
+ for (int j = offset; j < callData->argc; ++i, ++j) {
+ array->putIndexed(i, callData->args[j]);
+ }
+ dfc.m_args.set(engine, array);
+}
+
+void QQmlDelayedCallQueue::executeAllExpired_Later()
+{
+ // Make a local copy of the list and clear m_delayedFunctionCalls
+ // This ensures correct behavior in the case of recursive calls to Qt.callLater()
+ QVector<DelayedFunctionCall> delayedCalls = m_delayedFunctionCalls;
+ m_delayedFunctionCalls.clear();
+
+ QVector<DelayedFunctionCall>::Iterator iter = delayedCalls.begin();
+ while (iter != delayedCalls.end()) {
+ DelayedFunctionCall& dfc = *iter;
+ dfc.execute(m_engine);
+ ++iter;
+ }
+}
+
+void QQmlDelayedCallQueue::ticked()
+{
+ m_callbackOutstanding = false;
+ executeAllExpired_Later();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldelayedcallqueue_p.h b/src/qml/qml/qqmldelayedcallqueue_p.h
new file mode 100644
index 0000000000..ef899170a2
--- /dev/null
+++ b/src/qml/qml/qqmldelayedcallqueue_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDELAYEDCALLQUEUE_P_H
+#define QQMLDELAYEDCALLQUEUE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qmetatype.h>
+#include <private/qqmlguard_p.h>
+#include <private/qv4context_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+class QQmlDelayedCallQueue : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlDelayedCallQueue();
+ ~QQmlDelayedCallQueue();
+
+ void init(QV4::ExecutionEngine *);
+
+ QV4::ReturnedValue addUniquelyAndExecuteLater(QV4::CallContext *ctx);
+
+public Q_SLOTS:
+ void ticked();
+
+private:
+ struct DelayedFunctionCall
+ {
+ DelayedFunctionCall() {}
+ DelayedFunctionCall(QV4::PersistentValue function)
+ : m_function(function), m_guarded(false) { }
+
+ void execute(QV4::ExecutionEngine *engine) const;
+
+ QV4::PersistentValue m_function;
+ QV4::PersistentValue m_args;
+ QQmlGuard<QObject> m_objectGuard;
+ bool m_guarded;
+ };
+
+ void storeAnyArguments(DelayedFunctionCall& dfc, const QV4::CallData *callData, int offset, QV4::ExecutionEngine *engine);
+ void executeAllExpired_Later();
+
+ QV4::ExecutionEngine *m_engine;
+ QVector<DelayedFunctionCall> m_delayedFunctionCalls;
+ QMetaMethod m_tickedMethod;
+ bool m_callbackOutstanding;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDELAYEDCALLQUEUE_P_H
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 28f8bf4855..e4e7530af7 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -42,7 +42,6 @@
#include "qqmlcomponentattached_p.h"
#include "qqmlcontext_p.h"
-#include "qqmlcompiler_p.h"
#include "qqml.h"
#include "qqmlcontext.h"
#include "qqmlexpression.h"
@@ -53,35 +52,33 @@
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
#include "qqmlcomponent_p.h"
-#include "qqmlnetworkaccessmanagerfactory.h"
#include "qqmldirparser_p.h"
#include "qqmlextensioninterface.h"
#include "qqmllist_p.h"
#include "qqmltypenamecache_p.h"
#include "qqmlnotifier_p.h"
-#include <private/qqmldebugconnector_p.h>
#include "qqmlincubator.h"
#include "qqmlabstracturlinterceptor.h"
#include <private/qqmlboundsignal_p.h>
-
#include <QtCore/qstandardpaths.h>
#include <QtCore/qsettings.h>
-
#include <QtCore/qmetaobject.h>
-#include <QNetworkAccessManager>
#include <QDebug>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdir.h>
#include <QtCore/qmutex.h>
#include <QtCore/qthread.h>
#include <private/qthread_p.h>
+
+#ifndef QT_NO_NETWORK
+#include "qqmlnetworkaccessmanagerfactory.h"
+#include <QNetworkAccessManager>
#include <QtNetwork/qnetworkconfigmanager.h>
+#endif
#include <private/qobject_p.h>
#include <private/qmetaobject_p.h>
-
#include <private/qqmllocale_p.h>
-
#include <private/qqmlbind_p.h>
#include <private/qqmlconnections_p.h>
#include <private/qqmltimer_p.h>
@@ -94,17 +91,15 @@
#include <private/qqmlinstantiator_p.h>
#ifdef Q_OS_WIN // for %APPDATA%
-#include <qt_windows.h>
-# if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+# include <qt_windows.h>
+# ifndef Q_OS_WINRT
# include <shlobj.h>
# endif
-#include <qlibrary.h>
-#include <windows.h>
-
-#ifndef CSIDL_APPDATA
-# define CSIDL_APPDATA 0x001a // <username>\Application Data
-#endif
-#endif
+# include <qlibrary.h>
+# ifndef CSIDL_APPDATA
+# define CSIDL_APPDATA 0x001a // <username>\Application Data
+# endif
+#endif // Q_OS_WIN
Q_DECLARE_METATYPE(QQmlProperty)
@@ -182,6 +177,7 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int
qmlRegisterType<QQmlComponent>(uri,versionMajor,versionMinor,"Component");
qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject");
qmlRegisterType<QQmlBind>(uri, versionMajor, versionMinor,"Binding");
+ qmlRegisterType<QQmlBind,8>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "Binding"); //Only available in >=2.8
qmlRegisterType<QQmlConnections,1>(uri, versionMajor, (versionMinor < 3 ? 3 : versionMinor), "Connections"); //Only available in >=2.3
qmlRegisterType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections");
qmlRegisterType<QQmlTimer>(uri, versionMajor, versionMinor,"Timer");
@@ -493,6 +489,10 @@ The following functions are also on the Qt object.
from right to left.
\endlist
\row
+ \li \c application.font
+ \li This read-only property holds the default application font as
+ returned by \l QGuiApplication::font().
+ \row
\li \c application.arguments
\li This is a string list of the arguments the executable was invoked with.
\row
@@ -531,6 +531,7 @@ The following functions are also on the Qt object.
\li application.active
\li application.state
\li application.layoutDirection
+ \li application.font
\endlist
*/
@@ -601,12 +602,17 @@ the same object as is returned from the Qt.include() call.
QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
: propertyCapture(0), rootContext(0),
- profiler(0), outputWarningsToMsgLog(true),
+#ifndef QT_NO_QML_DEBUGGER
+ profiler(0),
+#endif
+ outputWarningsToMsgLog(true),
cleanup(0), erroredBindings(0), inProgressCreations(0),
workerScriptEngine(0),
activeObjectCreator(0),
- networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0),
- scarceResourcesRefCount(0), importDatabase(e), typeLoader(e),
+#ifndef QT_NO_NETWORK
+ networkAccessManager(0), networkAccessManagerFactory(0),
+#endif
+ urlInterceptor(0), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e),
uniqueId(1), incubatorCount(0), incubationController(0)
{
}
@@ -614,7 +620,6 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
QQmlEnginePrivate::~QQmlEnginePrivate()
{
typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::const_iterator TypePropertyCacheIt;
- typedef QHash<int, QQmlCompiledData *>::const_iterator CompositeTypesIt;
if (inProgressCreations)
qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
@@ -635,7 +640,7 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
for (TypePropertyCacheIt iter = typePropertyCache.cbegin(), end = typePropertyCache.cend(); iter != end; ++iter)
(*iter)->release();
- for (CompositeTypesIt iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) {
+ for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) {
iter.value()->isRegisteredWithEngine = false;
// since unregisterInternalCompositeType() will not be called in this
@@ -643,12 +648,9 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
QMetaType::unregisterType(iter.value()->metaTypeId);
QMetaType::unregisterType(iter.value()->listMetaTypeId);
}
+#ifndef QT_NO_QML_DEBUGGER
delete profiler;
-}
-
-void QQmlEnginePrivate::enableProfiler()
-{
- profiler = new QQmlProfiler();
+#endif
}
void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
@@ -677,7 +679,7 @@ QQmlData::QQmlData()
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(0), notifyList(0), context(0), outerContext(0),
bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0),
- lineNumber(0), columnNumber(0), jsEngineId(0), compiledData(0), deferredData(0),
+ lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), deferredData(0),
propertyCache(0), guards(0), extendedData(0)
{
init();
@@ -845,8 +847,8 @@ void QQmlData::flushPendingBindingImpl(int coreIndex)
b = b->nextBinding();
if (b && b->targetPropertyIndex() == coreIndex)
- b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::DontRemoveBinding);
+ b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
+ QQmlPropertyData::DontRemoveBinding);
}
bool QQmlEnginePrivate::baseModulesUninitialized = true;
@@ -1066,7 +1068,17 @@ QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
return d->urlInterceptor;
}
+void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
+{
+ if (activeObjectCreator) {
+ activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index));
+ } else {
+ void *args[] = { 0 };
+ QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
+ }
+}
+#ifndef QT_NO_NETWORK
/*!
Sets the \a factory to use for creating QNetworkAccessManager(s).
@@ -1095,16 +1107,6 @@ QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
return d->networkAccessManagerFactory;
}
-void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
-{
- if (activeObjectCreator) {
- activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index));
- } else {
- void *args[] = { 0 };
- QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
- }
-}
-
QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
{
QMutexLocker locker(&networkAccessManagerMutex);
@@ -1143,6 +1145,7 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const
Q_D(const QQmlEngine);
return d->getNetworkAccessManager();
}
+#endif // QT_NO_NETWORK
/*!
@@ -1405,7 +1408,7 @@ void qmlExecuteDeferred(QObject *object)
QQmlComponentPrivate::beginDeferred(ep, object, &state);
// Release the reference for the deferral action (we still have one from construction)
- data->deferredData->compiledData->release();
+ data->deferredData->compilationUnit->release();
delete data->deferredData;
data->deferredData = 0;
@@ -1636,13 +1639,13 @@ void QQmlData::destroyed(QObject *object)
if (bindings && !bindings->ref.deref())
delete bindings;
- if (compiledData) {
- compiledData->release();
- compiledData = 0;
+ if (compilationUnit) {
+ compilationUnit->release();
+ compilationUnit = 0;
}
if (deferredData) {
- deferredData->compiledData->release();
+ deferredData->compilationUnit->release();
delete deferredData;
deferredData = 0;
}
@@ -1665,7 +1668,7 @@ void QQmlData::destroyed(QObject *object)
QString source = expr->expression();
if (source.size() > 100) {
source.truncate(96);
- source.append(QStringLiteral(" ..."));
+ source.append(QLatin1String(" ..."));
}
locationString.append(source);
} else {
@@ -1801,14 +1804,16 @@ void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
QQmlData_setBit(this, obj, coreIndex * 2 + 1);
}
-void QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object)
+QQmlPropertyCache *QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object)
{
Q_ASSERT(engine);
QQmlData *ddata = QQmlData::get(object, /*create*/true);
- if (ddata->propertyCache)
- return;
- ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object);
- if (ddata->propertyCache) ddata->propertyCache->addref();
+ if (!ddata->propertyCache) {
+ ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object);
+ if (ddata->propertyCache)
+ ddata->propertyCache->addref();
+ }
+ return ddata->propertyCache;
}
void QQmlEnginePrivate::sendQuit()
@@ -2219,9 +2224,9 @@ int QQmlEnginePrivate::listType(int t) const
QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
{
Locker locker(this);
- QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t);
+ auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache);
+ return QQmlMetaObject((*iter)->rootPropertyCache());
} else {
QQmlType *type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type?type->baseMetaObject():0);
@@ -2231,9 +2236,9 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
{
Locker locker(this);
- QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t);
+ auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache);
+ return QQmlMetaObject((*iter)->rootPropertyCache());
} else {
QQmlType *type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type?type->metaObject():0);
@@ -2243,9 +2248,9 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
{
Locker locker(this);
- QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t);
+ auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache;
+ return (*iter)->rootPropertyCache();
} else {
QQmlType *type = QQmlMetaType::qmlType(t);
locker.unlock();
@@ -2256,9 +2261,9 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
{
Locker locker(this);
- QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t);
+ auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache;
+ return (*iter)->rootPropertyCache();
} else {
QQmlType *type = QQmlMetaType::qmlType(t);
locker.unlock();
@@ -2266,9 +2271,9 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
}
}
-void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data)
+void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
{
- QByteArray name = data->rootPropertyCache->className();
+ QByteArray name = compilationUnit->rootPropertyCache()->className();
QByteArray ptr = name + '*';
QByteArray lst = "QQmlListProperty<" + name + '>';
@@ -2286,21 +2291,21 @@ void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data)
static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
static_cast<QMetaObject*>(0));
- data->metaTypeId = ptr_type;
- data->listMetaTypeId = lst_type;
- data->isRegisteredWithEngine = true;
+ compilationUnit->metaTypeId = ptr_type;
+ compilationUnit->listMetaTypeId = lst_type;
+ compilationUnit->isRegisteredWithEngine = true;
Locker locker(this);
m_qmlLists.insert(lst_type, ptr_type);
// The QQmlCompiledData is not referenced here, but it is removed from this
// hash in the QQmlCompiledData destructor
- m_compositeTypes.insert(ptr_type, data);
+ m_compositeTypes.insert(ptr_type, compilationUnit);
}
-void QQmlEnginePrivate::unregisterInternalCompositeType(QQmlCompiledData *data)
+void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
{
- int ptr_type = data->metaTypeId;
- int lst_type = data->listMetaTypeId;
+ int ptr_type = compilationUnit->metaTypeId;
+ int lst_type = compilationUnit->listMetaTypeId;
Locker locker(this);
m_qmlLists.remove(lst_type);
@@ -2320,7 +2325,7 @@ bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
return typeLoader.isScriptLoaded(url);
}
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
// Normalize a file name using Shell API. As opposed to converting it
// to a short 8.3 name and back, this also works for drives where 8.3 notation
// is disabled (see 8dot3name options of fsutil.exe).
@@ -2352,7 +2357,7 @@ static inline QString shellNormalizeFileName(const QString &name)
canonicalName[0] = canonicalName.at(0).toUpper();
return QDir::cleanPath(canonicalName);
}
-#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT
+#endif // Q_OS_WIN && !Q_OS_WINRT
bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
{
@@ -2360,7 +2365,7 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
QFileInfo info(fileName);
const QString absolute = info.absoluteFilePath();
-#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) || defined(Q_OS_WINRT)
+#if defined(Q_OS_DARWIN) || defined(Q_OS_WINRT)
const QString canonical = info.canonicalFilePath();
#elif defined(Q_OS_WIN)
// No difference if the path is qrc based
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index bd2a3cfc48..132af78f80 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -87,8 +87,10 @@ class QQmlExpression;
class QQmlContext;
class QQmlType;
class QUrl;
+#ifndef QT_NO_NETWORK
class QNetworkAccessManager;
class QQmlNetworkAccessManagerFactory;
+#endif
class QQmlIncubationController;
class Q_QML_EXPORT QQmlEngine : public QJSEngine
{
@@ -115,10 +117,12 @@ public:
bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors);
+#ifndef QT_NO_NETWORK
void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *);
QQmlNetworkAccessManagerFactory *networkAccessManagerFactory() const;
QNetworkAccessManager *networkAccessManager() const;
+#endif
void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor);
QQmlAbstractUrlInterceptor* urlInterceptor() const;
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 003cfa0112..949060f395 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -134,8 +134,12 @@ public:
QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
QQmlContext *rootContext;
+
+#ifdef QT_NO_QML_DEBUGGER
+ static const quintptr profiler = 0;
+#else
QQmlProfiler *profiler;
- void enableProfiler();
+#endif
bool outputWarningsToMsgLog;
@@ -158,12 +162,12 @@ public:
void registerFinalizeCallback(QObject *obj, int index);
QQmlObjectCreator *activeObjectCreator;
-
+#ifndef QT_NO_NETWORK
QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
QNetworkAccessManager *getNetworkAccessManager() const;
mutable QNetworkAccessManager *networkAccessManager;
mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
-
+#endif
QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
QQmlAbstractUrlInterceptor* urlInterceptor;
@@ -216,8 +220,8 @@ public:
QQmlMetaObject metaObjectForType(int) const;
QQmlPropertyCache *propertyCacheForType(int);
QQmlPropertyCache *rawPropertyCacheForType(int);
- void registerInternalCompositeType(QQmlCompiledData *);
- void unregisterInternalCompositeType(QQmlCompiledData *);
+ void registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit);
+ void unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit);
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
@@ -260,7 +264,7 @@ private:
// the threaded loader. Only access them through their respective accessor methods.
QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
QHash<int, int> m_qmlLists;
- QHash<int, QQmlCompiledData *> m_compositeTypes;
+ QHash<int, QV4::CompiledData::CompilationUnit *> m_compositeTypes;
static bool s_designerMode;
// These members is protected by the full QQmlEnginePrivate::mutex mutex
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index 50880e70ea..6afbd05e3e 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -44,7 +44,7 @@
#include "qqmlengine_p.h"
#include "qqmlcontext_p.h"
#include "qqmlscriptstring_p.h"
-#include "qqmlcompiler_p.h"
+#include "qqmlbinding_p.h"
#include <private/qv8engine_p.h>
#include <QtCore/qdebug.h>
@@ -245,14 +245,15 @@ void QQmlExpression::setExpression(const QString &expression)
}
// Must be called with a valid handle scope
-QV4::ReturnedValue QQmlExpressionPrivate::v4value(bool *isUndefined)
+void QQmlExpressionPrivate::v4value(bool *isUndefined, QV4::Scope &scope)
{
if (!expressionFunctionValid) {
createQmlBinding(context(), scopeObject(), expression, url, line);
expressionFunctionValid = true;
}
- return evaluate(isUndefined);
+ QV4::ScopedCallData callData(scope);
+ evaluate(callData, isUndefined, scope);
}
QVariant QQmlExpressionPrivate::value(bool *isUndefined)
@@ -271,9 +272,9 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined)
{
QV4::Scope scope(QV8Engine::getV4(ep->v8engine()));
- QV4::ScopedValue result(scope, v4value(isUndefined));
+ v4value(isUndefined, scope);
if (!hasError())
- rv = scope.engine->toVariant(result, -1);
+ rv = scope.engine->toVariant(scope.result, -1);
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index 3d1df55a2d..741c25e206 100644
--- a/src/qml/qml/qqmlexpression_p.h
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -57,7 +57,6 @@
#include <private/qfieldlist_p.h>
#include <private/qflagpointer_p.h>
#include <private/qdeletewatcher_p.h>
-#include <private/qpointervaluepair_p.h>
#include <private/qqmljavascriptexpression_p.h>
QT_BEGIN_NAMESPACE
@@ -77,7 +76,7 @@ public:
QVariant value(bool *isUndefined = 0);
- QV4::ReturnedValue v4value(bool *isUndefined = 0);
+ void v4value(bool *isUndefined, QV4::Scope &scope);
static inline QQmlExpressionPrivate *get(QQmlExpression *expr);
static inline QQmlExpression *get(QQmlExpressionPrivate *expr);
diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp
index 5fe3cba5c3..4769402855 100644
--- a/src/qml/qml/qqmlfile.cpp
+++ b/src/qml/qml/qqmlfile.cpp
@@ -67,6 +67,8 @@ static char assets_string[] = "assets";
#endif
class QQmlFilePrivate;
+
+#ifndef QT_NO_NETWORK
class QQmlFileNetworkReply : public QObject
{
Q_OBJECT
@@ -97,6 +99,7 @@ private:
int m_redirectCount;
QNetworkReply *m_reply;
};
+#endif
class QQmlFilePrivate
{
@@ -114,10 +117,12 @@ public:
Error error;
QString errorString;
-
+#ifndef QT_NO_NETWORK
QQmlFileNetworkReply *reply;
+#endif
};
+#ifndef QT_NO_NETWORK
int QQmlFileNetworkReply::finishedIndex = -1;
int QQmlFileNetworkReply::downloadProgressIndex = -1;
int QQmlFileNetworkReply::networkFinishedIndex = -1;
@@ -200,9 +205,13 @@ void QQmlFileNetworkReply::networkDownloadProgress(qint64 a, qint64 b)
{
emit downloadProgress(a, b);
}
+#endif // QT_NO_NETWORK
QQmlFilePrivate::QQmlFilePrivate()
-: error(None), reply(0)
+: error(None)
+#ifndef QT_NO_NETWORK
+, reply(0)
+#endif
{
}
@@ -218,14 +227,15 @@ QQmlFile::QQmlFile(QQmlEngine *e, const QUrl &url)
}
QQmlFile::QQmlFile(QQmlEngine *e, const QString &url)
-: d(new QQmlFilePrivate)
+ : QQmlFile(e, QUrl(url))
{
- load(e, url);
}
QQmlFile::~QQmlFile()
{
+#ifndef QT_NO_NETWORK
delete d->reply;
+#endif
delete d;
d = 0;
}
@@ -263,8 +273,10 @@ QQmlFile::Status QQmlFile::status() const
{
if (d->url.isEmpty() && d->urlString.isEmpty())
return Null;
+#ifndef QT_NO_NETWORK
else if (d->reply)
return Loading;
+#endif
else if (d->error != QQmlFilePrivate::None)
return Error;
else
@@ -321,7 +333,11 @@ void QQmlFile::load(QQmlEngine *engine, const QUrl &url)
d->error = QQmlFilePrivate::NotFound;
}
} else {
+#ifndef QT_NO_NETWORK
d->reply = new QQmlFileNetworkReply(engine, d, url);
+#else
+ d->error = QQmlFilePrivate::NotFound;
+#endif
}
}
@@ -348,10 +364,14 @@ void QQmlFile::load(QQmlEngine *engine, const QString &url)
d->error = QQmlFilePrivate::NotFound;
}
} else {
+#ifndef QT_NO_NETWORK
QUrl qurl(url);
d->url = qurl;
d->urlString = QString();
d->reply = new QQmlFileNetworkReply(engine, d, qurl);
+#else
+ d->error = QQmlFilePrivate::NotFound;
+#endif
}
}
@@ -368,6 +388,7 @@ void QQmlFile::clear(QObject *)
clear();
}
+#ifndef QT_NO_NETWORK
bool QQmlFile::connectFinished(QObject *object, const char *method)
{
if (!d || !d->reply) {
@@ -411,6 +432,7 @@ bool QQmlFile::connectDownloadProgress(QObject *object, int method)
return QMetaObject::connect(d->reply, QQmlFileNetworkReply::downloadProgressIndex,
object, method);
}
+#endif
/*!
Returns true if QQmlFile will open \a url synchronously.
diff --git a/src/qml/qml/qqmlfile.h b/src/qml/qml/qqmlfile.h
index b0910cc0f4..3dd683a2cd 100644
--- a/src/qml/qml/qqmlfile.h
+++ b/src/qml/qml/qqmlfile.h
@@ -80,10 +80,12 @@ public:
void clear();
void clear(QObject *);
+#ifndef QT_NO_NETWORK
bool connectFinished(QObject *, const char *);
bool connectFinished(QObject *, int);
bool connectDownloadProgress(QObject *, const char *);
bool connectDownloadProgress(QObject *, int);
+#endif
static bool isSynchronous(const QString &url);
static bool isSynchronous(const QUrl &url);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index b51c78b8d4..9393f74a8d 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -191,7 +191,7 @@ void qmlClearEnginePlugins()
{
StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
QMutexLocker lock(&plugins->mutex);
- foreach (RegisteredPlugin plugin, plugins->values()) {
+ for (auto &plugin : qAsConst(*plugins)) {
QPluginLoader* loader = plugin.loader;
if (loader && !loader->unload())
qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString()));
@@ -913,7 +913,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
// To avoid traversing all static plugins for all imports, we cut down
// the list the first time called to only contain QML plugins:
foreach (const QStaticPlugin &plugin, QPluginLoader::staticPlugins()) {
- if (qobject_cast<QQmlExtensionPlugin *>(plugin.instance()))
+ if (plugin.metaData().value(QLatin1String("IID")).toString() == QLatin1String(QQmlExtensionInterface_iid))
plugins.append(plugin);
}
}
@@ -921,7 +921,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
foreach (const QStaticPlugin &plugin, plugins) {
// Since a module can list more than one plugin, we keep iterating even after we found a match.
if (QQmlExtensionPlugin *instance = qobject_cast<QQmlExtensionPlugin *>(plugin.instance())) {
- const QJsonArray metaTagsUriList = plugin.metaData().value(QStringLiteral("uri")).toArray();
+ const QJsonArray metaTagsUriList = plugin.metaData().value(QLatin1String("uri")).toArray();
if (metaTagsUriList.isEmpty()) {
if (errors) {
QQmlError error;
@@ -1702,10 +1702,7 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
resolvedPath += Slash;
foreach (const QString &suffix, suffixes) {
- QString pluginFileName = prefix;
-
- pluginFileName += baseName;
- pluginFileName += suffix;
+ QString pluginFileName = prefix + baseName + suffix;
QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + pluginFileName);
if (!absolutePath.isEmpty())
@@ -1820,7 +1817,7 @@ void QQmlImportDatabase::addImportPath(const QString& path)
} else if (path.startsWith(QLatin1Char(':'))) {
// qrc directory, e.g. :/foo
// need to convert to a qrc url, e.g. qrc:/foo
- cPath = QStringLiteral("qrc") + path;
+ cPath = QLatin1String("qrc") + path;
cPath.replace(Backslash, Slash);
} else if (url.isRelative() ||
(url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index f0f160e6f6..0ce769aaea 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -41,7 +41,6 @@
#include "qqmlcomponent.h"
#include "qqmlincubator_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlexpression_p.h"
#include "qqmlmemoryprofiler_p.h"
#include "qqmlobjectcreator_p.h"
@@ -132,7 +131,7 @@ QQmlIncubationController *QQmlEngine::incubationController() const
QQmlIncubatorPrivate::QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m)
: q(q), status(QQmlIncubator::Null), mode(m), isAsynchronous(false), progress(Execute),
- result(0), compiledData(0), waitingOnMe(0)
+ result(0), enginePriv(0), waitingOnMe(0)
{
}
@@ -143,20 +142,15 @@ QQmlIncubatorPrivate::~QQmlIncubatorPrivate()
void QQmlIncubatorPrivate::clear()
{
+ compilationUnit = nullptr;
if (next.isInList()) {
next.remove();
- Q_ASSERT(compiledData);
- QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(compiledData->engine);
- compiledData->release();
- compiledData = 0;
enginePriv->incubatorCount--;
QQmlIncubationController *controller = enginePriv->incubationController;
if (controller)
controller->incubatingObjectCountChanged(enginePriv->incubatorCount);
- } else if (compiledData) {
- compiledData->release();
- compiledData = 0;
}
+ enginePriv = 0;
if (!rootContext.isNull()) {
rootContext->activeVMEData = 0;
rootContext = 0;
@@ -278,21 +272,20 @@ void QQmlIncubatorPrivate::forceCompletion(QQmlInstantiationInterrupt &i)
void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
{
- if (!compiledData)
+ if (!compilationUnit)
return;
- QML_MEMORY_SCOPE_URL(compiledData->url());
+ QML_MEMORY_SCOPE_URL(compilationUnit->url());
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this);
QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(this);
-
- QQmlEngine *engine = compiledData->engine;
- QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
+ // get a copy of the engine pointer as it might get reset;
+ QQmlEnginePrivate *enginePriv = this->enginePriv;
if (!vmeGuard.isOK()) {
QQmlError error;
- error.setUrl(compiledData->url());
+ error.setUrl(compilationUnit->url());
error.setDescription(QQmlComponent::tr("Object destroyed during incubation"));
errors << error;
progress = QQmlIncubatorPrivate::Completed;
@@ -563,17 +556,16 @@ void QQmlIncubator::clear()
if (s == Null)
return;
- QQmlEnginePrivate *enginePriv = 0;
+ QQmlEnginePrivate *enginePriv = d->enginePriv;
if (s == Loading) {
- Q_ASSERT(d->compiledData);
- enginePriv = QQmlEnginePrivate::get(d->compiledData->engine);
+ Q_ASSERT(d->compilationUnit);
if (d->result) d->result->deleteLater();
d->result = 0;
}
d->clear();
- Q_ASSERT(d->compiledData == 0);
+ Q_ASSERT(d->compilationUnit.isNull());
Q_ASSERT(d->waitingOnMe.data() == 0);
Q_ASSERT(d->waitingFor.isEmpty());
@@ -713,7 +705,7 @@ QQmlIncubator::Status QQmlIncubatorPrivate::calculateStatus() const
return QQmlIncubator::Error;
else if (result && progress == QQmlIncubatorPrivate::Completed && waitingFor.isEmpty())
return QQmlIncubator::Ready;
- else if (compiledData)
+ else if (compilationUnit)
return QQmlIncubator::Loading;
else
return QQmlIncubator::Null;
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index a12ff9c5e2..ecf3b6d2ca 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -59,7 +59,6 @@
QT_BEGIN_NAMESPACE
-class QQmlCompiledData;
class QQmlIncubator;
class QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
{
@@ -85,7 +84,8 @@ public:
QPointer<QObject> result;
QQmlGuardedContextData rootContext;
- QQmlCompiledData *compiledData;
+ QQmlEnginePrivate *enginePriv;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
QScopedPointer<QQmlObjectCreator> creator;
int subComponentToCreate;
QQmlVMEGuard vmeGuard;
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 8ba4b5eba1..5d96240e5b 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -106,7 +106,8 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
m_nextExpression->m_prevExpression = m_prevExpression;
}
- clearGuards();
+ clearActiveGuards();
+ clearPermanentGuards();
if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion.
m_scopeObject.asT2()->_s = 0;
}
@@ -114,12 +115,12 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
{
activeGuards.setFlagValue(v);
- if (!v) clearGuards();
+ if (!v) clearActiveGuards();
}
void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
{
- clearGuards();
+ clearActiveGuards();
}
void QQmlJavaScriptExpression::setContext(QQmlContextData *context)
@@ -147,16 +148,9 @@ void QQmlJavaScriptExpression::refresh()
{
}
-QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(bool *isUndefined)
-{
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_context->engine);
- QV4::Scope scope(v4);
- QV4::ScopedCallData callData(scope);
- return evaluate(callData, isUndefined);
-}
-QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined)
+void QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined, QV4::Scope &scope)
{
Q_ASSERT(m_context && m_context->engine);
@@ -164,7 +158,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
if (!f || f->isUndefined()) {
if (isUndefined)
*isUndefined = true;
- return QV4::Encode::undefined();
+ return;
}
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_context->engine);
@@ -184,8 +178,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
capture.guards.copyAndClearPrepend(activeGuards);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
- QV4::Scope scope(v4);
- QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue());
+ scope.result = QV4::Primitive::undefinedValue();
callData->thisObject = v4->globalObject;
if (scopeObject()) {
QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(v4, scopeObject()));
@@ -193,7 +186,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
callData->thisObject = value;
}
- result = f->as<QV4::FunctionObject>()->call(callData);
+ f->as<QV4::FunctionObject>()->call(scope, callData);
if (scope.hasException()) {
if (watcher.wasDeleted())
scope.engine->catchException(); // ignore exception
@@ -203,7 +196,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
*isUndefined = true;
} else {
if (isUndefined)
- *isUndefined = result->isUndefined();
+ *isUndefined = scope.result.isUndefined();
if (!watcher.wasDeleted() && hasDelayedError())
delayedError()->clearError();
@@ -220,11 +213,9 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
g->Delete();
ep->propertyCapture = lastPropertyCapture;
-
- return result->asReturnedValue();
}
-void QQmlPropertyCapture::captureProperty(QQmlNotifier *n)
+void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration)
{
if (watcher->wasDeleted())
return;
@@ -244,14 +235,17 @@ void QQmlPropertyCapture::captureProperty(QQmlNotifier *n)
g->connect(n);
}
- expression->activeGuards.prepend(g);
+ if (duration == OnlyOnce)
+ expression->permanentGuards.prepend(g);
+ else
+ expression->activeGuards.prepend(g);
}
/*! \internal
\a n is in the signal index range (see QObjectPrivate::signalIndex()).
*/
-void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n)
+void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration duration)
{
if (watcher->wasDeleted())
return;
@@ -290,15 +284,19 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n)
g->connect(o, n, engine);
}
- expression->activeGuards.prepend(g);
+ if (duration == Permanently)
+ expression->permanentGuards.prepend(g);
+ else
+ expression->activeGuards.prepend(g);
}
}
-void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction)
+void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Function *compiledFunction, const QV4::Scope &scope)
{
// Let the caller check and avoid the function call :)
Q_ASSERT(compiledFunction->hasQmlDependencies());
+ QV4::ExecutionEngine *engine = scope.engine;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine());
if (!ep)
return;
@@ -306,33 +304,40 @@ void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine,
if (!capture)
return;
- QV4::Scope scope(engine);
+ if (capture->expression->m_permanentDependenciesRegistered)
+ return;
+
+ capture->expression->m_permanentDependenciesRegistered = true;
+
QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext());
QQmlContextData *qmlContext = context->qmlContext();
- const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
+ const QV4::CompiledData::LEUInt32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
const int idObjectDependencyCount = compiledFunction->nDependingIdObjects;
for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) {
Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount);
- capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings);
+ capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings,
+ QQmlPropertyCapture::Permanently);
}
Q_ASSERT(qmlContext->contextObject);
- const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
+ const QV4::CompiledData::LEUInt32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties;
for (int i = 0; i < contextPropertyDependencyCount; ++i) {
const int propertyIndex = *contextPropertyDependency++;
const int notifyIndex = *contextPropertyDependency++;
- capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex);
+ capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex,
+ QQmlPropertyCapture::Permanently);
}
QObject *scopeObject = context->qmlScope();
- const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
+ const QV4::CompiledData::LEUInt32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties;
for (int i = 0; i < scopePropertyDependencyCount; ++i) {
const int propertyIndex = *scopePropertyDependency++;
const int notifyIndex = *scopePropertyDependency++;
- capture->captureProperty(scopeObject, propertyIndex, notifyIndex);
+ capture->captureProperty(scopeObject, propertyIndex, notifyIndex,
+ QQmlPropertyCapture::Permanently);
}
}
@@ -416,12 +421,18 @@ void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject *
}
-void QQmlJavaScriptExpression::clearGuards()
+void QQmlJavaScriptExpression::clearActiveGuards()
{
while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst())
g->Delete();
}
+void QQmlJavaScriptExpression::clearPermanentGuards()
+{
+ while (QQmlJavaScriptExpressionGuard *g = permanentGuards.takeFirst())
+ g->Delete();
+}
+
void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **)
{
QQmlJavaScriptExpression *expression =
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index 64cb1bb242..a5c7a80153 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -54,7 +54,6 @@
#include <QtCore/qglobal.h>
#include <QtQml/qqmlerror.h>
#include <private/qqmlengine_p.h>
-#include <private/qpointervaluepair_p.h>
QT_BEGIN_NAMESPACE
@@ -104,8 +103,7 @@ public:
virtual QString expressionIdentifier() = 0;
virtual void expressionChanged() = 0;
- QV4::ReturnedValue evaluate(bool *isUndefined);
- QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined);
+ void evaluate(QV4::CallData *callData, bool *isUndefined, QV4::Scope &scope);
inline bool notifyOnValueChanged() const;
@@ -138,7 +136,8 @@ public:
inline bool hasDelayedError() const;
QQmlError error(QQmlEngine *) const;
void clearError();
- void clearGuards();
+ void clearActiveGuards();
+ void clearPermanentGuards();
QQmlDelayedError *delayedError();
static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope,
@@ -159,10 +158,12 @@ private:
// activeGuards:flag2 - useSharedContext
QBiPointer<QObject, DeleteWatcher> m_scopeObject;
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards;
+ QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> permanentGuards;
QQmlContextData *m_context;
QQmlJavaScriptExpression **m_prevExpression;
QQmlJavaScriptExpression *m_nextExpression;
+ bool m_permanentDependenciesRegistered = false;
protected:
QV4::PersistentValue m_function;
@@ -179,10 +180,14 @@ public:
Q_ASSERT(errorString == 0);
}
- void captureProperty(QQmlNotifier *);
- void captureProperty(QObject *, int, int);
+ enum Duration {
+ OnlyOnce,
+ Permanently
+ };
- static void registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction);
+ static void registerQmlDependencies(const QV4::CompiledData::Function *compiledFunction, const QV4::Scope &scope);
+ void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce);
+ void captureProperty(QObject *, int, int, Duration duration = OnlyOnce);
QQmlEngine *engine;
QQmlJavaScriptExpression *expression;
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 7b129e2b57..271b4f1b31 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -44,7 +44,6 @@
#include <private/qqmlcustomparser_p.h>
#include <private/qhashedstring_p.h>
#include <private/qqmlimport_p.h>
-#include <private/qqmlcompiler_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qstringlist.h>
@@ -493,8 +492,8 @@ QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt);
if (td.isNull() || !td->isComplete())
return 0;
- QQmlCompiledData *cd = td->compiledData();
- const QMetaObject *mo = cd->rootPropertyCache->firstCppMetaObject();
+ QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
+ const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
return QQmlMetaType::qmlType(mo);
}
@@ -1914,14 +1913,11 @@ QList<QQmlType*> QQmlMetaType::qmlSingletonTypes()
QMutexLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
- QList<QQmlType*> alltypes = data->nameToType.values();
QList<QQmlType*> retn;
- foreach (QQmlType* t, alltypes) {
- if (t->isSingleton()) {
- retn.append(t);
- }
+ for (const auto type : qAsConst(data->nameToType)) {
+ if (type->isSingleton())
+ retn.append(type);
}
-
return retn;
}
@@ -1929,9 +1925,9 @@ const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const
{
QMutexLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
- for (QVector<QQmlPrivate::QmlUnitCacheLookupFunction>::ConstIterator it = data->lookupCachedQmlUnit.constBegin(), end = data->lookupCachedQmlUnit.constEnd();
- it != end; ++it) {
- if (const QQmlPrivate::CachedQmlUnit *unit = (*it)(uri))
+
+ for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) {
+ if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri))
return unit;
}
return 0;
@@ -1961,8 +1957,7 @@ QString QQmlMetaType::prettyTypeName(const QObject *object)
marker = typeName.indexOf(QLatin1String("_QML_"));
if (marker != -1) {
- typeName = typeName.left(marker);
- typeName += QLatin1Char('*');
+ typeName = typeName.left(marker) + QLatin1Char('*');
type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
if (type) {
typeName = type->qmlTypeName();
diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
index f9fea0279e..c94db8e168 100644
--- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
+++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
@@ -41,6 +41,8 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_NETWORK
+
/*!
\class QQmlNetworkAccessManagerFactory
\since 5.0
@@ -101,4 +103,6 @@ QQmlNetworkAccessManagerFactory::~QQmlNetworkAccessManagerFactory()
implementation of this method is reentrant.
*/
+#endif //QT_NO_NETWORK
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
index 8e3b94fad3..ba3561b9f4 100644
--- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
+++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
@@ -45,6 +45,7 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_NETWORK
class QNetworkAccessManager;
class Q_QML_EXPORT QQmlNetworkAccessManagerFactory
@@ -55,6 +56,8 @@ public:
};
+#endif //QT_NO_NETWORK
+
QT_END_NAMESPACE
#endif // QQMLNETWORKACCESSMANAGERFACTORY_H
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 831965f36a..3000f3e695 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -54,6 +54,7 @@
#include <private/qqmlscriptstring_p.h>
#include <private/qqmlpropertyvalueinterceptor_p.h>
#include <private/qqmlvaluetypeproxybinding_p.h>
+#include <private/qqmlaccessors_p.h>
QT_USE_NAMESPACE
@@ -69,12 +70,11 @@ struct ActiveOCRestorer
};
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext)
+QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *creationContext, void *activeVMEDataForRootContext)
: phase(Startup)
- , compiledData(compiledData)
- , resolvedTypes(compiledData->resolvedTypes)
- , propertyCaches(compiledData->propertyCaches)
- , vmeMetaObjectData(compiledData->metaObjects)
+ , compilationUnit(compilationUnit)
+ , resolvedTypes(compilationUnit->resolvedTypes)
+ , propertyCaches(&compilationUnit->propertyCaches)
, activeVMEDataForRootContext(activeVMEDataForRootContext)
{
init(parentContext);
@@ -82,24 +82,26 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile
sharedState = new QQmlObjectCreatorSharedState;
topLevelCreator = true;
sharedState->componentAttached = 0;
- sharedState->allCreatedBindings.allocate(compiledData->totalBindingsCount);
- sharedState->allParserStatusCallbacks.allocate(compiledData->totalParserStatusCount);
- sharedState->allCreatedObjects.allocate(compiledData->totalObjectCount);
+ sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount);
+ sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount);
+ sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount);
sharedState->allJavaScriptObjects = 0;
sharedState->creationContext = creationContext;
sharedState->rootContext = 0;
- QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler;
- Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
- sharedState->profiler.init(profiler, compiledData->totalParserStatusCount));
+ if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) {
+ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
+ sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount));
+ } else {
+ Q_UNUSED(profiler);
+ }
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState)
+QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState)
: phase(Startup)
- , compiledData(compiledData)
- , resolvedTypes(compiledData->resolvedTypes)
- , propertyCaches(compiledData->propertyCaches)
- , vmeMetaObjectData(compiledData->metaObjects)
+ , compilationUnit(compilationUnit)
+ , resolvedTypes(compilationUnit->resolvedTypes)
+ , propertyCaches(&compilationUnit->propertyCaches)
, activeVMEDataForRootContext(0)
{
init(parentContext);
@@ -114,10 +116,10 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
engine = parentContext->engine;
v4 = QV8Engine::getV4(engine);
- if (!compiledData->isInitialized())
- compiledData->initialize(engine);
+ if (compilationUnit && !compilationUnit->engine)
+ compilationUnit->linkToEngine(v4);
- qmlUnit = compiledData->compilationUnit->data;
+ qmlUnit = compilationUnit->data;
context = 0;
_qobject = 0;
_scopeObject = 0;
@@ -160,19 +162,16 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
int objectToCreate;
if (subComponentIndex == -1) {
- objectIndexToId = compiledData->objectIndexToIdForRoot;
objectToCreate = qmlUnit->indexOfRootObject;
} else {
- objectIndexToId = compiledData->objectIndexToIdPerComponent[subComponentIndex];
const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex);
objectToCreate = compObj->bindingTable()->value.objectIndex;
}
context = new QQmlContextData;
context->isInternal = true;
- context->imports = compiledData->importCache;
- context->imports->addref();
- context->typeCompilationUnit = compiledData->compilationUnit;
+ context->imports = compilationUnit->importCache;
+ context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
context->setParent(parentContext);
if (!sharedState->rootContext) {
@@ -185,16 +184,14 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator);
if (topLevelCreator)
- sharedState->allJavaScriptObjects = scope.alloc(compiledData->totalObjectCount);
+ sharedState->allJavaScriptObjects = scope.alloc(compilationUnit->totalObjectCount);
- context->setIdPropertyData(objectIndexToId);
-
- if (subComponentIndex == -1 && compiledData->scripts.count()) {
- QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count()));
+ if (subComponentIndex == -1 && compilationUnit->dependentScripts.count()) {
+ QV4::ScopedObject scripts(scope, v4->newArrayObject(compilationUnit->dependentScripts.count()));
context->importedScripts.set(v4, scripts);
QV4::ScopedValue v(scope);
- for (int i = 0; i < compiledData->scripts.count(); ++i) {
- QQmlScriptData *s = compiledData->scripts.at(i);
+ for (int i = 0; i < compilationUnit->dependentScripts.count(); ++i) {
+ QQmlScriptData *s = compilationUnit->dependentScripts.at(i);
scripts->putIndexed(i, (v = s->scriptValueForContext(context)));
}
} else if (sharedState->creationContext) {
@@ -205,10 +202,10 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
if (instance) {
QQmlData *ddata = QQmlData::get(instance);
Q_ASSERT(ddata);
- if (ddata->compiledData)
- ddata->compiledData->release();
- ddata->compiledData = compiledData;
- ddata->compiledData->addref();
+ if (ddata->compilationUnit)
+ ddata->compilationUnit->release();
+ ddata->compilationUnit = compilationUnit;
+ ddata->compilationUnit->addref();
}
if (topLevelCreator)
@@ -242,7 +239,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
Q_ASSERT(topLevelCreator);
Q_ASSERT(!sharedState->allJavaScriptObjects);
- sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->totalObjectCount);
+ sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
@@ -261,11 +258,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
qSwap(_bindingTarget, bindingTarget);
qSwap(_vmeMetaObject, vmeMetaObject);
- QBitArray bindingSkipList = compiledData->deferredBindingsPerObject.value(_compiledObjectIndex);
- for (int i = 0; i < bindingSkipList.count(); ++i)
- bindingSkipList.setBit(i, !bindingSkipList.testBit(i));
-
- setupBindings(bindingSkipList);
+ setupBindings(/*applyDeferredBindings=*/true);
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
@@ -285,11 +278,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
{
- QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
- int propertyWriteStatus = -1;
- void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
-
+ QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite;
QV4::Scope scope(v4);
int propertyType = property->propType;
@@ -317,16 +306,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
} else {
int i = int(n);
QVariant value(i);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
} else {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromDouble(n));
} else {
QVariant value(n);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
} else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
@@ -334,8 +321,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
_vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromBoolean(binding->valueAsBoolean()));
} else {
QVariant value(binding->valueAsBoolean());
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
} else {
QString stringValue = binding->valueAsString(qmlUnit);
@@ -344,8 +330,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
_vmeMetaObject->setVMEProperty(property->coreIndex, s);
} else {
QVariant value = QQmlStringConverters::variantFromString(stringValue);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
}
@@ -353,22 +338,19 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QVariant::String: {
Q_ASSERT(binding->evaluatesToString());
QString value = binding->valueAsString(qmlUnit);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::StringList: {
Q_ASSERT(binding->evaluatesToString());
QStringList value(binding->valueAsString(qmlUnit));
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::ByteArray: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
QByteArray value(binding->valueAsString(qmlUnit).toUtf8());
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Url: {
@@ -376,20 +358,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QString string = binding->valueAsString(qmlUnit);
// Encoded dir-separators defeat QUrl processing - decode them first
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- QUrl value = string.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(string));
+ QUrl value = string.isEmpty() ? QUrl() : compilationUnit->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);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::UInt: {
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);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
}
break;
@@ -397,23 +377,20 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
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);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
}
break;
case QMetaType::Float: {
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);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Double: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
double value = binding->valueAsNumber();
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Color: {
@@ -422,8 +399,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
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);
+ property->writeProperty(_qobject, &buffer, propertyWriteFlags);
}
}
break;
@@ -432,16 +408,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = false;
QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Time: {
bool ok = false;
QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::DateTime: {
@@ -454,8 +428,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay));
}
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
#endif // QT_NO_DATESTRING
@@ -463,55 +436,48 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = false;
QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok).toPoint();
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::PointF: {
bool ok = false;
QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Size: {
bool ok = false;
QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok).toSize();
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::SizeF: {
bool ok = false;
QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Rect: {
bool ok = false;
QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok).toRect();
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::RectF: {
bool ok = false;
QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Bool: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
bool value = binding->valueAsBoolean();
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Vector2D: {
@@ -522,8 +488,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec));
Q_ASSERT(ok);
Q_UNUSED(ok);
- argv[0] = reinterpret_cast<void *>(&vec);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
break;
case QVariant::Vector3D: {
@@ -535,8 +500,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(qmlUnit), &vec, sizeof(vec));
Q_ASSERT(ok);
Q_UNUSED(ok);
- argv[0] = reinterpret_cast<void *>(&vec);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
break;
case QVariant::Vector4D: {
@@ -549,8 +513,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(qmlUnit), &vec, sizeof(vec));
Q_ASSERT(ok);
Q_UNUSED(ok);
- argv[0] = reinterpret_cast<void *>(&vec);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
break;
case QVariant::Quaternion: {
@@ -563,8 +526,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec));
Q_ASSERT(ok);
Q_UNUSED(ok);
- argv[0] = reinterpret_cast<void *>(&vec);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
break;
case QVariant::RegExp:
@@ -576,39 +538,34 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
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);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType == qMetaTypeId<QList<int> >()) {
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);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType == qMetaTypeId<QList<bool> >()) {
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);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
QString urlString = binding->valueAsString(qmlUnit);
- QUrl u = urlString.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(urlString));
+ QUrl u = urlString.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(urlString));
QList<QUrl> value;
value.append(u);
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType == qMetaTypeId<QList<QString> >()) {
Q_ASSERT(binding->evaluatesToString());
QList<QString> value;
value.append(binding->valueAsString(qmlUnit));
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType == qMetaTypeId<QJSValue>()) {
QJSValue value;
@@ -623,8 +580,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
} else {
value = QJSValue(binding->valueAsString(qmlUnit));
}
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
}
@@ -640,8 +596,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
}
- argv[0] = value.data();
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, value.data(), propertyWriteFlags);
}
break;
}
@@ -658,14 +613,14 @@ static QQmlType *qmlTypeForObject(QObject *object)
return type;
}
-void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
+void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
{
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
- const QV4::CompiledData::BindingPropertyData &propertyData = compiledData->compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
+ const QV4::CompiledData::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
- if (_compiledObject->idIndex) {
+ if (_compiledObject->idNameIndex) {
const QQmlPropertyData *idProperty = propertyData.last();
Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id"));
if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType == QMetaType::QString) {
@@ -673,7 +628,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
idBinding.propertyNameIndex = 0; // Not used
idBinding.flags = 0;
idBinding.type = QV4::CompiledData::Binding::Type_String;
- idBinding.stringIndex = _compiledObject->idIndex;
+ idBinding.stringIndex = _compiledObject->idNameIndex;
idBinding.location = _compiledObject->location; // ###
setPropertyValue(idProperty, &idBinding);
}
@@ -691,7 +646,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
if (qmlTypeForObject(_bindingTarget)) {
quint32 bindingSkipList = 0;
- QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultProperty != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
+ QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
@@ -709,9 +664,17 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
- if (static_cast<int>(i) < bindingsToSkip.size() && bindingsToSkip.testBit(i))
+ if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
continue;
+ if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) {
+ if (!applyDeferredBindings)
+ continue;
+ } else {
+ if (applyDeferredBindings)
+ continue;
+ }
+
const QQmlPropertyData *property = propertyData.at(i);
if (property && property->isQList()) {
@@ -736,7 +699,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
{
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
- QQmlCompiledData::TypeReference *tr = resolvedTypes.value(binding->propertyNameIndex);
+ QV4::CompiledData::ResolvedTypeReference *tr = resolvedTypes.value(binding->propertyNameIndex);
Q_ASSERT(tr);
QQmlType *attachedType = tr->type;
if (!attachedType) {
@@ -763,8 +726,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
ss.d.data()->numberValue = binding->valueAsNumber();
- QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+ QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
+ QQmlPropertyData::RemoveBindingOnAliasWrite;
int propertyWriteStatus = -1;
void *argv[] = { &ss, 0, &propertyWriteStatus, &propertyWriteFlags };
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
@@ -816,7 +779,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
if (valueType)
- valueType->write(_qobject, property->coreIndex, QQmlPropertyPrivate::BypassInterceptor);
+ valueType->write(_qobject, property->coreIndex, QQmlPropertyData::BypassInterceptor);
return true;
}
@@ -828,7 +791,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
QQmlPropertyPrivate::removeBinding(_bindingTarget, property->coreIndex);
if (binding->type == QV4::CompiledData::Binding::Type_Script) {
- QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
QV4::Scope scope(v4);
QV4::ScopedContext qmlContext(scope, currentQmlContext());
@@ -842,8 +805,6 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
bs->takeExpression(expr);
} else {
- QQmlBinding *qmlBinding = new QQmlBinding(function, _scopeObject, context);
-
// When writing bindings to grouped properties implemented as value types,
// such as point.x: { someExpression; }, then the binding is installed on
// the point property (_qobjectForBindings) and after evaluating the expression,
@@ -853,6 +814,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
if (_valueTypeProperty)
targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine);
+ QQmlBinding *qmlBinding = QQmlBinding::create(&targetCorePropertyData, function, _scopeObject, context);
sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding));
qmlBinding->setTarget(_bindingTarget, targetCorePropertyData);
@@ -943,8 +905,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return true;
}
- QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+ QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
+ QQmlPropertyData::RemoveBindingOnAliasWrite;
int propertyWriteStatus = -1;
void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
@@ -1009,9 +971,9 @@ void QQmlObjectCreator::setupFunctions()
QV4::ScopedValue function(scope);
QV4::ScopedContext qmlContext(scope, currentQmlContext());
- const quint32 *functionIdx = _compiledObject->functionOffsetTable();
+ const QV4::CompiledData::LEUInt32 *functionIdx = _compiledObject->functionOffsetTable();
for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
- QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[*functionIdx];
+ QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx];
const QString name = runtimeFunction->name()->toQString();
QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
@@ -1026,18 +988,17 @@ void QQmlObjectCreator::setupFunctions()
void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setUrl(compiledData->url());
+ error.setUrl(compilationUnit->url());
error.setLine(location.line);
error.setColumn(location.column);
error.setDescription(description);
errors << error;
}
-void QQmlObjectCreator::registerObjectWithContextById(int objectIndex, QObject *instance) const
+void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const
{
- QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(objectIndex);
- if (idEntry != objectIndexToId.constEnd())
- context->setIdProperty(idEntry.value(), instance);
+ if (object->id >= 0)
+ context->setIdProperty(object->id, instance);
}
QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext()
@@ -1050,7 +1011,9 @@ QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext()
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
{
- QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler);
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
+ QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler, obj);
+
ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
bool isComponent = false;
@@ -1060,23 +1023,22 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QQmlParserStatus *parserStatus = 0;
bool installPropertyCache = true;
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
- if (compiledData->isComponent(index)) {
+ if (obj->flags & QV4::CompiledData::Object::IsComponent) {
isComponent = true;
- QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
+ QQmlComponent *component = new QQmlComponent(engine, compilationUnit, index, parent);
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
- compiledData, obj, QStringLiteral("<component>"), context->url()));
+ compilationUnit, obj, QStringLiteral("<component>"), context->url()));
QQmlComponentPrivate::get(component)->creationContext = context;
instance = component;
ddata = QQmlData::get(instance, /*create*/true);
} else {
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ QV4::CompiledData::ResolvedTypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
installPropertyCache = !typeRef->isFullyDynamicType;
QQmlType *type = typeRef->type;
if (type) {
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
- compiledData, obj, type->qmlTypeName(), context->url()));
+ compilationUnit, obj, type->qmlTypeName(), context->url()));
instance = type->create();
if (!instance) {
recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
@@ -1097,17 +1059,17 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
sharedState->allCreatedObjects.push(instance);
} else {
- Q_ASSERT(typeRef->component);
+ Q_ASSERT(typeRef->compilationUnit);
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
- compiledData, obj, typeRef->component->fileName(),
+ compilationUnit, obj, typeRef->compilationUnit->fileName(),
context->url()));
- if (typeRef->component->compilationUnit->data->isSingleton())
+ if (typeRef->compilationUnit->data->isSingleton())
{
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
return 0;
}
- QQmlObjectCreator subCreator(context, typeRef->component, sharedState.data());
+ QQmlObjectCreator subCreator(context, typeRef->compilationUnit, sharedState.data());
instance = subCreator.create();
if (!instance) {
errors += subCreator.errors;
@@ -1153,32 +1115,30 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (isContextObject)
context->contextObject = instance;
- QBitArray bindingsToSkip;
- if (customParser) {
- QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.constFind(index);
- if (customParserBindings != compiledData->customParserBindings.constEnd()) {
- customParser->engine = QQmlEnginePrivate::get(engine);
- customParser->imports = compiledData->importCache;
-
- QList<const QV4::CompiledData::Binding *> bindings;
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
- for (int i = 0; i < customParserBindings->count(); ++i)
- if (customParserBindings->testBit(i))
- bindings << obj->bindingTable() + i;
- customParser->applyBindings(instance, compiledData, bindings);
-
- customParser->engine = 0;
- customParser->imports = (QQmlTypeNameCache*)0;
- bindingsToSkip = *customParserBindings;
+ if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
+ customParser->engine = QQmlEnginePrivate::get(engine);
+ customParser->imports = compilationUnit->importCache;
+
+ QList<const QV4::CompiledData::Binding *> bindings;
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
+ const QV4::CompiledData::Binding *binding = obj->bindingTable();
+ for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
+ if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) {
+ bindings << binding;
+ }
}
+ customParser->applyBindings(instance, compilationUnit, bindings);
+
+ customParser->engine = 0;
+ customParser->imports = (QQmlTypeNameCache*)0;
}
if (isComponent) {
- registerObjectWithContextById(index, instance);
+ registerObjectWithContextById(obj, instance);
return instance;
}
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index);
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(index);
Q_ASSERT(!cache.isNull());
if (installPropertyCache) {
if (ddata->propertyCache)
@@ -1199,7 +1159,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
qSwap(_qmlContext, qmlContext);
- bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0, bindingsToSkip);
+ bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0);
qSwap(_qmlContext, qmlContext);
qSwap(_scopeObject, scopeObject);
@@ -1224,8 +1184,8 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
QQmlData *data = QQmlData::get(b->targetObject());
Q_ASSERT(data);
data->clearPendingBindingBit(b->targetPropertyIndex());
- b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::DontRemoveBinding);
+ b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
+ QQmlPropertyData::DontRemoveBinding);
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
return 0;
@@ -1294,7 +1254,7 @@ void QQmlObjectCreator::clear()
phase = Done;
}
-bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip)
+bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty)
{
QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
@@ -1309,14 +1269,13 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
QV4::Scope valueScope(v4);
QV4::ScopedValue scopeObjectProtector(valueScope);
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(_compiledObjectIndex);
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(_compiledObjectIndex);
QQmlVMEMetaObject *vmeMetaObject = 0;
- const QByteArray data = vmeMetaObjectData.value(_compiledObjectIndex);
- if (!data.isEmpty()) {
+ if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) {
Q_ASSERT(!cache.isNull());
// install on _object
- vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()));
+ vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, compilationUnit, _compiledObjectIndex);
if (_ddata->propertyCache)
_ddata->propertyCache->release();
_ddata->propertyCache = cache;
@@ -1326,33 +1285,23 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
}
- registerObjectWithContextById(_compiledObjectIndex, _qobject);
+ registerObjectWithContextById(_compiledObject, _qobject);
qSwap(_propertyCache, cache);
qSwap(_vmeMetaObject, vmeMetaObject);
- QBitArray bindingSkipList = bindingsToSkip;
- {
- QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.constFind(_compiledObjectIndex);
- if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) {
- if (bindingSkipList.isEmpty())
- bindingSkipList.resize(deferredBindings->count());
-
- for (int i = 0; i < deferredBindings->count(); ++i)
- if (deferredBindings->testBit(i))
- bindingSkipList.setBit(i);
- QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
- deferData->deferredIdx = _compiledObjectIndex;
- deferData->compiledData = compiledData;
- deferData->compiledData->addref();
- deferData->context = context;
- _ddata->deferredData = deferData;
- }
+ if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) {
+ QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
+ deferData->deferredIdx = _compiledObjectIndex;
+ deferData->compilationUnit = compilationUnit;
+ deferData->compilationUnit->addref();
+ deferData->context = context;
+ _ddata->deferredData = deferData;
}
if (_compiledObject->nFunctions > 0)
setupFunctions();
- setupBindings(bindingSkipList);
+ setupBindings();
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 3d743954c9..e3312f9df5 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -53,7 +53,6 @@
#include <private/qqmlimport_p.h>
#include <private/qqmltypenamecache_p.h>
#include <private/qv4compileddata_p.h>
-#include <private/qqmlcompiler_p.h>
#include <private/qqmltypecompiler_p.h>
#include <private/qfinitestack_p.h>
#include <private/qrecursionwatcher_p.h>
@@ -66,7 +65,6 @@ QT_BEGIN_NAMESPACE
class QQmlAbstractBinding;
struct QQmlTypeCompiler;
class QQmlInstantiationInterrupt;
-struct QQmlVmeProfiler;
struct QQmlObjectCreatorSharedState : public QSharedData
{
@@ -86,7 +84,7 @@ class QQmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
public:
- QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext = 0);
+ QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *creationContext, void *activeVMEDataForRootContext = 0);
~QQmlObjectCreator();
QObject *create(int subComponentIndex = -1, QObject *parent = 0, QQmlInstantiationInterrupt *interrupt = 0);
@@ -104,17 +102,16 @@ public:
QFiniteStack<QPointer<QObject> > &allCreatedObjects() const { return sharedState->allCreatedObjects; }
private:
- QQmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState);
+ QQmlObjectCreator(QQmlContextData *contextData, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
void init(QQmlContextData *parentContext);
QObject *createInstance(int index, QObject *parent = 0, bool isContextObject = false);
bool populateInstance(int index, QObject *instance,
- QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty,
- const QBitArray &bindingsToSkip = QBitArray());
+ QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
- void setupBindings(const QBitArray &bindingsToSkip);
+ void setupBindings(bool applyDeferredBindings = false);
bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setupFunctions();
@@ -122,7 +119,7 @@ private:
QString stringAt(int idx) const { return qmlUnit->stringAt(idx); }
void recordError(const QV4::CompiledData::Location &location, const QString &description);
- void registerObjectWithContextById(int objectIndex, QObject *instance) const;
+ void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const;
QV4::Heap::QmlContext *currentQmlContext();
@@ -137,14 +134,12 @@ private:
QQmlEngine *engine;
QV4::ExecutionEngine *v4;
- QQmlCompiledData *compiledData;
+ QV4::CompiledData::CompilationUnit *compilationUnit;
const QV4::CompiledData::Unit *qmlUnit;
QQmlGuardedContextData parentContext;
QQmlContextData *context;
- const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
- const QVector<QQmlPropertyCache *> &propertyCaches;
- const QVector<QByteArray> &vmeMetaObjectData;
- QHash<int, int> objectIndexToId;
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes;
+ const QQmlPropertyCacheVector *propertyCaches;
QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
bool topLevelCreator;
void *activeVMEDataForRootContext;
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index 37d8d4748a..a47a0ab4a4 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -67,8 +67,6 @@ QString QQmlPlatform::os()
return QStringLiteral("tvos");
#elif defined(Q_OS_MAC)
return QStringLiteral("osx");
-#elif defined(Q_OS_WINCE)
- return QStringLiteral("wince");
#elif defined(Q_OS_WINPHONE)
return QStringLiteral("winphone");
#elif defined(Q_OS_WINRT)
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index df2ff05de1..b3eb0a5619 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -42,6 +42,7 @@
#include "qqml.h"
#include "qqmlbinding_p.h"
+#include "qqmlboundsignal_p.h"
#include "qqmlcontext.h"
#include "qqmlcontext_p.h"
#include "qqmlboundsignal_p.h"
@@ -50,7 +51,6 @@
#include "qqmldata_p.h"
#include "qqmlstringconverters_p.h"
#include "qqmllist_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlvmemetaobject_p.h"
#include "qqmlexpression_p.h"
#include "qqmlvaluetypeproxybinding_p.h"
@@ -317,8 +317,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
if (!property->isQObject())
return; // Not an object property
- void *args[] = { &currentObject, 0 };
- QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
+ property->readProperty(currentObject, &currentObject);
if (!currentObject) return; // No value
}
@@ -859,7 +858,7 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
}
-void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, WriteFlags writeFlags)
+void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags)
{
Q_ASSERT(binding);
@@ -1035,15 +1034,13 @@ QVariant QQmlPropertyPrivate::readValueProperty()
} else if (core.isQList()) {
QQmlListProperty<QObject> prop;
- void *args[] = { &prop, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ core.readProperty(object, &prop);
return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
} else if (core.isQObject()) {
QObject *rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ core.readProperty(object, &rv);
return QVariant::fromValue(rv);
} else {
@@ -1060,7 +1057,7 @@ QVariant QQmlPropertyPrivate::readValueProperty()
value = QVariant(core.propType, (void*)0);
args[0] = value.data();
}
- QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ core.readPropertyWithArgs(object, args);
if (core.propType != QMetaType::QVariant && args[0] != value.data())
return QVariant((QVariant::Type)core.propType, args[0]);
@@ -1148,7 +1145,7 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx,
return status;
}
-bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
+bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, QQmlPropertyData::WriteFlags flags)
{
return writeValueProperty(object, core, value, effectiveContext(), flags);
}
@@ -1157,10 +1154,10 @@ bool
QQmlPropertyPrivate::writeValueProperty(QObject *object,
const QQmlPropertyData &core,
const QVariant &value,
- QQmlContextData *context, WriteFlags flags)
+ QQmlContextData *context,QQmlPropertyData::WriteFlags flags)
{
// Remove any existing bindings on this property
- if (!(flags & DontRemoveBinding) && object)
+ if (!(flags & QQmlPropertyData::DontRemoveBinding) && object)
removeBinding(object, core.encodedIndex());
bool rv = false;
@@ -1190,145 +1187,151 @@ QQmlPropertyPrivate::writeValueProperty(QObject *object,
bool QQmlPropertyPrivate::write(QObject *object,
const QQmlPropertyData &property,
const QVariant &value, QQmlContextData *context,
- WriteFlags flags)
+ QQmlPropertyData::WriteFlags flags)
{
- int coreIdx = property.coreIndex;
- int status = -1; //for dbus
+ const int propertyType = property.propType;
+ const int variantType = value.userType();
if (property.isEnum()) {
QMetaProperty prop = object->metaObject()->property(property.coreIndex);
QVariant v = value;
// Enum values come through the script engine as doubles
- if (value.userType() == QVariant::Double) {
+ if (variantType == QVariant::Double) {
double integral;
double fractional = std::modf(value.toDouble(), &integral);
if (qFuzzyIsNull(fractional))
v.convert(QVariant::Int);
}
- return writeEnumProperty(prop, coreIdx, object, v, flags);
+ return writeEnumProperty(prop, property.coreIndex, object, v, flags);
}
- int propertyType = property.propType;
- int variantType = value.userType();
-
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
+ const bool isUrl = propertyType == QVariant::Url; // handled separately
+
+ // The cases below are in approximate order of likelyhood:
+ if (propertyType == variantType && !isUrl && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
+ return property.writeProperty(object, const_cast<void *>(value.constData()), flags);
+ } else if (property.isQObject()) {
+ QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, variantType);
+ if (valMo.isNull())
+ return false;
+ QObject *o = *static_cast<QObject *const *>(value.constData());
+ QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
- if (propertyType == QVariant::Url) {
+ if (o)
+ valMo = o;
+ if (QQmlMetaObject::canConvert(valMo, propMo)) {
+ return property.writeProperty(object, &o, flags);
+ } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
+ // In the case of a null QObject, we assign the null if there is
+ // any change that the null variant type could be up or down cast to
+ // the property type.
+ return property.writeProperty(object, &o, flags);
+ } else {
+ return false;
+ }
+ } else if (value.canConvert(propertyType) && !isUrl && variantType != QVariant::String && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
+ // common cases:
+ switch (propertyType) {
+ case QMetaType::Bool: {
+ bool b = value.toBool();
+ return property.writeProperty(object, &b, flags);
+ }
+ case QMetaType::Int: {
+ int i = value.toInt();
+ return property.writeProperty(object, &i, flags);
+ }
+ case QMetaType::Double: {
+ double d = value.toDouble();
+ return property.writeProperty(object, &d, flags);
+ }
+ case QMetaType::Float: {
+ float f = value.toFloat();
+ return property.writeProperty(object, &f, flags);
+ }
+ case QMetaType::QString: {
+ QString s = value.toString();
+ return property.writeProperty(object, &s, flags);
+ }
+ default: { // "fallback":
+ QVariant v = value;
+ v.convert(propertyType);
+ return property.writeProperty(object, const_cast<void *>(v.constData()), flags);
+ }
+ }
+ } else if (propertyType == qMetaTypeId<QVariant>()) {
+ return property.writeProperty(object, const_cast<QVariant *>(&value), flags);
+ } else if (isUrl) {
QUrl u;
- bool found = false;
if (variantType == QVariant::Url) {
u = value.toUrl();
- found = true;
} else if (variantType == QVariant::ByteArray) {
QString input(QString::fromUtf8(value.toByteArray()));
// Encoded dir-separators defeat QUrl processing - decode them first
input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
u = QUrl(input);
- found = true;
} else if (variantType == QVariant::String) {
QString input(value.toString());
// Encoded dir-separators defeat QUrl processing - decode them first
input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
u = QUrl(input);
- found = true;
- }
-
- if (!found)
- return false;
-
- if (context && u.isRelative() && !u.isEmpty())
- u = context->resolvedUrl(u);
- int status = -1;
- void *argv[] = { &u, 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
-
- } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
- QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
- int status = -1;
- void *argv[] = { &urlSeq, 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
- } else if (variantType == propertyType) {
-
- void *a[] = { const_cast<void *>(value.constData()), 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
-
- } else if (qMetaTypeId<QVariant>() == propertyType) {
-
- void *a[] = { const_cast<QVariant *>(&value), 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
-
- } else if (property.isQObject()) {
-
- QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, value.userType());
-
- if (valMo.isNull())
- return false;
-
- QObject *o = *(QObject *const *)value.constData();
- QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
-
- if (o) valMo = o;
-
- if (QQmlMetaObject::canConvert(valMo, propMo)) {
- void *args[] = { &o, 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
- } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
- // In the case of a null QObject, we assign the null if there is
- // any change that the null variant type could be up or down cast to
- // the property type.
- void *args[] = { &o, 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
} else {
return false;
}
+ if (context && u.isRelative() && !u.isEmpty())
+ u = context->resolvedUrl(u);
+ return property.writeProperty(object, &u, flags);
+ } else if (propertyType == qMetaTypeId<QList<QUrl>>()) {
+ QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl>>();
+ return property.writeProperty(object, &urlSeq, flags);
} else if (property.isQList()) {
-
QQmlMetaObject listType;
if (enginePriv) {
listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
} else {
QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
- if (!type) return false;
+ if (!type)
+ return false;
listType = type->baseMetaObject();
}
- if (listType.isNull()) return false;
+ if (listType.isNull())
+ return false;
QQmlListProperty<void> prop;
- void *args[] = { &prop, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
+ property.readProperty(object, &prop);
- if (!prop.clear) return false;
+ if (!prop.clear)
+ return false;
prop.clear(&prop);
- if (value.userType() == qMetaTypeId<QQmlListReference>()) {
+ if (variantType == qMetaTypeId<QQmlListReference>()) {
QQmlListReference qdlr = value.value<QQmlListReference>();
for (int ii = 0; ii < qdlr.count(); ++ii) {
QObject *o = qdlr.at(ii);
if (o && !QQmlMetaObject::canConvert(o, listType))
- o = 0;
- prop.append(&prop, (void *)o);
+ o = nullptr;
+ prop.append(&prop, o);
}
- } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
+ } else if (variantType == qMetaTypeId<QList<QObject *> >()) {
const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
for (int ii = 0; ii < list.count(); ++ii) {
QObject *o = list.at(ii);
if (o && !QQmlMetaObject::canConvert(o, listType))
- o = 0;
- prop.append(&prop, (void *)o);
+ o = nullptr;
+ prop.append(&prop, o);
}
} else {
QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
if (o && !QQmlMetaObject::canConvert(o, listType))
- o = 0;
- prop.append(&prop, (void *)o);
+ o = nullptr;
+ prop.append(&prop, o);
}
-
} else {
Q_ASSERT(variantType != propertyType);
@@ -1368,7 +1371,8 @@ bool QQmlPropertyPrivate::write(QObject *object,
// successful conversion.
Q_ASSERT(v.userType() == propertyType);
ok = true;
- } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
+ } else if (static_cast<uint>(propertyType) >= QVariant::UserType &&
+ variantType == QVariant::String) {
QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
if (con) {
v = con(value.toString());
@@ -1411,8 +1415,7 @@ bool QQmlPropertyPrivate::write(QObject *object,
}
if (ok) {
- void *a[] = { const_cast<void *>(v.constData()), 0, &status, &flags};
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+ return property.writeProperty(object, const_cast<void *>(v.constData()), flags);
} else {
return false;
}
@@ -1428,10 +1431,9 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi
return metaType.metaObject();
if (engine)
return engine->rawMetaObjectForType(userType);
- QQmlType *type = QQmlMetaType::qmlType(userType);
- if (type)
+ if (QQmlType *type = QQmlMetaType::qmlType(userType))
return QQmlMetaObject(type->baseMetaObject());
- return QQmlMetaObject((QObject*)0);
+ return QQmlMetaObject();
}
/*!
@@ -1513,7 +1515,7 @@ bool QQmlProperty::reset() const
}
bool QQmlPropertyPrivate::write(const QQmlProperty &that,
- const QVariant &value, WriteFlags flags)
+ const QVariant &value, QQmlPropertyData::WriteFlags flags)
{
if (!that.d)
return false;
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 58fea9c239..9398c74621 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -68,13 +68,6 @@ class QQmlJavaScriptExpression;
class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount
{
public:
- enum WriteFlag {
- BypassInterceptor = 0x01,
- DontRemoveBinding = 0x02,
- RemoveBindingOnAliasWrite = 0x04
- };
- Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
-
QQmlContextData *context;
QPointer<QQmlEngine> engine;
QPointer<QObject> object;
@@ -97,7 +90,7 @@ public:
QQmlProperty::PropertyTypeCategory propertyTypeCategory() const;
QVariant readValueProperty();
- bool writeValueProperty(const QVariant &, WriteFlags);
+ bool writeValueProperty(const QVariant &, QQmlPropertyData::WriteFlags);
static QQmlMetaObject rawMetaObjectForType(QQmlEnginePrivate *, int);
static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object,
@@ -105,9 +98,9 @@ public:
static bool writeValueProperty(QObject *,
const QQmlPropertyData &,
const QVariant &, QQmlContextData *,
- WriteFlags flags = 0);
+ QQmlPropertyData::WriteFlags flags = 0);
static bool write(QObject *, const QQmlPropertyData &, const QVariant &,
- QQmlContextData *, WriteFlags flags = 0);
+ QQmlContextData *, QQmlPropertyData::WriteFlags flags = 0);
static void findAliasTarget(QObject *, int, QObject **, int *);
enum BindingFlag {
@@ -116,7 +109,7 @@ public:
};
Q_DECLARE_FLAGS(BindingFlags, BindingFlag)
- static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, WriteFlags writeFlags = DontRemoveBinding);
+ static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, QQmlPropertyData::WriteFlags writeFlags = QQmlPropertyData::DontRemoveBinding);
static void removeBinding(const QQmlProperty &that);
static void removeBinding(QObject *o, int index);
@@ -144,7 +137,7 @@ public:
QQmlBoundSignalExpression *);
static void takeSignalExpression(const QQmlProperty &that,
QQmlBoundSignalExpression *);
- static bool write(const QQmlProperty &that, const QVariant &, WriteFlags);
+ static bool write(const QQmlProperty &that, const QVariant &, QQmlPropertyData::WriteFlags);
static int valueTypeCoreIndex(const QQmlProperty &that);
static int bindingIndex(const QQmlProperty &that);
static int bindingIndex(const QQmlPropertyData &that);
@@ -157,7 +150,6 @@ public:
static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context);
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::WriteFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags)
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 0522aa93ee..322e519706 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -184,10 +184,16 @@ void QQmlPropertyData::load(const QMetaMethod &m)
{
coreIndex = m.methodIndex();
arguments = 0;
+
+ propType = m.returnType();
+
flags |= IsFunction;
if (m.methodType() == QMetaMethod::Signal)
flags |= IsSignal;
- propType = m.returnType();
+ else if (m.methodType() == QMetaMethod::Constructor) {
+ flags |= IsConstructor;
+ propType = QMetaType::QObjectStar;
+ }
if (m.parameterCount()) {
flags |= HasArguments;
@@ -206,11 +212,15 @@ void QQmlPropertyData::load(const QMetaMethod &m)
void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
{
coreIndex = m.methodIndex();
+ propType = QMetaType::Void;
arguments = 0;
flags |= IsFunction;
if (m.methodType() == QMetaMethod::Signal)
flags |= IsSignal;
- propType = QMetaType::Void;
+ else if (m.methodType() == QMetaMethod::Constructor) {
+ flags |= IsConstructor;
+ propType = QMetaType::QObjectStar;
+ }
const char *returnType = m.typeName();
if (!returnType)
@@ -220,9 +230,10 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
flags |= NotFullyResolved;
}
- if (m.parameterCount()) {
+ const int paramCount = m.parameterCount();
+ if (paramCount) {
flags |= HasArguments;
- if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) {
+ if ((paramCount == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) {
flags |= IsV4Function;
}
}
@@ -249,11 +260,8 @@ QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e)
Creates a new QQmlPropertyCache of \a metaObject.
*/
QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject *metaObject)
- : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
- signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
- _metaObject(0), argumentsCache(0)
+ : QQmlPropertyCache(e)
{
- Q_ASSERT(engine);
Q_ASSERT(metaObject);
update(metaObject);
@@ -416,12 +424,6 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor
setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
}
-// Returns this property cache's metaObject. May be null if it hasn't been created yet.
-const QMetaObject *QQmlPropertyCache::metaObject() const
-{
- return _metaObject;
-}
-
// Returns this property cache's metaObject, creating it if necessary.
const QMetaObject *QQmlPropertyCache::createMetaObject()
{
@@ -437,34 +439,19 @@ const QMetaObject *QQmlPropertyCache::createMetaObject()
return _metaObject;
}
-// Returns the name of the default property for this cache
-QString QQmlPropertyCache::defaultPropertyName() const
-{
- return _defaultPropertyName;
-}
-
QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
return property(defaultPropertyName(), 0, 0);
}
-QQmlPropertyCache *QQmlPropertyCache::parent() const
-{
- return _parent;
-}
-
void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
{
+ if (_parent == newParent)
+ return;
+ if (_parent)
+ _parent->release();
_parent = newParent;
-}
-
-// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
-// QML
-const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
-{
- while (_parent && (_metaObject == 0 || _ownMetaObject))
- return _parent->firstCppMetaObject();
- return _metaObject;
+ _parent->addref();
}
QQmlPropertyCache *
@@ -523,11 +510,12 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
bool hasFastProperty = false;
for (int ii = 0; ii < classInfoCount; ++ii) {
int idx = ii + classInfoOffset;
-
- if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
+ QMetaClassInfo mci = metaObject->classInfo(idx);
+ const char *name = mci.name();
+ if (0 == qstrcmp(name, "qt_HasQmlAccessors")) {
hasFastProperty = true;
- } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
- _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
+ } else if (0 == qstrcmp(name, "DefaultProperty")) {
+ _defaultPropertyName = QString::fromUtf8(mci.value());
}
}
@@ -610,7 +598,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
setNamedProperty(methodName, ii, data, (old != 0));
if (data->isSignal()) {
- QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
+ QHashedString on(QLatin1String("on") % methodName.at(0).toUpper() % methodName.midRef(1));
setNamedProperty(on, ii, sigdata, (old != 0));
++signalHandlerIndex;
}
@@ -802,48 +790,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
}
}
-/*! \internal
- \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
- This is different from QMetaMethod::methodIndex().
-*/
-QQmlPropertyData *
-QQmlPropertyCache::signal(int index) const
-{
- if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
- return 0;
-
- if (index < signalHandlerIndexCacheStart)
- return _parent->signal(index);
-
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
- Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
- return ensureResolved(rv);
-}
-
-int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
-{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
- return index;
-
- if (index < methodIndexCacheStart)
- return _parent->methodIndexToSignalIndex(index);
-
- return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
-}
-
-QQmlPropertyData *
-QQmlPropertyCache::method(int index) const
-{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
- return 0;
-
- if (index < methodIndexCacheStart)
- return _parent->method(index);
-
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
- return ensureResolved(rv);
-}
-
QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
{
QQmlData *data = (object ? QQmlData::get(object) : 0);
@@ -860,11 +806,11 @@ inline bool contextHasNoExtensions(QQmlContextData *context)
return (!context->parent || !context->parent->imports);
}
-inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo)
+inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount)
{
- return (prop->isFunction() ? vmemo->methodCount()
- : prop->isSignalHandler() ? vmemo->signalCount()
- : vmemo->propertyCount());
+ return prop->isFunction() ? methodCount
+ : prop->isSignalHandler() ? signalCount
+ : propertyCount;
}
}
@@ -891,11 +837,15 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it,
}
if (vmemo) {
+ const int methodCount = vmemo->methodCount();
+ const int signalCount = vmemo->signalCount();
+ const int propertyCount = vmemo->propertyCount();
+
// Ensure that the property we resolve to is accessible from this meta-object
do {
const StringCache::mapped_type &property(it.value());
- if (property.first < maximumIndexForProperty(property.second, vmemo)) {
+ if (property.first < maximumIndexForProperty(property.second, methodCount, signalCount, propertyCount)) {
// This property is available in the specified context
if (property.second->isFunction() || property.second->isSignalHandler()) {
// Prefer the earlier resolution
@@ -1296,6 +1246,215 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
}
}
+namespace {
+template <typename StringVisitor, typename TypeInfoVisitor>
+int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount,
+ StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
+{
+ const int intsPerMethod = 5;
+
+ int fieldsForParameterData = 0;
+
+ bool hasRevisionedMethods = false;
+
+ for (int i = 0; i < methodCount; ++i) {
+ const int handle = methodOffset + i * intsPerMethod;
+
+ const uint flags = mo.d.data[handle + 4];
+ if (flags & MethodRevisioned)
+ hasRevisionedMethods = true;
+
+ visitString(mo.d.data[handle + 0]); // name
+ visitString(mo.d.data[handle + 3]); // tag
+
+ const int argc = mo.d.data[handle + 1];
+ const int paramIndex = mo.d.data[handle + 2];
+
+ fieldsForParameterData += argc * 2; // type and name
+ fieldsForParameterData += 1; // + return type
+
+ // return type + args
+ for (int i = 0; i < 1 + argc; ++i) {
+ // type name (maybe)
+ visitTypeInfo(mo.d.data[paramIndex + i]);
+
+ // parameter name
+ if (i > 0)
+ visitString(mo.d.data[paramIndex + argc + i]);
+ }
+ }
+
+ int fieldsForRevisions = 0;
+ if (hasRevisionedMethods)
+ fieldsForRevisions = methodCount;
+
+ return methodCount * intsPerMethod + fieldsForRevisions + fieldsForParameterData;
+}
+
+template <typename StringVisitor, typename TypeInfoVisitor>
+int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
+{
+ const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+ const int intsPerProperty = 3;
+
+ bool hasRevisionedProperties = false;
+ bool hasNotifySignals = false;
+
+ for (int i = 0; i < priv->propertyCount; ++i) {
+ const int handle = priv->propertyData + i * intsPerProperty;
+
+ const auto flags = mo.d.data[handle + 2];
+ if (flags & Revisioned) {
+ hasRevisionedProperties = true;
+ }
+ if (flags & Notify)
+ hasNotifySignals = true;
+
+ visitString(mo.d.data[handle]); // name
+ visitTypeInfo(mo.d.data[handle + 1]);
+ }
+
+ int fieldsForPropertyRevisions = 0;
+ if (hasRevisionedProperties)
+ fieldsForPropertyRevisions = priv->propertyCount;
+
+ int fieldsForNotifySignals = 0;
+ if (hasNotifySignals)
+ fieldsForNotifySignals = priv->propertyCount;
+
+ return priv->propertyCount * intsPerProperty + fieldsForPropertyRevisions
+ + fieldsForNotifySignals;
+}
+
+template <typename StringVisitor>
+int visitClassInfo(const QMetaObject &mo, StringVisitor visitString)
+{
+ const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+ const int intsPerClassInfo = 2;
+
+ for (int i = 0; i < priv->classInfoCount; ++i) {
+ const int handle = priv->classInfoData + i * intsPerClassInfo;
+
+ visitString(mo.d.data[handle]); // key
+ visitString(mo.d.data[handle + 1]); // value
+ }
+
+ return priv->classInfoCount * intsPerClassInfo;
+}
+
+template <typename StringVisitor>
+int visitEnumerations(const QMetaObject &mo, StringVisitor visitString)
+{
+ const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+ const int intsPerEnumerator = 4;
+
+ int fieldCount = priv->enumeratorCount * intsPerEnumerator;
+
+ for (int i = 0; i < priv->enumeratorCount; ++i) {
+ const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * intsPerEnumerator;
+
+ const uint keyCount = enumeratorData[2];
+ fieldCount += keyCount * 2;
+
+ visitString(enumeratorData[0]); // name
+
+ const uint keyOffset = enumeratorData[3];
+
+ for (uint j = 0; j < keyCount; ++j) {
+ visitString(mo.d.data[keyOffset + 2 * j]);
+ }
+ }
+
+ return fieldCount;
+}
+
+template <typename StringVisitor>
+int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor)
+{
+ const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+
+ const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) {
+ if (typeInfo & IsUnresolvedType)
+ stringVisitor(typeInfo & TypeNameIndexMask);
+ };
+
+ int fieldCount = MetaObjectPrivateFieldCount;
+
+ fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor,
+ typeInfoVisitor);
+ fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor,
+ typeInfoVisitor);
+
+ fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor);
+ fieldCount += visitClassInfo(mo, stringVisitor);
+ fieldCount += visitEnumerations(mo, stringVisitor);
+
+ return fieldCount;
+}
+
+} // anonymous namespace
+
+bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount,
+ int *stringCount)
+{
+ const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+ if (priv->revision != 7) {
+ return false;
+ }
+
+ uint highestStringIndex = 0;
+ const auto stringIndexVisitor = [&highestStringIndex](uint index) {
+ highestStringIndex = qMax(highestStringIndex, index);
+ };
+
+ *fieldCount = countMetaObjectFields(mo, stringIndexVisitor);
+ *stringCount = highestStringIndex + 1;
+
+ return true;
+}
+
+bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &mo)
+{
+ int fieldCount = 0;
+ int stringCount = 0;
+ if (!determineMetaObjectSizes(mo, &fieldCount, &stringCount)) {
+ return false;
+ }
+
+ hash.addData(reinterpret_cast<const char *>(mo.d.data), fieldCount * sizeof(uint));
+ for (int i = 0; i < stringCount; ++i) {
+ const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo.d.stringdata[i]) };
+ hash.addData(QByteArray(data));
+ }
+
+ return true;
+}
+
+QByteArray QQmlPropertyCache::checksum(bool *ok)
+{
+ if (!_checksum.isEmpty()) {
+ *ok = true;
+ return _checksum;
+ }
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+
+ if (_parent) {
+ hash.addData(_parent->checksum(ok));
+ if (!*ok)
+ return QByteArray();
+ }
+
+ if (!addToHash(hash, *createMetaObject())) {
+ *ok = false;
+ return QByteArray();
+ }
+
+ _checksum = hash.result();
+ *ok = !_checksum.isEmpty();
+ return _checksum;
+}
+
/*! \internal
\a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
This is different from QMetaMethod::methodIndex().
@@ -1451,7 +1610,8 @@ int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *u
return type;
}
-int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &dummy, QByteArray *unknownTypeError) const
+int *QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const
{
Q_ASSERT(!_m.isNull() && index >= 0);
@@ -1506,39 +1666,53 @@ int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &du
} else {
QMetaMethod m = _m.asT2()->method(index);
- int argc = m.parameterCount();
- dummy.resize(argc + 1);
- dummy[0] = argc;
- QList<QByteArray> argTypeNames; // Only loaded if needed
+ return methodParameterTypes(m, argStorage, unknownTypeError);
- for (int ii = 0; ii < argc; ++ii) {
- int type = m.parameterType(ii);
- QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
- if (flags & QMetaType::IsEnumeration)
- type = QVariant::Int;
- else if (type == QMetaType::UnknownType ||
- (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
- type != qMetaTypeId<QJSValue>())) {
- //the UserType clause is to catch registered QFlags)
- if (argTypeNames.isEmpty())
- argTypeNames = m.parameterTypes();
- type = EnumType(_m.asT2(), argTypeNames.at(ii), type);
- }
- if (type == QMetaType::UnknownType) {
- if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
- return 0;
- }
- dummy[ii + 1] = type;
- }
+ }
+}
- return dummy.data();
+int *QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const
+{
+ Q_ASSERT(argStorage);
+
+ int argc = m.parameterCount();
+ argStorage->resize(argc + 1);
+ argStorage->operator[](0) = argc;
+ QList<QByteArray> argTypeNames; // Only loaded if needed
+
+ for (int ii = 0; ii < argc; ++ii) {
+ int type = m.parameterType(ii);
+ QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
+ if (flags & QMetaType::IsEnumeration)
+ type = QVariant::Int;
+ else if (type == QMetaType::UnknownType ||
+ (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
+ type != qMetaTypeId<QJSValue>())) {
+ //the UserType clause is to catch registered QFlags)
+ if (argTypeNames.isEmpty())
+ argTypeNames = m.parameterTypes();
+ type = EnumType(_m.asT2(), argTypeNames.at(ii), type);
+ }
+ if (type == QMetaType::UnknownType) {
+ if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
+ return 0;
+ }
+ argStorage->operator[](ii + 1) = type;
}
+
+ return argStorage->data();
}
void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv) const
{
- if (ptr.isT1())
+ if (ptr.isNull()) {
+ const QMetaObject *metaObject = _m.asT2();
+ metaObject->d.static_metacall(0, type, index, argv);
+ }
+ else if (ptr.isT1()) {
QMetaObject::metacall(ptr.asT1(), type, index, argv);
+ }
else {
const QMetaObject *metaObject = _m.asT1()->metaObject();
QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &index);
@@ -1546,4 +1720,11 @@ void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv
}
}
+int *QQmlStaticMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy,
+ QByteArray *unknownTypeError) const
+{
+ QMetaMethod m = _m.asT2()->constructor(index);
+ return methodParameterTypes(m, dummy, unknownTypeError);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 96dbc72f32..750537e707 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -61,9 +61,11 @@
#include <QtCore/qvector.h>
#include <private/qv4value_p.h>
+#include <private/qqmlaccessors_p.h>
QT_BEGIN_NAMESPACE
+class QCryptographicHash;
class QMetaProperty;
class QQmlEngine;
class QJSEngine;
@@ -72,7 +74,8 @@ class QQmlAccessors;
class QMetaObjectBuilder;
class QQmlPropertyCacheMethodArguments;
class QQmlVMEMetaObject;
-class QQmlPropertyCacheCreator;
+template <typename T> class QQmlPropertyCacheCreator;
+template <typename T> class QQmlPropertyCacheAliasCreator;
// We have this somewhat awful split between RawData and Data so that RawData can be
// used in unions. In normal code, you should always use Data which initializes RawData
@@ -115,9 +118,10 @@ public:
IsSignalHandler = 0x00800000, // Function is a signal handler
IsOverload = 0x01000000, // Function is an overload of another function
IsCloned = 0x02000000, // The function was marked as cloned
+ IsConstructor = 0x04000000, // The function was marked is a constructor
// Internal QQmlPropertyCache flags
- NotFullyResolved = 0x04000000, // True if the type data is to be lazily resolved
+ NotFullyResolved = 0x08000000, // True if the type data is to be lazily resolved
// Flags that are set based on the propType field
PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue |
@@ -156,12 +160,15 @@ public:
bool isSignalHandler() const { return flags & IsSignalHandler; }
bool isOverload() const { return flags & IsOverload; }
bool isCloned() const { return flags & IsCloned; }
+ bool isConstructor() const { return flags & IsConstructor; }
bool hasOverride() const { return !(flags & IsValueTypeVirtual) &&
!(flags & HasAccessors) &&
overrideIndex >= 0; }
bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; }
+ bool isFullyResolved() const { return !(flags & NotFullyResolved); }
+
// Returns -1 if not a value type virtual property
inline int getValueTypeCoreIndex() const;
@@ -223,6 +230,13 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags)
class QQmlPropertyData : public QQmlPropertyRawData
{
public:
+ enum WriteFlag {
+ BypassInterceptor = 0x01,
+ DontRemoveBinding = 0x02,
+ RemoveBindingOnAliasWrite = 0x04
+ };
+ Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
+
inline QQmlPropertyData();
inline QQmlPropertyData(const QQmlPropertyRawData &);
@@ -236,6 +250,33 @@ public:
void markAsOverrideOf(QQmlPropertyData *predecessor);
+ inline void readProperty(QObject *target, void *property) const
+ {
+ void *args[] = { property, 0 };
+ readPropertyWithArgs(target, args);
+ }
+
+ inline void readPropertyWithArgs(QObject *target, void *args[]) const
+ {
+ if (hasAccessors()) {
+ accessors->read(target, args[0]);
+ } else {
+ QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, args);
+ }
+ }
+
+ bool writeProperty(QObject *target, void *value, WriteFlags flags) const
+ {
+ if (flags.testFlag(BypassInterceptor) && hasAccessors() && accessors->write) {
+ accessors->write(target, value);
+ } else {
+ int status = -1;
+ void *argv[] = { value, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex, argv);
+ }
+ return true;
+ }
+
private:
friend class QQmlPropertyCache;
void lazyLoad(const QMetaProperty &);
@@ -326,6 +367,11 @@ public:
void toMetaObjectBuilder(QMetaObjectBuilder &);
+ static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount);
+ static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo);
+
+ QByteArray checksum(bool *ok);
+
protected:
virtual void destroy();
virtual void clear();
@@ -333,7 +379,8 @@ protected:
private:
friend class QQmlEnginePrivate;
friend class QQmlCompiler;
- friend class QQmlPropertyCacheCreator;
+ template <typename T> friend class QQmlPropertyCacheCreator;
+ template <typename T> friend class QQmlPropertyCacheAliasCreator;
friend class QQmlComponentAndAliasResolver;
friend class QQmlMetaObject;
@@ -394,6 +441,7 @@ private:
QByteArray _dynamicStringData;
QString _defaultPropertyName;
QQmlPropertyCacheMethodArguments *argumentsCache;
+ QByteArray _checksum;
};
// QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.
@@ -406,6 +454,8 @@ class QQmlEnginePrivate;
class Q_QML_EXPORT QQmlMetaObject
{
public:
+ typedef QVarLengthArray<int, 9> ArgTypeStorage;
+
inline QQmlMetaObject();
inline QQmlMetaObject(QObject *);
inline QQmlMetaObject(const QMetaObject *);
@@ -425,7 +475,8 @@ public:
QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
int methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const;
- int *methodParameterTypes(int index, QVarLengthArray<int, 9> &dummy, QByteArray *unknownTypeError) const;
+ int *methodParameterTypes(int index, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const;
static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
@@ -435,6 +486,9 @@ public:
protected:
QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
+ int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const;
+
};
class QQmlObjectOrGadget: public QQmlMetaObject
@@ -453,6 +507,20 @@ public:
private:
QBiPointer<QObject, void> ptr;
+
+protected:
+ QQmlObjectOrGadget(const QMetaObject* metaObject)
+ : QQmlMetaObject(metaObject)
+ {}
+
+};
+
+class QQmlStaticMetaObject : public QQmlObjectOrGadget {
+public:
+ QQmlStaticMetaObject(const QMetaObject* metaObject)
+ : QQmlObjectOrGadget(metaObject)
+ {}
+ int *constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const;
};
QQmlPropertyData::QQmlPropertyData()
@@ -502,6 +570,21 @@ inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p)
return p;
}
+// Returns this property cache's metaObject. May be null if it hasn't been created yet.
+inline const QMetaObject *QQmlPropertyCache::metaObject() const
+{
+ return _metaObject;
+}
+
+// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
+// QML
+inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
+{
+ while (_parent && (_metaObject == 0 || _ownMetaObject))
+ return _parent->firstCppMetaObject();
+ return _metaObject;
+}
+
inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
{
if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
@@ -514,6 +597,57 @@ inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
return ensureResolved(rv);
}
+inline QQmlPropertyData *QQmlPropertyCache::method(int index) const
+{
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ return 0;
+
+ if (index < methodIndexCacheStart)
+ return _parent->method(index);
+
+ QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
+ return ensureResolved(rv);
+}
+
+/*! \internal
+ \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+ This is different from QMetaMethod::methodIndex().
+*/
+inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const
+{
+ if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
+ return 0;
+
+ if (index < signalHandlerIndexCacheStart)
+ return _parent->signal(index);
+
+ QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
+ Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
+ return ensureResolved(rv);
+}
+
+inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
+{
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ return index;
+
+ if (index < methodIndexCacheStart)
+ return _parent->methodIndexToSignalIndex(index);
+
+ return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
+}
+
+// Returns the name of the default property for this cache
+inline QString QQmlPropertyCache::defaultPropertyName() const
+{
+ return _defaultPropertyName;
+}
+
+inline QQmlPropertyCache *QQmlPropertyCache::parent() const
+{
+ return _parent;
+}
+
QQmlPropertyData *
QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
{
@@ -635,6 +769,51 @@ const QMetaObject *QQmlMetaObject::metaObject() const
else return _m.asT2();
}
+class QQmlPropertyCacheVector
+{
+public:
+ QQmlPropertyCacheVector() {}
+ QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other)
+ : data(std::move(other.data)) {}
+ QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) {
+ QVector<QFlagPointer<QQmlPropertyCache>> moved(std::move(other.data));
+ data.swap(moved);
+ return *this;
+ }
+
+ ~QQmlPropertyCacheVector() { clear(); }
+ void resize(int size) { return data.resize(size); }
+ int count() const { return data.count(); }
+ void clear()
+ {
+ for (int i = 0; i < data.count(); ++i) {
+ if (QQmlPropertyCache *cache = data.at(i).data())
+ cache->release();
+ }
+ data.clear();
+ }
+
+ void append(QQmlPropertyCache *cache) { cache->addref(); data.append(cache); }
+ QQmlPropertyCache *at(int index) const { return data.at(index).data(); }
+ void set(int index, QQmlPropertyCache *replacement) {
+ if (QQmlPropertyCache *oldCache = data.at(index).data()) {
+ if (replacement == oldCache)
+ return;
+ oldCache->release();
+ }
+ data[index] = replacement;
+ replacement->addref();
+ }
+
+ void setNeedsVMEMetaObject(int index) { data[index].setFlag(); }
+ bool needsVMEMetaObject(int index) const { return data.at(index).flag(); }
+private:
+ Q_DISABLE_COPY(QQmlPropertyCacheVector)
+ QVector<QFlagPointer<QQmlPropertyCache>> data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
+
QT_END_NAMESPACE
#endif // QQMLPROPERTYCACHE_P_H
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 739a833a30..c54af43a6f 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -45,14 +45,16 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlthread_p.h>
-#include <private/qqmlcompiler_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmlprofiler_p.h>
#include <private/qqmlmemoryprofiler_p.h>
#include <private/qqmltypecompiler_p.h>
+#include <private/qqmlpropertyvalidator_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
+#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
#include <QtCore/qmutex.h>
#include <QtCore/qthread.h>
@@ -62,6 +64,8 @@
#include <QtCore/qwaitcondition.h>
#include <QtQml/qqmlextensioninterface.h>
+#include <functional>
+
#if defined (Q_OS_UNIX)
#include <sys/types.h>
#include <sys/stat.h>
@@ -98,6 +102,8 @@
#endif
DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
+DEFINE_BOOL_CONFIG_OPTION(diskCache, QML_DISK_CACHE);
+DEFINE_BOOL_CONFIG_OPTION(forceDiskCacheRefresh, QML_FORCE_DISK_CACHE_REFRESH);
QT_BEGIN_NAMESPACE
@@ -110,8 +116,23 @@ namespace {
LockHolder(LockType *l) : lock(*l) { lock.lock(); }
~LockHolder() { lock.unlock(); }
};
+
+ struct DeferredCall
+ {
+ std::function<void()> callback;
+ ~DeferredCall() { callback(); }
+ };
+
+ template <typename Callback>
+ DeferredCall defer(Callback &&cb)
+ {
+ DeferredCall c;
+ c.callback = std::move(cb);
+ return c;
+ }
}
+#ifndef QT_NO_NETWORK
// This is a lame object that we need to ensure that slots connected to
// QNetworkReply get called in the correct thread (the loader thread).
// As QQmlTypeLoader lives in the main thread, and we can't use
@@ -131,6 +152,7 @@ public slots:
private:
QQmlTypeLoader *l;
};
+#endif // QT_NO_NETWORK
class QQmlTypeLoaderThread : public QQmlThread
{
@@ -138,9 +160,10 @@ class QQmlTypeLoaderThread : public QQmlThread
public:
QQmlTypeLoaderThread(QQmlTypeLoader *loader);
+#ifndef QT_NO_NETWORK
QNetworkAccessManager *networkAccessManager() const;
QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const;
-
+#endif // QT_NO_NETWORK
void load(QQmlDataBlob *b);
void loadAsync(QQmlDataBlob *b);
void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
@@ -163,11 +186,13 @@ private:
void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
QQmlTypeLoader *m_loader;
+#ifndef QT_NO_NETWORK
mutable QNetworkAccessManager *m_networkAccessManager;
mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy;
+#endif // QT_NO_NETWORK
};
-
+#ifndef QT_NO_NETWORK
QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l)
: l(l)
{
@@ -196,7 +221,7 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
l->networkReplyProgress(reply, replySize, replySize);
l->networkReplyFinished(reply);
}
-
+#endif // QT_NO_NETWORK
/*!
\class QQmlDataBlob
@@ -430,6 +455,39 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors)
tryDone();
}
+void QQmlDataBlob::setError(const QQmlCompileError &error)
+{
+ QQmlError e;
+ e.setColumn(error.location.column);
+ e.setLine(error.location.line);
+ e.setDescription(error.description);
+ e.setUrl(url());
+ setError(e);
+}
+
+void QQmlDataBlob::setError(const QVector<QQmlCompileError> &errors)
+{
+ QList<QQmlError> finalErrors;
+ finalErrors.reserve(errors.count());
+ for (const QQmlCompileError &error: errors) {
+ QQmlError e;
+ e.setColumn(error.location.column);
+ e.setLine(error.location.line);
+ e.setDescription(error.description);
+ e.setUrl(url());
+ finalErrors << e;
+ }
+ setError(finalErrors);
+}
+
+void QQmlDataBlob::setError(const QString &description)
+{
+ QQmlError e;
+ e.setDescription(description);
+ e.setUrl(finalUrl());
+ setError(e);
+}
+
/*!
Wait for \a blob to become complete or to error. If \a blob is already
complete or in error, or this blob is already complete, this has no effect.
@@ -480,6 +538,7 @@ void QQmlDataBlob::done()
{
}
+#ifndef QT_NO_NETWORK
/*!
Invoked if there is a network error while fetching this blob.
@@ -532,6 +591,7 @@ void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
setError(error);
}
+#endif // QT_NO_NETWORK
/*!
Called if \a blob, which was previously waited for, has an error.
@@ -730,12 +790,16 @@ void QQmlDataBlob::ThreadData::setProgress(quint8 v)
}
QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader)
-: m_loader(loader), m_networkAccessManager(0), m_networkReplyProxy(0)
+: m_loader(loader)
+#ifndef QT_NO_NETWORK
+, m_networkAccessManager(0), m_networkReplyProxy(0)
+#endif // QT_NO_NETWORK
{
// Do that after initializing all the members.
startup();
}
+#ifndef QT_NO_NETWORK
QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const
{
Q_ASSERT(isThisThread());
@@ -753,6 +817,7 @@ QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const
Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first
return m_networkReplyProxy;
}
+#endif // QT_NO_NETWORK
void QQmlTypeLoaderThread::load(QQmlDataBlob *b)
{
@@ -810,10 +875,12 @@ void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface,
void QQmlTypeLoaderThread::shutdownThread()
{
+#ifndef QT_NO_NETWORK
delete m_networkAccessManager;
m_networkAccessManager = 0;
delete m_networkReplyProxy;
m_networkReplyProxy = 0;
+#endif // QT_NO_NETWORK
}
void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b)
@@ -899,12 +966,14 @@ void QQmlTypeLoader::invalidate()
m_thread = 0;
}
+#ifndef QT_NO_NETWORK
// Need to delete the network replies after
// the loader thread is shutdown as it could be
// getting new replies while we clear them
for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
(*iter)->release();
m_networkReplies.clear();
+#endif // QT_NO_NETWORK
}
void QQmlTypeLoader::lock()
@@ -1065,13 +1134,9 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
QML_MEMORY_SCOPE_URL(blob->m_url);
if (QQmlFile::isSynchronous(blob->m_url)) {
- QQmlFile file(m_engine, blob->m_url);
-
- if (file.isError()) {
- QQmlError error;
- error.setUrl(blob->m_url);
- error.setDescription(file.error());
- blob->setError(error);
+ const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url);
+ if (!QQml_isFileCaseCorrect(fileName)) {
+ blob->setError(QLatin1String("File name case mismatch"));
return;
}
@@ -1079,10 +1144,10 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
if (blob->m_data.isAsync())
m_thread->callDownloadProgressChanged(blob, 1.);
- setData(blob, &file);
+ setData(blob, fileName);
} else {
-
+#ifndef QT_NO_NETWORK
QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url));
QQmlTypeLoaderNetworkReplyProxy *nrp = m_thread->networkReplyProxy();
blob->addref();
@@ -1099,14 +1164,15 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
#ifdef DATABLOB_DEBUG
qWarning("QQmlDataBlob: requested %s", qPrintable(blob->url().toString()));
-#endif
-
+#endif // DATABLOB_DEBUG
+#endif // QT_NO_NETWORK
}
}
#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
#define TYPELOADER_MINIMUM_TRIM_THRESHOLD 64
+#ifndef QT_NO_NETWORK
void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
{
Q_ASSERT(m_thread->isThisThread());
@@ -1162,6 +1228,7 @@ void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
m_thread->callDownloadProgressChanged(blob, blob->m_data.progress());
}
}
+#endif // QT_NO_NETWORK
/*!
Return the QQmlEngine associated with this loader
@@ -1197,11 +1264,11 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
setData(blob, d);
}
-void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file)
+void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
{
QML_MEMORY_SCOPE_URL(blob->url());
QQmlDataBlob::Data d;
- d.d = file;
+ d.d = &fileName;
setData(blob, d);
}
@@ -1252,7 +1319,7 @@ void QQmlTypeLoader::shutdownThread()
}
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
- : QQmlDataBlob(url, type, loader), m_importCache(loader), m_isSingleton(false)
+ : QQmlDataBlob(url, type, loader), m_importCache(loader)
{
}
@@ -1416,51 +1483,6 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
return true;
}
-bool QQmlTypeLoader::Blob::addPragma(const QmlIR::Pragma &pragma, QList<QQmlError> *errors)
-{
- Q_ASSERT(errors);
-
- if (pragma.type == QmlIR::Pragma::PragmaSingleton) {
- QUrl myUrl = finalUrl();
-
- QQmlType *ret = QQmlMetaType::qmlType(myUrl, true);
- if (!ret) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
- error.setUrl(myUrl);
- error.setLine(pragma.location.line);
- error.setColumn(pragma.location.column);
- errors->prepend(error);
- return false;
- }
-
- if (!ret->isCompositeSingleton()) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(ret->qmlTypeName()));
- error.setUrl(myUrl);
- error.setLine(pragma.location.line);
- error.setColumn(pragma.location.column);
- errors->prepend(error);
- return false;
- }
- // This flag is used for error checking when a qmldir file marks a type as
- // composite singleton, but there is no pragma Singleton defined in QML.
- m_isSingleton = true;
- } else {
- QQmlError error;
- error.setDescription(QLatin1String("Invalid pragma"));
- error.setUrl(finalUrl());
- error.setLine(pragma.location.line);
- error.setColumn(pragma.location.column);
- errors->prepend(error);
- return false;
- }
-
- return true;
-}
-
-
-
void QQmlTypeLoader::Blob::dependencyError(QQmlDataBlob *blob)
{
if (blob->type() == QQmlDataBlob::QmldirFile) {
@@ -1950,7 +1972,9 @@ void QQmlTypeLoader::trimCache()
QList<TypeCache::Iterator> unneededTypes;
for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter) {
QQmlTypeData *typeData = iter.value();
- if (typeData->m_compiledData && typeData->count() == 1
+ // typeData->m_compiledData may be set early on in the proccess of loading a file, so it's important
+ // to check the general loading status of the typeData before making any other decisions.
+ if (typeData->isComplete() && typeData->m_compiledData && typeData->count() == 1
&& typeData->m_compiledData->count() == 1) {
// There are no live objects of this type
unneededTypes.append(iter);
@@ -1992,7 +2016,7 @@ QQmlTypeData::TypeDataCallback::~TypeDataCallback()
QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
: QQmlTypeLoader::Blob(url, QmlFile, manager),
- m_typesResolved(false), m_compiledData(0), m_implicitImport(0), m_implicitImportLoaded(false)
+ m_typesResolved(false), m_implicitImportLoaded(false)
{
}
@@ -2005,14 +2029,11 @@ QQmlTypeData::~QQmlTypeData()
if (QQmlTypeData *tdata = m_compositeSingletons.at(ii).typeData)
tdata->release();
}
- for (QHash<int, TypeReference>::ConstIterator it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
+ for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
it != end; ++it) {
if (QQmlTypeData *tdata = it->typeData)
tdata->release();
}
-
- if (m_compiledData)
- m_compiledData->release();
}
const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
@@ -2020,19 +2041,9 @@ const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() cons
return m_scripts;
}
-const QSet<QString> &QQmlTypeData::namespaces() const
-{
- return m_namespaces;
-}
-
-const QList<QQmlTypeData::TypeReference> &QQmlTypeData::compositeSingletons() const
+QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit() const
{
- return m_compositeSingletons;
-}
-
-QQmlCompiledData *QQmlTypeData::compiledData() const
-{
- return m_compiledData;
+ return m_compiledData.data();
}
void QQmlTypeData::registerCallback(TypeDataCallback *callback)
@@ -2048,10 +2059,120 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
Q_ASSERT(!m_callbacks.contains(callback));
}
+bool QQmlTypeData::tryLoadFromDiskCache()
+{
+ if (!diskCache())
+ return false;
+
+ if (forceDiskCacheRefresh())
+ return false;
+
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
+ if (!v4)
+ return false;
+
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
+ {
+ QString error;
+ if (!unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) {
+ qDebug() << "Error loading" << url().toString() << "from disk cache:" << error;
+ return false;
+ }
+ }
+
+ m_compiledData = unit;
+
+ for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
+ m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ // For remote URLs, we don't delay the loading of the implicit import
+ // because the loading probably requires an asynchronous fetch of the
+ // qmldir (so we can't load it just in time).
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ if (!loadImplicitImport())
+ return false;
+
+ // find the implicit import
+ for (quint32 i = 0; i < m_compiledData->data->nImports; ++i) {
+ const QV4::CompiledData::Import *import = m_compiledData->data->importAt(i);
+ if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".")
+ && import->qualifierIndex == 0
+ && import->majorVersion == -1
+ && import->minorVersion == -1) {
+ QList<QQmlError> errors;
+ if (!fetchQmldir(qmldirUrl, import, 1, &errors)) {
+ setError(errors);
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ for (int i = 0, count = m_compiledData->data->nImports; i < count; ++i) {
+ const QV4::CompiledData::Import *import = m_compiledData->data->importAt(i);
+ QList<QQmlError> errors;
+ if (!addImport(import, &errors)) {
+ Q_ASSERT(errors.size());
+ QQmlError error(errors.takeFirst());
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error); // put it back on the list after filling out information.
+ setError(errors);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void QQmlTypeData::rebuildTypeAndPropertyCaches()
+{
+ Q_ASSERT(m_compiledData);
+
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+
+ {
+ QQmlCompileError error = buildTypeResolutionCaches(&m_compiledData->importCache, &m_compiledData->resolvedTypes);
+ if (error.isSet()) {
+ setError(error);
+ return;
+ }
+ }
+
+ {
+ QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(&m_compiledData->propertyCaches, engine, m_compiledData, &m_importCache);
+ QQmlCompileError error = propertyCacheCreator.buildMetaObjects();
+ if (error.isSet()) {
+ setError(error);
+ return;
+ }
+ }
+
+ QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> aliasCreator(&m_compiledData->propertyCaches, m_compiledData);
+ aliasCreator.appendAliasPropertiesToMetaObjects();
+}
+
void QQmlTypeData::done()
{
+ auto cleanup = defer([this]{
+ m_document.reset();
+ m_typeReferences.clear();
+ if (isError())
+ m_compiledData = nullptr;
+ });
+
+ if (isError())
+ return;
+
// Check all script dependencies for errors
- for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ for (int ii = 0; ii < m_scripts.count(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
Q_ASSERT(script.script->isCompleteOrError());
if (script.script->isError()) {
@@ -2063,16 +2184,17 @@ void QQmlTypeData::done()
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
errors.prepend(error);
setError(errors);
+ return;
}
}
// Check all type dependencies for errors
- for (QHash<int, TypeReference>::ConstIterator it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
- !isError() && it != end; ++it) {
+ for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
+ ++it) {
const TypeReference &type = *it;
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
if (type.typeData && type.typeData->isError()) {
- QString typeName = m_document->stringAt(it.key());
+ const QString typeName = stringAt(it.key());
QList<QQmlError> errors = type.typeData->errors();
QQmlError error;
@@ -2082,11 +2204,12 @@ void QQmlTypeData::done()
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
errors.prepend(error);
setError(errors);
+ return;
}
}
// Check all composite singleton type dependencies for errors
- for (int ii = 0; !isError() && ii < m_compositeSingletons.count(); ++ii) {
+ for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) {
const TypeReference &type = m_compositeSingletons.at(ii);
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
if (type.typeData && type.typeData->isError()) {
@@ -2100,27 +2223,81 @@ void QQmlTypeData::done()
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
errors.prepend(error);
setError(errors);
+ return;
}
}
- // If the type is CompositeSingleton but there was no pragma Singleton in the
- // QML file, lets report an error.
- QQmlType *type = QQmlMetaType::qmlType(url(), true);
- if (!isError() && type && type->isCompositeSingleton() && !m_isSingleton) {
- QString typeName = type->qmlTypeName();
+ if (!m_document.isNull()) {
+ // Compile component
+ compile();
+ } else {
+ rebuildTypeAndPropertyCaches();
+ }
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
- error.setUrl(finalUrl());
- setError(error);
+ if (isError())
+ return;
+
+ {
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+ {
+ // Sanity check property bindings
+ QQmlPropertyValidator validator(engine, m_importCache, m_compiledData);
+ QVector<QQmlCompileError> errors = validator.validate();
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ }
+
+ m_compiledData->finalize(engine);
}
- // Compile component
- if (!isError())
- compile();
+ {
+ QQmlType *type = QQmlMetaType::qmlType(finalUrl(), true);
+ if (m_compiledData && m_compiledData->data->flags & QV4::CompiledData::Unit::IsSingleton) {
+ if (!type) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
+ setError(error);
+ return;
+ } else if (!type->isCompositeSingleton()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type->qmlTypeName()));
+ setError(error);
+ return;
+ }
+ } else {
+ // If the type is CompositeSingleton but there was no pragma Singleton in the
+ // QML file, lets report an error.
+ if (type && type->isCompositeSingleton()) {
+ QString typeName = type->qmlTypeName();
+ setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
+ return;
+ }
+ }
+ }
+
+ {
+ // Collect imported scripts
+ m_compiledData->dependentScripts.reserve(m_scripts.count());
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
+
+ QStringRef qualifier(&script.qualifier);
+ QString enclosingNamespace;
+
+ const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
+ if (lastDotIndex != -1) {
+ enclosingNamespace = qualifier.left(lastDotIndex).toString();
+ qualifier = qualifier.mid(lastDotIndex+1);
+ }
- m_document.reset();
- m_implicitImport = 0;
+ m_compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ QQmlScriptData *scriptData = script.script->scriptData();
+ scriptData->addref();
+ m_compiledData->dependentScripts << scriptData;
+ }
+ }
}
void QQmlTypeData::completed()
@@ -2155,9 +2332,19 @@ bool QQmlTypeData::loadImplicitImport()
void QQmlTypeData::dataReceived(const Data &data)
{
- QString code = QString::fromUtf8(data.data(), data.size());
+ if (tryLoadFromDiskCache())
+ return;
+
+ qint64 sourceTimeStamp;
+ QString error;
+ QString code = QString::fromUtf8(data.readAll(&error, &sourceTimeStamp));
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
QQmlEngine *qmlEngine = typeLoader()->engine();
- m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0));
+ m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger() != 0));
+ m_document->jsModule.sourceTimeStamp = sourceTimeStamp;
QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames());
if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) {
QList<QQmlError> errors;
@@ -2180,14 +2367,14 @@ void QQmlTypeData::dataReceived(const Data &data)
void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
{
QQmlEngine *qmlEngine = typeLoader()->engine();
- m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0));
+ m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger() != 0));
unit->loadIR(m_document.data(), unit);
continueLoadFromIR();
}
void QQmlTypeData::continueLoadFromIR()
{
- m_document->collectTypeReferences();
+ m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
m_importCache.setBaseUrl(finalUrl(), finalUrlString());
// For remote URLs, we don't delay the loading of the implicit import
@@ -2200,14 +2387,14 @@ void QQmlTypeData::continueLoadFromIR()
return;
// This qmldir is for the implicit import
QQmlJS::MemoryPool *pool = m_document->jsParserEngine.pool();
- m_implicitImport = pool->New<QV4::CompiledData::Import>();
- m_implicitImport->uriIndex = m_document->registerString(QLatin1String("."));
- m_implicitImport->qualifierIndex = 0; // empty string
- m_implicitImport->majorVersion = -1;
- m_implicitImport->minorVersion = -1;
+ auto implicitImport = pool->New<QV4::CompiledData::Import>();
+ implicitImport->uriIndex = m_document->registerString(QLatin1String("."));
+ implicitImport->qualifierIndex = 0; // empty string
+ implicitImport->majorVersion = -1;
+ implicitImport->minorVersion = -1;
QList<QQmlError> errors;
- if (!fetchQmldir(qmldirUrl, m_implicitImport, 1, &errors)) {
+ if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
setError(errors);
return;
}
@@ -2228,14 +2415,6 @@ void QQmlTypeData::continueLoadFromIR()
return;
}
}
-
- foreach (QmlIR::Pragma *pragma, m_document->pragmas) {
- if (!addPragma(*pragma, &errors)) {
- Q_ASSERT(errors.size());
- setError(errors);
- return;
- }
- }
}
void QQmlTypeData::allDependenciesDone()
@@ -2280,20 +2459,34 @@ void QQmlTypeData::downloadProgressChanged(qreal p)
QString QQmlTypeData::stringAt(int index) const
{
+ if (m_compiledData)
+ return m_compiledData->stringAt(index);
return m_document->jsGenerator.stringTable.stringForIndex(index);
}
void QQmlTypeData::compile()
{
- Q_ASSERT(m_compiledData == 0);
+ Q_ASSERT(m_compiledData.isNull());
- m_compiledData = new QQmlCompiledData(typeLoader()->engine());
+ QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
+ QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache);
+ if (error.isSet()) {
+ setError(error);
+ return;
+ }
- QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data());
- if (!compiler.compile()) {
+ QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), this, m_document.data(), importCache, resolvedTypeCache);
+ m_compiledData = compiler.compile();
+ if (!m_compiledData) {
setError(compiler.compilationErrors());
- m_compiledData->release();
- m_compiledData = 0;
+ return;
+ }
+ if (diskCache() || forceDiskCacheRefresh()) {
+ QString errorString;
+ if (!m_compiledData->saveToDisk(&errorString)) {
+ qDebug() << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString;
+ }
}
}
@@ -2346,7 +2539,7 @@ void QQmlTypeData::resolveTypes()
}
}
- for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_document->typeReferences.constBegin(), end = m_document->typeReferences.constEnd();
+ for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
unresolvedRef != end; ++unresolvedRef) {
TypeReference ref; // resolved reference
@@ -2416,6 +2609,57 @@ void QQmlTypeData::resolveTypes()
}
}
+QQmlCompileError QQmlTypeData::buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const
+{
+ importCache->adopt(new QQmlTypeNameCache);
+
+ for (const QString &ns: m_namespaces)
+ (*importCache)->add(ns);
+
+ // Add any Composite Singletons that were used to the import cache
+ for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
+ (*importCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
+
+ m_importCache.populateCache(*importCache);
+
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+
+ for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
+ QScopedPointer<QV4::CompiledData::ResolvedTypeReference> ref(new QV4::CompiledData::ResolvedTypeReference);
+ QQmlType *qmlType = resolvedType->type;
+ if (resolvedType->typeData) {
+ if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) {
+ return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName()));
+ }
+ ref->compilationUnit = resolvedType->typeData->compilationUnit();
+ } else if (qmlType) {
+ ref->type = qmlType;
+ Q_ASSERT(ref->type);
+
+ if (resolvedType->needsCreation && !ref->type->isCreatable()) {
+ QString reason = ref->type->noCreationReason();
+ if (reason.isEmpty())
+ reason = tr("Element is not creatable.");
+ return QQmlCompileError(resolvedType->location, reason);
+ }
+
+ if (ref->type->containsRevisionedAttributes()) {
+ ref->typePropertyCache = engine->cache(ref->type,
+ resolvedType->minorVersion);
+ }
+ }
+ ref->majorVersion = resolvedType->majorVersion;
+ ref->minorVersion = resolvedType->minorVersion;
+ ref->doDynamicTypeCheck();
+ resolvedTypeCache->insert(resolvedType.key(), ref.take());
+ }
+ QQmlCompileError noError;
+ return noError;
+}
+
bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref)
{
QQmlImportNamespace *typeNamespace = 0;
@@ -2537,10 +2781,6 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
ctxt->importedScripts = effectiveCtxt->importedScripts;
}
- if (ctxt->imports) {
- ctxt->imports->addref();
- }
-
if (effectiveCtxt) {
ctxt->setParent(effectiveCtxt, true);
} else {
@@ -2628,10 +2868,29 @@ struct EmptyCompilationUnit : public QV4::CompiledData::CompilationUnit
void QQmlScriptBlob::dataReceived(const Data &data)
{
- QString source = QString::fromUtf8(data.data(), data.size());
-
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
- QmlIR::Document irUnit(v4->debugger != 0);
+
+ if (diskCache() && !forceDiskCacheRefresh()) {
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
+ QString error;
+ if (unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) {
+ initializeFromCompilationUnit(unit);
+ return;
+ } else {
+ qDebug() << "Error loading" << url().toString() << "from disk cache:" << error;
+ }
+ }
+
+
+ QmlIR::Document irUnit(v4->debugger() != 0);
+
+ QString error;
+ QString source = QString::fromUtf8(data.readAll(&error, &irUnit.jsModule.sourceTimeStamp));
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
+
QmlIR::ScriptDirectivesCollector collector(&irUnit.jsParserEngine, &irUnit.jsGenerator);
QList<QQmlError> errors;
@@ -2656,6 +2915,13 @@ void QQmlScriptBlob::dataReceived(const Data &data)
// The js unit owns the data and will free the qml unit.
unit->data = unitData;
+ if (diskCache() || forceDiskCacheRefresh()) {
+ QString errorString;
+ if (!unit->saveToDisk(&errorString)) {
+ qDebug() << "Error saving cached version of" << unit->url().toString() << "to disk:" << errorString;
+ }
+ }
+
initializeFromCompilationUnit(unit);
}
@@ -2666,8 +2932,11 @@ void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *
void QQmlScriptBlob::done()
{
+ if (isError())
+ return;
+
// Check all script dependencies for errors
- for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ for (int ii = 0; ii < m_scripts.count(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
Q_ASSERT(script.script->isCompleteOrError());
if (script.script->isError()) {
@@ -2679,17 +2948,15 @@ void QQmlScriptBlob::done()
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
errors.prepend(error);
setError(errors);
+ return;
}
}
- if (isError())
- return;
-
m_scriptData->importCache = new QQmlTypeNameCache();
QSet<QString> ns;
- for (int scriptIndex = 0; !isError() && scriptIndex < m_scripts.count(); ++scriptIndex) {
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
const ScriptReference &script = m_scripts.at(scriptIndex);
m_scriptData->scripts.append(script.script);
@@ -2783,7 +3050,12 @@ void QQmlQmldirData::setPriority(int priority)
void QQmlQmldirData::dataReceived(const Data &data)
{
- m_content = QString::fromUtf8(data.data(), data.size());
+ QString error;
+ m_content = QString::fromUtf8(data.readAll(&error));
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
}
void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *)
@@ -2791,6 +3063,30 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *
Q_UNIMPLEMENTED();
}
+QByteArray QQmlDataBlob::Data::readAll(QString *error, qint64 *sourceTimeStamp) const
+{
+ Q_ASSERT(!d.isNull());
+ error->clear();
+ if (d.isT1()) {
+ if (sourceTimeStamp)
+ *sourceTimeStamp = 0;
+ return *d.asT1();
+ }
+ QFile f(*d.asT2());
+ if (!f.open(QIODevice::ReadOnly)) {
+ *error = f.errorString();
+ return QByteArray();
+ }
+ if (sourceTimeStamp)
+ *sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch();
+ QByteArray data(f.size(), Qt::Uninitialized);
+ if (f.read(data.data(), data.length()) != data.length()) {
+ *error = f.errorString();
+ return QByteArray();
+ }
+ return data;
+}
+
QT_END_NAMESPACE
#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 51228eacc7..ab6b046fcf 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -53,7 +53,9 @@
#include <QtCore/qobject.h>
#include <QtCore/qatomic.h>
+#ifndef QT_NO_NETWORK
#include <QtNetwork/qnetworkreply.h>
+#endif
#include <QtQml/qqmlerror.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlfile.h>
@@ -75,11 +77,11 @@ class QQmlScriptData;
class QQmlScriptBlob;
class QQmlQmldirData;
class QQmlTypeLoader;
-class QQmlCompiledData;
class QQmlComponentPrivate;
class QQmlTypeData;
class QQmlTypeLoader;
class QQmlExtensionInterface;
+struct QQmlCompileError;
namespace QmlIR {
struct Document;
@@ -129,34 +131,32 @@ public:
class Data {
public:
- inline const char *data() const;
- inline int size() const;
-
- inline QByteArray asByteArray() const;
-
- inline bool isFile() const;
- inline QQmlFile *asFile() const;
-
+ QByteArray readAll(QString *error, qint64 *sourceTimeStamp = 0) const;
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoader;
inline Data();
Data(const Data &);
Data &operator=(const Data &);
- QBiPointer<const QByteArray, QQmlFile> d;
+ QBiPointer<const QByteArray, const QString> d;
};
protected:
// Can be called from within callbacks
void setError(const QQmlError &);
void setError(const QList<QQmlError> &errors);
+ void setError(const QQmlCompileError &error);
+ void setError(const QVector<QQmlCompileError> &errors);
+ void setError(const QString &description);
void addDependency(QQmlDataBlob *);
// Callbacks made in load thread
virtual void dataReceived(const Data &) = 0;
virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) = 0;
virtual void done();
+#ifndef QT_NO_NETWORK
virtual void networkError(QNetworkReply::NetworkError);
+#endif
virtual void dependencyError(QQmlDataBlob *);
virtual void dependencyComplete(QQmlDataBlob *);
virtual void allDependenciesDone();
@@ -233,7 +233,6 @@ public:
protected:
bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
- bool addPragma(const QmlIR::Pragma &pragma, QList<QQmlError> *errors);
bool fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors);
bool updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
@@ -250,7 +249,6 @@ public:
virtual QString stringAt(int) const { return QString(); }
QQmlImports m_importCache;
- bool m_isSingleton;
QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
QList<QQmlQmldirData *> m_qmldirs;
};
@@ -320,20 +318,24 @@ public:
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoaderThread;
+#ifndef QT_NO_NETWORK
friend class QQmlTypeLoaderNetworkReplyProxy;
+#endif // QT_NO_NETWORK
void shutdownThread();
void loadThread(QQmlDataBlob *);
void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
void loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
+#ifndef QT_NO_NETWORK
void networkReplyFinished(QNetworkReply *);
void networkReplyProgress(QNetworkReply *, qint64, qint64);
typedef QHash<QNetworkReply *, QQmlDataBlob *> NetworkReplies;
+#endif
void setData(QQmlDataBlob *, const QByteArray &);
- void setData(QQmlDataBlob *, QQmlFile *);
+ void setData(QQmlDataBlob *, const QString &fileName);
void setData(QQmlDataBlob *, const QQmlDataBlob::Data &);
void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
@@ -362,7 +364,9 @@ private:
QQmlEngine *m_engine;
QQmlTypeLoaderThread *m_thread;
+#ifndef QT_NO_NETWORK
NetworkReplies m_networkReplies;
+#endif
TypeCache m_typeCache;
int m_typeCacheTrimThreshold;
ScriptCache m_scriptCache;
@@ -381,6 +385,7 @@ private:
class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
{
+ Q_DECLARE_TR_FUNCTIONS(QQmlTypeData)
public:
struct TypeReference
{
@@ -412,13 +417,9 @@ private:
public:
~QQmlTypeData();
- const QHash<int, TypeReference> &resolvedTypeRefs() const { return m_resolvedTypes; }
-
const QList<ScriptReference> &resolvedScripts() const;
- const QSet<QString> &namespaces() const;
- const QList<TypeReference> &compositeSingletons() const;
- QQmlCompiledData *compiledData() const;
+ QV4::CompiledData::CompilationUnit *compilationUnit() const;
// Used by QQmlComponent to get notifications
struct TypeDataCallback {
@@ -440,14 +441,21 @@ protected:
virtual QString stringAt(int index) const;
private:
+ bool tryLoadFromDiskCache();
void continueLoadFromIR();
void resolveTypes();
+ QQmlCompileError buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const;
void compile();
+ void rebuildTypeAndPropertyCaches();
bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref);
virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace);
QScopedPointer<QmlIR::Document> m_document;
+ QV4::CompiledData::TypeReferenceMap m_typeReferences;
QList<ScriptReference> m_scripts;
@@ -458,11 +466,10 @@ private:
QHash<int, TypeReference> m_resolvedTypes;
bool m_typesResolved:1;
- QQmlCompiledData *m_compiledData;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compiledData;
QList<TypeDataCallback *> m_callbacks;
- QV4::CompiledData::Import *m_implicitImport;
bool m_implicitImportLoaded;
bool loadImplicitImport();
};
@@ -572,40 +579,7 @@ QQmlDataBlob::Data::Data()
{
}
-const char *QQmlDataBlob::Data::data() const
-{
- Q_ASSERT(!d.isNull());
-
- if (d.isT1()) return d.asT1()->constData();
- else return d.asT2()->data();
-}
-
-int QQmlDataBlob::Data::size() const
-{
- Q_ASSERT(!d.isNull());
-
- if (d.isT1()) return d.asT1()->size();
- else return d.asT2()->size();
-}
-
-bool QQmlDataBlob::Data::isFile() const
-{
- return d.isT2();
-}
-
-QByteArray QQmlDataBlob::Data::asByteArray() const
-{
- Q_ASSERT(!d.isNull());
-
- if (d.isT1()) return *d.asT1();
- else return d.asT2()->dataByteArray();
-}
-QQmlFile *QQmlDataBlob::Data::asFile() const
-{
- if (d.isT2()) return d.asT2();
- else return 0;
-}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index 44fd47244d..8e87ec7f63 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -219,7 +219,7 @@ void QQmlValueType::read(QObject *obj, int idx)
QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
}
-void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyPrivate::WriteFlags flags)
+void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags)
{
Q_ASSERT(gadgetPtr);
int status = -1;
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 910d39cf0a..11e1dfdb00 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -69,7 +69,7 @@ public:
QQmlValueType(int userType, const QMetaObject *metaObject);
~QQmlValueType();
void read(QObject *, int);
- void write(QObject *, int, QQmlPropertyPrivate::WriteFlags flags);
+ void write(QObject *, int, QQmlPropertyData::WriteFlags flags);
QVariant value();
void setValue(const QVariant &);
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
index 6858215a79..595cd01d05 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp
+++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
@@ -58,7 +58,7 @@ QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding()
}
}
-void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
+void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
{
QQmlAbstractBinding *b = m_bindings.data();
while (b) {
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
index de5acc2984..6e297bb3ea 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h
+++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
@@ -63,7 +63,7 @@ public:
QQmlAbstractBinding *binding(int targetPropertyIndex);
void removeBindings(quint32 mask);
- virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags);
+ virtual void setEnabled(bool, QQmlPropertyData::WriteFlags);
virtual bool isValueTypeProxy() const;
protected:
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 04a556f46c..b69eea61c5 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -50,6 +50,7 @@
#include <private/qv4functionobject_p.h>
#include <private/qv4variantobject_p.h>
#include <private/qv4alloca_p.h>
+#include <private/qv4objectiterator_p.h>
#include <private/qv4qobjectwrapper_p.h>
QT_BEGIN_NAMESPACE
@@ -245,6 +246,34 @@ PropertyAttributes QQmlValueTypeWrapper::query(const Managed *m, String *name)
return result ? Attr_Data : Attr_Invalid;
}
+void QQmlValueTypeWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
+{
+ name->setM(0);
+ *index = UINT_MAX;
+
+ QQmlValueTypeWrapper *that = static_cast<QQmlValueTypeWrapper*>(m);
+
+ if (QQmlValueTypeReference *ref = that->as<QQmlValueTypeReference>()) {
+ if (!ref->readReferenceValue())
+ return;
+ }
+
+ if (that->d()->propertyCache) {
+ const QMetaObject *mo = that->d()->propertyCache->createMetaObject();
+ const int propertyCount = mo->propertyCount();
+ if (it->arrayIndex < static_cast<uint>(propertyCount)) {
+ Scope scope(that->engine());
+ ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name())));
+ name->setM(propName->d());
+ ++it->arrayIndex;
+ *attributes = QV4::Attr_Data;
+ p->value = that->QV4::Object::get(propName);
+ return;
+ }
+ }
+ QV4::Object::advanceIterator(m, it, name, index, p, attributes);
+}
+
bool QQmlValueTypeWrapper::isEqual(const QVariant& value)
{
if (QQmlValueTypeReference *ref = as<QQmlValueTypeReference>())
@@ -303,8 +332,7 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx)
if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->typeId, &convertResult, QMetaType::QString)) {
result = convertResult;
} else {
- result = QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId));
- result += QLatin1Char('(');
+ result = QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId)) + QLatin1Char('(');
const QMetaObject *mo = w->d()->propertyCache->metaObject();
const int propCount = mo->propertyCount();
for (int i = 0; i < propCount; ++i) {
@@ -431,7 +459,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
bindingFunction->initBindingLocation();
- QQmlBinding *newBinding = new QQmlBinding(value, reference->d()->object, context);
+ QQmlBinding *newBinding = QQmlBinding::create(&cacheData, value, reference->d()->object, context);
newBinding->setTarget(reference->d()->object, cacheData);
QQmlPropertyPrivate::setBinding(newBinding);
return;
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index c2861f5bfa..94eeba366a 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -99,6 +99,7 @@ public:
static void put(Managed *m, String *name, const Value &value);
static bool isEqualTo(Managed *m, Managed *other);
static PropertyAttributes query(const Managed *, String *name);
+ static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static QV4::ReturnedValue method_toString(CallContext *ctx);
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 5f9fa69944..01c4f476d6 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -39,7 +39,6 @@
#include "qqmlvme_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlboundsignal_p.h"
#include "qqmlstringconverters_p.h"
#include <private/qmetaobjectbuilder_p.h>
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index ac9db5c046..99d63380ad 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -69,7 +69,6 @@ QT_BEGIN_NAMESPACE
class QObject;
class QJSValue;
class QQmlScriptData;
-class QQmlCompiledData;
class QQmlContextData;
namespace QQmlVMETypes {
@@ -84,10 +83,9 @@ namespace QQmlVMETypes {
struct State {
enum Flag { Deferred = 0x00000001 };
- State() : flags(0), context(0), compiledData(0), instructionStream(0) {}
+ State() : flags(0), context(0), instructionStream(0) {}
quint32 flags;
QQmlContextData *context;
- QQmlCompiledData *compiledData;
const char *instructionStream;
QBitField bindingSkipList;
};
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 775309d04a..d5001674ad 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -59,6 +59,32 @@
QT_BEGIN_NAMESPACE
+static void list_append(QQmlListProperty<QObject> *prop, QObject *o)
+{
+ QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
+ list->append(o);
+ static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), 0);
+}
+
+static int list_count(QQmlListProperty<QObject> *prop)
+{
+ QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
+ return list->count();
+}
+
+static QObject *list_at(QQmlListProperty<QObject> *prop, int index)
+{
+ QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
+ return list->at(index);
+}
+
+static void list_clear(QQmlListProperty<QObject> *prop)
+{
+ QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
+ list->clear();
+ static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), 0);
+}
+
QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
: QQmlGuard<QObject>(0), m_target(0), m_index(-1)
{
@@ -74,10 +100,10 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
return;
if (m_index >= 0) {
- QV4::ExecutionEngine *v4 = m_target->properties.engine();
+ QV4::ExecutionEngine *v4 = m_target->propertyAndMethodStorage.engine();
if (v4) {
QV4::Scope scope(v4);
- QV4::Scoped<QV4::MemberData> sp(scope, m_target->properties.value());
+ QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value());
if (sp)
*(sp->data() + m_index) = QV4::Primitive::nullValue();
}
@@ -115,22 +141,32 @@ void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **)
void QQmlVMEMetaObjectEndpoint::tryConnect()
{
+ Q_ASSERT(metaObject->compiledObject);
int aliasId = this - metaObject->aliasEndpoints;
if (metaObject.flag()) {
// This is actually notify
- int sigIdx = metaObject->methodOffset() + aliasId + metaObject->metaData->propertyCount;
+ int sigIdx = metaObject->methodOffset() + aliasId + metaObject->compiledObject->nProperties;
metaObject->activate(metaObject->object, sigIdx, 0);
} else {
- QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId;
- if (!d->isObjectAlias()) {
+ const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId];
+ if (!aliasData->isObjectAlias()) {
QQmlContextData *ctxt = metaObject->ctxt;
- QObject *target = ctxt->idValues[d->contextIdx].data();
+ QObject *target = ctxt->idValues[aliasData->targetObjectId].data();
if (!target)
return;
- if (d->notifySignal != -1)
- connect(target, d->notifySignal, ctxt->engine);
+ QQmlData *targetDData = QQmlData::get(target, /*create*/false);
+ if (!targetDData)
+ return;
+ int coreIndex;
+ QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, &coreIndex);
+ const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
+ if (!pd)
+ return;
+
+ if (pd->notifyIndex != -1)
+ connect(target, pd->notifyIndex, ctxt->engine);
}
metaObject.setFlag();
@@ -184,7 +220,7 @@ int QQmlInterceptorMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id,
bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
{
if (c == QMetaObject::WriteProperty && interceptors &&
- !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyPrivate::BypassInterceptor)) {
+ !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)) {
for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
if (vi->m_coreIndex != id)
@@ -242,7 +278,7 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
bool updated = false;
if (newComponentValue != prevComponentValue) {
valueProp.write(valueType, prevComponentValue);
- valueType->write(object, id, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
+ valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
vi->write(newComponentValue);
updated = true;
@@ -278,136 +314,124 @@ QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObje
}
QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
- QQmlPropertyCache *cache,
- const QQmlVMEMetaData *meta)
+ QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId)
: QQmlInterceptorMetaObject(obj, cache),
- ctxt(QQmlData::get(obj, true)->outerContext), metaData(meta),
- aliasEndpoints(0),
- methods(0)
+ ctxt(QQmlData::get(obj, true)->outerContext),
+ aliasEndpoints(0), compilationUnit(qmlCompilationUnit), compiledObject(0)
{
- cache->addref();
-
QQmlData::get(obj)->hasVMEMetaObject = true;
- int qobject_type = qMetaTypeId<QObject*>();
- int variant_type = qMetaTypeId<QVariant>();
- // Need JS wrapper to ensure properties are marked.
- // ### FIXME: I hope that this can be removed once we have the proper scope chain
- // set up and the JS wrappers always exist.
- bool needsJSWrapper = (metaData->propertyCount > 0);
-
- // ### Optimize
- for (int ii = 0; ii < metaData->propertyCount; ++ii) {
- int t = (metaData->propertyData() + ii)->propertyType;
- if (t == qobject_type || t == variant_type) {
- needsJSWrapper = true;
- break;
+ if (compilationUnit && qmlObjectId >= 0) {
+ compiledObject = compilationUnit->data->objectAt(qmlObjectId);
+
+ if (compiledObject->nProperties || compiledObject->nFunctions) {
+ Q_ASSERT(cache && cache->engine);
+ QV4::ExecutionEngine *v4 = cache->engine;
+ QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, compiledObject->nProperties + compiledObject->nFunctions);
+ propertyAndMethodStorage.set(v4, data);
+ std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
+
+ // Need JS wrapper to ensure properties/methods are marked.
+ ensureQObjectWrapper();
}
}
-
- if (needsJSWrapper)
- ensureQObjectWrapper();
}
QQmlVMEMetaObject::~QQmlVMEMetaObject()
{
if (parent.isT1()) parent.asT1()->objectDestroyed(object);
delete [] aliasEndpoints;
- delete [] methods;
qDeleteAll(varObjectGuards);
-
- cache->release();
}
-QV4::MemberData *QQmlVMEMetaObject::propertiesAsMemberData()
+QV4::MemberData *QQmlVMEMetaObject::propertyAndMethodStorageAsMemberData()
{
- if (properties.isUndefined()) {
- if (properties.valueRef())
+ if (propertyAndMethodStorage.isUndefined()) {
+ if (propertyAndMethodStorage.valueRef())
// in some situations, the QObject wrapper (and associated data,
// such as the varProperties array) will have been cleaned up, but the
// QObject ptr will not yet have been deleted (eg, waiting on deleteLater).
// In this situation, return 0.
return 0;
- allocateProperties();
}
- return static_cast<QV4::MemberData*>(properties.asManaged());
+ return static_cast<QV4::MemberData*>(propertyAndMethodStorage.asManaged());
}
void QQmlVMEMetaObject::writeProperty(int id, int v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = QV4::Primitive::fromInt32(v);
}
void QQmlVMEMetaObject::writeProperty(int id, bool v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = QV4::Primitive::fromBoolean(v);
}
void QQmlVMEMetaObject::writeProperty(int id, double v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = QV4::Primitive::fromDouble(v);
}
void QQmlVMEMetaObject::writeProperty(int id, const QString& v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newString(v);
}
void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QDate& v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = QV4::QObjectWrapper::wrap(cache->engine, v);
@@ -422,7 +446,7 @@ void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
int QQmlVMEMetaObject::readPropertyAsInt(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return 0;
@@ -435,7 +459,7 @@ int QQmlVMEMetaObject::readPropertyAsInt(int id)
bool QQmlVMEMetaObject::readPropertyAsBool(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return false;
@@ -448,7 +472,7 @@ bool QQmlVMEMetaObject::readPropertyAsBool(int id)
double QQmlVMEMetaObject::readPropertyAsDouble(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return 0.0;
@@ -461,7 +485,7 @@ double QQmlVMEMetaObject::readPropertyAsDouble(int id)
QString QQmlVMEMetaObject::readPropertyAsString(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QString();
@@ -474,7 +498,7 @@ QString QQmlVMEMetaObject::readPropertyAsString(int id)
QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QUrl();
@@ -488,7 +512,7 @@ QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id)
QDate QQmlVMEMetaObject::readPropertyAsDate(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QDate();
@@ -502,7 +526,7 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id)
QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QDateTime();
@@ -516,7 +540,7 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QSizeF();
@@ -530,7 +554,7 @@ QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id)
QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QPointF();
@@ -544,7 +568,7 @@ QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id)
QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return 0;
@@ -558,7 +582,7 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id)
QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return 0;
@@ -574,7 +598,7 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id)
QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QRectF();
@@ -596,15 +620,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (intercept(c, _id, a))
return -1;
+ const int propertyCount = compiledObject ? int(compiledObject->nProperties) : 0;
+ const int aliasCount = compiledObject ? int(compiledObject->nAliases) : 0;
+ const int signalCount = compiledObject ? int(compiledObject->nSignals) : 0;
+ const int methodCount = compiledObject ? int(compiledObject->nFunctions) : 0;
+
if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
if (id >= propOffset()) {
id -= propOffset();
- if (id < metaData->propertyCount) {
- int t = (metaData->propertyData() + id)->propertyType;
+ if (id < propertyCount) {
+ const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(qint32(compiledObject->propertyTable()[id].type));
bool needActivate = false;
- if (t == QQmlVMEMetaData::VarPropertyType) {
+ if (t == QV4::CompiledData::Property::Var) {
// the context can be null if accessing var properties from cpp after re-parenting an item.
QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine);
QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine();
@@ -620,132 +649,180 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
}
} else {
+ int fallbackMetaType = QMetaType::UnknownType;
+ switch (t) {
+ case QV4::CompiledData::Property::Font:
+ fallbackMetaType = QMetaType::QFont;
+ break;
+ case QV4::CompiledData::Property::Time:
+ fallbackMetaType = QMetaType::QTime;
+ break;
+ case QV4::CompiledData::Property::Color:
+ fallbackMetaType = QMetaType::QColor;
+ break;
+ case QV4::CompiledData::Property::Vector2D:
+ fallbackMetaType = QMetaType::QVector2D;
+ break;
+ case QV4::CompiledData::Property::Vector3D:
+ fallbackMetaType = QMetaType::QVector3D;
+ break;
+ case QV4::CompiledData::Property::Vector4D:
+ fallbackMetaType = QMetaType::QVector4D;
+ break;
+ case QV4::CompiledData::Property::Matrix4x4:
+ fallbackMetaType = QMetaType::QMatrix4x4;
+ break;
+ case QV4::CompiledData::Property::Quaternion:
+ fallbackMetaType = QMetaType::QQuaternion;
+ break;
+ default: break;
+ }
+
if (c == QMetaObject::ReadProperty) {
- switch(t) {
- case QVariant::Int:
+ switch (t) {
+ case QV4::CompiledData::Property::Int:
*reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
break;
- case QVariant::Bool:
+ case QV4::CompiledData::Property::Bool:
*reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
break;
- case QVariant::Double:
+ case QV4::CompiledData::Property::Real:
*reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
break;
- case QVariant::String:
+ case QV4::CompiledData::Property::String:
*reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
break;
- case QVariant::Url:
+ case QV4::CompiledData::Property::Url:
*reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id);
break;
- case QVariant::Date:
+ case QV4::CompiledData::Property::Date:
*reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id);
break;
- case QVariant::DateTime:
+ case QV4::CompiledData::Property::DateTime:
*reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id);
break;
- case QVariant::RectF:
+ case QV4::CompiledData::Property::Rect:
*reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id);
break;
- case QVariant::SizeF:
+ case QV4::CompiledData::Property::Size:
*reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id);
break;
- case QVariant::PointF:
+ case QV4::CompiledData::Property::Point:
*reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id);
break;
- case QMetaType::QObjectStar:
+ case QV4::CompiledData::Property::Custom:
*reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
break;
- case QMetaType::QVariant:
+ case QV4::CompiledData::Property::Variant:
*reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
break;
- default:
- {
- if (t == qMetaTypeId<QQmlListProperty<QObject> >()) {
- QList<QObject *> *list = readPropertyAsList(id);
- QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]);
- *p = QQmlListProperty<QObject>(object, list,
- list_append, list_count, list_at,
- list_clear);
- p->dummy1 = this;
- p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id));
- } else {
- QV4::MemberData *md = propertiesAsMemberData();
- if (md) {
- QVariant propertyAsVariant;
- if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
- propertyAsVariant = v->d()->data;
- QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], t);
- }
- }
+ case QV4::CompiledData::Property::CustomList: {
+ QList<QObject *> *list = readPropertyAsList(id);
+ QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]);
+ *p = QQmlListProperty<QObject>(object, list,
+ list_append, list_count, list_at,
+ list_clear);
+ p->dummy1 = this;
+ p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id));
break;
}
+ case QV4::CompiledData::Property::Font:
+ case QV4::CompiledData::Property::Time:
+ case QV4::CompiledData::Property::Color:
+ case QV4::CompiledData::Property::Vector2D:
+ case QV4::CompiledData::Property::Vector3D:
+ case QV4::CompiledData::Property::Vector4D:
+ case QV4::CompiledData::Property::Matrix4x4:
+ case QV4::CompiledData::Property::Quaternion:
+ Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
+ if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ QVariant propertyAsVariant;
+ if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
+ propertyAsVariant = v->d()->data;
+ QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType);
+ }
+ break;
+ case QV4::CompiledData::Property::Var:
+ Q_UNREACHABLE();
}
} else if (c == QMetaObject::WriteProperty) {
switch(t) {
- case QVariant::Int:
+ case QV4::CompiledData::Property::Int:
needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id);
writeProperty(id, *reinterpret_cast<int *>(a[0]));
break;
- case QVariant::Bool:
+ case QV4::CompiledData::Property::Bool:
needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id);
writeProperty(id, *reinterpret_cast<bool *>(a[0]));
break;
- case QVariant::Double:
+ case QV4::CompiledData::Property::Real:
needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id);
writeProperty(id, *reinterpret_cast<double *>(a[0]));
break;
- case QVariant::String:
+ case QV4::CompiledData::Property::String:
needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id);
writeProperty(id, *reinterpret_cast<QString *>(a[0]));
break;
- case QVariant::Url:
+ case QV4::CompiledData::Property::Url:
needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id);
writeProperty(id, *reinterpret_cast<QUrl *>(a[0]));
break;
- case QVariant::Date:
+ case QV4::CompiledData::Property::Date:
needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id);
writeProperty(id, *reinterpret_cast<QDate *>(a[0]));
break;
- case QVariant::DateTime:
+ case QV4::CompiledData::Property::DateTime:
needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id);
writeProperty(id, *reinterpret_cast<QDateTime *>(a[0]));
break;
- case QVariant::RectF:
+ case QV4::CompiledData::Property::Rect:
needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id);
writeProperty(id, *reinterpret_cast<QRectF *>(a[0]));
break;
- case QVariant::SizeF:
+ case QV4::CompiledData::Property::Size:
needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id);
writeProperty(id, *reinterpret_cast<QSizeF *>(a[0]));
break;
- case QVariant::PointF:
+ case QV4::CompiledData::Property::Point:
needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id);
writeProperty(id, *reinterpret_cast<QPointF *>(a[0]));
break;
- case QMetaType::QObjectStar:
+ case QV4::CompiledData::Property::Custom:
needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id);
writeProperty(id, *reinterpret_cast<QObject **>(a[0]));
break;
- case QMetaType::QVariant:
+ case QV4::CompiledData::Property::Variant:
writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
break;
- default: {
- QV4::MemberData *md = propertiesAsMemberData();
- if (md) {
+ case QV4::CompiledData::Property::CustomList:
+ // Writing such a property is not supported. Content is added through the list property
+ // methods.
+ break;
+ case QV4::CompiledData::Property::Font:
+ case QV4::CompiledData::Property::Time:
+ case QV4::CompiledData::Property::Color:
+ case QV4::CompiledData::Property::Vector2D:
+ case QV4::CompiledData::Property::Vector3D:
+ case QV4::CompiledData::Property::Vector4D:
+ case QV4::CompiledData::Property::Matrix4x4:
+ case QV4::CompiledData::Property::Quaternion:
+ Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
+ if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
if (!v) {
*(md->data() + id) = cache->engine->newVariantObject(QVariant());
v = (md->data() + id)->as<QV4::VariantObject>();
- QQml_valueTypeProvider()->initValueType(t, v->d()->data);
+ QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data);
}
- needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], v->d()->data);
- QQml_valueTypeProvider()->writeValueType(t, a[0], v->d()->data);
+ needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data);
+ QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data);
}
break;
- }
+ case QV4::CompiledData::Property::Var:
+ Q_UNREACHABLE();
}
}
@@ -758,56 +835,68 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
return -1;
}
- id -= metaData->propertyCount;
-
- if (id < metaData->aliasCount) {
+ id -= propertyCount;
- QQmlVMEMetaData::AliasData *d = metaData->aliasData() + id;
+ if (id < aliasCount) {
+ const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id];
- if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty)
+ if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty)
*reinterpret_cast<void **>(a[0]) = 0;
if (!ctxt) return -1;
+ while (aliasData->aliasToLocalAlias)
+ aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
+
QQmlContext *context = ctxt->asQQmlContext();
QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
- QObject *target = ctxtPriv->data->idValues[d->contextIdx].data();
+ QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId].data();
if (!target)
return -1;
connectAlias(id);
- if (d->isObjectAlias()) {
+ if (aliasData->isObjectAlias()) {
*reinterpret_cast<QObject **>(a[0]) = target;
return -1;
}
+ QQmlData *targetDData = QQmlData::get(target, /*create*/false);
+ if (!targetDData)
+ return -1;
+
+ int coreIndex;
+ const int valueTypePropertyIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, &coreIndex);
+
// Remove binding (if any) on write
if(c == QMetaObject::WriteProperty) {
int flags = *reinterpret_cast<int*>(a[3]);
- if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) {
+ if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) {
QQmlData *targetData = QQmlData::get(target);
- if (targetData && targetData->hasBindingBit(d->propertyIndex()))
- QQmlPropertyPrivate::removeBinding(target, d->propertyIdx);
+ if (targetData && targetData->hasBindingBit(coreIndex))
+ QQmlPropertyPrivate::removeBinding(target, aliasData->encodedMetaPropertyIndex);
}
}
- if (d->isValueTypeAlias()) {
+ if (valueTypePropertyIndex != -1) {
+ if (!targetDData->propertyCache)
+ return -1;
+ const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
// Value type property
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(d->valueType());
+ QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType);
Q_ASSERT(valueType);
- valueType->read(target, d->propertyIndex());
- int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a);
+ valueType->read(target, coreIndex);
+ int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
if (c == QMetaObject::WriteProperty)
- valueType->write(target, d->propertyIndex(), 0x00);
+ valueType->write(target, coreIndex, 0x00);
return rv;
} else {
- return QMetaObject::metacall(target, c, d->propertyIndex(), a);
+ return QMetaObject::metacall(target, c, coreIndex, a);
}
}
@@ -820,8 +909,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (id >= methodOffset()) {
id -= methodOffset();
- int plainSignals = metaData->signalCount + metaData->propertyCount +
- metaData->aliasCount;
+ int plainSignals = signalCount + propertyCount + aliasCount;
if (id < plainSignals) {
activate(object, _id, a);
return -1;
@@ -829,7 +917,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
id -= plainSignals;
- if (id < metaData->methodCount) {
+ if (id < methodCount) {
if (!ctxt->engine)
return -1; // We can't run the method
@@ -853,23 +941,21 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
return -1; // The dynamic method with that id is not available.
}
- QQmlVMEMetaData::MethodData *data = metaData->methodData() + id;
-
- QV4::ScopedCallData callData(scope, data->parameterCount);
+ const unsigned int parameterCount = function->formalParameterCount();
+ QV4::ScopedCallData callData(scope, parameterCount);
callData->thisObject = ep->v8engine()->global();
- for (int ii = 0; ii < data->parameterCount; ++ii)
+ for (uint ii = 0; ii < parameterCount; ++ii)
callData->args[ii] = scope.engine->fromVariant(*(QVariant *)a[ii + 1]);
- QV4::ScopedValue result(scope);
- result = function->call(callData);
+ function->call(scope, callData);
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
if (error.isValid())
ep->warning(error);
if (a[0]) *(QVariant *)a[0] = QVariant();
} else {
- if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(result, 0);
+ if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(scope.result, 0);
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
@@ -887,22 +973,23 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
QV4::ReturnedValue QQmlVMEMetaObject::method(int index)
{
- if (!ctxt || !ctxt->isValid()) {
+ if (!ctxt || !ctxt->isValid() || !compiledObject) {
qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context");
return QV4::Encode::undefined();
}
- if (!methods)
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
+ if (!md)
return QV4::Encode::undefined();
- return methods[index].value();
+ return (md->data() + index + compiledObject->nProperties)->asReturnedValue();
}
QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id)
{
- Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType);
+ Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var);
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
return (md->data() + id)->asReturnedValue();
return QV4::Primitive::undefinedValue().asReturnedValue();
@@ -910,7 +997,7 @@ QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id)
QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
{
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md) {
const QV4::QObjectWrapper *wrapper = (md->data() + id)->as<QV4::QObjectWrapper>();
if (wrapper)
@@ -925,9 +1012,9 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
{
- Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType);
+ Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var);
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
@@ -965,8 +1052,8 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
{
- if ((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType) {
- QV4::MemberData *md = propertiesAsMemberData();
+ if (compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var) {
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
@@ -996,7 +1083,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
needActivate = readPropertyAsQObject(id) != o; // TODO: still correct?
writeProperty(id, o);
} else {
- QV4::MemberData *md = propertiesAsMemberData();
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md) {
QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
needActivate = (!v ||
@@ -1015,61 +1102,16 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
}
}
-void QQmlVMEMetaObject::listChanged(int id)
-{
- activate(object, methodOffset() + id, 0);
-}
-
-void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o)
-{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- list->append(o);
- static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), 0);
-}
-
-int QQmlVMEMetaObject::list_count(QQmlListProperty<QObject> *prop)
-{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->count();
-}
-
-QObject *QQmlVMEMetaObject::list_at(QQmlListProperty<QObject> *prop, int index)
-{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->at(index);
-}
-
-void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop)
-{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- list->clear();
- static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), 0);
-}
-
-quint16 QQmlVMEMetaObject::vmeMethodLineNumber(int index)
-{
- if (index < methodOffset()) {
- Q_ASSERT(parentVMEMetaObject());
- return parentVMEMetaObject()->vmeMethodLineNumber(index);
- }
-
- int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
- Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
-
- int rawIndex = index - methodOffset() - plainSignals;
-
- QQmlVMEMetaData::MethodData *data = metaData->methodData() + rawIndex;
- return data->lineNumber;
-}
-
QV4::ReturnedValue QQmlVMEMetaObject::vmeMethod(int index)
{
if (index < methodOffset()) {
Q_ASSERT(parentVMEMetaObject());
return parentVMEMetaObject()->vmeMethod(index);
}
- int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
- Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
+ if (!compiledObject)
+ return QV4::Primitive::undefinedValue().asReturnedValue();
+ const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases;
+ Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions)));
return method(index - methodOffset() - plainSignals);
}
@@ -1080,14 +1122,16 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function)
Q_ASSERT(parentVMEMetaObject());
return parentVMEMetaObject()->setVmeMethod(index, function);
}
- int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
- Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
-
- if (!methods)
- methods = new QV4::PersistentValue[metaData->methodCount];
+ if (!compiledObject)
+ return;
+ const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases;
+ Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions)));
int methodIndex = index - methodOffset() - plainSignals;
- methods[methodIndex].set(function.as<QV4::Object>()->engine(), function);
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
+ if (!md)
+ return;
+ *(md->data() + methodIndex + compiledObject->nProperties) = function;
}
QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index)
@@ -1122,26 +1166,15 @@ void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e)
if (v4 != e)
return;
- properties.markOnce(e);
+ propertyAndMethodStorage.markOnce(e);
if (QQmlVMEMetaObject *parent = parentVMEMetaObject())
parent->mark(e);
}
-void QQmlVMEMetaObject::allocateProperties()
-{
- Q_ASSERT(cache && cache->engine);
- Q_ASSERT(!properties.valueRef());
- QV4::ExecutionEngine *v4 = cache->engine;
- QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, metaData->propertyCount);
- properties.set(v4, data);
- for (uint i = 0; i < data->size; ++i)
- data->data[i] = QV4::Encode::undefined();
-}
-
bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
{
- Q_ASSERT(index >= propOffset() + metaData->propertyCount);
+ Q_ASSERT(compiledObject && (index >= propOffset() + int(compiledObject->nProperties)));
*target = 0;
*coreIndex = -1;
@@ -1150,31 +1183,24 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
if (!ctxt)
return false;
- QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset() - metaData->propertyCount);
- QQmlContext *context = ctxt->asQQmlContext();
- QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
-
- *target = ctxtPriv->data->idValues[d->contextIdx].data();
+ const int aliasId = index - propOffset() - compiledObject->nProperties;
+ const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
+ *target = ctxt->idValues[aliasData->targetObjectId].data();
if (!*target)
return false;
- if (d->isObjectAlias()) {
- } else if (d->isValueTypeAlias()) {
- *coreIndex = d->propertyIndex();
- *valueTypeIndex = d->valueTypeIndex();
- } else {
- *coreIndex = d->propertyIndex();
- }
-
+ if (!aliasData->isObjectAlias())
+ *valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, coreIndex);
return true;
}
void QQmlVMEMetaObject::connectAlias(int aliasId)
{
+ Q_ASSERT(compiledObject);
if (!aliasEndpoints)
- aliasEndpoints = new QQmlVMEMetaObjectEndpoint[metaData->aliasCount];
+ aliasEndpoints = new QQmlVMEMetaObjectEndpoint[compiledObject->nAliases];
- QQmlVMEMetaData::AliasData *d = metaData->aliasData() + aliasId;
+ const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
QQmlVMEMetaObjectEndpoint *endpoint = aliasEndpoints + aliasId;
if (endpoint->metaObject.data()) {
@@ -1184,14 +1210,15 @@ void QQmlVMEMetaObject::connectAlias(int aliasId)
}
endpoint->metaObject = this;
- endpoint->connect(&ctxt->idValues[d->contextIdx].bindings);
+ endpoint->connect(&ctxt->idValues[aliasData->targetObjectId].bindings);
endpoint->tryConnect();
}
void QQmlVMEMetaObject::connectAliasSignal(int index, bool indexInSignalRange)
{
- int aliasId = (index - (indexInSignalRange ? signalOffset() : methodOffset())) - metaData->propertyCount;
- if (aliasId < 0 || aliasId >= metaData->aliasCount)
+ Q_ASSERT(compiledObject);
+ int aliasId = (index - (indexInSignalRange ? signalOffset() : methodOffset())) - compiledObject->nProperties;
+ if (aliasId < 0 || aliasId >= int(compiledObject->nAliases))
return;
connectAlias(aliasId);
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 98fdae60ee..4a81fc50d2 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -64,82 +64,18 @@
#include <private/qobject_p.h>
#include "qqmlguard_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlcontext_p.h"
+#include "qqmlpropertycache_p.h"
#include <private/qv8engine_p.h>
#include <private/qflagpointer_p.h>
+#include <private/qv4object_p.h>
#include <private/qv4value_p.h>
+#include <private/qqmlpropertyvalueinterceptor_p.h>
QT_BEGIN_NAMESPACE
-#define QML_ALIAS_FLAG_PTR 0x00000001
-
-struct QQmlVMEMetaData
-{
- short propertyCount;
- short aliasCount;
- short signalCount;
- short methodCount;
- // Make sure this structure is always aligned to int
-
- struct AliasData {
- int contextIdx;
- int propertyIdx;
- int propType;
- int flags;
- int notifySignal;
-
- bool isObjectAlias() const {
- return propertyIdx == -1;
- }
- bool isPropertyAlias() const {
- return !isObjectAlias() && valueTypeIndex() == -1;
- }
- bool isValueTypeAlias() const {
- return !isObjectAlias() && valueTypeIndex() != -1;
- }
- int propertyIndex() const {
- int index;
- QQmlPropertyData::decodeValueTypePropertyIndex(propertyIdx, &index);
- return index;
- }
- int valueTypeIndex() const {
- return QQmlPropertyData::decodeValueTypePropertyIndex(propertyIdx);
- }
- int valueType() const {
- return (valueTypeIndex() != -1) ? propType : 0;
- }
- };
-
- enum {
- VarPropertyType = -1
- };
-
- struct PropertyData {
- int propertyType;
- };
-
- struct MethodData {
- int runtimeFunctionIndex;
- int parameterCount;
- quint16 lineNumber;
- };
-
- PropertyData *propertyData() const {
- return (PropertyData *)(((char *)const_cast<QQmlVMEMetaData *>(this)) + sizeof(QQmlVMEMetaData));
- }
-
- AliasData *aliasData() const {
- return (AliasData *)(propertyData() + propertyCount);
- }
-
- MethodData *methodData() const {
- return (MethodData *)(aliasData() + aliasCount);
- }
-};
-
class QQmlVMEMetaObject;
class QQmlVMEVariantQObjectPtr : public QQmlGuard<QObject>
{
@@ -165,18 +101,27 @@ public:
static QQmlInterceptorMetaObject *get(QObject *obj);
- virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *o);
+ QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *o) Q_DECL_OVERRIDE;
// Used by auto-tests for inspection
QQmlPropertyCache *propertyCache() const { return cache; }
+ bool intercepts(int coreIndex) const
+ {
+ for (auto it = interceptors; it; it = it->m_next) {
+ if (it->m_coreIndex == coreIndex)
+ return true;
+ }
+ return false;
+ }
+
protected:
- virtual int metaCall(QObject *o, QMetaObject::Call c, int id, void **a);
+ int metaCall(QObject *o, QMetaObject::Call c, int id, void **a) Q_DECL_OVERRIDE;
bool intercept(QMetaObject::Call c, int id, void **a);
public:
QObject *object;
- QQmlPropertyCache *cache;
+ QQmlRefPointer<QQmlPropertyCache> cache;
QBiPointer<QDynamicMetaObjectData, const QMetaObject> parent;
QQmlPropertyValueInterceptor *interceptors;
@@ -195,18 +140,15 @@ inline QQmlInterceptorMetaObject *QQmlInterceptorMetaObject::get(QObject *obj)
return 0;
}
-class QQmlVMEVariant;
-class QQmlRefCount;
class QQmlVMEMetaObjectEndpoint;
class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject
{
public:
- QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data);
+ QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId);
~QQmlVMEMetaObject();
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
QV4::ReturnedValue vmeMethod(int index);
- quint16 vmeMethodLineNumber(int index);
void setVmeMethod(int index, const QV4::Value &function);
QV4::ReturnedValue vmeProperty(int index);
void setVMEProperty(int index, const QV4::Value &v);
@@ -219,16 +161,11 @@ public:
static QQmlVMEMetaObject *getForSignal(QObject *o, int coreIndex);
protected:
- virtual int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a);
+ int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) Q_DECL_OVERRIDE;
public:
- friend class QQmlVMEMetaObjectEndpoint;
- friend class QQmlVMEVariantQObjectPtr;
- friend class QQmlPropertyCache;
-
QQmlGuardedContextData ctxt;
- const QQmlVMEMetaData *metaData;
inline int propOffset() const;
inline int methodOffset() const;
inline int signalOffset() const;
@@ -236,9 +173,8 @@ public:
QQmlVMEMetaObjectEndpoint *aliasEndpoints;
- QV4::WeakValue properties;
- inline void allocateProperties();
- QV4::MemberData *propertiesAsMemberData();
+ QV4::WeakValue propertyAndMethodStorage;
+ QV4::MemberData *propertyAndMethodStorageAsMemberData();
int readPropertyAsInt(int id);
bool readPropertyAsBool(int id);
@@ -271,7 +207,6 @@ public:
void connectAlias(int aliasId);
- QV4::PersistentValue *methods;
QV4::ReturnedValue method(int);
QV4::ReturnedValue readVarProperty(int);
@@ -281,18 +216,17 @@ public:
inline QQmlVMEMetaObject *parentVMEMetaObject() const;
- void listChanged(int);
-
- static void list_append(QQmlListProperty<QObject> *, QObject *);
- static int list_count(QQmlListProperty<QObject> *);
- static QObject *list_at(QQmlListProperty<QObject> *, int);
- static void list_clear(QQmlListProperty<QObject> *);
-
void activate(QObject *, int, void **);
QList<QQmlVMEVariantQObjectPtr *> varObjectGuards;
QQmlVMEVariantQObjectPtr *getQObjectGuardForProperty(int) const;
+
+
+ // keep a reference to the compilation unit in order to still
+ // do property access when the context has been invalidated.
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ const QV4::CompiledData::Object *compiledObject;
};
QQmlVMEMetaObject *QQmlVMEMetaObject::get(QObject *obj)
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 24f49eb6e7..201d634411 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -70,7 +70,7 @@
using namespace QV4;
-#ifndef QT_NO_XMLSTREAMREADER
+#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_NETWORK)
#define V4THROW_REFERENCE(string) { \
ScopedObject error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \
@@ -158,7 +158,7 @@ class DocumentImpl : public QQmlRefCount, public NodeImpl
public:
DocumentImpl() : root(0) { type = Document; }
virtual ~DocumentImpl() {
- if (root) delete root;
+ delete root;
}
QString version;
@@ -715,7 +715,7 @@ ReturnedValue Text::method_isElementContentWhitespace(CallContext *ctx)
Scoped<Node> r(scope, ctx->thisObject().as<Node>());
if (!r) return Encode::undefined();
- return Encode(r->d()->d->data.trimmed().isEmpty());
+ return Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty());
}
ReturnedValue Text::method_wholeText(CallContext *ctx)
@@ -1235,7 +1235,8 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
} else if (m_method == QLatin1String("DELETE")) {
m_network = networkAccessManager()->deleteResource(request);
} else if ((m_method == QLatin1String("OPTIONS")) ||
- m_method == QLatin1String("PROPFIND")) {
+ m_method == QLatin1String("PROPFIND") ||
+ m_method == QLatin1String("PATCH")) {
QBuffer *buffer = new QBuffer;
buffer->setData(m_data);
buffer->open(QIODevice::ReadOnly);
@@ -1559,7 +1560,7 @@ void QQmlXMLHttpRequest::dispatchCallback(Object *thisObj, QQmlContextData *cont
QV4::ScopedCallData callData(scope);
callData->thisObject = Encode::undefined();
- callback->call(callData);
+ callback->call(scope, callData);
if (scope.engine->hasException) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
@@ -1620,22 +1621,23 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
c->proto->mark(e);
FunctionObject::markObjects(that, e);
}
- static ReturnedValue construct(const Managed *that, QV4::CallData *)
+ static void construct(const Managed *that, Scope &scope, QV4::CallData *)
{
- Scope scope(static_cast<const QQmlXMLHttpRequestCtor *>(that)->engine());
Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>());
- if (!ctor)
- return scope.engine->throwTypeError();
+ if (!ctor) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager());
Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocObject<QQmlXMLHttpRequestWrapper>(r));
ScopedObject proto(scope, ctor->d()->proto);
w->setPrototype(proto);
- return w.asReturnedValue();
+ scope.result = w.asReturnedValue();
}
- static ReturnedValue call(const Managed *, QV4::CallData *) {
- return Primitive::undefinedValue().asReturnedValue();
+ static void call(const Managed *, Scope &scope, QV4::CallData *) {
+ scope.result = Primitive::undefinedValue();
}
void setupProto();
@@ -1735,7 +1737,8 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
method != QLatin1String("POST") &&
method != QLatin1String("DELETE") &&
method != QLatin1String("OPTIONS") &&
- method != QLatin1String("PROPFIND"))
+ method != QLatin1String("PROPFIND") &&
+ method != QLatin1String("PATCH"))
V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
// Argument 1 - URL
@@ -2038,6 +2041,6 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4)
QT_END_NAMESPACE
-#endif // QT_NO_XMLSTREAMREADER
+#endif // QT_NO_XMLSTREAMREADER && QT_NO_NETWORK
#include <qqmlxmlhttprequest.moc>
diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h
index 7bbfb5243c..df30873915 100644
--- a/src/qml/qml/qqmlxmlhttprequest_p.h
+++ b/src/qml/qml/qqmlxmlhttprequest_p.h
@@ -55,7 +55,7 @@
#include <QtCore/qglobal.h>
#include <private/qqmlglobal_p.h>
-#ifndef QT_NO_XMLSTREAMREADER
+#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_NETWORK)
QT_BEGIN_NAMESPACE
@@ -64,7 +64,7 @@ void qt_rem_qmlxmlhttprequest(QV4::ExecutionEngine *engine, void *);
QT_END_NAMESPACE
-#endif // QT_NO_XMLSTREAMREADER
+#endif // QT_NO_XMLSTREAMREADER && QT_NO_NETWORK
#endif // QQMLXMLHTTPREQUEST_P_H
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index b9fb1f4ffe..76a900c846 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -45,6 +45,7 @@
#include <private/qqmlstringconverters_p.h>
#include <private/qqmllocale_p.h>
#include <private/qv8engine_p.h>
+#include <private/qqmldelayedcallqueue_p.h>
#include <QFileInfo>
#include <private/qqmldebugconnector_p.h>
@@ -146,6 +147,8 @@ Heap::QtObject::QtObject(QQmlEngine *qmlEngine)
o->defineAccessorProperty(QStringLiteral("inputMethod"), QV4::QtObject::method_get_inputMethod, 0);
#endif
o->defineAccessorProperty(QStringLiteral("styleHints"), QV4::QtObject::method_get_styleHints, 0);
+
+ o->defineDefaultProperty(QStringLiteral("callLater"), QV4::QtObject::method_callLater);
}
void QtObject::addAll()
@@ -1282,11 +1285,10 @@ void QQmlBindingFunction::initBindingLocation()
d()->bindingLocation.line = frame.line;
}
-ReturnedValue QQmlBindingFunction::call(const Managed *that, CallData *callData)
+void QQmlBindingFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const QQmlBindingFunction*>(that)->engine());
ScopedFunctionObject function(scope, static_cast<const QQmlBindingFunction*>(that)->d()->originalFunction);
- return function->call(callData);
+ function->call(scope, callData);
}
void QQmlBindingFunction::markObjects(Heap::Base *that, ExecutionEngine *e)
@@ -1995,6 +1997,31 @@ ReturnedValue GlobalExtensions::method_string_arg(CallContext *ctx)
return ctx->d()->engine->newString(value.arg(arg->toQString()))->asReturnedValue();
}
+/*!
+\qmlmethod Qt::callLater(function)
+\qmlmethod Qt::callLater(function, argument1, argument2, ...)
+\since 5.8
+Use this function to eliminate redundant calls to a function or signal.
+
+The function passed as the first argument to Qt.callLater()
+will be called later, once the QML engine returns to the event loop.
+
+When this function is called multiple times in quick succession with the
+same function as its first argument, that function will be called only once.
+
+For example:
+\snippet qml/qtLater.qml 0
+
+Any additional arguments passed to Qt.callLater() will
+be passed on to the function invoked. Note that if redundant calls
+are eliminated, then only the last set of arguments will be passed to the
+function.
+*/
+ReturnedValue QtObject::method_callLater(CallContext *ctx)
+{
+ QV8Engine *v8engine = ctx->engine()->v8Engine;
+ return v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(ctx);
+}
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index dc806c6031..d29983c476 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -135,6 +135,8 @@ struct QtObject : Object
#endif
static ReturnedValue method_get_styleHints(CallContext *ctx);
+ static ReturnedValue method_callLater(CallContext *ctx);
+
private:
void addAll();
ReturnedValue findAndAdd(const QString *name, bool &foundProperty) const;
@@ -186,7 +188,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject
void initBindingLocation(); // from caller stack trace
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 46fd4fbbeb..e08ff3b979 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -150,6 +150,7 @@ QV8Engine::QV8Engine(QJSEngine* qq)
m_v4Engine = new QV4::ExecutionEngine;
m_v4Engine->v8Engine = this;
+ m_delayedCallQueue.init(m_v4Engine);
QV4::QObjectWrapper::initializeBindings(m_v4Engine);
}
@@ -159,18 +160,22 @@ QV8Engine::~QV8Engine()
qDeleteAll(m_extensionData);
m_extensionData.clear();
+#if !defined(QT_NO_XMLSTREAMREADER) && defined(QT_NO_NETWORK)
qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData);
m_xmlHttpRequestData = 0;
+#endif
delete m_listModelData;
m_listModelData = 0;
delete m_v4Engine;
}
+#ifndef QT_NO_NETWORK
QNetworkAccessManager *QV8Engine::networkAccessManager()
{
return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager();
}
+#endif
const QSet<QString> &QV8Engine::illegalNames() const
{
@@ -189,8 +194,10 @@ void QV8Engine::initializeGlobal()
QQmlDateExtension::registerExtension(m_v4Engine);
QQmlNumberExtension::registerExtension(m_v4Engine);
+#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_NETWORK)
qt_add_domexceptions(m_v4Engine);
m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(m_v4Engine);
+#endif
qt_add_sqlexceptions(m_v4Engine);
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index 2cfa996409..390831609b 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -67,6 +67,7 @@
#include <private/qv4value_p.h>
#include <private/qv4identifier_p.h>
#include <private/qv4context_p.h>
+#include <private/qqmldelayedcallqueue_p.h>
QT_BEGIN_NAMESPACE
@@ -76,12 +77,6 @@ namespace QV4 {
struct QObjectMethod;
}
-// Uncomment the following line to enable global handle debugging. When enabled, all the persistent
-// handles allocated using qPersistentNew() (or registered with qPersistentRegsiter()) and disposed
-// with qPersistentDispose() are tracked. If you try and do something illegal, like double disposing
-// a handle, qFatal() is called.
-// #define QML_GLOBAL_HANDLE_DEBUGGING
-
#define V4THROW_ERROR(string) \
return ctx->engine()->throwError(QString::fromUtf8(string));
@@ -184,6 +179,7 @@ public:
QQmlEngine *engine() { return m_engine; }
QJSEngine *publicEngine() { return q; }
QV4::ReturnedValue global();
+ QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; }
void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
@@ -192,10 +188,12 @@ public:
void freezeObject(const QV4::Value &value);
+#ifndef QT_NO_NETWORK
// Return the network access manager for this engine. By default this returns the network
// access manager of the QQmlEngine. It is overridden in the case of a threaded v8
// instance (like in WorkerScript).
virtual QNetworkAccessManager *networkAccessManager();
+#endif
// Return the list of illegal id names (the names of the properties on the global object)
const QSet<QString> &illegalNames() const;
@@ -217,6 +215,7 @@ public:
protected:
QJSEngine* q;
QQmlEngine *m_engine;
+ QQmlDelayedCallQueue m_delayedCallQueue;
QV4::ExecutionEngine *m_v4Engine;
diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri
index 3d6a012481..4592022939 100644
--- a/src/qml/qml/v8/v8.pri
+++ b/src/qml/qml/v8/v8.pri
@@ -9,4 +9,3 @@ SOURCES += \
$$PWD/qv4domerrors.cpp \
$$PWD/qv4sqlerrors.cpp \
$$PWD/qqmlbuiltinfunctions.cpp
-
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index ed9a8533c0..a545fe57ca 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -51,6 +51,7 @@
#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
#include <private/qobject_p.h>
@@ -59,16 +60,18 @@ QT_BEGIN_NAMESPACE
class QQmlBindPrivate : public QObjectPrivate
{
public:
- QQmlBindPrivate() : componentComplete(true), obj(0) {}
+ QQmlBindPrivate() : obj(0), componentComplete(true), delayed(false), pendingEval(false) {}
~QQmlBindPrivate() { }
QQmlNullableValue<bool> when;
- bool componentComplete;
QPointer<QObject> obj;
QString propName;
QQmlNullableValue<QVariant> value;
QQmlProperty prop;
QQmlAbstractBinding::Ptr prevBind;
+ bool componentComplete:1;
+ bool delayed:1;
+ bool pendingEval:1;
void validate(QObject *binding) const;
};
@@ -281,7 +284,43 @@ void QQmlBind::setValue(const QVariant &v)
{
Q_D(QQmlBind);
d->value = v;
- eval();
+ prepareEval();
+}
+
+/*!
+ \qmlproperty bool QtQml::Binding::delayed
+ \since 5.8
+
+ This property holds whether the binding should be delayed.
+
+ A delayed binding will not immediately update the target, but rather wait
+ until the event queue has been cleared. This can be used as an optimization,
+ or to prevent intermediary values from being assigned.
+
+ \code
+ Binding {
+ target: contactName; property: 'text'
+ value: givenName + " " + familyName; when: list.ListView.isCurrentItem
+ delayed: true
+ }
+ \endcode
+*/
+bool QQmlBind::delayed() const
+{
+ Q_D(const QQmlBind);
+ return d->delayed;
+}
+
+void QQmlBind::setDelayed(bool delayed)
+{
+ Q_D(QQmlBind);
+ if (d->delayed == delayed)
+ return;
+
+ d->delayed = delayed;
+
+ if (!d->delayed)
+ eval();
}
void QQmlBind::setTarget(const QQmlProperty &p)
@@ -307,9 +346,22 @@ void QQmlBind::componentComplete()
eval();
}
+void QQmlBind::prepareEval()
+{
+ Q_D(QQmlBind);
+ if (d->delayed) {
+ if (!d->pendingEval)
+ QTimer::singleShot(0, this, &QQmlBind::eval);
+ d->pendingEval = true;
+ } else {
+ eval();
+ }
+}
+
void QQmlBind::eval()
{
Q_D(QQmlBind);
+ d->pendingEval = false;
if (!d->prop.isValid() || d->value.isNull || !d->componentComplete)
return;
diff --git a/src/qml/types/qqmlbind_p.h b/src/qml/types/qqmlbind_p.h
index 581995af56..77939a40bc 100644
--- a/src/qml/types/qqmlbind_p.h
+++ b/src/qml/types/qqmlbind_p.h
@@ -68,6 +68,7 @@ class Q_AUTOTEST_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSourc
Q_PROPERTY(QString property READ property WRITE setProperty)
Q_PROPERTY(QVariant value READ value WRITE setValue)
Q_PROPERTY(bool when READ when WRITE setWhen)
+ Q_PROPERTY(bool delayed READ delayed WRITE setDelayed REVISION 8)
public:
QQmlBind(QObject *parent=0);
@@ -85,12 +86,16 @@ public:
QVariant value() const;
void setValue(const QVariant &);
+ bool delayed() const;
+ void setDelayed(bool);
+
protected:
virtual void setTarget(const QQmlProperty &);
virtual void classBegin();
virtual void componentComplete();
private:
+ void prepareEval();
void eval();
};
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index a16acac3ab..84782114ac 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -44,7 +44,6 @@
#include <private/qqmlboundsignal_p.h>
#include <qqmlcontext.h>
#include <private/qqmlcontext_p.h>
-#include <private/qqmlcompiler_p.h>
#include <qqmlinfo.h>
#include <QtCore/qdebug.h>
@@ -67,7 +66,7 @@ public:
bool ignoreUnknownSignals;
bool componentcomplete;
- QQmlRefPointer<QQmlCompiledData> cdata;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding *> bindings;
};
@@ -258,11 +257,11 @@ void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::Unit *qmlUni
}
}
-void QQmlConnectionsParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
+void QQmlConnectionsParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
QQmlConnectionsPrivate *p =
static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object));
- p->cdata = cdata;
+ p->compilationUnit = compilationUnit;
p->bindings = bindings;
}
@@ -278,7 +277,7 @@ void QQmlConnections::connectSignals()
QQmlData *ddata = QQmlData::get(this);
QQmlContextData *ctxtdata = ddata ? ddata->outerContext : 0;
- const QV4::CompiledData::Unit *qmlUnit = d->cdata->compilationUnit->data;
+ const QV4::CompiledData::Unit *qmlUnit = d->compilationUnit->data;
foreach (const QV4::CompiledData::Binding *binding, d->bindings) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
QString propName = qmlUnit->stringAt(binding->propertyNameIndex);
@@ -291,7 +290,7 @@ void QQmlConnections::connectSignals()
QQmlBoundSignalExpression *expression = ctxtdata ?
new QQmlBoundSignalExpression(target, signalIndex,
- ctxtdata, this, d->cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0;
+ ctxtdata, this, d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0;
signal->takeExpression(expression);
d->boundsignals += signal;
} else {
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index ff128a0ca6..d454affba8 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -99,7 +99,7 @@ class QQmlConnectionsParser : public QQmlCustomParser
{
public:
virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
- virtual void applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings);
+ virtual void applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
};
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 0e7b0c1b14..d6d4553946 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -48,7 +48,6 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmlincubator_p.h>
-#include <private/qqmlcompiler_p.h>
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
@@ -92,17 +91,17 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
return scope->engine()->memoryManager->allocObject<DelegateModelGroupFunction>(scope, flag, code);
}
- static QV4::ReturnedValue call(const QV4::Managed *that, QV4::CallData *callData)
+ static void call(const QV4::Managed *that, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::ExecutionEngine *v4 = static_cast<const DelegateModelGroupFunction *>(that)->engine();
- QV4::Scope scope(v4);
QV4::Scoped<DelegateModelGroupFunction> f(scope, static_cast<const DelegateModelGroupFunction *>(that));
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject);
- if (!o)
- return v4->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ if (!o) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return;
+ }
QV4::ScopedValue v(scope, callData->argument(0));
- return f->d()->code(o->d()->item, f->d()->flag, v);
+ scope.result = f->d()->code(o->d()->item, f->d()->flag, v);
}
};
@@ -235,10 +234,8 @@ void QQmlDelegateModelPrivate::init()
}
QQmlDelegateModel::QQmlDelegateModel()
-: QQmlInstanceModel(*(new QQmlDelegateModelPrivate(0)))
+ : QQmlDelegateModel(nullptr, nullptr)
{
- Q_D(QQmlDelegateModel);
- d->init();
}
QQmlDelegateModel::QQmlDelegateModel(QQmlContext *ctxt, QObject *parent)
@@ -1657,7 +1654,7 @@ void QQmlDelegateModelItemMetaType::initializeMetaObject()
int notifierId = 0;
for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
- QString propertyName = QStringLiteral("in") + groupNames.at(i);
+ QString propertyName = QLatin1String("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
QMetaPropertyBuilder propertyBuilder = builder.addProperty(
@@ -1665,7 +1662,7 @@ void QQmlDelegateModelItemMetaType::initializeMetaObject()
propertyBuilder.setWritable(true);
}
for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
- const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
+ const QString propertyName = groupNames.at(i) + QLatin1String("Index");
builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
QMetaPropertyBuilder propertyBuilder = builder.addProperty(
propertyName.toUtf8(), "int", notifierId);
@@ -1713,7 +1710,7 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
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);
+ QString propertyName = QLatin1String("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
s = v4->newString(propertyName);
p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_member)));
@@ -1721,7 +1718,7 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
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");
+ const QString propertyName = groupNames.at(i) + QLatin1String("Index");
s = v4->newString(propertyName);
p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_index)));
p->setSetter(0);
@@ -1921,9 +1918,10 @@ void QQmlDelegateModelItem::incubateObject(
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
- incubatorPriv->compiledData = componentPriv->cc;
- incubatorPriv->compiledData->addref();
- incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->cc, componentPriv->creationContext));
+ incubatorPriv->compilationUnit = componentPriv->compilationUnit;
+ incubatorPriv->compilationUnit->addref();
+ incubatorPriv->enginePriv = enginePriv;
+ incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
incubatorPriv->subComponentToCreate = componentPriv->start;
enginePriv->incubate(*incubationTask, forContext);
@@ -2322,7 +2320,7 @@ QQmlDelegateModelGroup::QQmlDelegateModelGroup(QObject *parent)
QQmlDelegateModelGroup::QQmlDelegateModelGroup(
const QString &name, QQmlDelegateModel *model, int index, QObject *parent)
- : QObject(*new QQmlDelegateModelGroupPrivate, parent)
+ : QQmlDelegateModelGroup(parent)
{
Q_D(QQmlDelegateModelGroup);
d->name = name;
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 1e1ebc4939..f7fdbf0d80 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -42,7 +42,6 @@
#include <private/qqmlopenmetaobject_p.h>
#include <private/qqmljsast_p.h>
#include <private/qqmljsengine_p.h>
-#include <private/qqmlcompiler_p.h>
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlengine_p.h>
@@ -79,13 +78,16 @@ static bool isMemoryUsed(const char *mem)
static QString roleTypeName(ListLayout::Role::DataType t)
{
- QString result;
- const char *roleTypeNames[] = { "String", "Number", "Bool", "List", "QObject", "VariantMap", "DateTime" };
+ static const QString roleTypeNames[] = {
+ QStringLiteral("String"), QStringLiteral("Number"), QStringLiteral("Bool"),
+ QStringLiteral("List"), QStringLiteral("QObject"), QStringLiteral("VariantMap"),
+ QStringLiteral("DateTime")
+ };
if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType)
- result = QString::fromLatin1(roleTypeNames[t]);
+ return roleTypeNames[t];
- return result;
+ return QString();
}
const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::DataType type)
@@ -1440,8 +1442,7 @@ void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int>
const QByteArray &keyUtf8 = key.toUtf8();
QQmlListModel *existingModel = qobject_cast<QQmlListModel *>(m_meta->value(keyUtf8).value<QObject *>());
- if (existingModel)
- delete existingModel;
+ delete existingModel;
if (m_meta->setValue(keyUtf8, value))
roles << roleIndex;
@@ -1457,8 +1458,7 @@ DynamicRoleModelNodeMetaObject::~DynamicRoleModelNodeMetaObject()
{
for (int i=0 ; i < count() ; ++i) {
QQmlListModel *subModel = qobject_cast<QQmlListModel *>(value(i).value<QObject *>());
- if (subModel)
- delete subModel;
+ delete subModel;
}
}
@@ -1469,8 +1469,7 @@ void DynamicRoleModelNodeMetaObject::propertyWrite(int index)
QVariant v = value(index);
QQmlListModel *model = qobject_cast<QQmlListModel *>(v.value<QObject *>());
- if (model)
- delete model;
+ delete model;
}
void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
@@ -1981,15 +1980,7 @@ void QQmlListModel::setDynamicRoles(bool enableDynamicRoles)
*/
int QQmlListModel::count() const
{
- int count;
-
- if (m_dynamicRoles)
- count = m_modelObjects.count();
- else {
- count = m_listModel->elementCount();
- }
-
- return count;
+ return m_dynamicRoles ? m_modelObjects.count() : m_listModel->elementCount();
}
/*!
@@ -2001,7 +1992,7 @@ int QQmlListModel::count() const
*/
void QQmlListModel::clear()
{
- int cleared = count();
+ const int cleared = count();
emitItemsAboutToBeRemoved(0, cleared);
@@ -2411,7 +2402,7 @@ bool QQmlListModelParser::verifyProperty(const QV4::CompiledData::Unit *qmlUnit,
listElementTypeName = objName; // cache right name for next time
}
- if (!qmlUnit->stringAt(target->idIndex).isEmpty()) {
+ if (!qmlUnit->stringAt(target->idNameIndex).isEmpty()) {
error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property"));
return false;
}
@@ -2518,13 +2509,13 @@ void QQmlListModelParser::verifyBindings(const QV4::CompiledData::Unit *qmlUnit,
}
}
-void QQmlListModelParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
+void QQmlListModelParser::applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
QQmlListModel *rv = static_cast<QQmlListModel *>(obj);
rv->m_engine = QV8Engine::getV4(qmlEngine(rv));
- const QV4::CompiledData::Unit *qmlUnit = cdata->compilationUnit->data;
+ const QV4::CompiledData::Unit *qmlUnit = compilationUnit->data;
bool setRoles = false;
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
index b35a5a1224..220b0e54b5 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qml/types/qqmllistmodel_p.h
@@ -187,8 +187,8 @@ public:
QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
- virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
- virtual void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings);
+ void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
+ void applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
private:
bool verifyProperty(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding);
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index f519b5ff61..d3ff032ae9 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -199,7 +199,7 @@ public:
explicit Role(const Role *other);
~Role();
- // This enum must be kept in sync with the roleTypeNames variable in qdeclarativelistmodel.cpp
+ // This enum must be kept in sync with the roleTypeNames variable in qqmllistmodel.cpp
enum DataType
{
Invalid = -1,
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index e819e4ee7d..10666476fe 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -52,10 +52,12 @@
#include <QtCore/qwaitcondition.h>
#include <QtCore/qfile.h>
#include <QtCore/qdatetime.h>
-#include <QtNetwork/qnetworkaccessmanager.h>
#include <QtQml/qqmlinfo.h>
#include <QtQml/qqmlfile.h>
+#ifndef QT_NO_NETWORK
+#include <QtNetwork/qnetworkaccessmanager.h>
#include "qqmlnetworkaccessmanagerfactory.h"
+#endif
#include <private/qv8engine_p.h>
#include <private/qv4serialize_p.h>
@@ -141,7 +143,10 @@ public:
~WorkerEngine();
void init();
+
+#ifndef QT_NO_NETWORK
virtual QNetworkAccessManager *networkAccessManager();
+#endif
QQuickWorkerScriptEnginePrivate *p;
@@ -150,7 +155,9 @@ public:
QV4::PersistentValue onmessage;
private:
QV4::PersistentValue createsend;
+#ifndef QT_NO_NETWORK
QNetworkAccessManager *accessManager;
+#endif
};
WorkerEngine *workerEngine;
@@ -194,14 +201,19 @@ private:
};
QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEnginePrivate *parent)
-: QV8Engine(0), p(parent), accessManager(0)
+: QV8Engine(0), p(parent)
+#ifndef QT_NO_NETWORK
+, accessManager(0)
+#endif
{
m_v4Engine->v8Engine = this;
}
QQuickWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine()
{
+#ifndef QT_NO_NETWORK
delete accessManager;
+#endif
}
void QQuickWorkerScriptEnginePrivate::WorkerEngine::init()
@@ -239,7 +251,8 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init()
QV4::ScopedCallData callData(scope, 1);
callData->args[0] = function;
callData->thisObject = global();
- createsend.set(scope.engine, createsendconstructor->call(callData));
+ createsendconstructor->call(scope, callData);
+ createsend.set(scope.engine, scope.result.asReturnedValue());
}
// Requires handle and context scope
@@ -252,16 +265,16 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(i
QV4::Scope scope(v4);
QV4::ScopedFunctionObject f(scope, createsend.value());
- QV4::ScopedValue v(scope);
QV4::ScopedCallData callData(scope, 1);
callData->args[0] = QV4::Primitive::fromInt32(id);
callData->thisObject = global();
- v = f->call(callData);
+ f->call(scope, callData);
if (scope.hasException())
- v = scope.engine->catchException();
- return v->asReturnedValue();
+ scope.result = scope.engine->catchException();
+ return scope.result.asReturnedValue();
}
+#ifndef QT_NO_NETWORK
QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager()
{
if (!accessManager) {
@@ -273,6 +286,7 @@ QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerEngine::networkAcc
}
return accessManager;
}
+#endif
QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *engine)
: workerEngine(0), qmlengine(engine), m_nextId(0)
@@ -366,7 +380,7 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d
callData->thisObject = workerEngine->global();
callData->args[0] = qmlContext->d()->qml; // ###
callData->args[1] = value;
- f->call(callData);
+ f->call(scope, callData);
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
reportScriptException(script, error);